libopenmpt-0.8.1+release.autotools/0000755000175000017500000000000015023302363014333 500000000000000libopenmpt-0.8.1+release.autotools/soundlib/0000755000175000017500000000000015023302362016151 500000000000000libopenmpt-0.8.1+release.autotools/soundlib/Load_far.cpp0000644000175000017500000001721014644610543020320 00000000000000/* * Load_far.cpp * ------------ * Purpose: Farandole (FAR) module loader * Notes : (currently none) * Authors: OpenMPT Devs (partly inspired by Storlek's FAR loader from Schism Tracker) * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN // FAR File Header struct FARFileHeader { uint8le magic[4]; char songName[40]; uint8le eof[3]; uint16le headerLength; uint8le version; uint8le onOff[16]; uint8le editingState[9]; // Stuff we don't care about uint8le defaultSpeed; uint8le chnPanning[16]; uint8le patternState[4]; // More stuff we don't care about uint16le messageLength; }; MPT_BINARY_STRUCT(FARFileHeader, 98) struct FAROrderHeader { uint8le orders[256]; uint8le numPatterns; // supposed to be "number of patterns stored in the file"; apparently that's wrong uint8le numOrders; uint8le restartPos; uint16le patternSize[256]; }; MPT_BINARY_STRUCT(FAROrderHeader, 771) // FAR Sample header struct FARSampleHeader { // Sample flags enum SampleFlags { smp16Bit = 0x01, smpLoop = 0x08, }; char name[32]; uint32le length; uint8le finetune; uint8le volume; uint32le loopStart; uint32le loopEnd; uint8le type; uint8le loop; // Convert sample header to OpenMPT's internal format. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; mptSmp.nC5Speed = 8363 * 2; mptSmp.nVolume = volume * 16; if(type & smp16Bit) { mptSmp.nLength /= 2; mptSmp.nLoopStart /= 2; mptSmp.nLoopEnd /= 2; } if((loop & 8) && mptSmp.nLoopEnd > mptSmp.nLoopStart) { mptSmp.uFlags.set(CHN_LOOP); } } // Retrieve the internal sample format flags for this sample. SampleIO GetSampleFormat() const { return SampleIO( (type & smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM); } }; MPT_BINARY_STRUCT(FARSampleHeader, 48) static bool ValidateHeader(const FARFileHeader &fileHeader) { if(std::memcmp(fileHeader.magic, "FAR\xFE", 4) != 0 || std::memcmp(fileHeader.eof, "\x0D\x0A\x1A", 3) ) { return false; } if(fileHeader.headerLength < sizeof(FARFileHeader)) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const FARFileHeader &fileHeader) { return fileHeader.headerLength - sizeof(FARFileHeader); } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize) { FARFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadFAR(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); FARFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } // Globals InitializeGlobals(MOD_TYPE_FAR, 16); m_nSamplePreAmp = 32; Order().SetDefaultSpeed(fileHeader.defaultSpeed); Order().SetDefaultTempoInt(80); m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; m_SongFlags = SONG_LINEARSLIDES | SONG_AUTO_TONEPORTA | SONG_AUTO_TONEPORTA_CONT; m_playBehaviour.set(kPeriodsAreHertz); m_modFormat.formatName = UL_("Farandole Composer"); m_modFormat.type = UL_("far"); m_modFormat.charset = mpt::Charset::CP437; m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songName); // Read channel settings for(CHANNELINDEX chn = 0; chn < 16; chn++) { ChnSettings[chn].dwFlags = fileHeader.onOff[chn] ? ChannelFlags(0) : CHN_MUTE; ChnSettings[chn].nPan = ((fileHeader.chnPanning[chn] & 0x0F) << 4) + 8; } // Read song message if(fileHeader.messageLength != 0) { m_songMessage.ReadFixedLineLength(file, fileHeader.messageLength, 132, 0); // 132 characters per line... wow. :) } // Read orders FAROrderHeader orderHeader; if(!file.ReadStruct(orderHeader)) { return false; } ReadOrderFromArray(Order(), orderHeader.orders, orderHeader.numOrders, 0xFF, 0xFE); Order().SetRestartPos(orderHeader.restartPos); file.Seek(fileHeader.headerLength); // Pattern effect LUT static constexpr EffectCommand farEffects[] = { CMD_NONE, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_RETRIG, CMD_VIBRATO, // depth CMD_VIBRATO, // speed CMD_VOLUMESLIDE, // up CMD_VOLUMESLIDE, // down CMD_VIBRATO, // sustained (?) CMD_NONE, // actually slide-to-volume CMD_S3MCMDEX, // panning CMD_S3MCMDEX, // note offset => note delay? CMD_NONE, // fine tempo down CMD_NONE, // fine tempo up CMD_SPEED, }; // Read patterns for(PATTERNINDEX pat = 0; pat < 256; pat++) { if(!orderHeader.patternSize[pat]) { continue; } FileReader patternChunk = file.ReadChunk(orderHeader.patternSize[pat]); // Calculate pattern length in rows (every event is 4 bytes, and we have 16 channels) ROWINDEX numRows = (orderHeader.patternSize[pat] - 2) / (16 * 4); if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, numRows)) { continue; } // Read break row and unused value (used to be pattern tempo) ROWINDEX breakRow = patternChunk.ReadUint8(); patternChunk.Skip(1); if(breakRow > 0 && breakRow < numRows - 2) breakRow++; else breakRow = ROWINDEX_INVALID; // Read pattern data for(ROWINDEX row = 0; row < numRows; row++) { for(ModCommand &m : Patterns[pat].GetRow(row)) { const auto [note, instr, volume, effect] = patternChunk.ReadArray(); if(note > 0 && note <= 72) { m.note = note + 35 + NOTE_MIN; m.instr = instr + 1; } if(volume > 0 && volume <= 16) { m.SetVolumeCommand(VOLCMD_VOLUME, static_cast((volume - 1u) * 64u / 15u)); } m.param = effect & 0x0F; switch(effect >> 4) { case 0x01: case 0x02: m.param |= 0xF0; break; case 0x03: // Porta to note (TODO: Parameter is number of rows the portamento should take) if(m.param != 0) m.param = 60 / m.param; break; case 0x04: // Retrig m.param = static_cast(6 / (1 + (m.param & 0xf)) + 1); break; case 0x06: // Vibrato speed case 0x07: // Volume slide up m.param *= 8; break; case 0x0A: // Volume-portamento (what!) m.volcmd = VOLCMD_VOLUME; m.vol = static_cast((m.param << 2) + 4); break; case 0x0B: // Panning m.param |= 0x80; break; case 0x0C: // Note offset m.param = static_cast(6 / (1 + m.param) + 1); m.param |= 0x0D; } m.command = farEffects[effect >> 4]; } } Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(breakRow).RetryNextRow()); } if(!(loadFlags & loadSampleData)) { return true; } // Read samples uint8 sampleMap[8]; // Sample usage bitset file.ReadArray(sampleMap); for(SAMPLEINDEX smp = 0; smp < 64; smp++) { if(!(sampleMap[smp >> 3] & (1 << (smp & 7)))) { continue; } FARSampleHeader sampleHeader; if(!file.ReadStruct(sampleHeader)) { return true; } m_nSamples = smp + 1; ModSample &sample = Samples[m_nSamples]; m_szNames[m_nSamples] = mpt::String::ReadBuf(mpt::String::nullTerminated, sampleHeader.name); sampleHeader.ConvertToMPT(sample); sampleHeader.GetSampleFormat().ReadSample(sample, file); } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ModSampleCopy.h0000644000175000017500000001316114053010430020752 00000000000000/* * ModSampleCopy.h * --------------- * Purpose: Functions for copying ModSample data. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/soundbase/SampleDecode.hpp" OPENMPT_NAMESPACE_BEGIN struct ModSample; // Copy a mono sample data buffer. template size_t CopyMonoSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion()) { MPT_ASSERT(sample.GetNumChannels() == 1); MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t)); const size_t frameSize = SampleConversion::input_inc; const size_t countFrames = std::min(sourceSize / frameSize, static_cast(sample.nLength)); size_t numFrames = countFrames; SampleConversion sampleConv(conv); const std::byte * MPT_RESTRICT inBuf = mpt::byte_cast(sourceBuffer); typename SampleConversion::output_t * MPT_RESTRICT outBuf = static_cast(sample.samplev()); while(numFrames--) { *outBuf = sampleConv(inBuf); inBuf += SampleConversion::input_inc; outBuf++; } return frameSize * countFrames; } // Copy a stereo interleaved sample data buffer. template size_t CopyStereoInterleavedSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion()) { MPT_ASSERT(sample.GetNumChannels() == 2); MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t)); const size_t frameSize = 2 * SampleConversion::input_inc; const size_t countFrames = std::min(sourceSize / frameSize, static_cast(sample.nLength)); size_t numFrames = countFrames; SampleConversion sampleConvLeft(conv); SampleConversion sampleConvRight(conv); const std::byte * MPT_RESTRICT inBuf = mpt::byte_cast(sourceBuffer); typename SampleConversion::output_t * MPT_RESTRICT outBuf = static_cast(sample.samplev()); while(numFrames--) { *outBuf = sampleConvLeft(inBuf); inBuf += SampleConversion::input_inc; outBuf++; *outBuf = sampleConvRight(inBuf); inBuf += SampleConversion::input_inc; outBuf++; } return frameSize * countFrames; } // Copy a stereo split sample data buffer. template size_t CopyStereoSplitSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion()) { MPT_ASSERT(sample.GetNumChannels() == 2); MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t)); const size_t sampleSize = SampleConversion::input_inc; const size_t sourceSizeLeft = std::min(static_cast(sample.nLength) * SampleConversion::input_inc, sourceSize); const size_t sourceSizeRight = std::min(static_cast(sample.nLength) * SampleConversion::input_inc, sourceSize - sourceSizeLeft); const size_t countSamplesLeft = sourceSizeLeft / sampleSize; const size_t countSamplesRight = sourceSizeRight / sampleSize; size_t numSamplesLeft = countSamplesLeft; SampleConversion sampleConvLeft(conv); const std::byte * MPT_RESTRICT inBufLeft = mpt::byte_cast(sourceBuffer); typename SampleConversion::output_t * MPT_RESTRICT outBufLeft = static_cast(sample.samplev()); while(numSamplesLeft--) { *outBufLeft = sampleConvLeft(inBufLeft); inBufLeft += SampleConversion::input_inc; outBufLeft += 2; } size_t numSamplesRight = countSamplesRight; SampleConversion sampleConvRight(conv); const std::byte * MPT_RESTRICT inBufRight = mpt::byte_cast(sourceBuffer) + sample.nLength * SampleConversion::input_inc; typename SampleConversion::output_t * MPT_RESTRICT outBufRight = static_cast(sample.samplev()) + 1; while(numSamplesRight--) { *outBufRight = sampleConvRight(inBufRight); inBufRight += SampleConversion::input_inc; outBufRight += 2; } return (countSamplesLeft + countSamplesRight) * sampleSize; } // Copy a sample data buffer and normalize it. Requires slightly advanced sample conversion functor. template size_t CopyAndNormalizeSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, typename SampleConversion::peak_t *srcPeak = nullptr, SampleConversion conv = SampleConversion()) { const size_t sampleSize = SampleConversion::input_inc; MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t)); size_t numSamples = sample.nLength * sample.GetNumChannels(); LimitMax(numSamples, sourceSize / sampleSize); const std::byte * inBuf = mpt::byte_cast(sourceBuffer); // Finding max value SampleConversion sampleConv(conv); for(size_t i = numSamples; i != 0; i--) { sampleConv.FindMax(inBuf); inBuf += SampleConversion::input_inc; } // If buffer is silent (maximum is 0), don't bother normalizing the sample - just keep the already silent buffer. if(!sampleConv.IsSilent()) { inBuf = sourceBuffer; // Copying buffer. typename SampleConversion::output_t *outBuf = static_cast(sample.samplev()); for(size_t i = numSamples; i != 0; i--) { *outBuf = sampleConv(inBuf); outBuf++; inBuf += SampleConversion::input_inc; } } if(srcPeak) { *srcPeak = sampleConv.GetSrcPeak(); } return numSamples * sampleSize; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Tagging.cpp0000644000175000017500000000120314356623461020167 00000000000000/* * tagging.cpp * ----------- * Purpose: Structure holding a superset of tags for all supported output sample or stream files or types. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Tagging.h" #include "../common/version.h" OPENMPT_NAMESPACE_BEGIN mpt::ustring GetSampleNameFromTags(const FileTags &tags) { mpt::ustring result; if(tags.artist.empty()) { result = tags.title; } else { result = MPT_UFORMAT("{} (by {})")(tags.title, tags.artist); } return result; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MPEGFrame.cpp0000644000175000017500000000670014361204733020312 00000000000000/* * MPEGFrame.cpp * ------------- * Purpose: Basic MPEG frame parsing functionality * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "MPEGFrame.h" #include "mpt/io_read/filereader.hpp" #include "../common/FileReader.h" OPENMPT_NAMESPACE_BEGIN // Samples per frame - for each MPEG version and all three layers static constexpr uint16 samplesPerFrame[2][3] = { { 384, 1152, 1152 }, // MPEG 1 { 384, 1152, 576 } // MPEG 2 / 2.5 }; // Bit rates for each MPEG version and all three layers static constexpr uint16 bitRates[2][3][15] = { // MPEG 1 { { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 }, // Layer 1 { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 }, // Layer 2 { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } // Layer 3 }, // MPEG 2 / 2.5 { { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 }, // Layer 1 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 }, // Layer 2 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 } // Layer 3 } }; // Sampling rates for each MPEG version and all three layers static constexpr uint16 samplingRates[4][3] = { { 11025, 12000, 8000 }, // MPEG 2.5 { 0, 0, 0 }, // Invalid { 22050, 24000, 16000 }, // MPEG 2 { 44100, 48000, 32000 } // MPEG 1 }; // Samples per Frame / 8 static constexpr uint8 mpegCoefficients[2][3] = { { 12, 144, 144 }, // MPEG 1 { 12, 144, 72 } // MPEG 2 / 2.5 }; // Side info size = Offset in frame where Xing/Info magic starts static constexpr uint8 sideInfoSize[2][2] = { { 17, 32 }, // MPEG 1 { 9, 17 } // MPEG 2 / 2.5 }; bool MPEGFrame::IsMPEGHeader(const uint8 (&header)[3]) { return header[0] == 0xFF && (header[1] & 0xE0) == 0xE0 // Sync && (header[1] & 0x18) != 0x08 // Invalid MPEG version && (header[1] & 0x06) != 0x00 // Invalid MPEG layer && (header[2] & 0x0C) != 0x0C // Invalid frequency && (header[2] & 0xF0) != 0xF0; // Invalid bitrate } MPEGFrame::MPEGFrame(FileCursor &file) : frameSize(0) , numSamples(0) , isValid(false) , isLAME(false) { uint8 header[4] = {}; mpt::FR::ReadArray(file, header); if(!IsMPEGHeader(reinterpret_cast(header))) { return; } uint8 version = (header[1] & 0x18) >> 3; uint8 mpeg1 = (version == 3) ? 0 : 1; uint8 layer = 3 - ((header[1] & 0x06) >> 1); uint8 bitRate = (header[2] & 0xF0) >> 4; uint8 sampleRate = (header[2] & 0x0C) >> 2; uint8 padding = (header[2] & 0x02) >> 1; bool stereo = ((header[3] & 0xC0) >> 6) != 3; isValid = true; frameSize = static_cast((((mpegCoefficients[mpeg1][layer] * (bitRates[mpeg1][layer][bitRate] * 1000) / samplingRates[version][sampleRate]) + padding)) * (layer == 0 ? uint16(4u) : uint16(1u))); numSamples = samplesPerFrame[mpeg1][layer]; if(stereo) { numSamples *= 2u; } uint32 lameOffset = sideInfoSize[mpeg1][stereo ? 1 : 0]; if(frameSize < lameOffset + 8) { return; } uint8 frame[36] = {}; mpt::FR::ReadStructPartial(file, frame, lameOffset + 4); // Don't check first two bytes, might be CRC for(uint32 i = 2; i < lameOffset; i++) { if(frame[i] != 0) { return; } } // This is all we really need to know for our purposes in the MO3 decoder. isLAME = !std::memcmp(frame + lameOffset, "Info", 4) || !std::memcmp(frame + lameOffset, "Xing", 4); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Message.h0000644000175000017500000000552414364471512017647 00000000000000/* * Message.h * --------- * Purpose: Various functions for processing song messages (allocating, reading from file...) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include #include "../common/FileReaderFwd.h" OPENMPT_NAMESPACE_BEGIN class SongMessage : public std::string { public: // Line ending types (for reading song messages from module files) enum LineEnding { leCR, // Carriage Return (0x0D, \r) leLF, // Line Feed (0x0A \n) leCRLF, // Carriage Return, Line Feed (0x0D0A, \r\n) leMixed, // It is not defined whether Carriage Return or Line Feed is the actual line ending. Both are accepted. leAutodetect, // Detect suitable line ending }; enum { InternalLineEnding = '\r', // The character that represents line endings internally }; // Read song message from a mapped file. // [in] data: pointer to the data in memory that is going to be read // [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended). // [in] lineEnding: line ending formatting of the text in memory. // [out] returns true on success. bool Read(const std::byte *data, const size_t length, LineEnding lineEnding); bool Read(FileReader &file, const size_t length, LineEnding lineEnding); // Read comments with fixed line length from a mapped file. // [in] data: pointer to the data in memory that is going to be read // [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended). // [in] lineLength: The fixed length of a line. // [in] lineEndingLength: The padding space between two fixed lines. (there could for example be a null char after every line) // [out] returns true on success. bool ReadFixedLineLength(const std::byte *data, const size_t length, const size_t lineLength, const size_t lineEndingLength); bool ReadFixedLineLength(FileReader &file, const size_t length, const size_t lineLength, const size_t lineEndingLength); // Retrieve song message. // [in] lineEnding: line ending formatting of the text in memory. // [out] returns formatted song message. std::string GetFormatted(const LineEnding lineEnding) const; // Set song message. // [in] lineEnding: line ending formatting of the text in memory. Must be leCR or leLF or leCRLF, // [out] returns true if the message has been changed. bool SetFormatted(std::string message, LineEnding lineEnding); // Sets the song message. Expects the provided string to already use the internal line ending character. void SetRaw(std::string message) noexcept { assign(std::move(message)); } std::string GetString() const { return *this; } }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_ftm.cpp0000644000175000017500000004272714721715306020350 00000000000000/* * Load_ftm.cpp * ------------ * Purpose: FTM (Face The Music) loader * Notes : I actually bought a copy of Face The Music with its manual in order to write this loader. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct FTMSampleHeader { char name[30]; // FTM cannot load samples with a filename longer than 29 characters uint8 unknown; // Probably padding. Usually contains null or space (probably overflowing from name) uint8 iffOctave; // Only relevant in song mode }; MPT_BINARY_STRUCT(FTMSampleHeader, 32) struct FTMFileHeader { char magic[4]; // "FTMN" uint8 version; // ...I guess? uint8 numSamples; // 0...63 uint16be numMeasures; uint16be tempo; // Smaller values = faster, the default of 14209 is ~125.098 BPM (though it seems to fluctuate and *sometimes* it drops to 124.307 BPM?) uint8 tonality; // Not relevant for playback (0 = C/a, 1 = Db/bb, etc.) uint8 muteStatus; uint8 globalVolume; // 0...63 uint8 flags; // 1 = module (embedded samples), 2 = enable LED filter uint8 ticksPerRow; uint8 rowsPerMeasure; char title[32]; char artist[32]; uint8 numEffects; uint8 padding; bool IsValid() const { return !memcmp(magic, "FTMN", 4) && version == 3 && numSamples < 64 && tempo >= 0x1000 && tempo <= 0x4FFF && tonality < 12 && globalVolume < 64 #if !defined(MPT_EXTERNAL_SAMPLES) && !defined(MPT_BUILD_FUZZER) && (flags & 0x01) #endif && !(flags & 0xFC) && ticksPerRow >= 1 && ticksPerRow <= 24 && rowsPerMeasure >= 4 && rowsPerMeasure <= 96 && rowsPerMeasure == 96 / ticksPerRow && numEffects <= 64 && padding == 0; } uint32 GetHeaderMinimumAdditionalSize() const { return static_cast(numSamples * sizeof(FTMSampleHeader) + numEffects * 4); } }; MPT_BINARY_STRUCT(FTMFileHeader, 82) struct FTMScriptItem { uint8 type; std::array data; }; MPT_BINARY_STRUCT(FTMScriptItem, 4) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderFTM(MemoryFileReader file, const uint64 *pfilesize) { FTMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadFTM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); FTMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return false; if(!fileHeader.IsValid()) return false; if(!file.CanRead(fileHeader.GetHeaderMinimumAdditionalSize())) return false; else if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_MOD, 8); for(CHANNELINDEX chn = 0; chn < 8; chn++) { ChnSettings[chn].nPan = (chn < 2 || chn > 5) ? 64 : 192; ChnSettings[chn].dwFlags.set(CHN_MUTE, !(fileHeader.muteStatus & (1 << chn))); } m_SongFlags.set(SONG_LINEARSLIDES | SONG_ISAMIGA | SONG_IMPORTED | SONG_FORMAT_NO_VOLCOL); m_playBehaviour.set(kContinueSampleWithoutInstr); m_playBehaviour.set(kST3NoMutedChannels); m_playBehaviour.set(kApplyUpperPeriodLimit); Order().SetDefaultSpeed(fileHeader.ticksPerRow); Order().SetDefaultTempo(TEMPO(1777517.482 / fileHeader.tempo)); m_nDefaultRowsPerMeasure = fileHeader.rowsPerMeasure; if(fileHeader.ticksPerRow == 2 || fileHeader.ticksPerRow == 4 || fileHeader.ticksPerRow == 8 || fileHeader.ticksPerRow == 16) m_nDefaultRowsPerBeat = m_nDefaultRowsPerMeasure / 3; else m_nDefaultRowsPerBeat = m_nDefaultRowsPerMeasure / 4; m_nDefaultGlobalVolume = Util::muldivr_unsigned(fileHeader.globalVolume, MAX_GLOBAL_VOLUME, 63); m_nMinPeriod = 3208; m_nMaxPeriod = 5376; const bool moduleWithSamples = (fileHeader.flags & 0x01); m_modFormat.formatName = UL_("Face The Music"); m_modFormat.type = UL_("ftm"); m_modFormat.madeWithTracker = UL_("Face The Music"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; m_songName = mpt::String::ReadBuf(mpt::String::nullTerminated, fileHeader.title); m_songArtist = mpt::ToUnicode(mpt::Charset::Amiga_no_C1, mpt::String::ReadBuf(mpt::String::nullTerminated, fileHeader.artist)); m_nSamples = fileHeader.numSamples; for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { Samples[smp].Initialize(MOD_TYPE_MOD); FTMSampleHeader sampleHeader; file.ReadStruct(sampleHeader); const auto name = mpt::String::ReadBuf(mpt::String::nullTerminated, sampleHeader.name); #if defined(MPT_EXTERNAL_SAMPLES) if(!moduleWithSamples && !name.empty() && (loadFlags & loadSampleData)) { const auto filename = mpt::PathString::FromUnicode(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, name)); bool ok = false; if(const auto moduleFilename = file.GetOptionalFileName()) { // Try to load the sample directly, so that we can retain IFF loop points, octave selection and raw samples mpt::IO::InputFile f(moduleFilename->GetDirectoryWithDrive() + filename, SettingCacheCompleteFileBeforeLoading()); if(f.IsValid()) { FileReader sampleFile = GetFileReader(f); if(!ReadIFFSample(smp, sampleFile, false, sampleHeader.iffOctave)) { SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(Samples[smp], sampleFile); } ok = true; } } if(!ok) { // Fall back to external sample mechanism. TODO: external sample loading ignores loop data on purpose, and does not support raw samples or IFF octave selection. How do we get it back? Samples[smp].uFlags.set(SMP_KEEPONDISK); SetSamplePath(smp, filename); } } #endif // MPT_EXTERNAL_SAMPLES m_szNames[smp] = name; Samples[smp].nC5Speed = 8287; Samples[smp].RelativeTone = Samples[smp].nFineTune = 0; } auto &events = m_globalScript; constexpr uint16 STOP_INDEX = uint16_max - 1; std::map offsetToIndex; std::bitset<64> effectDefined; for(uint8 effect = 0; effect < fileHeader.numEffects; effect++) { const auto [numLines, index] = file.ReadArray(); if(numLines > 0x200 || index > 63 || offsetToIndex.count(index << 10)) return false; effectDefined.set(index); events.reserve(events.size() + 4 + numLines); events.push_back(InstrumentSynth::Event::Jump(STOP_INDEX)); events.push_back(InstrumentSynth::Event::JumpMarker(index)); events.push_back(InstrumentSynth::Event::FTM_SetWorkTrack(uint8_max, false)); events.push_back(InstrumentSynth::Event::FTM_SetInterrupt(uint16_max, uint8_max)); std::vector items; file.ReadVector(items, numLines); for(uint16 i = 0; i < numLines; i++) { const auto &item = items[i]; const uint32 u24 = (item.data[0] << 16) | (item.data[1] << 8) | item.data[2]; const uint16 u16 = static_cast(u24 & 0xFFFF); const uint16 u12lo = u16 & 0xFFF, u12hi = static_cast(u24 >> 12); const uint8 u8 = item.data[2]; const uint16 jumpTarget = static_cast((index << 10) | std::min(u12lo, uint16(0x200))); offsetToIndex[(index << 10u) | i] = static_cast(events.size()); switch(item.type) { case 0: // NOP [......] break; case 1: // WAIT t TICKS [..tttt] if(u16) events.push_back(InstrumentSynth::Event::Delay(u16 - 1)); else events.push_back(InstrumentSynth::Event::StopScript()); break; case 2: // GOTO LINE l [...lll] events.push_back(InstrumentSynth::Event::Jump(jumpTarget)); break; case 3: // LOOP x TIMES TO l [xxxlll] events.push_back(InstrumentSynth::Event::SetLoopCounter(u12hi, false)); events.push_back(InstrumentSynth::Event::EvaluateLoopCounter(jumpTarget)); break; case 4: // GOTO EFF e / LINE l [eeelll] events.push_back(InstrumentSynth::Event::Jump(static_cast((u12hi << 10) | (jumpTarget & 0x3FF)))); break; case 5: // END OF EFFECT [......] events.push_back(InstrumentSynth::Event::Jump(STOP_INDEX)); break; case 6: // IF PITCH=v GOTO l [ppplll] case 7: // IF PITCHv GOTO l [ppplll] case 9: // IF VOLUM=v GOTO l [vvvlll] case 10: // IF VOLUMv GOTO l [vvvlll] events.push_back(InstrumentSynth::Event::FTM_SetCondition(u12hi, item.type - 6)); events.push_back(InstrumentSynth::Event::JumpIfTrue(jumpTarget)); break; case 12: // ON NEWPIT. GOTO l [...lll] case 13: // ON NEWVOL. GOTO l [...lll] case 14: // ON NEWSAM. GOTO l [...lll] case 15: // ON RELEASE GOTO l [...lll] case 16: // ON PB GOTO l [...lll] case 17: // ON VD GOTO l [...lll] events.push_back(InstrumentSynth::Event::FTM_SetInterrupt(jumpTarget, 1 << (item.type - 12))); break; case 18: // PLAY CURR. SAMPLE [......] events.push_back(InstrumentSynth::Event::FTM_PlaySample()); break; case 19: // PLAY QUIET SAMPLE [......] events.push_back(InstrumentSynth::Event::NoteCut()); break; case 20: // PLAYPOSITION = [.ppppp] events.push_back(InstrumentSynth::Event::SampleOffset((u24 & 0xFFFFF) << 1)); break; case 21: // PLAYPOSITION ADD [.ppppp] events.push_back(InstrumentSynth::Event::SampleOffsetAdd((u24 & 0xFFFFF) << 1)); break; case 22: // PLAYPOSITION SUB [.ppppp] events.push_back(InstrumentSynth::Event::SampleOffsetSub((u24 & 0xFFFFF) << 1)); break; case 23: // PITCH = [...ppp] events.push_back(InstrumentSynth::Event::FTM_SetPitch(std::min(u12lo, uint16(0x10F)))); break; case 24: // DETUNE = [...ddd] events.push_back(InstrumentSynth::Event::FTM_SetDetune(u12lo)); break; case 25: // DETUNE/PITCH ADD [dddppp] case 26: // DETUNE/PITCH SUB [dddppp] events.push_back(InstrumentSynth::Event::FTM_AddDetune((item.type == 26) ? -static_cast(u12hi) : u12hi)); events.push_back(InstrumentSynth::Event::FTM_AddPitch((item.type == 26) ? -static_cast(u12lo) : u12lo)); break; case 27: // VOLUME = [....vv] events.push_back(InstrumentSynth::Event::FTM_SetVolume(u8)); break; case 28: // VOLUME ADD [....vv] case 29: // VOLUME SUB [....vv] events.push_back(InstrumentSynth::Event::FTM_AddVolume((item.type == 29) ? -static_cast(u8) : u8)); break; case 30: // CURRENT SAMPLE = [....ss] events.push_back(InstrumentSynth::Event::FTM_SetSample(u8)); break; case 31: // SAMPLESTART = [.sssss] case 32: // SAMPLESTART ADD [.sssss] case 33: // SAMPLESTART SUB [.sssss] events.push_back(InstrumentSynth::Event::FTM_SetSampleStart(mpt::saturate_cast((u24 & 0xFFFFF) >> 1), item.type - 31)); break; case 34: // ONESHOTLENGTH = [..oooo] case 35: // ONESHOTLENGTH ADD [..oooo] case 36: // ONESHOTLENGTH SUB [..oooo] events.push_back(InstrumentSynth::Event::FTM_SetOneshotLength(u16, item.type - 34)); break; case 37: // REPEATLENGTH = [..rrrr] case 38: // REPEATLENGTH ADD [..rrrr] case 39: // REPEATLENGTH SUB [..rrrr] events.push_back(InstrumentSynth::Event::FTM_SetRepeatLength(u16, item.type - 37)); break; case 40: // GET PIT.OF TRACK [.....t] case 41: // GET VOL.OF TRACK [.....t] case 42: // GET SAM.OF TRACK [.....t] case 43: // CLONE TRACK [.....t] events.push_back(InstrumentSynth::Event::FTM_CloneTrack(u8 & 0x07, 1 << (item.type - 40))); break; case 44: // 1ST LFO START [mfssdd] case 47: // 2ND LFO START [mfssdd] case 50: // 3RD LFO START [mfssdd] case 53: // 4TH LFO START [mfssdd] events.push_back(InstrumentSynth::Event::FTM_StartLFO(static_cast((item.type - 44u) / 3u), item.data[0])); [[fallthrough]]; case 45: // 1ST LFO SP/DE ADD [..ssdd] case 46: // 1ST LFO SP/DE SUB [..ssdd] case 48: // 2ND LFO SP/DE ADD [..ssdd] case 49: // 2ND LFO SP/DE SUB [..ssdd] case 51: // 3RD LFO SP/DE ADD [..ssdd] case 52: // 3RD LFO SP/DE SUB [..ssdd] case 54: // 4TH LFO SP/DE ADD [..ssdd] case 55: // 4TH LFO SP/DE SUB [..ssdd] events.push_back(InstrumentSynth::Event::FTM_LFOAddSub(static_cast(((item.type - 44u) / 3u) | (((item.type - 44u) % 3u == 2) ? 4 : 0)), item.data[1], item.data[2])); break; case 56: // WORK ON TRACK t [.....t] case 57: // WORKTRACK ADD [.....t] events.push_back(InstrumentSynth::Event::FTM_SetWorkTrack(u8 & 0x07, item.type == 57)); break; case 58: // GLOBAL VOLUME = [....vv] events.push_back(InstrumentSynth::Event::FTM_SetGlobalVolume(mpt::saturate_cast(Util::muldivr_unsigned(u8, MAX_GLOBAL_VOLUME, 64)))); break; case 59: // GLOBAL SPEED = [..ssss] events.push_back(InstrumentSynth::Event::FTM_SetTempo(u16)); break; case 60: // TICKS PER LINE = [....tt] events.push_back(InstrumentSynth::Event::FTM_SetSpeed(u8)); break; case 61: // JUMP TO SONGLINE [..llll] events.push_back(InstrumentSynth::Event::FTM_SetPlayPosition(u16 / fileHeader.rowsPerMeasure, static_cast(u16 % fileHeader.rowsPerMeasure))); break; } } } if(fileHeader.numEffects) { events.push_back(InstrumentSynth::Event::JumpMarker(64)); offsetToIndex[STOP_INDEX] = static_cast(events.size()); events.push_back(InstrumentSynth::Event::FTM_SetInterrupt(uint16_max, uint8_max)); } for(auto &event : events) { event.FixupJumpTarget(offsetToIndex); } if(fileHeader.numMeasures) { Patterns.ResizeArray(fileHeader.numMeasures); Order().resize(fileHeader.numMeasures); for(uint16 measure = 0; measure < fileHeader.numMeasures; measure++) { Order()[measure] = measure; if(!Patterns.Insert(measure, fileHeader.rowsPerMeasure)) return false; } struct PatternLoopPoint { ORDERINDEX order; uint16 param : 6, channel : 3, row : 7; bool operator<(const PatternLoopPoint other) const noexcept { return std::tie(order, row, channel) < std::tie(other.order, other.row, other.channel); } }; std::vector loopPoints; for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { const uint16 defaultSpacing = file.ReadUint16BE(); FileReader channelChunk = file.ReadChunk(file.ReadUint32BE()); if(!(loadFlags & loadPatternData)) continue; uint32 globalRow = 0; uint16 spacing = defaultSpacing; while(channelChunk.CanRead(2)) { const auto data = channelChunk.ReadArray(); if((data[0] & 0xF0) == 0xF0) { spacing = data[1] | ((data[0] & 0x0F) << 8); continue; } const auto position = std::div(globalRow + spacing, fileHeader.rowsPerMeasure); if(position.quot >= fileHeader.numMeasures) break; const PATTERNINDEX pat = static_cast(position.quot); ModCommand &m = *Patterns[pat].GetpModCommand(position.rem, chn); const uint8 param = ((data[0] & 0x0F) << 2) | (data[1] >> 6); // 0...63 switch(data[0] & 0xF0) { case 0x00: // Set instrument, no effect m.instr = param; break; case 0xB0: // SEL effect m.SetEffectCommand(CMD_MED_SYNTH_JUMP, (param < effectDefined.size() && effectDefined[param]) ? param : 64); break; case 0xC0: // Pitch bend m.SetEffectCommand(CMD_TONEPORTA_DURATION, param); break; case 0xD0: // Volume down m.SetEffectCommand(CMD_VOLUMEDOWN_DURATION, param); break; case 0xE0: // Loop loopPoints.push_back({pat, static_cast(param & 0x3F), static_cast(chn & 0x07), static_cast(position.rem & 0x7F)}); break; case 0xF0: // Already handled break; default: m.SetEffectCommand(CMD_CHANNELVOLUME, static_cast(Util::muldivr_unsigned((data[0] >> 4) - 1, 64, 9))); m.instr = param; break; } if(uint8 note = data[1] & 0x3F; note >= 35) m.note = NOTE_KEYOFF; else if(note != 0) m.note = NOTE_MIDDLEC - 13 + note; globalRow += 1 + spacing; spacing = defaultSpacing; } } if(Patterns.IsValidPat(0) && (fileHeader.flags & 0x02)) { Patterns[0].WriteEffect(EffectWriter(CMD_MODCMDEX, 0).Row(0).RetryNextRow()); } // Evaluate pattern loops (there can be 16 nested loops at most) std::sort(loopPoints.begin(), loopPoints.end()); std::array, 16> loopStart; ORDERINDEX ordersInserted = 0; uint8 activeLoops = 0; bool canAddMore = true; for(const auto &loop : loopPoints) { ORDERINDEX ord = loop.order + ordersInserted; if(loop.param && activeLoops < loopStart.size()) { loopStart[activeLoops++] = std::make_pair(ord, static_cast(loop.param)); } else if(!loop.param && activeLoops > 0) { activeLoops--; const auto start = loopStart[activeLoops].first; const std::vector ordersToCopy(Order().begin() + start, Order().begin() + ord + 1); for(uint8 rep = 1; rep < loopStart[activeLoops].second && canAddMore; rep++) { if(ORDERINDEX inserted = Order().insert(ord + 1, mpt::as_span(ordersToCopy), false); inserted == ordersToCopy.size()) ordersInserted += inserted; else canAddMore = false; } if(!canAddMore) break; } } } if((loadFlags & loadSampleData) && moduleWithSamples) { for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { if(!m_szNames[smp][0]) continue; ModSample &mptSmp = Samples[smp]; SmpLength loopStart = file.ReadUint16BE() * 2u; SmpLength loopLength = file.ReadUint16BE() * 2u; mptSmp.nLength = loopStart + loopLength; if(!mptSmp.nLength) continue; if(loopLength) { mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopStart + loopLength; mptSmp.uFlags.set(CHN_LOOP); } SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(mptSmp, file); } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_mod.cpp0000644000175000017500000011376015007077310020327 00000000000000/* * Load_mod.cpp * ------------ * Purpose: MOD / NST (ProTracker / NoiseTracker / Startrekker) module loader / saver * Notes : "1100 LOC for processing MOD files?!" you say? * Well, extensive heuristics for more or less broken MOD files and files saved with tons of different trackers, to allow for the most optimal playback, * do take up some space... and then there's also Startrekker synthesized instruments support, of course. It all adds up. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "MODTools.h" #include "Tables.h" #ifndef MODPLUG_NO_FILESAVE #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "../common/mptFileIO.h" #endif #ifdef MPT_EXTERNAL_SAMPLES // For loading external data in Startrekker files #include "mpt/fs/fs.hpp" #include "mpt/io_file/inputfile.hpp" #include "mpt/io_file_read/inputfile_filecursor.hpp" #include "../common/mptPathString.h" #endif // MPT_EXTERNAL_SAMPLES OPENMPT_NAMESPACE_BEGIN // Synthesized StarTrekker instruments struct AMInstrument { char am[2]; // "AM" char zero[4]; uint16be startLevel; // Start level uint16be attack1Level; // Attack 1 level uint16be attack1Speed; // Attack 1 speed uint16be attack2Level; // Attack 2 level uint16be attack2Speed; // Attack 2 speed uint16be sustainLevel; // Sustain level uint16be decaySpeed; // Decay speed uint16be sustainTime; // Sustain time uint16be nt; // ? uint16be releaseSpeed; // Release speed uint16be waveform; // Waveform int16be pitchFall; // Pitch fall uint16be vibAmp; // Vibrato amplitude uint16be vibSpeed; // Vibrato speed uint16be octave; // Base frequency void ConvertToMPT(ModSample &sample, ModInstrument &ins, mpt::fast_prng &rng) const { sample.nLength = waveform == 3 ? 1024 : 32; sample.nLoopStart = 0; sample.nLoopEnd = sample.nLength; sample.uFlags.set(CHN_LOOP); sample.nVolume = 256; // prelude.mod has volume 0 in sample header sample.nVibDepth = mpt::saturate_cast(vibAmp * 2); sample.nVibRate = static_cast(vibSpeed); sample.nVibType = VIB_SINE; sample.RelativeTone = static_cast(-12 * octave); if(sample.AllocateSample()) { int8 *p = sample.sample8(); for(SmpLength i = 0; i < sample.nLength; i++) { switch(waveform) { default: case 0: p[i] = ModSinusTable[i * 2]; break; // Sine case 1: p[i] = static_cast(-128 + i * 8); break; // Saw case 2: p[i] = i < 16 ? -128 : 127; break; // Square case 3: p[i] = mpt::random(rng); break; // Noise } } } InstrumentEnvelope &volEnv = ins.VolEnv; volEnv.dwFlags.set(ENV_ENABLED); volEnv.reserve(6); volEnv.push_back(0, static_cast(startLevel / 4)); const struct { uint16 level, speed; } points[] = {{startLevel, 0}, {attack1Level, attack1Speed}, {attack2Level, attack2Speed}, {sustainLevel, decaySpeed}, {sustainLevel, sustainTime}, {0, releaseSpeed}}; for(uint8 i = 1; i < std::size(points); i++) { int duration = std::min(points[i].speed, uint16(256)); // Sustain time is already in ticks, no need to compute the segment duration. if(i != 4) { if(duration == 0) { volEnv.dwFlags.set(ENV_LOOP); volEnv.nLoopStart = volEnv.nLoopEnd = static_cast(volEnv.size() - 1); break; } // Startrekker increments / decrements the envelope level by the stage speed // until it reaches the next stage level. int a, b; if(points[i].level > points[i - 1].level) { a = points[i].level - points[i - 1].level; b = 256 - points[i - 1].level; } else { a = points[i - 1].level - points[i].level; b = points[i - 1].level; } // Release time is again special. if(i == 5) b = 256; else if(b == 0) b = 1; duration = std::max((256 * a) / (duration * b), 1); } if(duration > 0) { volEnv.push_back(volEnv.back().tick + static_cast(duration), static_cast(points[i].level / 4)); } } if(pitchFall) { InstrumentEnvelope &pitchEnv = ins.PitchEnv; pitchEnv.dwFlags.set(ENV_ENABLED); pitchEnv.reserve(2); pitchEnv.push_back(0, ENVELOPE_MID); // cppcheck false-positive // cppcheck-suppress zerodiv pitchEnv.push_back(static_cast(1024 / abs(pitchFall)), pitchFall > 0 ? ENVELOPE_MIN : ENVELOPE_MAX); } } }; MPT_BINARY_STRUCT(AMInstrument, 36) struct MODMagicResult { const mpt::uchar *madeWithTracker = nullptr; uint32 invalidByteThreshold = MODSampleHeader::INVALID_BYTE_THRESHOLD; uint16 patternDataOffset = 1084; CHANNELINDEX numChannels = 0; bool isNoiseTracker = false; bool isStartrekker = false; bool isGenericMultiChannel = false; bool setMODVBlankTiming = false; bool swapBytes = false; }; static bool CheckMODMagic(const char magic[4], MODMagicResult &result) { if(IsMagic(magic, "M.K.") // ProTracker and compatible || IsMagic(magic, "M!K!") // ProTracker (>64 patterns) || IsMagic(magic, "PATT") // ProTracker 3.6 || IsMagic(magic, "NSMS") // kingdomofpleasure.mod by bee hunter || IsMagic(magic, "LARD")) // judgement_day_gvine.mod by 4-mat { result.madeWithTracker = UL_("Generic ProTracker or compatible"); result.numChannels = 4; } else if(IsMagic(magic, "M&K!") // "His Master's Noise" musicdisk || IsMagic(magic, "FEST") // "His Master's Noise" musicdisk || IsMagic(magic, "N.T.")) { result.madeWithTracker = IsMagic(magic, "N.T.") ? UL_("NoiseTracker") : UL_("His Master's NoiseTracker"); result.isNoiseTracker = true; result.setMODVBlankTiming = true; result.numChannels = 4; } else if(IsMagic(magic, "OKTA") || IsMagic(magic, "OCTA")) { // Oktalyzer result.madeWithTracker = UL_("Oktalyzer"); result.numChannels = 8; } else if(IsMagic(magic, "CD81") || IsMagic(magic, "CD61")) { // Octalyser on Atari STe/Falcon result.madeWithTracker = UL_("Octalyser (Atari)"); result.numChannels = static_cast(magic[2] - '0'); } else if(IsMagic(magic, "M\0\0\0") || IsMagic(magic, "8\0\0\0")) { // Inconexia demo by Iguana, delta samples (https://www.pouet.net/prod.php?which=830) result.madeWithTracker = UL_("Inconexia demo (delta samples)"); result.invalidByteThreshold = MODSampleHeader::INVALID_BYTE_FRAGILE_THRESHOLD; result.numChannels = (magic[0] == '8') ? 8 : 4; } else if(!memcmp(magic, "FA0", 3) && magic[3] >= '4' && magic[3] <= '8') { // Digital Tracker on Atari Falcon result.madeWithTracker = UL_("Digital Tracker"); result.numChannels = static_cast(magic[3] - '0'); // Digital Tracker MODs contain four bytes (00 40 00 00) right after the magic bytes which don't seem to do anything special. result.patternDataOffset = 1088; } else if((!memcmp(magic, "FLT", 3) || !memcmp(magic, "EXO", 3)) && (magic[3] == '4' || magic[3] == '8')) { // FLTx / EXOx - Startrekker by Exolon / Fairlight result.madeWithTracker = UL_("Startrekker"); result.isStartrekker = true; result.setMODVBlankTiming = true; result.numChannels = static_cast(magic[3] - '0'); } else if(magic[0] >= '1' && magic[0] <= '9' && !memcmp(magic + 1, "CHN", 3)) { // xCHN - Many trackers result.madeWithTracker = UL_("Generic MOD-compatible Tracker"); result.isGenericMultiChannel = true; result.numChannels = static_cast(magic[0] - '0'); } else if(magic[0] >= '1' && magic[0] <= '9' && magic[1] >= '0' && magic[1] <= '9' && (!memcmp(magic + 2, "CH", 2) || !memcmp(magic + 2, "CN", 2))) { // xxCN / xxCH - Many trackers result.madeWithTracker = UL_("Generic MOD-compatible Tracker"); result.isGenericMultiChannel = true; result.numChannels = static_cast((magic[0] - '0') * 10 + magic[1] - '0'); } else if(!memcmp(magic, "TDZ", 3) && magic[3] >= '1' && magic[3] <= '9') { // TDZx - TakeTracker (only TDZ1-TDZ3 should exist, but historically this code only supported 4-9 channels, so we keep those for the unlikely case that they were actually used for something) result.madeWithTracker = UL_("TakeTracker"); result.numChannels = static_cast(magic[3] - '0'); } else if(IsMagic(magic, ".M.K")) { // Hacked .DMF files from the game "Apocalypse Abyss" result.numChannels = 4; result.swapBytes = true; } else if(IsMagic(magic, "WARD")) { // MUSIC*.DTA files from the DOS game Aleshar - The World Of Ice result.madeWithTracker = UL_("Generic MOD-compatible Tracker"); result.isGenericMultiChannel = true; result.numChannels = 8; } else { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize) { if(!file.LengthIsAtLeast(1080 + 4)) { return ProbeWantMoreData; } file.Seek(1080); char magic[4]; file.ReadArray(magic); MODMagicResult modMagicResult; if(!CheckMODMagic(magic, modMagicResult)) { return ProbeFailure; } file.Seek(20); uint32 invalidBytes = 0; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { MODSampleHeader sampleHeader = ReadAndSwap(file, modMagicResult.swapBytes); invalidBytes += sampleHeader.GetInvalidByteScore(); } if(invalidBytes > modMagicResult.invalidByteThreshold) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) { char magic[4]; if(!file.Seek(1080) || !file.ReadArray(magic)) { return false; } MODMagicResult modMagicResult; if(!CheckMODMagic(magic, modMagicResult) || modMagicResult.numChannels < 1 || modMagicResult.numChannels > MAX_BASECHANNELS) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_MOD, modMagicResult.numChannels); bool isNoiseTracker = modMagicResult.isNoiseTracker; bool isStartrekker = modMagicResult.isStartrekker; bool isGenericMultiChannel = modMagicResult.isGenericMultiChannel; bool isInconexia = IsMagic(magic, "M\0\0\0") || IsMagic(magic, "8\0\0\0"); // A loop length of zero will freeze ProTracker, so assume that modules having such a value were not meant to be played on Amiga. Fixes LHS_MI.MOD bool hasRepLen0 = false; // Empty sample slots typically should have a default volume of 0 in ProTracker bool hasEmptySampleWithVolume = false; if(modMagicResult.setMODVBlankTiming) { m_playBehaviour.set(kMODVBlankTiming); } // Startrekker 8 channel mod (needs special treatment, see below) const bool isFLT8 = isStartrekker && GetNumChannels() == 8; const bool isMdKd = IsMagic(magic, "M.K."); // Adjust finetune values for modules saved with "His Master's Noisetracker" const bool isHMNT = IsMagic(magic, "M&K!") || IsMagic(magic, "FEST"); bool maybeWOW = isMdKd; // Reading song title file.Seek(0); const auto songTitle = ReadAndSwap>(file, modMagicResult.swapBytes); m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, songTitle); // Load Sample Headers SmpLength totalSampleLen = 0, wowSampleLen = 0; m_nSamples = 31; uint32 invalidBytes = 0; bool hasLongSamples = false; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { MODSampleHeader sampleHeader = ReadAndSwap(file, modMagicResult.swapBytes); invalidBytes += ReadMODSample(sampleHeader, Samples[smp], m_szNames[smp], GetNumChannels() == 4); totalSampleLen += Samples[smp].nLength; if(isHMNT) Samples[smp].nFineTune = -static_cast(sampleHeader.finetune << 3); else if(Samples[smp].nLength > 65535) hasLongSamples = true; if(sampleHeader.length && !sampleHeader.loopLength) hasRepLen0 = true; else if(!sampleHeader.length && sampleHeader.volume == 64) hasEmptySampleWithVolume = true; if(maybeWOW) { // Some WOW files rely on sample length 1 being counted as well wowSampleLen += sampleHeader.length * 2; // WOW files are converted 669 files, which don't support finetune or default volume if(sampleHeader.finetune) maybeWOW = false; else if(sampleHeader.length > 0 && sampleHeader.volume != 64) maybeWOW = false; } } // If there is too much binary garbage in the sample headers, reject the file. if(invalidBytes > modMagicResult.invalidByteThreshold) { return false; } // Read order information const MODFileHeader fileHeader = ReadAndSwap(file, modMagicResult.swapBytes); file.Seek(modMagicResult.patternDataOffset); if(fileHeader.restartPos > 0) maybeWOW = false; if(!maybeWOW) wowSampleLen = 0; ReadOrderFromArray(Order(), fileHeader.orderList); ORDERINDEX realOrders = fileHeader.numOrders; if(realOrders > 128) { // beatwave.mod by Sidewinder claims to have 129 orders. (MD5: 8a029ac498d453beb929db9a73c3c6b4, SHA1: f7b76fb9f477b07a2e78eb10d8624f0df262cde7 - the version from ModArchive, not ModLand) realOrders = 128; } else if(realOrders == 0) { // Is this necessary? realOrders = 128; while(realOrders > 1 && Order()[realOrders - 1] == 0) { realOrders--; } } // Get number of patterns (including some order list sanity checks) PATTERNINDEX numPatterns = GetNumPatterns(file, *this, realOrders, totalSampleLen, wowSampleLen, false); if(maybeWOW && GetNumChannels() == 8) { // M.K. with 8 channels = Mod's Grave modMagicResult.madeWithTracker = UL_("Mod's Grave"); isGenericMultiChannel = true; } if(isFLT8) { // FLT8 has only even order items, so divide by two. for(auto &pat : Order()) { pat /= 2u; } } // Restart position sanity checks realOrders--; Order().SetRestartPos(fileHeader.restartPos); // (Ultimate) Soundtracker didn't have a restart position, but instead stored a default tempo in this value. // The default value for this is 0x78 (120 BPM). This is probably the reason why some M.K. modules // have this weird restart position. I think I've read somewhere that NoiseTracker actually writes 0x78 there. // M.K. files that have restart pos == 0x78: action's batman by DJ Uno, VALLEY.MOD, WormsTDC.MOD, ZWARTZ.MOD // Files that have an order list longer than 0x78 with restart pos = 0x78: my_shoe_is_barking.mod, papermix.mod // - in both cases it does not appear like the restart position should be used. MPT_ASSERT(fileHeader.restartPos != 0x78 || fileHeader.restartPos + 1u >= realOrders); if(fileHeader.restartPos > realOrders || (fileHeader.restartPos == 0x78 && GetNumChannels() == 4)) { Order().SetRestartPos(0); } Order().SetDefaultSpeed(6); Order().SetDefaultTempoInt(125); m_nMinPeriod = 14 * 4; m_nMaxPeriod = 3424 * 4; // Prevent clipping based on number of channels... If all channels are playing at full volume, "256 / #channels" // is the maximum possible sample pre-amp without getting distortion (Compatible mix levels given). // The more channels we have, the less likely it is that all of them are used at the same time, though, so cap at 32... m_nSamplePreAmp = Clamp(256 / GetNumChannels(), 32, 128); m_SongFlags = SONG_FORMAT_NO_VOLCOL; // SONG_ISAMIGA will be set conditionally // Setup channel pan positions and volume SetupMODPanning(); // Before loading patterns, apply some heuristics: // - Scan patterns to check if file could be a NoiseTracker file in disguise. // In this case, the parameter of Dxx commands needs to be ignored (see 1.11song2.mod, 2-3song6.mod). // - Use the same code to find notes that would be out-of-range on Amiga. // - Detect 7-bit panning and whether 8xx / E8x commands should be interpreted as panning at all. bool onlyAmigaNotes = true; bool fix7BitPanning = false; uint8 maxPanning = 0; // For detecting 8xx-as-sync const uint8 ENABLE_MOD_PANNING_THRESHOLD = 0x30; if(!isNoiseTracker) { const uint32 patternLength = GetNumChannels() * 64; bool leftPanning = false, extendedPanning = false; // For detecting 800-880 panning isNoiseTracker = isMdKd && !hasEmptySampleWithVolume && !hasLongSamples; for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { uint16 patternBreaks = 0; for(uint32 i = 0; i < patternLength; i++) { ModCommand m; const auto data = ReadAndSwap>(file, modMagicResult.swapBytes && pat == 0); const auto [command, param] = ReadMODPatternEntry(data, m); if(!m.IsAmigaNote()) { isNoiseTracker = onlyAmigaNotes = false; } if((command > 0x06 && command < 0x0A) || (command == 0x0E && param > 0x01) || (command == 0x0F && param > 0x1F) || (command == 0x0D && ++patternBreaks > 1)) { isNoiseTracker = false; } if(command == 0x08) { // Note: commands 880...88F are not considered for determining the panning style, as some modules use 7-bit panning but slightly overshoot: // LOOKATME.MOD (MD5: dedcec1a2a135aeb1a311841cea2c60c, SHA1: 42bf92bf824ef9fb904704b8ee7e3a30df60038d) has an 88A command as its rightmost panning. maxPanning = std::max(maxPanning, param); if(param < 0x80) leftPanning = true; else if(param > 0x8F && param != 0xA4) extendedPanning = true; } else if(command == 0x0E && (param & 0xF0) == 0x80) { maxPanning = std::max(maxPanning, static_cast((param & 0x0F) << 4)); } } } fix7BitPanning = leftPanning && !extendedPanning && maxPanning >= ENABLE_MOD_PANNING_THRESHOLD; } file.Seek(modMagicResult.patternDataOffset); const CHANNELINDEX readChannels = (isFLT8 ? 4 : GetNumChannels()); // 4 channels per pattern in FLT8 format. if(isFLT8) numPatterns++; // as one logical pattern consists of two real patterns in FLT8 format, the highest pattern number has to be increased by one. bool hasTempoCommands = false, definitelyCIA = hasLongSamples; // for detecting VBlank MODs // Heuristic for rejecting E0x commands that are most likely not intended to actually toggle the Amiga LED filter, like in naen_leijasi_ptk.mod by ilmarque bool filterState = false; int filterTransitions = 0; // Reading patterns Patterns.ResizeArray(numPatterns); std::bitset<32> referencedSamples; for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { ModCommand *rowBase = nullptr; if(isFLT8) { // FLT8: Only create "even" patterns and either write to channel 1 to 4 (even patterns) or 5 to 8 (odd patterns). PATTERNINDEX actualPattern = pat / 2u; if((pat % 2u) == 0 && !Patterns.Insert(actualPattern, 64)) { break; } rowBase = Patterns[actualPattern].GetpModCommand(0, (pat % 2u) == 0 ? 0 : 4); } else { if(!Patterns.Insert(pat, 64)) { break; } rowBase = Patterns[pat].GetpModCommand(0, 0); } if(rowBase == nullptr || !(loadFlags & loadPatternData)) { break; } // For detecting PT1x mode std::vector lastInstrument(GetNumChannels(), 0); std::vector instrWithoutNoteCount(GetNumChannels(), 0); for(ROWINDEX row = 0; row < 64; row++, rowBase += GetNumChannels()) { // If we have more than one Fxx command on this row and one can be interpreted as speed // and the other as tempo, we can be rather sure that it is not a VBlank mod. bool hasSpeedOnRow = false, hasTempoOnRow = false; for(CHANNELINDEX chn = 0; chn < readChannels; chn++) { ModCommand &m = rowBase[chn]; const auto data = ReadAndSwap>(file, modMagicResult.swapBytes && pat == 0); auto [command, param] = ReadMODPatternEntry(data, m); if(command || param) { if(isStartrekker && command == 0x0E) { // No support for Startrekker assembly macros command = param = 0; } else if(isStartrekker && command == 0x0F && param > 0x1F) { // Startrekker caps speed at 31 ticks per row param = 0x1F; } ConvertModCommand(m, command, param); } // Perform some checks for our heuristics... if(m.command == CMD_TEMPO) { hasTempoOnRow = true; if(m.param < 100) hasTempoCommands = true; } else if(m.command == CMD_SPEED) { hasSpeedOnRow = true; } else if(m.command == CMD_PATTERNBREAK && isNoiseTracker) { m.param = 0; } else if(m.command == CMD_TREMOLO && isHMNT) { m.command = CMD_HMN_MEGA_ARP; } else if(m.command == CMD_PANNING8 && fix7BitPanning) { // Fix MODs with 7-bit + surround panning if(m.param == 0xA4) { m.command = CMD_S3MCMDEX; m.param = 0x91; } else { m.param = mpt::saturate_cast(m.param * 2); } } else if(m.command == CMD_MODCMDEX && m.param < 0x10) { // Count LED filter transitions bool newState = !(m.param & 0x01); if(newState != filterState) { filterState = newState; filterTransitions++; } } if(m.note == NOTE_NONE && m.instr > 0 && !isFLT8) { if(lastInstrument[chn] > 0 && lastInstrument[chn] != m.instr) { // Arbitrary threshold for enabling sample swapping: 4 consecutive "sample swaps" in one pattern. if(++instrWithoutNoteCount[chn] >= 4) { m_playBehaviour.set(kMODSampleSwap); } } } else if(m.note != NOTE_NONE) { instrWithoutNoteCount[chn] = 0; } if(m.instr != 0) { lastInstrument[chn] = m.instr; if(isStartrekker) referencedSamples.set(m.instr & 0x1F); } } if(hasSpeedOnRow && hasTempoOnRow) definitelyCIA = true; } } if(onlyAmigaNotes && !hasRepLen0 && (IsMagic(magic, "M.K.") || IsMagic(magic, "M!K!") || IsMagic(magic, "PATT"))) { // M.K. files that don't exceed the Amiga note limit (fixes mod.mothergoose) m_SongFlags.set(SONG_AMIGALIMITS); // Need this for professionaltracker.mod by h0ffman (SHA1: 9a7c52cbad73ed2a198ee3fa18d3704ea9f546ff) m_SongFlags.set(SONG_PT_MODE); m_playBehaviour.set(kMODSampleSwap); m_playBehaviour.set(kMODOutOfRangeNoteDelay); m_playBehaviour.set(kMODTempoOnSecondTick); // Arbitrary threshold for deciding that 8xx effects are only used as sync markers if(maxPanning < ENABLE_MOD_PANNING_THRESHOLD) { m_playBehaviour.set(kMODIgnorePanning); if(fileHeader.restartPos != 0x7F) { // Don't enable these hacks for ScreamTracker modules (restart position = 0x7F), to fix e.g. sample 10 in BASIC001.MOD (SHA1: 11298a5620e677beaa50bd4ed00c3710b75c81af) // Note: restart position = 0x7F can also be found in ProTracker modules, e.g. professionaltracker.mod by h0ffman m_playBehaviour.set(kMODOneShotLoops); } } } else if(!onlyAmigaNotes && fileHeader.restartPos == 0x7F && isMdKd && fileHeader.restartPos + 1u >= realOrders) { modMagicResult.madeWithTracker = UL_("Scream Tracker"); } if(onlyAmigaNotes && !isGenericMultiChannel && filterTransitions < 7) { m_SongFlags.set(SONG_ISAMIGA); } if(isGenericMultiChannel || isMdKd || IsMagic(magic, "M!K!")) { m_playBehaviour.set(kFT2MODTremoloRampWaveform); } if(isInconexia) { m_playBehaviour.set(kMODIgnorePanning); } // Reading samples bool anyADPCM = false; if(loadFlags & loadSampleData) { file.Seek(modMagicResult.patternDataOffset + (readChannels * 64 * 4) * numPatterns); for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { ModSample &sample = Samples[smp]; if(sample.nLength) { SampleIO::Encoding encoding = SampleIO::signedPCM; if(isInconexia) { encoding = SampleIO::deltaPCM; } else if(file.ReadMagic("ADPCM")) { encoding = SampleIO::ADPCM; anyADPCM = true; } SampleIO sampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, encoding); // Fix sample 6 in MOD.shorttune2, which has a replen longer than the sample itself. // ProTracker reads beyond the end of the sample when playing. Normally samples are // adjacent in PT's memory, so we simply read into the next sample in the file. // On the other hand, the loop points in Purple Motions's SOUL-O-M.MOD are completely broken and shouldn't be treated like this. // As it was most likely written in Scream Tracker, it has empty sample slots with a default volume of 64, which we use for // rejecting this quirk for that file. FileReader::pos_type nextSample = file.GetPosition() + sampleIO.CalculateEncodedSize(sample.nLength); if(isMdKd && onlyAmigaNotes && !hasEmptySampleWithVolume) sample.nLength = std::max(sample.nLength, sample.nLoopEnd); sampleIO.ReadSample(sample, file); file.Seek(nextSample); } } // XOR with 0xDF gives the message "TakeTrackered with version 0.9E!!!!!" if(GetNumChannels() <= 16 && file.ReadMagic("\x8B\xBE\xB4\xBA\x8B\xAD\xBE\xBC\xB4\xBA\xAD\xBA\xBB\xFF\xA8\xB6\xAB\xB7\xFF\xA9\xBA\xAD\xAC\xB6\xB0\xB1\xFF\xEF\xF1\xE6\xBA\xFE\xFE\xFE\xFE\xFE")) modMagicResult.madeWithTracker = UL_("TakeTracker"); else if(isMdKd && file.ReadArray() == std::array{0x00, 0x11, 0x55, 0x33, 0x22, 0x11} && file.CanRead(3)) // 3 more bytes that differ between modules and Tetramed version, purpose unknown modMagicResult.madeWithTracker = UL_("Tetramed"); } #if defined(MPT_EXTERNAL_SAMPLES) || defined(MPT_BUILD_FUZZER) // Detect Startrekker files with external synth instruments. // Note: Synthesized AM samples may overwrite existing samples (e.g. sample 1 in fa.worse face.mod), // hence they are loaded here after all regular samples have been loaded. if((loadFlags & loadSampleData) && isStartrekker) { #ifdef MPT_EXTERNAL_SAMPLES std::optional amFile; FileReader amData; if(file.GetOptionalFileName()) { #if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE) mpt::PathString filename = *(file.GetOptionalFileName()); #else mpt::PathString filename = file.GetOptionalFileName().value(); #endif // Find instrument definition file const mpt::PathString exts[] = {P_(".nt"), P_(".NT"), P_(".as"), P_(".AS")}; for(const auto &ext : exts) { mpt::PathString infoName = filename + ext; char stMagic[16]; if(mpt::native_fs{}.is_file(infoName)) { amFile.emplace(infoName, SettingCacheCompleteFileBeforeLoading()); if(amFile->IsValid() && (amData = GetFileReader(*amFile)).IsValid() && amData.ReadArray(stMagic)) { if(!memcmp(stMagic, "ST1.2 ModuleINFO", 16)) modMagicResult.madeWithTracker = UL_("Startrekker 1.2"); else if(!memcmp(stMagic, "ST1.3 ModuleINFO", 16)) modMagicResult.madeWithTracker = UL_("Startrekker 1.3"); else if(!memcmp(stMagic, "AudioSculpture10", 16)) modMagicResult.madeWithTracker = UL_("AudioSculpture 1.0"); else continue; if(amData.Seek(144)) { // Looks like a valid instrument definition file! m_nInstruments = 31; break; } } } } } #elif defined(MPT_BUILD_FUZZER) // For fuzzing this part of the code, just take random data from patterns FileReader amData = file.GetChunkAt(1084, 31 * 120); m_nInstruments = 31; #endif mpt::deterministic_random_device rd; auto prng = mpt::make_prng(rd); for(SAMPLEINDEX smp = 1; smp <= GetNumInstruments(); smp++) { // For Startrekker AM synthesis, we need instrument envelopes. ModInstrument *ins = AllocateInstrument(smp, smp); if(ins == nullptr) { break; } ins->name = m_szNames[smp]; AMInstrument am; // Allow partial reads for fa.worse face.mod if(amData.ReadStructPartial(am) && !memcmp(am.am, "AM", 2) && am.waveform < 4) { am.ConvertToMPT(Samples[smp], *ins, prng); } // This extra padding is probably present to have identical block sizes for AM and FM instruments. amData.Skip(120 - sizeof(AMInstrument)); } } #endif // MPT_EXTERNAL_SAMPLES || MPT_BUILD_FUZZER if((loadFlags & loadSampleData) && isStartrekker && !m_nInstruments) { uint8 emptySampleReferences = 0; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { if(referencedSamples[smp] && !Samples[smp].nLength) { if(++emptySampleReferences > 1) { #ifdef MPT_EXTERNAL_SAMPLES mpt::ustring filenameHint; if(file.GetOptionalFileName()) { const auto filename = file.GetOptionalFileName()->GetFilename().ToUnicode(); filenameHint = MPT_UFORMAT(" ({}.nt or {}.as)")(filename, filename); } AddToLog(LogWarning, MPT_UFORMAT("This Startrekker AM file is most likely missing its companion file{}. Synthesized instruments will not play.")(filenameHint)); #else AddToLog(LogWarning, U_("This appears to be a Startrekker AM file with external synthesizes instruments. External instruments are currently not supported.")); #endif // MPT_EXTERNAL_SAMPLES break; } } } } // His Master's Noise "Mupp" instrument extensions if((loadFlags & loadSampleData) && isHMNT) { uint8 muppCount = 0; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { file.Seek(20 + (smp - 1) * sizeof(MODSampleHeader)); if(!file.ReadMagic("Mupp") || !CanAddMoreSamples(28)) continue; if(!m_nInstruments) { m_playBehaviour.set(kMODSampleSwap); m_nInstruments = 31; for(INSTRUMENTINDEX ins = 1; ins <= 31; ins++) { if(ModInstrument *instr = AllocateInstrument(ins, ins); instr != nullptr) instr->name = m_szNames[ins]; } } ModInstrument *instr = Instruments[smp]; if(!instr) continue; const auto [muppPattern, loopStart, loopEnd] = file.ReadArray(); file.Seek(1084 + 1024 * muppPattern); SAMPLEINDEX startSmp = m_nSamples + 1; m_nSamples += 28; instr->AssignSample(startSmp); SampleIO sampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM); for(SAMPLEINDEX muppSmp = startSmp; muppSmp <= m_nSamples; muppSmp++) { ModSample &mptSmp = Samples[muppSmp]; mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.nLength = 32; mptSmp.nLoopStart = 0; mptSmp.nLoopEnd = 32; mptSmp.nFineTune = Samples[smp].nFineTune; mptSmp.nVolume = Samples[smp].nVolume; mptSmp.uFlags.set(CHN_LOOP); sampleIO.ReadSample(mptSmp, file); } auto &events = instr->synth.m_scripts.emplace_back(); events.reserve(std::min(loopEnd + 2, 65)); const auto waveforms = file.ReadArray(); const auto volumes = file.ReadArray(); for(uint8 i = 0; i < 64; i++) { events.push_back(InstrumentSynth::Event::Mupp_SetWaveform(muppCount, waveforms[i], volumes[i])); if(i == loopEnd && loopStart <= loopEnd) { events.push_back(InstrumentSynth::Event::Jump(loopStart)); break; } } muppCount++; } } // For "the ultimate beeper.mod" { ModSample &sample = Samples[0]; sample.Initialize(MOD_TYPE_MOD); sample.nLength = 2; sample.nLoopStart = 0; sample.nLoopEnd = 2; sample.nVolume = 0; sample.uFlags.set(CHN_LOOP); sample.AllocateSample(); } // Fix VBlank MODs. Arbitrary threshold: 8 minutes (enough for "frame of mind" by Dascon...). // Basically, this just converts all tempo commands into speed commands // for MODs which are supposed to have VBlank timing (instead of CIA timing). // There is no perfect way to do this, since both MOD types look the same, // but the most reliable way is to simply check for extremely long songs // (as this would indicate that e.g. a F30 command was really meant to set // the ticks per row to 48, and not the tempo to 48 BPM). // In the pattern loader above, a second condition is used: Only tempo commands // below 100 BPM are taken into account. Furthermore, only ProTracker (M.K. / M!K!) // modules are checked. if((isMdKd || IsMagic(magic, "M!K!")) && hasTempoCommands && !definitelyCIA) { const double songTime = GetLength(eNoAdjust).front().duration; if(songTime >= 480.0) { m_playBehaviour.set(kMODVBlankTiming); if(GetLength(eNoAdjust, GetLengthTarget(songTime)).front().targetReached) { // This just makes things worse, song is at least as long as in CIA mode // Obviously we should keep using CIA timing then... m_playBehaviour.reset(kMODVBlankTiming); } else { modMagicResult.madeWithTracker = UL_("ProTracker (VBlank)"); } } } std::transform(std::begin(magic), std::end(magic), std::begin(magic), [](unsigned char c) -> unsigned char { return (c < ' ') ? ' ' : c; }); m_modFormat.formatName = MPT_UFORMAT("ProTracker MOD ({})")(mpt::ToUnicode(mpt::Charset::ASCII, std::string(std::begin(magic), std::end(magic)))); m_modFormat.type = UL_("mod"); if(modMagicResult.madeWithTracker) m_modFormat.madeWithTracker = modMagicResult.madeWithTracker; m_modFormat.charset = mpt::Charset::Amiga_no_C1; if(anyADPCM) m_modFormat.madeWithTracker += UL_(" (ADPCM packed)"); return true; } #ifndef MODPLUG_NO_FILESAVE bool CSoundFile::SaveMod(std::ostream &f) const { if(GetNumChannels() == 0) { return false; } // Write song title { char name[20]; mpt::String::WriteBuf(mpt::String::maybeNullTerminated, name) = m_songName; mpt::IO::Write(f, name); } std::vector sampleLength(32, 0); std::vector sampleSource(32, 0); if(GetNumInstruments()) { INSTRUMENTINDEX lastIns = std::min(INSTRUMENTINDEX(31), GetNumInstruments()); for(INSTRUMENTINDEX ins = 1; ins <= lastIns; ins++) if (Instruments[ins]) { // Find some valid sample associated with this instrument. for(auto smp : Instruments[ins]->Keyboard) { if(smp > 0 && smp <= GetNumSamples()) { sampleSource[ins] = smp; break; } } } } else { for(SAMPLEINDEX i = 1; i <= 31; i++) { sampleSource[i] = i; } } // Write sample headers for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { MODSampleHeader sampleHeader; mpt::String::WriteBuf(mpt::String::maybeNullTerminated, sampleHeader.name) = m_szNames[sampleSource[smp]]; sampleLength[smp] = sampleHeader.ConvertToMOD(sampleSource[smp] <= GetNumSamples() ? GetSample(sampleSource[smp]) : ModSample(MOD_TYPE_MOD)); mpt::IO::Write(f, sampleHeader); } // Write order list MODFileHeader fileHeader; MemsetZero(fileHeader); PATTERNINDEX writePatterns = 0; uint8 writtenOrders = 0; for(ORDERINDEX ord = 0; ord < Order().GetLength() && writtenOrders < 128; ord++) { // Ignore +++ and --- patterns in order list, as well as high patterns (MOD officially only supports up to 128 patterns) if(ord == Order().GetRestartPos()) { fileHeader.restartPos = writtenOrders; } if(Order()[ord] < 128) { fileHeader.orderList[writtenOrders++] = static_cast(Order()[ord]); if(writePatterns <= Order()[ord]) { writePatterns = Order()[ord] + 1; } } } fileHeader.numOrders = writtenOrders; mpt::IO::Write(f, fileHeader); // Write magic bytes char modMagic[4]; CHANNELINDEX writeChannels = std::min(CHANNELINDEX(99), GetNumChannels()); if(writeChannels == 4) { // ProTracker may not load files with more than 64 patterns correctly if we do not specify the M!K! magic. if(writePatterns <= 64) memcpy(modMagic, "M.K.", 4); else memcpy(modMagic, "M!K!", 4); } else if(writeChannels < 10) { memcpy(modMagic, "0CHN", 4); modMagic[0] += static_cast(writeChannels); } else { memcpy(modMagic, "00CH", 4); modMagic[0] += static_cast(writeChannels / 10u); modMagic[1] += static_cast(writeChannels % 10u); } mpt::IO::Write(f, modMagic); // Write patterns bool invalidInstruments = false; std::vector events; for(PATTERNINDEX pat = 0; pat < writePatterns; pat++) { if(!Patterns.IsValidPat(pat)) { // Invent empty pattern events.assign(writeChannels * 64 * 4, 0); mpt::IO::Write(f, events); continue; } for(ROWINDEX row = 0; row < 64; row++) { if(row >= Patterns[pat].GetNumRows()) { // Invent empty row events.assign(writeChannels * 4, 0); mpt::IO::Write(f, events); continue; } const auto rowBase = Patterns[pat].GetRow(row); bool writePatternBreak = (Patterns[pat].GetNumRows() < 64 && row + 1 == Patterns[pat].GetNumRows() && !Patterns[pat].RowHasJump(row)); events.resize(writeChannels * 4); size_t eventByte = 0; for(CHANNELINDEX chn = 0; chn < writeChannels; chn++, eventByte += 4) { const ModCommand &m = rowBase[chn]; uint8 command = 0, param = 0; ModSaveCommand(m, command, param, false, true); if(m.volcmd == VOLCMD_VOLUME && !command && !param) { // Maybe we can save some volume commands... command = 0x0C; param = std::min(m.vol, uint8(64)); } if(writePatternBreak && !command && !param) { command = 0x0D; writePatternBreak = false; } uint16 period = 0; // Convert note to period if(m.note >= 24 + NOTE_MIN && m.note < std::size(ProTrackerPeriodTable) + 24 + NOTE_MIN) { period = ProTrackerPeriodTable[m.note - 24 - NOTE_MIN]; } const uint8 instr = (m.instr > 31) ? 0 : m.instr; if(m.instr > 31) invalidInstruments = true; events[eventByte + 0] = ((period >> 8) & 0x0F) | (instr & 0x10); events[eventByte + 1] = period & 0xFFu; events[eventByte + 2] = ((instr & 0x0F) << 4) | (command & 0x0F); events[eventByte + 3] = param; } mpt::IO::WriteRaw(f, mpt::as_span(events)); } } if(invalidInstruments) { AddToLog(LogWarning, U_("Warning: This track references sample slots higher than 31. Such samples cannot be saved in the MOD format, and thus the notes will not sound correct. Use the Cleanup tool to rearrange and remove unused samples.")); } //Check for unsaved patterns for(PATTERNINDEX pat = writePatterns; pat < Patterns.Size(); pat++) { if(Patterns.IsValidPat(pat)) { AddToLog(LogWarning, U_("Warning: This track contains at least one pattern after the highest pattern number referred to in the sequence. Such patterns are not saved in the MOD format.")); break; } } // Writing samples for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { if(sampleLength[smp] == 0) { continue; } const ModSample &sample = Samples[sampleSource[smp]]; const mpt::IO::Offset sampleStart = mpt::IO::TellWrite(f); const size_t writtenBytes = MODSampleHeader::GetSampleFormat().WriteSample(f, sample, sampleLength[smp]); const int8 silence = 0; // Write padding byte if the sample size is odd. if((writtenBytes % 2u) != 0) { mpt::IO::Write(f, silence); } if(!sample.uFlags[CHN_LOOP] && writtenBytes >= 2) { // First two bytes of oneshot samples have to be 0 due to PT's one-shot loop const mpt::IO::Offset sampleEnd = mpt::IO::TellWrite(f); mpt::IO::SeekAbsolute(f, sampleStart); mpt::IO::Write(f, silence); mpt::IO::Write(f, silence); mpt::IO::SeekAbsolute(f, sampleEnd); } } return true; } #endif // MODPLUG_NO_FILESAVE OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/WAVTools.h0000644000175000017500000001437714766102360017745 00000000000000/* * WAVTools.h * ---------- * Purpose: Definition of WAV file structures and helper functions * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #ifndef MODPLUG_NO_FILESAVE #include "mpt/io/io_virtual_wrapper.hpp" #endif #include "openmpt/soundfile_data/wav.hpp" #ifndef MODPLUG_NO_FILESAVE #include "openmpt/soundfile_write/wav_write.hpp" #endif #include "../common/FileReader.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct FileTags; // Sample information chunk struct WAVSampleInfoChunk { uint32le manufacturer; uint32le product; uint32le samplePeriod; // 1000000000 / sampleRate uint32le baseNote; // MIDI base note of sample uint32le pitchFraction; uint32le SMPTEFormat; uint32le SMPTEOffset; uint32le numLoops; // number of loops uint32le samplerData; // Set up information void ConvertToWAV(uint32 freq, uint8 rootNote) { manufacturer = 0; product = 0; samplePeriod = 1000000000 / freq; if(rootNote != 0) baseNote = rootNote - NOTE_MIN; else baseNote = NOTE_MIDDLEC - NOTE_MIN; pitchFraction = 0; SMPTEFormat = 0; SMPTEOffset = 0; numLoops = 0; samplerData = 0; } }; MPT_BINARY_STRUCT(WAVSampleInfoChunk, 36) // Sample loop information chunk (found after WAVSampleInfoChunk in "smpl" chunk) struct WAVSampleLoop { // Sample Loop Types enum LoopType { loopForward = 0, loopBidi = 1, loopBackward = 2, }; uint32le identifier; uint32le loopType; // See LoopType uint32le loopStart; // Loop start in samples uint32le loopEnd; // Loop end in samples uint32le fraction; uint32le playCount; // Loop Count, 0 = infinite // Apply WAV loop information to a mod sample. void ApplyToSample(SmpLength &start, SmpLength &end, SmpLength sampleLength, SampleFlags &flags, ChannelFlags enableFlag, ChannelFlags bidiFlag, bool mptLoopFix) const; // Convert internal loop information into a WAV loop. void ConvertToWAV(SmpLength start, SmpLength end, bool bidi); }; MPT_BINARY_STRUCT(WAVSampleLoop, 24) // Instrument information chunk struct WAVInstrumentChunk { uint8 unshiftedNote; // Root key of sample, 0...127 int8 finetune; // Finetune of root key in cents int8 gain; // in dB uint8 lowNote; // Note range, 0...127 uint8 highNote; uint8 lowVelocity; // Velocity range, 0...127 uint8 highVelocity; }; MPT_BINARY_STRUCT(WAVInstrumentChunk, 7) // MPT-specific "xtra" chunk struct WAVExtraChunk { enum Flags { setPanning = 0x20, }; uint32le flags; uint16le defaultPan; uint16le defaultVolume; uint16le globalVolume; uint16le reserved; uint8le vibratoType; uint8le vibratoSweep; uint8le vibratoDepth; uint8le vibratoRate; // Set up sample information void ConvertToWAV(const ModSample &sample, MODTYPE modType) { if(sample.uFlags[CHN_PANNING]) { flags = WAVExtraChunk::setPanning; } else { flags = 0; } defaultPan = sample.nPan; defaultVolume = sample.nVolume; globalVolume = sample.nGlobalVol; vibratoType = sample.nVibType; vibratoSweep = sample.nVibSweep; vibratoDepth = sample.nVibDepth; vibratoRate = sample.nVibRate; if((modType & MOD_TYPE_XM) && (vibratoDepth | vibratoRate)) { // XM vibrato is upside down vibratoSweep = 255 - vibratoSweep; } } }; MPT_BINARY_STRUCT(WAVExtraChunk, 16) // Set up sample information inline WAVCuePoint ConvertToWAVCuePoint(uint32 id_, SmpLength offset_) { WAVCuePoint result{}; result.id = id_; result.position = offset_; result.riffChunkID = static_cast(RIFFChunk::iddata); result.chunkStart = 0; // we use no Wave List Chunk (wavl) as we have only one data block, so this should be 0. result.blockStart = 0; // ditto result.offset = offset_; return result; } class WAVReader { protected: FileReader file; FileReader sampleData, smplChunk, instChunk, xtraChunk, wsmpChunk, cueChunk; FileReader::ChunkList infoChunk; FileReader::pos_type sampleLength; WAVFormatChunk formatInfo; uint16 subFormat; uint16 codePage; bool isDLS; bool mayBeCoolEdit16_8; uint16 GetFileCodePage(FileReader::ChunkList &chunks); public: WAVReader(FileReader &inputFile); bool IsValid() const { return sampleData.IsValid(); } void FindMetadataChunks(FileReader::ChunkList &chunks); // Self-explanatory getters. WAVFormatChunk::SampleFormats GetSampleFormat() const { return IsExtensibleFormat() ? static_cast(subFormat) : static_cast(formatInfo.format.get()); } uint16 GetNumChannels() const { return formatInfo.numChannels; } uint16 GetBitsPerSample() const { return formatInfo.bitsPerSample; } uint32 GetSampleRate() const { return formatInfo.sampleRate; } uint16 GetBlockAlign() const { return formatInfo.blockAlign; } FileReader GetSampleData() const { return sampleData; } FileReader GetWsmpChunk() const { return wsmpChunk; } bool IsExtensibleFormat() const { return formatInfo.format == WAVFormatChunk::fmtExtensible; } bool MayBeCoolEdit16_8() const { return mayBeCoolEdit16_8; } // Get size of a single sample point, in bytes. uint16 GetSampleSize() const { return static_cast(((static_cast(GetNumChannels()) * static_cast(GetBitsPerSample())) + 7) / 8); } // Get sample length (in samples) SmpLength GetSampleLength() const { return mpt::saturate_cast(sampleLength); } // Apply sample settings from file (loop points, MPT extra settings, ...) to a sample. void ApplySampleSettings(ModSample &sample, mpt::Charset sampleCharset, mpt::charbuf &sampleName); }; #ifndef MODPLUG_NO_FILESAVE class WAVSampleWriter : public WAVWriter { public: WAVSampleWriter(mpt::IO::OFileBase &stream); ~WAVSampleWriter(); public: // Write a sample loop information chunk to the file. void WriteLoopInformation(const ModSample &sample, SmpLength rangeStart = 0, SmpLength rangeEnd = 0); // Write a sample's cue points to the file. void WriteCueInformation(const ModSample &sample, SmpLength rangeStart = 0, SmpLength rangeEnd = 0); // Write MPT's sample information chunk to the file. void WriteExtraInformation(const ModSample &sample, MODTYPE modType, const char *sampleName = nullptr); }; #endif // MODPLUG_NO_FILESAVE OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_mo3.cpp0000644000175000017500000020012114731350227020236 00000000000000/* * Load_mo3.cpp * ------------ * Purpose: MO3 module loader. * Notes : (currently none) * Authors: Johannes Schultz / OpenMPT Devs * Based on documentation and the decompression routines from the * open-source UNMO3 project (https://github.com/lclevy/unmo3). * The modified decompression code has been relicensed to the BSD * license with permission from Laurent ClĂŠvy. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "../common/ComponentManager.h" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/io_read/filedata_base_unseekable_buffer.hpp" #include "Tables.h" #include "../common/version.h" #include "mpt/audio/span.hpp" #include "MPEGFrame.h" #include "OggStream.h" #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE) #include #endif #if defined(MPT_WITH_VORBIS) #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif // MPT_COMPILER_CLANG #include #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #endif #if defined(MPT_WITH_VORBISFILE) #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif // MPT_COMPILER_CLANG #include #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #include "openmpt/soundbase/Copy.hpp" #endif #ifdef MPT_WITH_STBVORBIS #include #include "openmpt/soundbase/Copy.hpp" #endif // MPT_WITH_STBVORBIS OPENMPT_NAMESPACE_BEGIN struct MO3FileHeader { enum MO3HeaderFlags { linearSlides = 0x0001, isS3M = 0x0002, s3mFastSlides = 0x0004, isMTM = 0x0008, // Actually this is simply "not XM". But if none of the S3M, MOD and IT flags are set, it's an MTM. s3mAmigaLimits = 0x0010, // 0x20 and 0x40 have been used in old versions for things that can be inferred from the file format anyway. // The official UNMO3 ignores them. isMOD = 0x0080, isIT = 0x0100, instrumentMode = 0x0200, itCompatGxx = 0x0400, itOldFX = 0x0800, modplugMode = 0x10000, unknown = 0x20000, // Always set (internal BASS flag to designate modules) modVBlank = 0x80000, hasPlugins = 0x100000, extFilterRange = 0x200000, }; uint8le numChannels; // 1...64 (limited by channel panning and volume) uint16le numOrders; uint16le restartPos; uint16le numPatterns; uint16le numTracks; uint16le numInstruments; uint16le numSamples; uint8le defaultSpeed; uint8le defaultTempo; uint32le flags; // See MO3HeaderFlags uint8le globalVol; // 0...128 in IT, 0...64 in S3M uint8le panSeparation; // 0...128 in IT int8le sampleVolume; // Only used in IT uint8le chnVolume[64]; // 0...64 uint8le chnPan[64]; // 0...256, 127 = surround uint8le sfxMacros[16]; uint8le fixedMacros[128][2]; }; MPT_BINARY_STRUCT(MO3FileHeader, 422) struct MO3Envelope { enum MO3EnvelopeFlags { envEnabled = 0x01, envSustain = 0x02, envLoop = 0x04, envFilter = 0x10, envCarry = 0x20, }; uint8le flags; // See MO3EnvelopeFlags uint8le numNodes; uint8le sustainStart; uint8le sustainEnd; uint8le loopStart; uint8le loopEnd; int16le points[25][2]; // Convert MO3 envelope data into OpenMPT's internal envelope format void ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envShift, MODTYPE type) const { if(flags & envEnabled) mptEnv.dwFlags.set(ENV_ENABLED); if(flags & envSustain) mptEnv.dwFlags.set(ENV_SUSTAIN); if(flags & envLoop) mptEnv.dwFlags.set(ENV_LOOP); if(flags & envFilter) mptEnv.dwFlags.set(ENV_FILTER); if(flags & envCarry) mptEnv.dwFlags.set(ENV_CARRY); mptEnv.resize(std::min(numNodes.get(), uint8(25))); mptEnv.nSustainStart = sustainStart; mptEnv.nSustainEnd = (type == MOD_TYPE_XM) ? sustainStart : sustainEnd; mptEnv.nLoopStart = loopStart; mptEnv.nLoopEnd = loopEnd; for(uint32 ev = 0; ev < mptEnv.size(); ev++) { mptEnv[ev].tick = points[ev][0]; if(ev > 0 && mptEnv[ev].tick < mptEnv[ev - 1].tick) mptEnv[ev].tick = mptEnv[ev - 1].tick + 1; mptEnv[ev].value = static_cast(Clamp(points[ev][1] >> envShift, 0, 64)); } } }; MPT_BINARY_STRUCT(MO3Envelope, 106) struct MO3Instrument { enum MO3InstrumentFlags { playOnMIDI = 0x01, mute = 0x02, }; uint32le flags; // See MO3InstrumentFlags uint16le sampleMap[120][2]; MO3Envelope volEnv; MO3Envelope panEnv; MO3Envelope pitchEnv; struct XMVibratoSettings { uint8le type; uint8le sweep; uint8le depth; uint8le rate; } vibrato; // Applies to all samples of this instrument (XM) uint16le fadeOut; uint8le midiChannel; uint8le midiBank; uint8le midiPatch; uint8le midiBend; uint8le globalVol; // 0...128 uint16le panning; // 0...256 if enabled, 0xFFFF otherwise uint8le nna; uint8le pps; uint8le ppc; uint8le dct; uint8le dca; uint16le volSwing; // 0...100 uint16le panSwing; // 0...256 uint8le cutoff; // 0...127, + 128 if enabled uint8le resonance; // 0...127, + 128 if enabled // Convert MO3 instrument data into OpenMPT's internal instrument format void ConvertToMPT(ModInstrument &mptIns, MODTYPE type) const { if(type == MOD_TYPE_XM) { for(size_t i = 0; i < 96; i++) { mptIns.Keyboard[i + 12] = sampleMap[i][1] + 1; } } else { for(size_t i = 0; i < 120; i++) { mptIns.NoteMap[i] = static_cast(sampleMap[i][0] + NOTE_MIN); mptIns.Keyboard[i] = sampleMap[i][1] + 1; } } volEnv.ConvertToMPT(mptIns.VolEnv, 0, type); panEnv.ConvertToMPT(mptIns.PanEnv, 0, type); pitchEnv.ConvertToMPT(mptIns.PitchEnv, 5, type); mptIns.nFadeOut = fadeOut; if(midiChannel >= 128) { // Plugin mptIns.nMixPlug = midiChannel - 127; } else if(midiChannel < 17 && (flags & playOnMIDI)) { // XM, or IT with recent encoder mptIns.nMidiChannel = midiChannel + MidiFirstChannel; } else if(midiChannel > 0 && midiChannel < 17) { // IT encoded with MO3 version prior to 2.4.1 (yes, channel 0 is represented the same way as "no channel") mptIns.nMidiChannel = midiChannel + MidiFirstChannel; } if(mptIns.nMidiChannel != MidiNoChannel) { if(type == MOD_TYPE_XM) { mptIns.nMidiProgram = midiPatch + 1; } else { if(midiBank < 128) mptIns.wMidiBank = midiBank + 1; if(midiPatch < 128) mptIns.nMidiProgram = midiPatch + 1; } mptIns.midiPWD = midiBend; } if(type == MOD_TYPE_IT) mptIns.nGlobalVol = std::min(static_cast(globalVol), uint8(128)) / 2u; if(panning <= 256) { mptIns.nPan = panning; mptIns.dwFlags.set(INS_SETPANNING); } mptIns.nNNA = static_cast(nna.get()); mptIns.nPPS = pps; mptIns.nPPC = ppc; mptIns.nDCT = static_cast(dct.get()); mptIns.nDNA = static_cast(dca.get()); mptIns.nVolSwing = static_cast(std::min(volSwing.get(), uint16(100))); mptIns.nPanSwing = static_cast(std::min(panSwing.get(), uint16(256)) / 4u); mptIns.SetCutoff(cutoff & 0x7F, (cutoff & 0x80) != 0); mptIns.SetResonance(resonance & 0x7F, (resonance & 0x80) != 0); } }; MPT_BINARY_STRUCT(MO3Instrument, 826) struct MO3Sample { enum MO3SampleFlags { smp16Bit = 0x01, smpLoop = 0x10, smpPingPongLoop = 0x20, smpSustain = 0x100, smpSustainPingPong = 0x200, smpStereo = 0x400, smpCompressionMPEG = 0x1000, // MPEG 1.0 / 2.0 / 2.5 sample smpCompressionOgg = 0x1000 | 0x2000, // Ogg sample smpSharedOgg = 0x1000 | 0x2000 | 0x4000, // Ogg sample with shared vorbis header smpDeltaCompression = 0x2000, // Deltas + compression smpDeltaPrediction = 0x4000, // Delta prediction + compression smpOPLInstrument = 0x8000, // OPL patch data smpCompressionMask = 0x1000 | 0x2000 | 0x4000 | 0x8000 }; uint32le freqFinetune; // Frequency in S3M and IT, finetune (0...255) in MOD, MTM, XM int8le transpose; uint8le defaultVolume; // 0...64 uint16le panning; // 0...256 if enabled, 0xFFFF otherwise uint32le length; uint32le loopStart; uint32le loopEnd; uint16le flags; // See MO3SampleFlags uint8le vibType; uint8le vibSweep; uint8le vibDepth; uint8le vibRate; uint8le globalVol; // 0...64 in IT, in XM it represents the instrument number uint32le sustainStart; uint32le sustainEnd; int32le compressedSize; uint16le encoderDelay; // MP3: Ignore first n bytes of decoded output. Ogg: Shared Ogg header size // Convert MO3 sample data into OpenMPT's internal instrument format void ConvertToMPT(ModSample &mptSmp, MODTYPE type, bool frequencyIsHertz) const { mptSmp.Initialize(); mptSmp.SetDefaultCuePoints(); if(type & (MOD_TYPE_IT | MOD_TYPE_S3M)) { if(frequencyIsHertz) mptSmp.nC5Speed = freqFinetune; else mptSmp.nC5Speed = mpt::saturate_round(8363.0 * std::pow(2.0, static_cast(freqFinetune + 1408) / 1536.0)); } else { mptSmp.nFineTune = static_cast(freqFinetune); if(type != MOD_TYPE_MTM) mptSmp.nFineTune -= 128; mptSmp.RelativeTone = transpose; } mptSmp.nVolume = std::min(defaultVolume.get(), uint8(64)) * 4u; if(panning <= 256) { mptSmp.nPan = panning; mptSmp.uFlags.set(CHN_PANNING); } mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; if(flags & smpLoop) mptSmp.uFlags.set(CHN_LOOP); if(flags & smpPingPongLoop) mptSmp.uFlags.set(CHN_PINGPONGLOOP); if(flags & smpSustain) mptSmp.uFlags.set(CHN_SUSTAINLOOP); if(flags & smpSustainPingPong) mptSmp.uFlags.set(CHN_PINGPONGSUSTAIN); mptSmp.nVibType = static_cast(AutoVibratoIT2XM[vibType & 7]); mptSmp.nVibSweep = vibSweep; mptSmp.nVibDepth = vibDepth; mptSmp.nVibRate = vibRate; if(type == MOD_TYPE_IT) mptSmp.nGlobalVol = std::min(static_cast(globalVol), uint8(64)); mptSmp.nSustainStart = sustainStart; mptSmp.nSustainEnd = sustainEnd; } }; MPT_BINARY_STRUCT(MO3Sample, 41) // We need all this information for Ogg-compressed samples with shared headers: // A shared header can be taken from a sample that has not been read yet, so // we first need to read all headers, and then load the Ogg samples afterwards. struct MO3SampleInfo { FileReader chunk; const MO3Sample smpHeader; const int16 sharedHeader; MO3SampleInfo(MO3Sample smpHeader, int16 sharedHeader) : smpHeader{smpHeader}, sharedHeader{sharedHeader} {} }; // Unpack macros // shift control bits until it is empty: // a 0 bit means literal : the next data byte is copied // a 1 means compressed data // then the next 2 bits determines what is the LZ ptr // ('00' same as previous, else stored in stream) #define READ_CTRL_BIT \ data <<= 1; \ carry = (data > 0xFF); \ data &= 0xFF; \ if(data == 0) \ { \ uint8 nextByte; \ if(!file.Read(nextByte)) \ break; \ data = nextByte; \ data <<= 1; \ data += 1; \ carry = (data > 0xFF); \ data &= 0xFF; \ } // length coded within control stream: // most significant bit is 1 // then the first bit of each bits pair (noted n1), // until second bit is 0 (noted n0) #define DECODE_CTRL_BITS \ { \ strLen++; \ do \ { \ READ_CTRL_BIT; \ strLen = mpt::lshift_signed(strLen, 1) + carry; \ READ_CTRL_BIT; \ } while(carry); \ } class MO3FileReaderBuffer final : public mpt::IO::FileDataUnseekableBuffer { public: MO3FileReaderBuffer(const FileReader &file, uint32 targetSize, uint32 suggestedReserveSize) : file{file} , m_suggestedReserveSize{suggestedReserveSize} , m_targetSize{targetSize} , m_totalRemain{targetSize} { } bool UnpackedSuccessfully() const { return !m_totalRemain && !m_broken; } auto SourcePosition() const { return file.GetPosition(); } protected: bool InternalEof() const override { return !m_totalRemain || m_broken; } void InternalReadContinue(std::vector &streamCache, std::size_t suggestedCount) const override { if(!suggestedCount|| !m_targetSize || m_broken) return; uint32 remain = std::min(m_totalRemain, mpt::saturate_cast(suggestedCount)); if(streamCache.empty()) { // Fist byte is always read verbatim streamCache.reserve(std::min(m_targetSize, m_suggestedReserveSize)); streamCache.push_back(mpt::byte_cast(file.ReadUint8())); m_totalRemain--; remain--; } int32 strLen = m_strLen; if(strLen) { // Previous string copy is still in progress uint32 copyLen = std::min(static_cast(strLen), remain); m_totalRemain -= copyLen; remain -= copyLen; strLen -= copyLen; streamCache.insert(streamCache.end(), copyLen, std::byte{}); auto src = streamCache.cend() - copyLen + m_strOffset; auto dst = streamCache.end() - copyLen; do { copyLen--; *dst++ = *src++; } while(copyLen > 0); } uint16 data = m_data; int8 carry = 0; // x86 carry (used to propagate the most significant bit from one byte to another) while(remain) { READ_CTRL_BIT; if(!carry) { // a 0 ctrl bit means 'copy', not compressed byte if(std::byte b; file.Read(b)) streamCache.push_back(b); else break; m_totalRemain--; remain--; } else { // a 1 ctrl bit means compressed bytes are following uint8 lengthAdjust = 0; // length adjustment DECODE_CTRL_BITS; // read length, and if strLen > 3 (coded using more than 1 bits pair) also part of the offset value strLen -= 3; if(strLen < 0) { // reuse same previous relative LZ ptr (m_strOffset is not re-computed) strLen++; } else { // LZ ptr in ctrl stream if(uint8 b; file.Read(b)) m_strOffset = mpt::lshift_signed(strLen, 8) | b; // read less significant offset byte from stream else break; strLen = 0; m_strOffset = ~m_strOffset; if(m_strOffset < -1280) lengthAdjust++; lengthAdjust++; // length is always at least 1 if(m_strOffset < -32000) lengthAdjust++; } if(m_strOffset >= 0 || -static_cast(streamCache.size()) > m_strOffset) break; // read the next 2 bits as part of strLen READ_CTRL_BIT; strLen = mpt::lshift_signed(strLen, 1) + carry; READ_CTRL_BIT; strLen = mpt::lshift_signed(strLen, 1) + carry; if(strLen == 0) { // length does not fit in 2 bits DECODE_CTRL_BITS; // decode length: 1 is the most significant bit, strLen += 2; // then first bit of each bits pairs (noted n1), until n0. } strLen += lengthAdjust; // length adjustment if(strLen <= 0 || m_totalRemain < static_cast(strLen)) break; // Copy previous string // Need to do this in two steps (allocate, then copy) as source and destination may overlap (e.g. strOffset = -1, strLen = 2 repeats last character twice) uint32 copyLen = std::min(static_cast(strLen), remain); m_totalRemain -= copyLen; remain -= copyLen; strLen -= copyLen; streamCache.insert(streamCache.end(), copyLen, std::byte{}); auto src = streamCache.cend() - copyLen + m_strOffset; auto dst = streamCache.end() - copyLen; do { copyLen--; *dst++ = *src++; } while(copyLen > 0); } } m_data = data; m_strLen = strLen; // Premature EOF or corrupted stream? if(remain) m_broken = true; } bool HasPinnedView() const override { return false; } mutable FileReader file; const uint32 m_suggestedReserveSize; const uint32 m_targetSize; mutable bool m_broken = false; mutable uint16 m_data = 0; mutable int32 m_strLen = 0; // Length of repeated string mutable int32 m_strOffset = 0; // Offset of repeated string mutable uint32 m_totalRemain = 0; }; struct MO3Delta8BitParams { using sample_t = int8; using unsigned_t = uint8; static constexpr int shift = 7; static constexpr uint8 dhInit = 4; static inline void Decode(FileReader &file, int8 &carry, uint16 &data, uint8 & /*dh*/, unsigned_t &val) { do { READ_CTRL_BIT; val = static_cast((val << 1) + carry); READ_CTRL_BIT; } while(carry); } }; struct MO3Delta16BitParams { using sample_t = int16; using unsigned_t = uint16; static constexpr int shift = 15; static constexpr uint8 dhInit = 8; static inline void Decode(FileReader &file, int8 &carry, uint16 &data, uint8 &dh, unsigned_t &val) { if(dh < 5) { do { READ_CTRL_BIT; val = static_cast((val << 1) + carry); READ_CTRL_BIT; val = static_cast((val << 1) + carry); READ_CTRL_BIT; } while(carry); } else { do { READ_CTRL_BIT; val = static_cast((val << 1) + carry); READ_CTRL_BIT; } while(carry); } } }; template static void UnpackMO3DeltaSample(FileReader &file, typename Properties::sample_t *dst, uint32 length, uint8 numChannels) { uint8 dh = Properties::dhInit, cl = 0; int8 carry = 0; uint16 data = 0; typename Properties::unsigned_t val; typename Properties::sample_t previous = 0; for(uint8 chn = 0; chn < numChannels; chn++) { typename Properties::sample_t *p = dst + chn; const typename Properties::sample_t *const pEnd = p + length * numChannels; while(p < pEnd) { val = 0; Properties::Decode(file, carry, data, dh, val); cl = dh; while(cl > 0) { READ_CTRL_BIT; val = static_cast((val << 1) + carry); cl--; } cl = 1; if(val >= 4) { cl = Properties::shift; while(((1 << cl) & val) == 0 && cl > 1) cl--; } dh = dh + cl; dh >>= 1; // next length in bits of encoded delta second part carry = val & 1; // sign of delta 1=+, 0=not val >>= 1; if(carry == 0) val = ~val; // negative delta val = static_cast(val + previous); // previous value + delta *p = val; p += numChannels; previous = val; } } } template static void UnpackMO3DeltaPredictionSample(FileReader &file, typename Properties::sample_t *dst, uint32 length, uint8 numChannels) { uint8 dh = Properties::dhInit, cl = 0; int8 carry; uint16 data = 0; int32 next = 0; typename Properties::unsigned_t val = 0; typename Properties::sample_t sval = 0, delta = 0, previous = 0; for(uint8 chn = 0; chn < numChannels; chn++) { typename Properties::sample_t *p = dst + chn; const typename Properties::sample_t *const pEnd = p + length * numChannels; while(p < pEnd) { val = 0; Properties::Decode(file, carry, data, dh, val); cl = dh; // length in bits of: delta second part (right most bits of delta) and sign bit while(cl > 0) { READ_CTRL_BIT; val = static_cast((val << 1) + carry); cl--; } cl = 1; if(val >= 4) { cl = Properties::shift; while(((1 << cl) & val) == 0 && cl > 1) cl--; } dh = dh + cl; dh >>= 1; // next length in bits of encoded delta second part carry = val & 1; // sign of delta 1=+, 0=not val >>= 1; if(carry == 0) val = ~val; // negative delta delta = static_cast(val); val = val + static_cast(next); // predicted value + delta *p = val; p += numChannels; sval = static_cast(val); next = (sval * (1 << 1)) + (delta >> 1) - previous; // corrected next value Limit(next, std::numeric_limits::min(), std::numeric_limits::max()); previous = sval; } } } #undef READ_CTRL_BIT #undef DECODE_CTRL_BITS #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE) static size_t VorbisfileFilereaderRead(void *ptr, size_t size, size_t nmemb, void *datasource) { FileReader &file = *mpt::void_ptr(datasource); return file.ReadRaw(mpt::span(mpt::void_cast(ptr), size * nmemb)).size() / size; } static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int whence) { FileReader &file = *mpt::void_ptr(datasource); switch(whence) { case SEEK_SET: if(!mpt::in_range(offset)) { return -1; } return file.Seek(mpt::saturate_cast(offset)) ? 0 : -1; case SEEK_CUR: if(offset < 0) { if(offset == std::numeric_limits::min()) { return -1; } if(!mpt::in_range(0 - offset)) { return -1; } return file.SkipBack(mpt::saturate_cast(0 - offset)) ? 0 : -1; } else { if(!mpt::in_range(offset)) { return -1; } return file.Skip(mpt::saturate_cast(offset)) ? 0 : -1; } break; case SEEK_END: if(!mpt::in_range(offset)) { return -1; } if(!mpt::in_range(file.GetLength() + offset)) { return -1; } return file.Seek(mpt::saturate_cast(file.GetLength() + offset)) ? 0 : -1; default: return -1; } } static long VorbisfileFilereaderTell(void *datasource) { FileReader &file = *mpt::void_ptr(datasource); FileReader::pos_type result = file.GetPosition(); if(!mpt::in_range(result)) { return -1; } return static_cast(result); } #endif // MPT_WITH_VORBIS && MPT_WITH_VORBISFILE struct MO3ContainerHeader { char magic[3]; // MO3 uint8le version; uint32le musicSize; }; MPT_BINARY_STRUCT(MO3ContainerHeader, 8) static bool ValidateHeader(const MO3ContainerHeader &containerHeader) { if(std::memcmp(containerHeader.magic, "MO3", 3)) { return false; } // Due to the LZ algorithm's unbounded back window, we could reach gigantic sizes with just a few dozen bytes. // 512 MB of music data (not samples) is chosen as a safeguard that is probably (hopefully) *way* beyond anything a real-world module will ever reach. if(containerHeader.musicSize <= sizeof(MO3FileHeader) || containerHeader.musicSize >= 0x2000'0000) { return false; } if(containerHeader.version > 5) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize) { MO3ContainerHeader containerHeader; if(!file.ReadStruct(containerHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(containerHeader)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); MO3ContainerHeader containerHeader; if(!file.ReadStruct(containerHeader)) { return false; } if(!ValidateHeader(containerHeader)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } const uint8 version = containerHeader.version; uint32 compressedSize = uint32_max, reserveSize = 1024 * 1024; // Generous estimate based on biggest pre-v5 MO3s found in the wild (~350K music data) if(version >= 5) { // Size of compressed music chunk compressedSize = file.ReadUint32LE(); if(!file.CanRead(compressedSize)) return false; // Generous estimate based on highest real-world compression ratio I found in a module (~20:1) reserveSize = std::min(Util::MaxValueOfType(reserveSize) / 32u, compressedSize) * 32u; } std::shared_ptr filenamePtr; if(auto filename = file.GetOptionalFileName(); filename) filenamePtr = std::make_shared(std::move(*filename)); auto musicChunkData = std::make_shared(file, containerHeader.musicSize, reserveSize); mpt::IO::FileCursor> fileCursor{musicChunkData, std::move(filenamePtr)}; FileReader musicChunk{fileCursor}; std::string songName, songMessage; musicChunk.ReadNullString(songName); musicChunk.ReadNullString(songMessage); MO3FileHeader fileHeader; if(!musicChunk.ReadStruct(fileHeader) || fileHeader.numChannels == 0 || fileHeader.numChannels > MAX_BASECHANNELS || fileHeader.restartPos > fileHeader.numOrders || fileHeader.numInstruments >= MAX_INSTRUMENTS || fileHeader.numSamples >= MAX_SAMPLES) { return false; } MODTYPE modType = MOD_TYPE_XM; if(fileHeader.flags & MO3FileHeader::isIT) modType = MOD_TYPE_IT; else if(fileHeader.flags & MO3FileHeader::isS3M) modType = MOD_TYPE_S3M; else if(fileHeader.flags & MO3FileHeader::isMOD) modType = MOD_TYPE_MOD; else if(fileHeader.flags & MO3FileHeader::isMTM) modType = MOD_TYPE_MTM; InitializeGlobals(modType, fileHeader.numChannels); Order().SetRestartPos(fileHeader.restartPos); m_nInstruments = fileHeader.numInstruments; m_nSamples = fileHeader.numSamples; Order().SetDefaultSpeed(fileHeader.defaultSpeed ? fileHeader.defaultSpeed : 6); Order().SetDefaultTempoInt(fileHeader.defaultTempo ? fileHeader.defaultTempo : 125); m_songName = std::move(songName); m_songMessage.SetRaw(std::move(songMessage)); m_SongFlags.set(SONG_IMPORTED); if(fileHeader.flags & MO3FileHeader::linearSlides) m_SongFlags.set(SONG_LINEARSLIDES); if((fileHeader.flags & MO3FileHeader::s3mAmigaLimits) && m_nType == MOD_TYPE_S3M) m_SongFlags.set(SONG_AMIGALIMITS); if((fileHeader.flags & MO3FileHeader::s3mFastSlides) && m_nType == MOD_TYPE_S3M) m_SongFlags.set(SONG_FASTVOLSLIDES); if(!(fileHeader.flags & MO3FileHeader::itOldFX) && m_nType == MOD_TYPE_IT) m_SongFlags.set(SONG_ITOLDEFFECTS); if(!(fileHeader.flags & MO3FileHeader::itCompatGxx) && m_nType == MOD_TYPE_IT) m_SongFlags.set(SONG_ITCOMPATGXX); if(fileHeader.flags & MO3FileHeader::extFilterRange) m_SongFlags.set(SONG_EXFILTERRANGE); if(fileHeader.flags & MO3FileHeader::modVBlank) m_playBehaviour.set(kMODVBlankTiming); if(m_nType == MOD_TYPE_IT) m_nDefaultGlobalVolume = std::min(fileHeader.globalVol.get(), uint8(128)) * 2; else if(m_nType == MOD_TYPE_S3M) m_nDefaultGlobalVolume = std::min(fileHeader.globalVol.get(), uint8(64)) * 4; else if(m_nType == MOD_TYPE_MOD) m_SongFlags.set(SONG_FORMAT_NO_VOLCOL); if(fileHeader.sampleVolume < 0) m_nSamplePreAmp = fileHeader.sampleVolume + 52; else m_nSamplePreAmp = static_cast(std::exp(fileHeader.sampleVolume * 3.1 / 20.0)) + 51; // Header only has room for 64 channels, like in IT const CHANNELINDEX headerChannels = std::min(GetNumChannels(), CHANNELINDEX(64)); for(CHANNELINDEX i = 0; i < headerChannels; i++) { if(m_nType == MOD_TYPE_IT) ChnSettings[i].nVolume = std::min(fileHeader.chnVolume[i].get(), uint8(64)); if(m_nType != MOD_TYPE_XM) { if(fileHeader.chnPan[i] == 127) ChnSettings[i].dwFlags = CHN_SURROUND; else if(fileHeader.chnPan[i] == 255) ChnSettings[i].nPan = 256; else ChnSettings[i].nPan = fileHeader.chnPan[i]; } } bool anyMacros = false; for(uint32 i = 0; i < 16; i++) { if(fileHeader.sfxMacros[i]) anyMacros = true; } for(uint32 i = 0; i < 128; i++) { if(fileHeader.fixedMacros[i][1]) anyMacros = true; } if(anyMacros) { for(uint32 i = 0; i < 16; i++) { if(fileHeader.sfxMacros[i]) m_MidiCfg.SFx[i] = MPT_AFORMAT("F0F0{}z")(mpt::afmt::HEX0<2>(fileHeader.sfxMacros[i] - 1)); else m_MidiCfg.SFx[i] = ""; } for(uint32 i = 0; i < 128; i++) { if(fileHeader.fixedMacros[i][1]) m_MidiCfg.Zxx[i] = MPT_AFORMAT("F0F0{}{}")(mpt::afmt::HEX0<2>(fileHeader.fixedMacros[i][1] - 1), mpt::afmt::HEX0<2>(fileHeader.fixedMacros[i][0].get())); else m_MidiCfg.Zxx[i] = ""; } } const bool hasOrderSeparators = !(m_nType & (MOD_TYPE_MOD | MOD_TYPE_XM)); ReadOrderFromFile(Order(), musicChunk, fileHeader.numOrders, hasOrderSeparators ? 0xFF : uint16_max, hasOrderSeparators ? 0xFE : uint16_max); // Track assignments for all patterns FileReader trackChunk = musicChunk.ReadChunk(fileHeader.numPatterns * fileHeader.numChannels * sizeof(uint16)); FileReader patLengthChunk = musicChunk.ReadChunk(fileHeader.numPatterns * sizeof(uint16)); std::vector tracks(fileHeader.numTracks); for(auto &track : tracks) { uint32 len = musicChunk.ReadUint32LE(); // A pattern can be at most 65535 rows long, one row can contain at most 15 events (with the status bytes, that 31 bytes per row). // Leaving some margin for error, that gives us an upper limit of 2MB per track. if(len >= 0x20'0000) return false; track = musicChunk.ReadChunk(len); } /* MO3 pattern commands: 01 = Note 02 = Instrument 03 = CMD_ARPEGGIO (IT, XM, S3M, MOD, MTM) 04 = CMD_PORTAMENTOUP (XM, MOD, MTM) [for formats with separate fine slides] 05 = CMD_PORTAMENTODOWN (XM, MOD, MTM) [for formats with separate fine slides] 06 = CMD_TONEPORTAMENTO (IT, XM, S3M, MOD, MTM) / VOLCMD_TONEPORTA (IT, XM) 07 = CMD_VIBRATO (IT, XM, S3M, MOD, MTM) / VOLCMD_VIBRATODEPTH (IT) 08 = CMD_TONEPORTAVOL (XM, MOD, MTM) 09 = CMD_VIBRATOVOL (XM, MOD, MTM) 0A = CMD_TREMOLO (IT, XM, S3M, MOD, MTM) 0B = CMD_PANNING8 (IT, XM, S3M, MOD, MTM) / VOLCMD_PANNING (IT, XM) 0C = CMD_OFFSET (IT, XM, S3M, MOD, MTM) 0D = CMD_VOLUMESLIDE (XM, MOD, MTM) 0E = CMD_POSITIONJUMP (IT, XM, S3M, MOD, MTM) 0F = CMD_VOLUME (XM, MOD, MTM) / VOLCMD_VOLUME (IT, XM, S3M) 10 = CMD_PATTERNBREAK (IT, XM, MOD, MTM) - BCD-encoded in MOD/XM/S3M/MTM! 11 = CMD_MODCMDEX (XM, MOD, MTM) 12 = CMD_TEMPO (XM, MOD, MTM) / CMD_SPEED (XM, MOD, MTM) 13 = CMD_TREMOR (XM) 14 = VOLCMD_VOLSLIDEUP x=X0 (XM) / VOLCMD_VOLSLIDEDOWN x=0X (XM) 15 = VOLCMD_FINEVOLUP x=X0 (XM) / VOLCMD_FINEVOLDOWN x=0X (XM) 16 = CMD_GLOBALVOLUME (IT, XM, S3M) 17 = CMD_GLOBALVOLSLIDE (XM) 18 = CMD_KEYOFF (XM) 19 = CMD_SETENVPOSITION (XM) 1A = CMD_PANNINGSLIDE (XM) 1B = VOLCMD_PANSLIDELEFT x=0X (XM) / VOLCMD_PANSLIDERIGHT x=X0 (XM) 1C = CMD_RETRIG (XM) 1D = CMD_XFINEPORTAUPDOWN X1x (XM) 1E = CMD_XFINEPORTAUPDOWN X2x (XM) 1F = VOLCMD_VIBRATOSPEED (XM) 20 = VOLCMD_VIBRATODEPTH (XM) 21 = CMD_SPEED (IT, S3M) 22 = CMD_VOLUMESLIDE (IT, S3M) 23 = CMD_PORTAMENTODOWN (IT, S3M) [for formats without separate fine slides] 24 = CMD_PORTAMENTOUP (IT, S3M) [for formats without separate fine slides] 25 = CMD_TREMOR (IT, S3M) 26 = CMD_RETRIG (IT, S3M) 27 = CMD_FINEVIBRATO (IT, S3M) 28 = CMD_CHANNELVOLUME (IT, S3M) 29 = CMD_CHANNELVOLSLIDE (IT, S3M) 2A = CMD_PANNINGSLIDE (IT, S3M) 2B = CMD_S3MCMDEX (IT, S3M) 2C = CMD_TEMPO (IT, S3M) 2D = CMD_GLOBALVOLSLIDE (IT, S3M) 2E = CMD_PANBRELLO (IT, XM, S3M) 2F = CMD_MIDI (IT, XM, S3M) 30 = VOLCMD_FINEVOLUP x=0...9 (IT) / VOLCMD_FINEVOLDOWN x=10...19 (IT) / VOLCMD_VOLSLIDEUP x=20...29 (IT) / VOLCMD_VOLSLIDEDOWN x=30...39 (IT) 31 = VOLCMD_PORTADOWN (IT) 32 = VOLCMD_PORTAUP (IT) 33 = Unused XM command "W" (XM) 34 = Any other IT volume column command to support OpenMPT extensions (IT) 35 = CMD_XPARAM (IT) 36 = CMD_SMOOTHMIDI (IT) 37 = CMD_DELAYCUT (IT) 38 = CMD_FINETUNE (MPTM) 39 = CMD_FINETUNE_SMOOTH (MPTM) Note: S3M/IT CMD_TONEPORTAVOL / CMD_VIBRATOVOL are encoded as two commands: K= 07 00 22 x L= 06 00 22 x */ static constexpr EffectCommand effTrans[] = { CMD_NONE, CMD_NONE, CMD_NONE, CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, CMD_PANNING8, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_POSITIONJUMP, CMD_VOLUME, CMD_PATTERNBREAK, CMD_MODCMDEX, CMD_TEMPO, CMD_TREMOR, CMD_NONE,/*VolSlideUp*/ CMD_NONE,/*VolSlideDn*/ CMD_GLOBALVOLUME, CMD_GLOBALVOLSLIDE, CMD_KEYOFF, CMD_SETENVPOSITION, CMD_PANNINGSLIDE, CMD_NONE,/*PanSlide*/ CMD_RETRIG, CMD_XFINEPORTAUPDOWN, CMD_XFINEPORTAUPDOWN, CMD_NONE,/*VibSpeed*/ CMD_NONE,/*VibDepth*/ CMD_SPEED, CMD_VOLUMESLIDE, CMD_PORTAMENTODOWN, CMD_PORTAMENTOUP, CMD_TREMOR, CMD_RETRIG, CMD_FINEVIBRATO, CMD_CHANNELVOLUME, CMD_CHANNELVOLSLIDE, CMD_PANNINGSLIDE, CMD_S3MCMDEX, CMD_TEMPO, CMD_GLOBALVOLSLIDE, CMD_PANBRELLO, CMD_MIDI, CMD_NONE,/*FineVolSld*/ CMD_NONE,/*PortaDown*/ CMD_NONE, /*PortaUp*/ CMD_DUMMY, CMD_NONE,/*ITVolCol*/ CMD_XPARAM, CMD_SMOOTHMIDI, CMD_DELAYCUT, CMD_FINETUNE, CMD_FINETUNE_SMOOTH, }; uint8 noteOffset = NOTE_MIN; if(m_nType == MOD_TYPE_MTM) noteOffset = 13 + NOTE_MIN; else if(m_nType != MOD_TYPE_IT) noteOffset = 12 + NOTE_MIN; bool onlyAmigaNotes = true; if(loadFlags & loadPatternData) Patterns.ResizeArray(fileHeader.numPatterns); for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++) { const ROWINDEX numRows = patLengthChunk.ReadUint16LE(); if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, numRows)) continue; for(CHANNELINDEX chn = 0; chn < fileHeader.numChannels; chn++) { uint16 trackIndex = trackChunk.ReadUint16LE(); if(trackIndex >= tracks.size()) continue; FileReader &track = tracks[trackIndex]; track.Rewind(); ROWINDEX row = 0; ModCommand *patData = Patterns[pat].GetpModCommand(0, chn); while(row < numRows) { const uint8 b = track.ReadUint8(); if(!b) break; const uint8 numCommands = (b & 0x0F), rep = (b >> 4); ModCommand m; for(uint8 c = 0; c < numCommands; c++) { const auto cmd = track.ReadArray(); // Import pattern commands switch(cmd[0]) { case 0x01: // Note m.note = cmd[1]; if(m.note < 120) m.note += noteOffset; else if(m.note == 0xFF) m.note = NOTE_KEYOFF; else if(m.note == 0xFE) m.note = NOTE_NOTECUT; else m.note = NOTE_FADE; if(!m.IsAmigaNote()) onlyAmigaNotes = false; break; case 0x02: // Instrument m.instr = cmd[1] + 1; break; case 0x06: // Tone portamento if(m.volcmd == VOLCMD_NONE && m_nType == MOD_TYPE_XM && !(cmd[1] & 0x0F)) { m.SetVolumeCommand(VOLCMD_TONEPORTAMENTO, cmd[1] >> 4); break; } else if(m.volcmd == VOLCMD_NONE && m_nType == MOD_TYPE_IT) { for(uint8 i = 0; i < 10; i++) { if(ImpulseTrackerPortaVolCmd[i] == cmd[1]) { m.SetVolumeCommand(VOLCMD_TONEPORTAMENTO, i); break; } } if(m.volcmd != VOLCMD_NONE) break; } m.SetEffectCommand(CMD_TONEPORTAMENTO, cmd[1]); break; case 0x07: // Vibrato if(m.volcmd == VOLCMD_NONE && cmd[1] < 10 && m_nType == MOD_TYPE_IT) { m.SetVolumeCommand(VOLCMD_VIBRATODEPTH, cmd[1]); } else { m.SetEffectCommand(CMD_VIBRATO, cmd[1]); } break; case 0x0B: // Panning if(m.volcmd == VOLCMD_NONE) { if(m_nType == MOD_TYPE_IT && cmd[1] == 0xFF) { m.SetVolumeCommand(VOLCMD_PANNING, 64); break; } if((m_nType == MOD_TYPE_IT && !(cmd[1] & 0x03)) || (m_nType == MOD_TYPE_XM && !(cmd[1] & 0x0F))) { m.SetVolumeCommand(VOLCMD_PANNING, cmd[1] / 4); break; } } m.SetEffectCommand(CMD_PANNING8, cmd[1]); break; case 0x0F: // Volume if(m_nType != MOD_TYPE_MOD && m.volcmd == VOLCMD_NONE && cmd[1] <= 64) m.SetVolumeCommand(VOLCMD_VOLUME, cmd[1]); else m.SetEffectCommand(CMD_VOLUME, cmd[1]); break; case 0x10: // Pattern break m.SetEffectCommand(CMD_PATTERNBREAK, cmd[1]); if(m_nType != MOD_TYPE_IT) m.param = static_cast(((m.param >> 4) * 10) + (m.param & 0x0F)); break; case 0x12: // Combined Tempo / Speed command m.SetEffectCommand((cmd[1] < 0x20) ? CMD_SPEED : CMD_TEMPO, cmd[1]); break; case 0x14: case 0x15: // XM volume column volume slides if(cmd[1] & 0xF0) { m.SetVolumeCommand((cmd[0] == 0x14) ? VOLCMD_VOLSLIDEUP : VOLCMD_FINEVOLUP, cmd[1] >> 4); } else { m.SetVolumeCommand((cmd[0] == 0x14) ? VOLCMD_VOLSLIDEDOWN : VOLCMD_FINEVOLDOWN, cmd[1] & 0x0F); } break; case 0x1B: // XM volume column panning slides if(cmd[1] & 0xF0) m.SetVolumeCommand(VOLCMD_PANSLIDERIGHT, cmd[1] >> 4); else m.SetVolumeCommand(VOLCMD_PANSLIDELEFT, cmd[1] & 0x0F); break; case 0x1D: // XM extra fine porta up m.SetEffectCommand(CMD_XFINEPORTAUPDOWN, 0x10 | cmd[1]); break; case 0x1E: // XM extra fine porta down m.SetEffectCommand(CMD_XFINEPORTAUPDOWN, 0x20 | cmd[1]); break; case 0x1F: case 0x20: // XM volume column vibrato m.SetVolumeCommand((cmd[0] == 0x1F) ? VOLCMD_VIBRATOSPEED: VOLCMD_VIBRATODEPTH, cmd[1]); break; case 0x22: // IT / S3M volume slide if(m.command == CMD_TONEPORTAMENTO) m.command = CMD_TONEPORTAVOL; else if(m.command == CMD_VIBRATO) m.command = CMD_VIBRATOVOL; else m.command = CMD_VOLUMESLIDE; m.param = cmd[1]; break; case 0x30: // IT volume column volume slides m.vol = cmd[1] % 10; if(cmd[1] < 10) m.volcmd = VOLCMD_FINEVOLUP; else if(cmd[1] < 20) m.volcmd = VOLCMD_FINEVOLDOWN; else if(cmd[1] < 30) m.volcmd = VOLCMD_VOLSLIDEUP; else if(cmd[1] < 40) m.volcmd = VOLCMD_VOLSLIDEDOWN; break; case 0x31: case 0x32: // IT volume column portamento m.SetVolumeCommand((cmd[0] == 0x31) ? VOLCMD_PORTADOWN: VOLCMD_PORTAUP, cmd[1]); break; case 0x34: // Any unrecognized IT volume command if(cmd[1] >= 223 && cmd[1] <= 232) m.SetVolumeCommand(VOLCMD_OFFSET, cmd[1] - 223); break; default: if(cmd[0] < std::size(effTrans)) m.SetEffectCommand(effTrans[cmd[0]], cmd[1]); break; } } #ifdef MODPLUG_TRACKER if(m_nType == MOD_TYPE_MTM) m.Convert(MOD_TYPE_MTM, MOD_TYPE_S3M, *this); #endif ROWINDEX targetRow = std::min(row + rep, numRows); while(row < targetRow) { *patData = m; patData += fileHeader.numChannels; row++; } } } } if(GetType() == MOD_TYPE_MOD && GetNumChannels() == 4 && onlyAmigaNotes) { m_SongFlags.set(SONG_AMIGALIMITS | SONG_ISAMIGA); } const bool isSampleMode = (m_nType != MOD_TYPE_XM && !(fileHeader.flags & MO3FileHeader::instrumentMode)); std::vector instrVibrato(m_nType == MOD_TYPE_XM ? m_nInstruments : 0); for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++) { ModInstrument *pIns = nullptr; if(isSampleMode || (pIns = AllocateInstrument(ins)) == nullptr) { // Even in IT sample mode, instrument headers are still stored.... while(musicChunk.ReadUint8() != 0) ; if(version >= 5) { while(musicChunk.ReadUint8() != 0) ; } if(!musicChunk.Skip(sizeof(MO3Instrument))) return false; continue; } std::string name; musicChunk.ReadNullString(name); pIns->name = name; if(version >= 5) { musicChunk.ReadNullString(name); pIns->filename = name; } MO3Instrument insHeader; if(!musicChunk.ReadStruct(insHeader)) return false; insHeader.ConvertToMPT(*pIns, m_nType); if(m_nType == MOD_TYPE_XM) instrVibrato[ins - 1] = insHeader.vibrato; } if(isSampleMode) m_nInstruments = 0; std::vector sampleInfos; const bool frequencyIsHertz = (version >= 5 || !(fileHeader.flags & MO3FileHeader::linearSlides)); for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { ModSample &sample = Samples[smp]; std::string name; musicChunk.ReadNullString(name); m_szNames[smp] = name; if(version >= 5) musicChunk.ReadNullString(name); else name.clear(); MO3Sample smpHeader; if(!musicChunk.ReadStruct(smpHeader)) return false; smpHeader.ConvertToMPT(sample, m_nType, frequencyIsHertz); sample.filename = name; int16 sharedOggHeader = 0; if(version >= 5 && (smpHeader.flags & MO3Sample::smpCompressionMask) == MO3Sample::smpSharedOgg) { sharedOggHeader = musicChunk.ReadInt16LE(); } if(loadFlags & loadSampleData) { sampleInfos.reserve(m_nSamples); sampleInfos.emplace_back(smpHeader, sharedOggHeader); } } if(m_nType == MOD_TYPE_XM) { // Transfer XM instrument vibrato to samples for(INSTRUMENTINDEX ins = 0; ins < m_nInstruments; ins++) { PropagateXMAutoVibrato(ins + 1, static_cast(instrVibrato[ins].type.get()), instrVibrato[ins].sweep, instrVibrato[ins].depth, instrVibrato[ins].rate); } } if((fileHeader.flags & MO3FileHeader::hasPlugins) && musicChunk.CanRead(1)) { // Plugin data uint8 pluginFlags = musicChunk.ReadUint8(); if(pluginFlags & 1) { // Channel plugins for(auto &chn : ChnSettings) { chn.nMixPlugin = static_cast(musicChunk.ReadUint32LE()); } } while(musicChunk.CanRead(1)) { PLUGINDEX plug = musicChunk.ReadUint8(); if(!plug) break; uint32 len = musicChunk.ReadUint32LE(); if(len >= containerHeader.musicSize || containerHeader.musicSize - len < musicChunk.GetPosition()) return false; FileReader pluginChunk = musicChunk.ReadChunk(len); #ifndef NO_PLUGINS if(plug <= MAX_MIXPLUGINS) { ReadMixPluginChunk(pluginChunk, m_MixPlugins[plug - 1]); } #endif // NO_PLUGINS } } mpt::ustring madeWithTracker; uint16 cwtv = 0; uint16 cmwt = 0; while(musicChunk.CanRead(8)) { uint32 id = musicChunk.ReadUint32LE(); uint32 len = musicChunk.ReadUint32LE(); if(len >= containerHeader.musicSize || containerHeader.musicSize - len < musicChunk.GetPosition()) return false; FileReader chunk = musicChunk.ReadChunk(len); switch(id) { case MagicLE("VERS"): // Tracker magic bytes (depending on format) switch(m_nType) { case MOD_TYPE_IT: cwtv = chunk.ReadUint16LE(); cmwt = chunk.ReadUint16LE(); /*switch(cwtv >> 12) { }*/ break; case MOD_TYPE_S3M: cwtv = chunk.ReadUint16LE(); break; case MOD_TYPE_XM: chunk.ReadString(madeWithTracker, mpt::Charset::CP437, std::min(FileReader::pos_type(32), chunk.GetLength())); break; case MOD_TYPE_MTM: { uint8 mtmVersion = chunk.ReadUint8(); madeWithTracker = MPT_UFORMAT("MultiTracker {}.{}")(mtmVersion >> 4, mtmVersion & 0x0F); } break; default: break; } break; case MagicLE("PRHI"): m_nDefaultRowsPerBeat = chunk.ReadUint8(); m_nDefaultRowsPerMeasure = chunk.ReadUint8(); break; case MagicLE("MIDI"): // Full MIDI config chunk.ReadStruct(m_MidiCfg); m_MidiCfg.Sanitize(); break; case MagicLE("OMPT"): // Read pattern names: "PNAM" if(chunk.ReadMagic("PNAM")) { FileReader patterns = chunk.ReadChunk(chunk.ReadUint32LE()); const PATTERNINDEX namedPats = std::min(static_cast(patterns.GetLength() / MAX_PATTERNNAME), Patterns.Size()); for(PATTERNINDEX pat = 0; pat < namedPats; pat++) { char patName[MAX_PATTERNNAME]; patterns.ReadString(patName, MAX_PATTERNNAME); Patterns[pat].SetName(patName); } } // Read channel names: "CNAM" if(chunk.ReadMagic("CNAM")) { FileReader channels = chunk.ReadChunk(chunk.ReadUint32LE()); const CHANNELINDEX namedChans = std::min(static_cast(channels.GetLength() / MAX_CHANNELNAME), GetNumChannels()); for(CHANNELINDEX chn = 0; chn < namedChans; chn++) { channels.ReadString(ChnSettings[chn].szName, MAX_CHANNELNAME); } } LoadExtendedInstrumentProperties(chunk); LoadExtendedSongProperties(chunk, true); if(cwtv > 0x0889 && cwtv <= 0x8FF) { m_nType = MOD_TYPE_MPT; LoadMPTMProperties(chunk, cwtv); } if(m_dwLastSavedWithVersion) { madeWithTracker = UL_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion); } break; } } if((GetType() == MOD_TYPE_IT && cwtv >= 0x0100 && cwtv < 0x0214) || (GetType() == MOD_TYPE_S3M && cwtv >= 0x3100 && cwtv < 0x3214) || (GetType() == MOD_TYPE_S3M && cwtv >= 0x1300 && cwtv < 0x1320)) { // Ignore MIDI data in files made with IT older than version 2.14 and old ST3 versions. m_MidiCfg.ClearZxxMacros(); } if(fileHeader.flags & MO3FileHeader::modplugMode) { // Apply some old ModPlug (mis-)behaviour if(!m_dwLastSavedWithVersion) { // These fixes are only applied when the OpenMPT version number is not known, as otherwise the song upgrade feature will take care of it. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { if(ModInstrument *ins = Instruments[i]) { // Fix pitch / filter envelope being shortened by one tick (for files before v1.20) ins->GetEnvelope(ENV_PITCH).Convert(MOD_TYPE_XM, GetType()); // Fix excessive pan swing range (for files before v1.26) ins->nPanSwing = static_cast((ins->nPanSwing + 3) / 4u); } } } if(m_dwLastSavedWithVersion < MPT_V("1.18.00.00")) { m_playBehaviour.reset(kITOffset); m_playBehaviour.reset(kFT2ST3OffsetOutOfRange); } if(m_dwLastSavedWithVersion < MPT_V("1.23.00.00")) m_playBehaviour.reset(kFT2Periods); if(m_dwLastSavedWithVersion < MPT_V("1.26.00.00")) m_playBehaviour.reset(kITInstrWithNoteOff); } if(madeWithTracker.empty()) madeWithTracker = MPT_UFORMAT("MO3 v{}")(version); else madeWithTracker = MPT_UFORMAT("MO3 v{} ({})")(version, madeWithTracker); m_modFormat.formatName = MPT_UFORMAT("Un4seen MO3 v{}")(version); m_modFormat.type = UL_("mo3"); switch(GetType()) { case MOD_TYPE_MTM: m_modFormat.originalType = UL_("mtm"); m_modFormat.originalFormatName = UL_("MultiTracker"); break; case MOD_TYPE_MOD: m_modFormat.originalType = UL_("mod"); m_modFormat.originalFormatName = UL_("Generic MOD"); break; case MOD_TYPE_XM: m_modFormat.originalType = UL_("xm"); m_modFormat.originalFormatName = UL_("FastTracker 2"); break; case MOD_TYPE_S3M: m_modFormat.originalType = UL_("s3m"); m_modFormat.originalFormatName = UL_("Scream Tracker 3"); break; case MOD_TYPE_IT: m_modFormat.originalType = UL_("it"); if(cmwt) m_modFormat.originalFormatName = MPT_UFORMAT("Impulse Tracker {}.{}")(cmwt >> 8, mpt::ufmt::hex0<2>(cmwt & 0xFF)); else m_modFormat.originalFormatName = UL_("Impulse Tracker"); break; case MOD_TYPE_MPT: m_modFormat.originalType = UL_("mptm"); m_modFormat.originalFormatName = UL_("OpenMPT MPTM"); break; default: MPT_ASSERT_NOTREACHED(); } m_modFormat.madeWithTracker = std::move(madeWithTracker); if(m_dwLastSavedWithVersion) m_modFormat.charset = mpt::Charset::Windows1252; else if(GetType() == MOD_TYPE_MOD) m_modFormat.charset = mpt::Charset::Amiga_no_C1; else m_modFormat.charset = mpt::Charset::CP437; if(!(loadFlags & loadSampleData)) return true; if(containerHeader.version < 5) { // As we don't know where the compressed data ends, we don't know where the sample data starts, either. if(!musicChunkData->UnpackedSuccessfully()) return false; file.Seek(musicChunkData->SourcePosition()); } else { file.Seek(12 + compressedSize); } bool unsupportedSamples = false; for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { MO3SampleInfo &smpInfo = sampleInfos[smp - 1]; const MO3Sample &smpHeader = smpInfo.smpHeader; const uint32 compression = (smpHeader.flags & MO3Sample::smpCompressionMask); if(!compression && smpHeader.compressedSize == 0) { // Uncompressed sample SampleIO( (smpHeader.flags & MO3Sample::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit, (smpHeader.flags & MO3Sample::smpStereo) ? SampleIO::stereoSplit : SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(Samples[smp], file); } else if(smpHeader.compressedSize > 0) { // Compressed sample; we read those in a second pass because Ogg samples with shared headers may reference a later sample's header smpInfo.chunk = file.ReadChunk(smpHeader.compressedSize); } } for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { ModSample &sample = Samples[smp]; MO3SampleInfo &smpInfo = sampleInfos[smp - 1]; const MO3Sample &smpHeader = smpInfo.smpHeader; if(smpHeader.compressedSize < 0 && (smp + smpHeader.compressedSize) > 0) { // Duplicate sample sample.CopyWaveform(Samples[smp + smpHeader.compressedSize]); continue; } // Not a compressed sample? if(!smpHeader.length || !smpInfo.chunk.IsValid()) continue; if(smpHeader.flags & MO3Sample::smp16Bit) sample.uFlags.set(CHN_16BIT); if(smpHeader.flags & MO3Sample::smpStereo) sample.uFlags.set(CHN_STEREO); FileReader &sampleData = smpInfo.chunk; const uint8 numChannels = sample.GetNumChannels(); const uint32 compression = (smpHeader.flags & MO3Sample::smpCompressionMask); if(compression == MO3Sample::smpDeltaCompression || compression == MO3Sample::smpDeltaPrediction) { // In the best case, MO3 compression represents each sample point as two bits. // As a result, if we have a file length of n, we know that the sample can be at most n*4 sample points long. auto maxLength = sampleData.GetLength(); uint8 maxSamplesPerByte = 4 / numChannels; if(Util::MaxValueOfType(maxLength) / maxSamplesPerByte >= maxLength) maxLength *= maxSamplesPerByte; else maxLength = Util::MaxValueOfType(maxLength); LimitMax(sample.nLength, mpt::saturate_cast(maxLength)); } if(compression == MO3Sample::smpDeltaCompression) { if(sample.AllocateSample()) { if(smpHeader.flags & MO3Sample::smp16Bit) UnpackMO3DeltaSample(sampleData, sample.sample16(), sample.nLength, numChannels); else UnpackMO3DeltaSample(sampleData, sample.sample8(), sample.nLength, numChannels); } } else if(compression == MO3Sample::smpDeltaPrediction) { if(sample.AllocateSample()) { if(smpHeader.flags & MO3Sample::smp16Bit) UnpackMO3DeltaPredictionSample(sampleData, sample.sample16(), sample.nLength, numChannels); else UnpackMO3DeltaPredictionSample(sampleData, sample.sample8(), sample.nLength, numChannels); } } else if(compression == MO3Sample::smpCompressionOgg || compression == MO3Sample::smpSharedOgg) { const uint16 sharedHeaderSize = smpHeader.encoderDelay; SAMPLEINDEX sharedOggHeader = (smp + smpInfo.sharedHeader > 0) ? static_cast(smp + smpInfo.sharedHeader) : smp; // Which chunk are we going to read the header from? // Note: Every Ogg stream has a unique serial number. // stb_vorbis (currently) ignores this serial number so we can just stitch // together our sample without adjusting the shared header's serial number. const bool sharedHeader = sharedOggHeader != smp && sharedOggHeader > 0 && sharedOggHeader <= m_nSamples && sharedHeaderSize > 0; #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE) std::vector mergedData; if(sharedHeader) { // Prepend the shared header to the actual sample data and adjust bitstream serial numbers. // We do not handle multiple muxed logical streams as they do not exist in practice in mo3. // We assume sequence numbers are consecutive at the end of the headers. // Corrupted pages get dropped as required by Ogg spec. We cannot do any further sane parsing on them anyway. // We do not match up multiple muxed stream properly as this would need parsing of actual packet data to determine or guess the codec. // Ogg Vorbis files may contain at least an additional Ogg Skeleton stream. It is not clear whether these actually exist in MO3. // We do not validate packet structure or logical bitstream structure (i.e. sequence numbers and granule positions). // TODO: At least handle Skeleton streams here, as they violate our stream ordering assumptions here. #if 0 // This block may still turn out to be useful as it does a more thourough validation of the stream than the optimized version below. // We copy the whole data into a single consecutive buffer in order to keep things simple when interfacing libvorbisfile. // We could in theory only adjust the header and pass 2 chunks to libvorbisfile. // Another option would be to demux both chunks on our own (or using libogg) and pass the raw packet data to libvorbis directly. std::ostringstream mergedStream(std::ios::binary); mergedStream.imbue(std::locale::classic()); sampleInfos[sharedOggHeader - 1].chunk.Rewind(); FileReader sharedChunk = sampleInfos[sharedOggHeader - 1].chunk.ReadChunk(sharedHeaderSize); sharedChunk.Rewind(); std::vector streamSerials; Ogg::PageInfo oggPageInfo; std::vector oggPageData; streamSerials.clear(); while(Ogg::ReadPageAndSkipJunk(sharedChunk, oggPageInfo, oggPageData)) { auto it = std::find(streamSerials.begin(), streamSerials.end(), oggPageInfo.header.bitstream_serial_number); if(it == streamSerials.end()) { streamSerials.push_back(oggPageInfo.header.bitstream_serial_number); it = streamSerials.begin() + (streamSerials.size() - 1); } uint32 newSerial = it - streamSerials.begin() + 1; oggPageInfo.header.bitstream_serial_number = newSerial; Ogg::UpdatePageCRC(oggPageInfo, oggPageData); Ogg::WritePage(mergedStream, oggPageInfo, oggPageData); } streamSerials.clear(); while(Ogg::ReadPageAndSkipJunk(smpInfo.chunk, oggPageInfo, oggPageData)) { auto it = std::find(streamSerials.begin(), streamSerials.end(), oggPageInfo.header.bitstream_serial_number); if(it == streamSerials.end()) { streamSerials.push_back(oggPageInfo.header.bitstream_serial_number); it = streamSerials.begin() + (streamSerials.size() - 1); } uint32 newSerial = it - streamSerials.begin() + 1; oggPageInfo.header.bitstream_serial_number = newSerial; Ogg::UpdatePageCRC(oggPageInfo, oggPageData); Ogg::WritePage(mergedStream, oggPageInfo, oggPageData); } std::string mergedStreamData = mergedStream.str(); mergedData.insert(mergedData.end(), mergedStreamData.begin(), mergedStreamData.end()); #else // We assume same ordering of streams in both header and data if // multiple streams are present. std::ostringstream mergedStream(std::ios::binary); mergedStream.imbue(std::locale::classic()); sampleInfos[sharedOggHeader - 1].chunk.Rewind(); FileReader sharedChunk = sampleInfos[sharedOggHeader - 1].chunk.ReadChunk(sharedHeaderSize); sharedChunk.Rewind(); std::vector dataStreamSerials; std::vector headStreamSerials; Ogg::PageInfo oggPageInfo; std::vector oggPageData; // Gather bitstream serial numbers form sample data chunk dataStreamSerials.clear(); while(Ogg::ReadPageAndSkipJunk(smpInfo.chunk, oggPageInfo, oggPageData)) { if(!mpt::contains(dataStreamSerials, oggPageInfo.header.bitstream_serial_number)) { dataStreamSerials.push_back(oggPageInfo.header.bitstream_serial_number); } } // Apply the data bitstream serial numbers to the header headStreamSerials.clear(); while(Ogg::ReadPageAndSkipJunk(sharedChunk, oggPageInfo, oggPageData)) { auto it = std::find(headStreamSerials.begin(), headStreamSerials.end(), oggPageInfo.header.bitstream_serial_number); if(it == headStreamSerials.end()) { headStreamSerials.push_back(oggPageInfo.header.bitstream_serial_number); it = headStreamSerials.begin() + (headStreamSerials.size() - 1); } uint32 newSerial = 0; if(dataStreamSerials.size() >= static_cast(it - headStreamSerials.begin())) { // Found corresponding stream in data chunk. newSerial = dataStreamSerials[it - headStreamSerials.begin()]; } else { // No corresponding stream in data chunk. Find a free serialno. std::size_t extraIndex = (it - headStreamSerials.begin()) - dataStreamSerials.size(); for(newSerial = 1; newSerial < 0xffffffffu; ++newSerial) { if(!mpt::contains(dataStreamSerials, newSerial)) { extraIndex -= 1; } if(extraIndex == 0) { break; } } } oggPageInfo.header.bitstream_serial_number = newSerial; Ogg::UpdatePageCRC(oggPageInfo, oggPageData); Ogg::WritePage(mergedStream, oggPageInfo, oggPageData); } if(headStreamSerials.size() > 1) { AddToLog(LogWarning, MPT_UFORMAT("Sample {}: Ogg Vorbis data with shared header and multiple logical bitstreams in header chunk found. This may be handled incorrectly.")(smp)); } else if(dataStreamSerials.size() > 1) { AddToLog(LogWarning, MPT_UFORMAT("Sample {}: Ogg Vorbis sample with shared header and multiple logical bitstreams found. This may be handled incorrectly.")(smp)); } else if((dataStreamSerials.size() == 1) && (headStreamSerials.size() == 1) && (dataStreamSerials[0] != headStreamSerials[0])) { AddToLog(LogInformation, MPT_UFORMAT("Sample {}: Ogg Vorbis data with shared header and different logical bitstream serials found.")(smp)); } std::string mergedStreamData = mergedStream.str(); mergedData.insert(mergedData.end(), mergedStreamData.begin(), mergedStreamData.end()); smpInfo.chunk.Rewind(); FileReader::PinnedView sampleChunkView = smpInfo.chunk.GetPinnedView(); mpt::span sampleChunkViewSpan = mpt::byte_cast>(sampleChunkView.span()); mergedData.insert(mergedData.end(), sampleChunkViewSpan.begin(), sampleChunkViewSpan.end()); #endif } FileReader mergedDataChunk(mpt::byte_cast(mpt::as_span(mergedData))); FileReader &sampleChunk = sharedHeader ? mergedDataChunk : smpInfo.chunk; FileReader &headerChunk = sampleChunk; #else // !(MPT_WITH_VORBIS && MPT_WITH_VORBISFILE) FileReader &headerChunk = sharedHeader ? sampleInfos[sharedOggHeader - 1].chunk : sampleData; #if defined(MPT_WITH_STBVORBIS) std::size_t initialRead = sharedHeader ? sharedHeaderSize : headerChunk.GetLength(); #endif // MPT_WITH_STBVORBIS #endif // MPT_WITH_VORBIS && MPT_WITH_VORBISFILE headerChunk.Rewind(); if(sharedHeader && !headerChunk.CanRead(sharedHeaderSize)) continue; #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE) ov_callbacks callbacks = { &VorbisfileFilereaderRead, &VorbisfileFilereaderSeek, nullptr, &VorbisfileFilereaderTell}; OggVorbis_File vf; MemsetZero(vf); if(ov_open_callbacks(mpt::void_ptr(&sampleChunk), &vf, nullptr, 0, callbacks) == 0) { if(ov_streams(&vf) == 1) { // we do not support chained vorbis samples vorbis_info *vi = ov_info(&vf, -1); if(vi && vi->rate > 0 && vi->channels > 0) { sample.AllocateSample(); SmpLength offset = 0; int channels = vi->channels; int current_section = 0; long decodedSamples = 0; bool eof = false; while(!eof && offset < sample.nLength && sample.HasSampleData()) { float **output = nullptr; long ret = ov_read_float(&vf, &output, 1024, ¤t_section); if(ret == 0) { eof = true; } else if(ret < 0) { // stream error, just try to continue } else { decodedSamples = ret; LimitMax(decodedSamples, mpt::saturate_cast(sample.nLength - offset)); if(decodedSamples > 0 && channels == sample.GetNumChannels()) { if(sample.uFlags[CHN_16BIT]) { CopyAudio(mpt::audio_span_interleaved(sample.sample16() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples)); } else { CopyAudio(mpt::audio_span_interleaved(sample.sample8() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples)); } } offset += static_cast(decodedSamples); } } } else { unsupportedSamples = true; } } else { AddToLog(LogWarning, MPT_UFORMAT("Sample {}: Unsupported Ogg Vorbis chained stream found.")(smp)); unsupportedSamples = true; } ov_clear(&vf); } else { unsupportedSamples = true; } #elif defined(MPT_WITH_STBVORBIS) // NOTE/TODO: stb_vorbis does not handle inferred negative PCM sample // position at stream start. (See // ). // This means that, for remuxed and re-aligned/cutted (at stream start) // Vorbis files, stb_vorbis will include superfluous samples at the // beginning. MO3 files with this property are yet to be spotted in the // wild, thus, this behaviour is currently not problematic. int consumed = 0, error = 0; stb_vorbis *vorb = nullptr; if(sharedHeader) { FileReader::PinnedView headChunkView = headerChunk.GetPinnedView(initialRead); vorb = stb_vorbis_open_pushdata(mpt::byte_cast(headChunkView.data()), mpt::saturate_cast(headChunkView.size()), &consumed, &error, nullptr); headerChunk.Skip(consumed); } FileReader::PinnedView sampleDataView = sampleData.GetPinnedView(); const std::byte *data = sampleDataView.data(); std::size_t dataLeft = sampleDataView.size(); if(!sharedHeader) { vorb = stb_vorbis_open_pushdata(mpt::byte_cast(data), mpt::saturate_cast(dataLeft), &consumed, &error, nullptr); sampleData.Skip(consumed); data += consumed; dataLeft -= consumed; } if(vorb) { // Header has been read, proceed to reading the sample data sample.AllocateSample(); SmpLength offset = 0; while((error == VORBIS__no_error || (error == VORBIS_need_more_data && dataLeft > 0)) && offset < sample.nLength && sample.HasSampleData()) { int channels = 0, decodedSamples = 0; float **output; consumed = stb_vorbis_decode_frame_pushdata(vorb, mpt::byte_cast(data), mpt::saturate_cast(dataLeft), &channels, &output, &decodedSamples); sampleData.Skip(consumed); data += consumed; dataLeft -= consumed; LimitMax(decodedSamples, mpt::saturate_cast(sample.nLength - offset)); if(decodedSamples > 0 && channels == sample.GetNumChannels()) { if(sample.uFlags[CHN_16BIT]) { CopyAudio(mpt::audio_span_interleaved(sample.sample16() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples)); } else { CopyAudio(mpt::audio_span_interleaved(sample.sample8() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples)); } } offset += decodedSamples; error = stb_vorbis_get_error(vorb); } stb_vorbis_close(vorb); } else { unsupportedSamples = true; } #else // !VORBIS unsupportedSamples = true; #endif // VORBIS } else if(compression == MO3Sample::smpCompressionMPEG) { // Old MO3 encoders didn't remove LAME info frames. This is unfortunate since the encoder delay // specified in the sample header does not take the gapless information from the LAME info frame // into account. We should not depend on the MP3 decoder's capabilities to read or ignore such frames: // - libmpg123 has MPG123_IGNORE_INFOFRAME but that requires API version 31 (mpg123 v1.14) or higher // - Media Foundation does (currently) not read LAME gapless information at all // So we just play safe and remove such frames. FileReader mpegData(sampleData); MPEGFrame frame(sampleData); uint16 encoderDelay = smpHeader.encoderDelay; uint16 frameDelay = frame.numSamples * 2; if(frame.isLAME && encoderDelay >= frameDelay) { // The info frame does not produce any output, but still counts towards the encoder delay. encoderDelay -= frameDelay; sampleData.Seek(frame.frameSize); mpegData = sampleData.ReadChunk(sampleData.BytesLeft()); } if(ReadMP3Sample(smp, mpegData, true, true) || ReadMediaFoundationSample(smp, mpegData, true)) { if(encoderDelay > 0 && encoderDelay < sample.GetSampleSizeInBytes()) { SmpLength delay = encoderDelay / sample.GetBytesPerSample(); memmove(sample.sampleb(), sample.sampleb() + encoderDelay, sample.GetSampleSizeInBytes() - encoderDelay); sample.nLength -= delay; } LimitMax(sample.nLength, smpHeader.length); } else { unsupportedSamples = true; } } else if(compression == MO3Sample::smpOPLInstrument) { OPLPatch patch; if(sampleData.ReadArray(patch)) { sample.SetAdlib(true, patch); } } else { unsupportedSamples = true; } } if(unsupportedSamples) { AddToLog(LogWarning, U_("Some compressed samples could not be loaded because they use an unsupported codec.")); } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MixFuncTable.cpp0000644000175000017500000000567614500065511021135 00000000000000/* * MixFuncTable.cpp * ---------------- * Purpose: Table containing all mixer functions. * Notes : The Visual Studio project settings for this file have been adjusted * to force function inlining, so that the mixer has a somewhat acceptable * performance in debug mode. If you need to debug anything here, be sure * to disable those optimizations if needed. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "MixFuncTable.h" #include "Mixer.h" #include "ModChannel.h" #include "Snd_defs.h" #ifdef MPT_INTMIXER #include "IntMixer.h" #else #include "FloatMixer.h" #endif // MPT_INTMIXER OPENMPT_NAMESPACE_BEGIN namespace MixFuncTable { #ifdef MPT_INTMIXER using I8M = Int8MToIntS; using I16M = Int16MToIntS; using I8S = Int8SToIntS; using I16S = Int16SToIntS; #else using I8M = Int8MToFloatS; using I16M = Int16MToFloatS; using I8S = Int8SToFloatS; using I16S = Int16SToFloatS; #endif // MPT_INTMIXER // Build mix function table for given resampling, filter and ramping settings: One function each for 8-Bit / 16-Bit Mono / Stereo #define BuildMixFuncTableRamp(resampling, filter, ramp) \ SampleLoop, filter, MixMono ## ramp >, \ SampleLoop, filter, MixMono ## ramp >, \ SampleLoop, filter, MixStereo ## ramp >, \ SampleLoop, filter, MixStereo ## ramp > // Build mix function table for given resampling, filter settings: With and without ramping #define BuildMixFuncTableFilter(resampling, filter) \ BuildMixFuncTableRamp(resampling, filter, NoRamp), \ BuildMixFuncTableRamp(resampling, filter, Ramp) // Build mix function table for given resampling settings: With and without filter #define BuildMixFuncTable(resampling) \ BuildMixFuncTableFilter(resampling, NoFilter), \ BuildMixFuncTableFilter(resampling, ResonantFilter) const MixFuncInterface Functions[6 * 16] = { BuildMixFuncTable(NoInterpolation), // No SRC BuildMixFuncTable(LinearInterpolation), // Linear SRC BuildMixFuncTable(FastSincInterpolation), // Fast Sinc (Cubic Spline) SRC BuildMixFuncTable(PolyphaseInterpolation), // Kaiser SRC BuildMixFuncTable(FIRFilterInterpolation), // FIR SRC BuildMixFuncTable(AmigaBlepInterpolation), // Amiga emulation }; #undef BuildMixFuncTableRamp #undef BuildMixFuncTableFilter #undef BuildMixFuncTable ResamplingIndex ResamplingModeToMixFlags(ResamplingMode resamplingMode) { switch(resamplingMode) { case SRCMODE_NEAREST: return ndxNoInterpolation; case SRCMODE_LINEAR: return ndxLinear; case SRCMODE_CUBIC: return ndxFastSinc; case SRCMODE_SINC8LP: return ndxKaiser; case SRCMODE_SINC8: return ndxFIRFilter; case SRCMODE_AMIGA: return ndxAmigaBlep; default: MPT_ASSERT_NOTREACHED(); } return ndxNoInterpolation; } } // namespace MixFuncTable OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Sndfile.cpp0000644000175000017500000017556315022626104020204 00000000000000/* * Sndfile.cpp * ----------- * Purpose: Core class of the playback engine. Every song is represented by a CSoundFile object. * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Sndfile.h" #include "Container.h" #include "mod_specifications.h" #include "OPL.h" #include "Tables.h" #include "tuningcollection.h" #include "plugins/PluginManager.h" #include "plugins/PlugInterface.h" #include "../common/FileReader.h" #include "../common/mptStringBuffer.h" #include "../common/serialization_utils.h" #include "../common/version.h" #include "../soundlib/AudioCriticalSection.h" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/random/seed.hpp" #ifdef MODPLUG_TRACKER #include "../mptrack/Mainfrm.h" #include "../mptrack/Moddoc.h" #include "../mptrack/Mptrack.h" // For CTrackApp::OpenURL #include "../mptrack/Reporting.h" #include "../mptrack/TrackerSettings.h" #endif // MODPLUG_TRACKER #ifdef MPT_EXTERNAL_SAMPLES #include "../common/mptFileIO.h" #include "mpt/io_file/inputfile.hpp" #include "mpt/io_file_read/inputfile_filecursor.hpp" #endif // MPT_EXTERNAL_SAMPLES #ifndef NO_ARCHIVE_SUPPORT #include "../unarchiver/unarchiver.h" #endif // NO_ARCHIVE_SUPPORT OPENMPT_NAMESPACE_BEGIN bool SettingCacheCompleteFileBeforeLoading() { #ifdef MODPLUG_TRACKER return TrackerSettings::Instance().MiscCacheCompleteFileBeforeLoading; #else return false; #endif } mpt::ustring FileHistory::AsISO8601(mpt::Date::LogicalTimezone internalTimezone) const { if(openTime > 0) { // Calculate the date when editing finished. double openSeconds = static_cast(openTime) / HISTORY_TIMER_PRECISION; mpt::Date::AnyGregorian tmpLoadDate = loadDate; if (internalTimezone == mpt::Date::LogicalTimezone::UTC) { int64 loadDateSinceEpoch = mpt::Date::UnixAsSeconds(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(tmpLoadDate))); int64 saveDateSinceEpoch = loadDateSinceEpoch + mpt::saturate_round(openSeconds); return mpt::Date::ToShortenedISO8601(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds(saveDateSinceEpoch))); #ifdef MODPLUG_TRACKER } else if(internalTimezone == mpt::Date::LogicalTimezone::Local) { int64 loadDateSinceEpoch = mpt::Date::UnixAsSeconds(mpt::Date::UnixFromLocal(mpt::Date::interpret_as_timezone(tmpLoadDate))); int64 saveDateSinceEpoch = loadDateSinceEpoch + mpt::saturate_round(openSeconds); return mpt::Date::ToShortenedISO8601(mpt::Date::UnixAsLocal(mpt::Date::UnixFromSeconds(saveDateSinceEpoch))); #endif // MODPLUG_TRACKER } else { // assume UTC for unspecified timezone when calculating int64 loadDateSinceEpoch = mpt::Date::UnixAsSeconds(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(tmpLoadDate))); int64 saveDateSinceEpoch = loadDateSinceEpoch + mpt::saturate_round(openSeconds); return mpt::Date::ToShortenedISO8601(mpt::Date::forget_timezone(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds(saveDateSinceEpoch)))); } } else { if(internalTimezone == mpt::Date::LogicalTimezone::UTC) { return mpt::Date::ToShortenedISO8601(mpt::Date::interpret_as_timezone(loadDate)); #ifdef MODPLUG_TRACKER } else if(internalTimezone == mpt::Date::LogicalTimezone::Local) { return mpt::Date::ToShortenedISO8601(mpt::Date::interpret_as_timezone(loadDate)); #endif // MODPLUG_TRACKER } else { return mpt::Date::ToShortenedISO8601(loadDate); } } } ////////////////////////////////////////////////////////// // CSoundFile #ifdef MODPLUG_TRACKER const NoteName *CSoundFile::m_NoteNames = NoteNamesFlat; #endif CSoundFile::CSoundFile() : #ifndef MODPLUG_TRACKER m_NoteNames(NoteNamesSharp), #endif m_pModSpecs(&ModSpecs::itEx), m_nType(MOD_TYPE_NONE), Patterns(*this), Order(*this), m_PRNG(mpt::make_prng(mpt::global_prng())), m_visitedRows(*this) #ifdef MODPLUG_TRACKER , m_MIDIMapper(*this) #endif { MemsetZero(MixSoundBuffer); MemsetZero(MixRearBuffer); MemsetZero(MixFloatBuffer); #ifdef MODPLUG_TRACKER m_bChannelMuteTogglePending.reset(); m_nDefaultRowsPerBeat = m_PlayState.m_nCurrentRowsPerBeat = (TrackerSettings::Instance().m_nRowHighlightBeats) ? TrackerSettings::Instance().m_nRowHighlightBeats : DEFAULT_ROWS_PER_BEAT; m_nDefaultRowsPerMeasure = m_PlayState.m_nCurrentRowsPerMeasure = (TrackerSettings::Instance().m_nRowHighlightMeasures >= m_nDefaultRowsPerBeat) ? TrackerSettings::Instance().m_nRowHighlightMeasures : m_nDefaultRowsPerBeat * 4; #else m_nDefaultRowsPerBeat = m_PlayState.m_nCurrentRowsPerBeat = DEFAULT_ROWS_PER_BEAT; m_nDefaultRowsPerMeasure = m_PlayState.m_nCurrentRowsPerMeasure = DEFAULT_ROWS_PER_MEASURE; #endif // MODPLUG_TRACKER MemsetZero(Instruments); Clear(m_szNames); m_pTuningsTuneSpecific = new CTuningCollection(); } CSoundFile::~CSoundFile() { Destroy(); delete m_pTuningsTuneSpecific; m_pTuningsTuneSpecific = nullptr; } void CSoundFile::AddToLog(LogLevel level, const mpt::ustring &text) const { if(m_pCustomLog) { m_pCustomLog->AddToLog(level, text); } else { #ifdef MODPLUG_TRACKER if(GetpModDoc()) GetpModDoc()->AddToLog(level, text); #else MPT_LOG_GLOBAL(level, "soundlib", text); #endif } } // Global variable initializer for loader functions void CSoundFile::InitializeGlobals(MODTYPE type, CHANNELINDEX numChannels) { // Do not add or change any of these values! And if you do, review each and every loader to check if they require these defaults! m_nType = type; MPT_ASSERT(numChannels <= MAX_BASECHANNELS); LimitMax(numChannels, MAX_BASECHANNELS); MODTYPE bestType = GetBestSaveFormat(); m_playBehaviour = GetDefaultPlaybackBehaviour(bestType); if(bestType == MOD_TYPE_IT && type != bestType) { // This is such an odd behaviour that it's unlikely that any of the other formats will need it by default. Re-enable as needed. m_playBehaviour.reset(kITInitialNoteMemory); } m_pModSpecs = &GetModSpecifications(bestType); // Delete instruments in case some previously called loader already created them. for(INSTRUMENTINDEX i = 1; i <= m_nInstruments; i++) { delete Instruments[i]; Instruments[i] = nullptr; } m_ContainerType = ModContainerType::None; m_nInstruments = 0; m_nSamples = 0; m_nSamplePreAmp = 48; m_nVSTiVolume = 48; m_OPLVolumeFactor = m_OPLVolumeFactorScale; m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; m_SongFlags.reset(); m_nMinPeriod = 16; m_nMaxPeriod = 32767; m_nResampling = SRCMODE_DEFAULT; m_dwLastSavedWithVersion = Version(0); m_dwCreatedWithVersion = Version(0); m_nTempoMode = TempoMode::Classic; SetMixLevels(MixLevels::Compatible); Patterns.DestroyPatterns(); Order.Initialize(); m_globalScript.clear(); m_songName.clear(); m_songArtist.clear(); m_songMessage.clear(); m_modFormat = ModFormatDetails(); m_FileHistory.clear(); m_tempoSwing.clear(); #ifdef MPT_EXTERNAL_SAMPLES m_samplePaths.clear(); #endif // MPT_EXTERNAL_SAMPLES // Note: we do not use the Amiga resampler for DBM as it's a multichannel format and can make use of higher-quality Amiga soundcards instead of Paula. if(GetType() & (/*MOD_TYPE_DBM | */MOD_TYPE_DIGI | MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_OKT | MOD_TYPE_SFX | MOD_TYPE_STP)) m_SongFlags.set(SONG_ISAMIGA); if(GetType() & (MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_MTM)) m_SongFlags.set(SONG_FORMAT_NO_VOLCOL); ChnSettings.assign(numChannels, {}); } struct FileFormatLoader { decltype(CSoundFile::ProbeFileHeaderXM) *prober; decltype(&CSoundFile::ReadXM) loader; }; #if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_DEBUG) #define MPT_DECLARE_FORMAT(format) { nullptr, &CSoundFile::Read ## format } #else #define MPT_DECLARE_FORMAT(format) { CSoundFile::ProbeFileHeader ## format, &CSoundFile::Read ## format } #endif // All module format loaders, in the order they should be executed. // This order matters, depending on the format, due to some unfortunate // clashes or lack of magic bytes that can lead to mis-detection of some formats. // Apart from that, more common formats with sane magic bytes are also found // at the top of the list to match the most common cases more quickly. static constexpr FileFormatLoader ModuleFormatLoaders[] = { MPT_DECLARE_FORMAT(XM), MPT_DECLARE_FORMAT(IT), MPT_DECLARE_FORMAT(S3M), MPT_DECLARE_FORMAT(STM), MPT_DECLARE_FORMAT(MED), MPT_DECLARE_FORMAT(MTM), MPT_DECLARE_FORMAT(MDL), MPT_DECLARE_FORMAT(DBM), MPT_DECLARE_FORMAT(FAR), MPT_DECLARE_FORMAT(AMS), MPT_DECLARE_FORMAT(AMS2), MPT_DECLARE_FORMAT(OKT), MPT_DECLARE_FORMAT(PTM), MPT_DECLARE_FORMAT(ULT), MPT_DECLARE_FORMAT(DMF), MPT_DECLARE_FORMAT(DSM), MPT_DECLARE_FORMAT(AMF_Asylum), MPT_DECLARE_FORMAT(AMF_DSMI), MPT_DECLARE_FORMAT(PSM), MPT_DECLARE_FORMAT(PSM16), MPT_DECLARE_FORMAT(MT2), MPT_DECLARE_FORMAT(ITP), #if defined(MODPLUG_TRACKER) || defined(MPT_FUZZ_TRACKER) // These make little sense for a module player library MPT_DECLARE_FORMAT(UAX), MPT_DECLARE_FORMAT(WAV), MPT_DECLARE_FORMAT(MID), #endif // MODPLUG_TRACKER || MPT_FUZZ_TRACKER MPT_DECLARE_FORMAT(GDM), MPT_DECLARE_FORMAT(IMF), MPT_DECLARE_FORMAT(DIGI), MPT_DECLARE_FORMAT(DTM), MPT_DECLARE_FORMAT(PLM), MPT_DECLARE_FORMAT(AM), MPT_DECLARE_FORMAT(J2B), MPT_DECLARE_FORMAT(GT2), MPT_DECLARE_FORMAT(GTK), MPT_DECLARE_FORMAT(PT36), MPT_DECLARE_FORMAT(SymMOD), MPT_DECLARE_FORMAT(MUS_KM), MPT_DECLARE_FORMAT(FMT), MPT_DECLARE_FORMAT(SFX), MPT_DECLARE_FORMAT(STP), MPT_DECLARE_FORMAT(DSym), MPT_DECLARE_FORMAT(STX), MPT_DECLARE_FORMAT(UNIC), // Magic bytes clash with MOD, must be tried first MPT_DECLARE_FORMAT(MOD), MPT_DECLARE_FORMAT(ICE), MPT_DECLARE_FORMAT(KRIS), MPT_DECLARE_FORMAT(669), MPT_DECLARE_FORMAT(667), MPT_DECLARE_FORMAT(C67), MPT_DECLARE_FORMAT(MO3), MPT_DECLARE_FORMAT(FC), MPT_DECLARE_FORMAT(FTM), MPT_DECLARE_FORMAT(RTM), MPT_DECLARE_FORMAT(TCB), MPT_DECLARE_FORMAT(CBA), MPT_DECLARE_FORMAT(ETX), MPT_DECLARE_FORMAT(DSm), MPT_DECLARE_FORMAT(STK), MPT_DECLARE_FORMAT(XMF), MPT_DECLARE_FORMAT(Puma), MPT_DECLARE_FORMAT(GMC), MPT_DECLARE_FORMAT(IMS), }; #undef MPT_DECLARE_FORMAT CSoundFile::ProbeResult CSoundFile::ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize) { const uint64 availableFileSize = file.GetLength(); const uint64 fileSize = (pfilesize ? *pfilesize : file.GetLength()); //const uint64 validFileSize = std::min(fileSize, static_cast(ProbeRecommendedSize)); const uint64 goalSize = file.GetPosition() + minimumAdditionalSize; //const uint64 goalMinimumSize = std::min(goalSize, static_cast(ProbeRecommendedSize)); if(pfilesize) { if(availableFileSize < std::min(fileSize, static_cast(ProbeRecommendedSize))) { if(availableFileSize < goalSize) { return ProbeWantMoreData; } } else { if(fileSize < goalSize) { return ProbeFailure; } } return ProbeSuccess; } return ProbeSuccess; } #define MPT_DO_PROBE( storedResult , call ) \ do { \ ProbeResult lastResult = call ; \ if(lastResult == ProbeSuccess) { \ return ProbeSuccess; \ } else if(lastResult == ProbeWantMoreData) { \ storedResult = ProbeWantMoreData; \ } \ } while(0) \ /**/ CSoundFile::ProbeResult CSoundFile::Probe(ProbeFlags flags, mpt::span data, const uint64 *pfilesize) { ProbeResult result = ProbeFailure; if(pfilesize && (*pfilesize < data.size())) { throw std::out_of_range(""); } if(!data.data()) { throw std::invalid_argument(""); } MemoryFileReader file(data); if(flags & ProbeContainers) { #if !defined(MPT_WITH_ANCIENT) MPT_DO_PROBE(result, ProbeFileHeaderMMCMP(file, pfilesize)); MPT_DO_PROBE(result, ProbeFileHeaderPP20(file, pfilesize)); MPT_DO_PROBE(result, ProbeFileHeaderXPK(file, pfilesize)); #endif // !MPT_WITH_ANCIENT MPT_DO_PROBE(result, ProbeFileHeaderUMX(file, pfilesize)); } if(flags & ProbeModules) { for(const auto &format : ModuleFormatLoaders) { if(format.prober != nullptr) { MPT_DO_PROBE(result, format.prober(file, pfilesize)); } } } if(pfilesize) { if((result == ProbeWantMoreData) && (mpt::saturate_cast(*pfilesize) <= data.size())) { // If the prober wants more data but we already reached EOF, // probing must fail. result = ProbeFailure; } } else { if((result == ProbeWantMoreData) && (data.size() >= ProbeRecommendedSize)) { // If the prober wants more data but we already provided the recommended required maximum, // just return success as this is the best we can do for the suggestesd probing size. result = ProbeSuccess; } } return result; } void CSoundFile::Create(MODTYPE type, CHANNELINDEX numChannels, CModDoc *modDoc) { Create(FileReader{}, CSoundFile::loadCompleteModule, modDoc); SetType(type); ChnSettings.resize(numChannels); } bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags, CModDoc *pModDoc) { m_nMixChannels = 0; #ifdef MODPLUG_TRACKER m_pModDoc = pModDoc; #else MPT_UNUSED(pModDoc); m_nFreqFactor = m_nTempoFactor = 65536; #endif // MODPLUG_TRACKER Clear(m_szNames); #ifndef NO_PLUGINS std::fill(std::begin(m_MixPlugins), std::end(m_MixPlugins), SNDMIXPLUGIN()); #endif // NO_PLUGINS if(CreateInternal(file, loadFlags)) return true; #ifndef NO_ARCHIVE_SUPPORT if(!(loadFlags & skipContainer) && file.IsValid()) { CUnarchiver unarchiver(file); if(unarchiver.ExtractBestFile(GetSupportedExtensions(true))) { FileReader outputFile = unarchiver.GetOutputFile(); #if defined(MPT_WITH_ANCIENT) // Special case for MMCMP/PP20/XPK/etc. inside ZIP/RAR/LHA std::unique_ptr ancientArchive; if(!unarchiver.IsKind()) { ancientArchive = std::make_unique(outputFile); if(ancientArchive->IsArchive() && ancientArchive->ExtractFile(0)) outputFile = ancientArchive->GetOutputFile(); } #endif if(CreateInternal(outputFile, loadFlags)) { // Read archive comment if there is no song comment if(m_songMessage.empty()) { m_songMessage.assign(mpt::ToCharset(mpt::Charset::Locale, unarchiver.GetComment())); } m_ContainerType = ModContainerType::Generic; return true; } } } #endif return false; } bool CSoundFile::CreateInternal(FileReader file, ModLoadingFlags loadFlags) { if(file.IsValid()) { std::vector containerItems; ModContainerType packedContainerType = ModContainerType::None; if(!(loadFlags & skipContainer)) { ContainerLoadingFlags containerLoadFlags = (loadFlags == onlyVerifyHeader) ? ContainerOnlyVerifyHeader : ContainerUnwrapData; #if !defined(MPT_WITH_ANCIENT) if(packedContainerType == ModContainerType::None && UnpackXPK(containerItems, file, containerLoadFlags)) packedContainerType = ModContainerType::XPK; if(packedContainerType == ModContainerType::None && UnpackPP20(containerItems, file, containerLoadFlags)) packedContainerType = ModContainerType::PP20; if(packedContainerType == ModContainerType::None && UnpackMMCMP(containerItems, file, containerLoadFlags)) packedContainerType = ModContainerType::MMCMP; #endif // !MPT_WITH_ANCIENT if(packedContainerType == ModContainerType::None && UnpackUMX(containerItems, file, containerLoadFlags)) packedContainerType = ModContainerType::UMX; if(packedContainerType != ModContainerType::None) { if(loadFlags == onlyVerifyHeader) { return true; } if(!containerItems.empty()) { // cppcheck false-positive // cppcheck-suppress containerOutOfBounds file = containerItems[0].file; } } } if(loadFlags & skipModules) { return false; } // Try all module format loaders bool loaderSuccess = false; for(const auto &format : ModuleFormatLoaders) { loaderSuccess = (this->*(format.loader))(file, loadFlags); if(loaderSuccess) { #if defined(MPT_BUILD_DEBUG) // Verify that the probing function is consistent with our API contract file.Rewind(); const auto data = file.GetRawDataAsByteVector(ProbeRecommendedSize); MemoryFileReader mf{mpt::as_span(data)}; const uint64 size = file.GetLength(); MPT_ASSERT(format.prober(mf, &size) != ProbeFailure); #endif break; } } if(!loaderSuccess) { m_nType = MOD_TYPE_NONE; m_ContainerType = ModContainerType::None; } if(loadFlags == onlyVerifyHeader) { return loaderSuccess; } if(packedContainerType != ModContainerType::None && m_ContainerType == ModContainerType::None) { m_ContainerType = packedContainerType; } m_visitedRows.Initialize(true); } else { // New song InitializeGlobals(MOD_TYPE_NONE, 0); m_visitedRows.Initialize(true); m_dwCreatedWithVersion = Version::Current(); #if MPT_TIME_UTC_ON_DISK #ifdef MODPLUG_TRACKER if(GetType() & MOD_TYPE_IT) { m_modFormat.timezone = mpt::Date::LogicalTimezone::UTC; } else { m_modFormat.timezone = mpt::Date::LogicalTimezone::Local; } #else // !MODPLUG_TRACKER if (GetType() & MOD_TYPE_IT) { m_modFormat.timezone = mpt::Date::LogicalTimezone::UTC; } else { m_modFormat.timezone = mpt::Date::LogicalTimezone::Unspecified; } #endif // MODPLUG_TRACKER #else #ifdef MODPLUG_TRACKER m_modFormat.timezone = mpt::Date::LogicalTimezone::Local; #else // !MODPLUG_TRACKER m_modFormat.timezone = mpt::Date::LogicalTimezone::Unspecified; #endif // MODPLUG_TRACKER #endif } #if MPT_TIME_UTC_ON_DISK #ifdef MODPLUG_TRACKER // convert timestamps to UTC if(m_modFormat.timezone == mpt::Date::LogicalTimezone::Local) { for(auto & fileHistoryEntry : m_FileHistory) { if(fileHistoryEntry.HasValidDate()) { fileHistoryEntry.loadDate = mpt::Date::forget_timezone(mpt::Date::UnixAsUTC(mpt::Date::UnixFromLocal(mpt::Date::interpret_as_timezone(fileHistoryEntry.loadDate)))); } } m_modFormat.timezone = mpt::Date::LogicalTimezone::UTC; } #endif // MODPLUG_TRACKER #endif // Adjust channels const auto muteFlag = GetChannelMuteFlag(); for(CHANNELINDEX chn = 0; chn < ChnSettings.size(); chn++) { LimitMax(ChnSettings[chn].nVolume, uint8(64)); if(ChnSettings[chn].nPan > 256) ChnSettings[chn].nPan = 128; if(ChnSettings[chn].nMixPlugin > MAX_MIXPLUGINS) ChnSettings[chn].nMixPlugin = 0; m_PlayState.Chn[chn].Reset(ModChannel::resetTotal, *this, chn, muteFlag); } // Checking samples, load external samples for(SAMPLEINDEX nSmp = 1; nSmp <= m_nSamples; nSmp++) { ModSample &sample = Samples[nSmp]; LimitMax(sample.nLength, MAX_SAMPLE_LENGTH); sample.SanitizeLoops(); #ifdef MPT_EXTERNAL_SAMPLES if(SampleHasPath(nSmp) && (loadFlags & loadSampleData)) { mpt::PathString filename = GetSamplePath(nSmp); if(file.GetOptionalFileName()) { filename = mpt::RelativePathToAbsolute(filename, file.GetOptionalFileName()->GetDirectoryWithDrive()); } else if(GetpModDoc() != nullptr) { filename = mpt::RelativePathToAbsolute(filename, GetpModDoc()->GetPathNameMpt().GetDirectoryWithDrive()); } filename = filename.Simplify(); if(!LoadExternalSample(nSmp, filename)) { #ifndef MODPLUG_TRACKER // OpenMPT has its own way of reporting this error in CModDoc. AddToLog(LogError, MPT_UFORMAT("Unable to load sample {}: {}")(i, filename.ToUnicode())); #endif // MODPLUG_TRACKER } } else { sample.uFlags.reset(SMP_KEEPONDISK); } #endif // MPT_EXTERNAL_SAMPLES if(sample.HasSampleData()) { sample.PrecomputeLoops(*this, false); } else if(!sample.uFlags[SMP_KEEPONDISK]) { sample.nLength = 0; sample.nLoopStart = 0; sample.nLoopEnd = 0; sample.nSustainStart = 0; sample.nSustainEnd = 0; sample.uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN); } if(sample.nGlobalVol > 64) sample.nGlobalVol = 64; if(sample.uFlags[CHN_ADLIB] && m_opl == nullptr) InitOPL(); } // Check invalid instruments INSTRUMENTINDEX maxInstr = 0; for(INSTRUMENTINDEX i = 0; i <= m_nInstruments; i++) { if(Instruments[i] != nullptr) { maxInstr = i; Instruments[i]->Sanitize(GetType()); } } m_nInstruments = maxInstr; // Set default play state values if(!m_nDefaultRowsPerBeat && m_nTempoMode == TempoMode::Modern) m_nDefaultRowsPerBeat = 1; if(m_nDefaultRowsPerMeasure < m_nDefaultRowsPerBeat) m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat; LimitMax(m_nDefaultRowsPerBeat, MAX_ROWS_PER_BEAT); LimitMax(m_nDefaultRowsPerMeasure, MAX_ROWS_PER_BEAT); LimitMax(m_nDefaultGlobalVolume, MAX_GLOBAL_VOLUME); LimitMax(m_nSamplePreAmp, MAX_PREAMP); LimitMax(m_nVSTiVolume, MAX_PREAMP); if(!m_tempoSwing.empty()) m_tempoSwing.resize(m_nDefaultRowsPerBeat); m_PlayState.m_nMusicSpeed = Order().GetDefaultSpeed(); m_PlayState.m_nMusicTempo = Order().GetDefaultTempo(); m_PlayState.m_nCurrentRowsPerBeat = m_nDefaultRowsPerBeat; m_PlayState.m_nCurrentRowsPerMeasure = m_nDefaultRowsPerMeasure; m_PlayState.m_nGlobalVolume = static_cast(m_nDefaultGlobalVolume); m_PlayState.ResetGlobalVolumeRamping(); m_PlayState.m_nNextOrder = 0; m_PlayState.m_nCurrentOrder = 0; m_PlayState.m_nPattern = 0; m_PlayState.m_nBufferCount = 0; m_PlayState.m_dBufferDiff = 0; m_PlayState.m_nTickCount = TICKS_ROW_FINISHED; m_PlayState.m_nNextRow = 0; m_PlayState.m_nRow = 0; m_PlayState.m_nPatternDelay = 0; m_PlayState.m_nFrameDelay = 0; m_PlayState.m_nextPatStartRow = 0; m_PlayState.m_nSeqOverride = ORDERINDEX_INVALID; if(UseFinetuneAndTranspose()) m_playBehaviour.reset(kPeriodsAreHertz); m_restartOverridePos = m_maxOrderPosition = 0; RecalculateSamplesPerTick(); for(auto &order : Order) { order.Shrink(); if(order.GetRestartPos() >= order.size()) order.SetRestartPos(0); } if(GetType() == MOD_TYPE_NONE) { return false; } m_pModSpecs = &GetModSpecifications(GetBestSaveFormat()); // When reading a file made with an older version of MPT, it might be necessary to upgrade some settings automatically. if(m_dwLastSavedWithVersion) { UpgradeModule(); } #ifndef NO_PLUGINS // Load plugins #ifdef MODPLUG_TRACKER mpt::ustring notFoundText; #endif // MODPLUG_TRACKER std::vector notFoundIDs; if((loadFlags & (loadPluginData | loadPluginInstance)) == (loadPluginData | loadPluginInstance)) { for(PLUGINDEX plug = 0; plug < MAX_MIXPLUGINS; plug++) { auto &plugin = m_MixPlugins[plug]; if(plugin.IsValidPlugin()) { #ifdef MODPLUG_TRACKER // Provide some visual feedback { mpt::ustring s = MPT_UFORMAT("Loading Plugin FX{}: {} ({})")( mpt::ufmt::dec0<2>(plug + 1), mpt::ToUnicode(mpt::Charset::UTF8, plugin.Info.szLibraryName), mpt::ToUnicode(mpt::Charset::Locale, plugin.Info.szName)); CMainFrame::GetMainFrame()->SetHelpText(mpt::ToCString(s)); } #endif // MODPLUG_TRACKER CreateMixPluginProc(plugin, *this); if(plugin.pMixPlugin) { // Plugin was found plugin.pMixPlugin->RestoreAllParameters(plugin.defaultProgram); // Special handling for instrument plugins in ProcessMixOps was removed if(m_dwLastSavedWithVersion < MPT_V("1.32.00.11")) { if(plugin.pMixPlugin->IsInstrument()) plugin.SetMixMode(PluginMixMode::Instrument); if(!plugin.pMixPlugin->GetNumInputChannels()) plugin.SetExpandedMix(false); } } else { // Plugin not found - add to list bool found = std::find_if(notFoundIDs.cbegin(), notFoundIDs.cend(), [&plugin](const SNDMIXPLUGININFO *info) { return info->dwPluginId2 == plugin.Info.dwPluginId2 && info->dwPluginId1 == plugin.Info.dwPluginId1; }) != notFoundIDs.cend(); if(!found) { notFoundIDs.push_back(&plugin.Info); #ifdef MODPLUG_TRACKER notFoundText.append(plugin.GetLibraryName()); notFoundText.append(UL_("\n")); #else AddToLog(LogWarning, U_("Plugin not found: ") + plugin.GetLibraryName()); #endif // MODPLUG_TRACKER } } } } } // Set up mix levels (also recalculates plugin mix levels - must be done after plugins were loaded) SetMixLevels(m_nMixLevels); #ifdef MODPLUG_TRACKER // Display a nice message so the user sees which plugins are missing // TODO: Use IDD_MODLOADING_WARNINGS dialog (NON-MODAL!) to display all warnings that are encountered when loading a module. if(!notFoundIDs.empty()) { if(notFoundIDs.size() == 1) { notFoundText = UL_("The following plugin has not been found:\n\n") + notFoundText + UL_("\nDo you want to search for it online?"); } else { notFoundText = UL_("The following plugins have not been found:\n\n") + notFoundText + UL_("\nDo you want to search for them online?"); } if(Reporting::Confirm(notFoundText, U_("OpenMPT - Plugins missing"), false, true) == cnfYes) { mpt::ustring url = U_("https://resources.openmpt.org/plugins/search.php?p="); for(const auto &id : notFoundIDs) { url += mpt::ufmt::HEX0<8>(id->dwPluginId2.get()); url += mpt::ToUnicode(mpt::Charset::UTF8, id->szLibraryName); url += UL_("%0a"); } CTrackApp::OpenURL(mpt::PathString::FromUnicode(url)); } } #endif // MODPLUG_TRACKER #endif // NO_PLUGINS return true; } bool CSoundFile::Destroy() { for(auto &chn : m_PlayState.Chn) { chn.pModInstrument = nullptr; chn.pModSample = nullptr; chn.pCurrentSample = nullptr; chn.nLength = 0; } Patterns.DestroyPatterns(); m_songName.clear(); m_songArtist.clear(); m_songMessage.clear(); m_FileHistory.clear(); ChnSettings.clear(); #ifdef MPT_EXTERNAL_SAMPLES m_samplePaths.clear(); #endif // MPT_EXTERNAL_SAMPLES for(auto &smp : Samples) { smp.FreeSample(); } for(auto &ins : Instruments) { delete ins; ins = nullptr; } #ifndef NO_PLUGINS for(auto &plug : m_MixPlugins) { plug.Destroy(); } #endif // NO_PLUGINS m_nType = MOD_TYPE_NONE; m_ContainerType = ModContainerType::None; m_nSamples = m_nInstruments = 0; return true; } ////////////////////////////////////////////////////////////////////////// // Misc functions void CSoundFile::SetDspEffects(uint32 DSPMask) { m_MixerSettings.DSPMask = DSPMask; InitPlayer(false); } void CSoundFile::SetPreAmp(uint32 nVol) { if (nVol < 1) nVol = 1; if (nVol > 0x200) nVol = 0x200; // x4 maximum #ifndef NO_AGC if ((nVol < m_MixerSettings.m_nPreAmp) && (nVol) && (m_MixerSettings.DSPMask & SNDDSP_AGC)) { m_AGC.Adjust(m_MixerSettings.m_nPreAmp, nVol); } #endif m_MixerSettings.m_nPreAmp = nVol; } double CSoundFile::GetCurrentBPM() const { double bpm; if (m_nTempoMode == TempoMode::Modern) { // With modern mode, we trust that true bpm is close enough to what user chose. // This avoids oscillation due to tick-to-tick corrections. bpm = m_PlayState.m_nMusicTempo.ToDouble(); } else { // With other modes, we calculate it: ROWINDEX rowsPerBeat = m_PlayState.m_nCurrentRowsPerBeat ? m_PlayState.m_nCurrentRowsPerBeat : DEFAULT_ROWS_PER_BEAT; double ticksPerBeat = m_PlayState.m_nMusicSpeed * rowsPerBeat; // Ticks/beat = ticks/row * rows/beat double samplesPerBeat = m_PlayState.m_nSamplesPerTick * ticksPerBeat; // Samps/beat = samps/tick * ticks/beat bpm = m_MixerSettings.gdwMixingFreq / samplesPerBeat * 60; // Beats/sec = samps/sec / samps/beat } // Beats/min = beats/sec * 60 return bpm; } void CSoundFile::ResetPlayPos() { const auto muteFlag = GetChannelMuteFlag(); for(CHANNELINDEX i = 0; i < m_PlayState.Chn.size(); i++) m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i, muteFlag); m_visitedRows.Initialize(true); m_PlayState.m_flags.reset(SONG_FADINGSONG | SONG_ENDREACHED); m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume; m_PlayState.m_nMusicSpeed = Order().GetDefaultSpeed(); m_PlayState.m_nMusicTempo = Order().GetDefaultTempo(); // Do not ramp global volume when starting playback m_PlayState.ResetGlobalVolumeRamping(); m_PlayState.m_nNextOrder = 0; m_PlayState.m_nNextRow = 0; m_PlayState.m_nTickCount = TICKS_ROW_FINISHED; m_PlayState.m_nBufferCount = 0; m_PlayState.m_nPatternDelay = 0; m_PlayState.m_nFrameDelay = 0; m_PlayState.m_nextPatStartRow = 0; m_PlayState.m_lTotalSampleCount = 0; m_PlayState.m_ppqPosFract = 0.0; m_PlayState.m_ppqPosBeat = 0; m_PlayState.m_globalScriptState.Initialize(*this); } void CSoundFile::SetCurrentOrder(ORDERINDEX nOrder) { while(nOrder < Order().size() && !Order().IsValidPat(nOrder)) nOrder++; if(nOrder >= Order().size()) return; for(auto &chn : m_PlayState.Chn) { chn.nPeriod = 0; chn.nNote = NOTE_NONE; chn.nPortamentoDest = 0; chn.nCommand = 0; chn.nPatternLoopCount = 0; chn.nPatternLoop = 0; chn.nVibratoPos = chn.nTremoloPos = chn.nPanbrelloPos = 0; //IT compatibility 15. Retrigger if(m_playBehaviour[kITRetrigger]) { chn.nRetrigCount = 0; chn.nRetrigParam = 1; } chn.nTremorCount = 0; } #ifndef NO_PLUGINS // Stop hanging notes from VST instruments as well StopAllVsti(); #endif // NO_PLUGINS if (!nOrder) { ResetPlayPos(); } else { m_PlayState.m_nNextOrder = nOrder; m_PlayState.m_nRow = m_PlayState.m_nNextRow = 0; m_PlayState.m_nPattern = 0; m_PlayState.m_nTickCount = TICKS_ROW_FINISHED; m_PlayState.m_nBufferCount = 0; m_PlayState.m_nPatternDelay = 0; m_PlayState.m_nFrameDelay = 0; m_PlayState.m_nextPatStartRow = 0; m_PlayState.m_globalScriptState.Initialize(*this); } m_PlayState.m_flags.reset(SONG_FADINGSONG | SONG_ENDREACHED); } void CSoundFile::SuspendPlugins() { #ifndef NO_PLUGINS for(auto &plug : m_MixPlugins) { IMixPlugin *pPlugin = plug.pMixPlugin; if(pPlugin != nullptr && pPlugin->IsResumed()) { pPlugin->NotifySongPlaying(false); pPlugin->HardAllNotesOff(); pPlugin->Suspend(); } } #endif // NO_PLUGINS } void CSoundFile::ResumePlugins() { #ifndef NO_PLUGINS for(auto &plugin : m_MixPlugins) { IMixPlugin *pPlugin = plugin.pMixPlugin; if(pPlugin != nullptr && !pPlugin->IsResumed()) { pPlugin->NotifySongPlaying(true); pPlugin->Resume(); } } #endif // NO_PLUGINS } void CSoundFile::UpdatePluginPositions() { #ifndef NO_PLUGINS for(auto &plugin : m_MixPlugins) { IMixPlugin *pPlugin = plugin.pMixPlugin; if(pPlugin != nullptr && !pPlugin->IsResumed()) { pPlugin->PositionChanged(); } } #endif // NO_PLUGINS } void CSoundFile::StopAllVsti() { #ifndef NO_PLUGINS for(auto &plugin : m_MixPlugins) { IMixPlugin *pPlugin = plugin.pMixPlugin; if(pPlugin != nullptr && pPlugin->IsResumed()) { pPlugin->HardAllNotesOff(); } } #endif // NO_PLUGINS } void CSoundFile::SetMixLevels(MixLevels levels) { m_nMixLevels = levels; m_PlayConfig.SetMixLevels(m_nMixLevels); RecalculateGainForAllPlugs(); } void CSoundFile::RecalculateGainForAllPlugs() { #ifndef NO_PLUGINS for(auto &plugin : m_MixPlugins) { if(plugin.pMixPlugin != nullptr) plugin.pMixPlugin->RecalculateGain(); } #endif // NO_PLUGINS } void CSoundFile::ResetChannels() { m_PlayState.m_flags.reset(SONG_FADINGSONG | SONG_ENDREACHED); m_PlayState.m_nBufferCount = 0; for(CHANNELINDEX channel = 0; channel < m_PlayState.Chn.size(); channel++) { ModChannel &chn = m_PlayState.Chn[channel]; chn.dwFlags.set(CHN_NOTEFADE); chn.nROfs = chn.nLOfs = 0; chn.nLength = 0; chn.nFadeOutVol = 0; if(chn.dwFlags[CHN_ADLIB] && m_opl) m_opl->NoteCut(channel); } } #ifdef MODPLUG_TRACKER void CSoundFile::PatternTranstionChnSolo(const CHANNELINDEX first, const CHANNELINDEX last) { if(first >= GetNumChannels() || last < first) return; for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { if(i >= first && i <= last) m_bChannelMuteTogglePending[i] = ChnSettings[i].dwFlags[CHN_MUTE]; else m_bChannelMuteTogglePending[i] = !ChnSettings[i].dwFlags[CHN_MUTE]; } } void CSoundFile::PatternTransitionChnUnmuteAll() { for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { m_bChannelMuteTogglePending[i] = ChnSettings[i].dwFlags[CHN_MUTE]; } } #endif // MODPLUG_TRACKER void CSoundFile::LoopPattern(PATTERNINDEX nPat, ROWINDEX nRow) { if(!Patterns.IsValidPat(nPat)) { m_PlayState.m_flags.reset(SONG_PATTERNLOOP); } else { if(nRow >= Patterns[nPat].GetNumRows()) nRow = 0; m_PlayState.m_nPattern = nPat; m_PlayState.m_nRow = m_PlayState.m_nNextRow = nRow; m_PlayState.m_nTickCount = TICKS_ROW_FINISHED; m_PlayState.m_nPatternDelay = 0; m_PlayState.m_nFrameDelay = 0; m_PlayState.m_nextPatStartRow = 0; m_PlayState.m_flags.set(SONG_PATTERNLOOP); } m_PlayState.m_nBufferCount = 0; } void CSoundFile::DontLoopPattern(PATTERNINDEX nPat, ROWINDEX nRow) { if(!Patterns.IsValidPat(nPat)) nPat = 0; if(nRow >= Patterns[nPat].GetNumRows()) nRow = 0; m_PlayState.m_nPattern = nPat; m_PlayState.m_nRow = m_PlayState.m_nNextRow = nRow; m_PlayState.m_nTickCount = TICKS_ROW_FINISHED; m_PlayState.m_nPatternDelay = 0; m_PlayState.m_nFrameDelay = 0; m_PlayState.m_nBufferCount = 0; m_PlayState.m_nextPatStartRow = 0; m_PlayState.m_flags.reset(SONG_PATTERNLOOP); } void CSoundFile::SetDefaultPlaybackBehaviour(MODTYPE type) { m_playBehaviour = GetDefaultPlaybackBehaviour(type); } PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type) { PlayBehaviourSet playBehaviour; switch(type) { case MOD_TYPE_MPT: playBehaviour.set(kOPLFlexibleNoteOff); playBehaviour.set(kOPLwithNNA); playBehaviour.set(kOPLNoteOffOnNoteChange); [[fallthrough]]; case MOD_TYPE_IT: playBehaviour.set(MSF_COMPATIBLE_PLAY); playBehaviour.set(kPeriodsAreHertz); playBehaviour.set(kTempoClamp); playBehaviour.set(kPerChannelGlobalVolSlide); playBehaviour.set(kPanOverride); playBehaviour.set(kITInstrWithoutNote); playBehaviour.set(kITVolColFinePortamento); playBehaviour.set(kITArpeggio); playBehaviour.set(kITOutOfRangeDelay); playBehaviour.set(kITPortaMemoryShare); playBehaviour.set(kITPatternLoopTargetReset); playBehaviour.set(kITFT2PatternLoop); playBehaviour.set(kITPingPongNoReset); playBehaviour.set(kITEnvelopeReset); playBehaviour.set(kITClearOldNoteAfterCut); playBehaviour.set(kITVibratoTremoloPanbrello); playBehaviour.set(kITTremor); playBehaviour.set(kITRetrigger); playBehaviour.set(kITMultiSampleBehaviour); playBehaviour.set(kITPortaTargetReached); playBehaviour.set(kITPatternLoopBreak); playBehaviour.set(kITOffset); playBehaviour.set(kITSwingBehaviour); playBehaviour.set(kITNNAReset); playBehaviour.set(kITSCxStopsSample); playBehaviour.set(kITEnvelopePositionHandling); playBehaviour.set(kITPortamentoInstrument); playBehaviour.set(kITPingPongMode); playBehaviour.set(kITRealNoteMapping); playBehaviour.set(kITHighOffsetNoRetrig); playBehaviour.set(kITFilterBehaviour); playBehaviour.set(kITNoSurroundPan); playBehaviour.set(kITShortSampleRetrig); playBehaviour.set(kITPortaNoNote); playBehaviour.set(kITFT2DontResetNoteOffOnPorta); playBehaviour.set(kITVolColMemory); playBehaviour.set(kITPortamentoSwapResetsPos); playBehaviour.set(kITEmptyNoteMapSlot); playBehaviour.set(kITFirstTickHandling); playBehaviour.set(kITSampleAndHoldPanbrello); playBehaviour.set(kITClearPortaTarget); playBehaviour.set(kITPanbrelloHold); playBehaviour.set(kITPanningReset); playBehaviour.set(kITPatternLoopWithJumps); playBehaviour.set(kITInstrWithNoteOff); playBehaviour.set(kITMultiSampleInstrumentNumber); playBehaviour.set(kRowDelayWithNoteDelay); playBehaviour.set(kITInstrWithNoteOffOldEffects); playBehaviour.set(kITDoNotOverrideChannelPan); playBehaviour.set(kITDCTBehaviour); playBehaviour.set(kITPitchPanSeparation); playBehaviour.set(kITResetFilterOnPortaSmpChange); playBehaviour.set(kITInitialNoteMemory); playBehaviour.set(kITNoSustainOnPortamento); playBehaviour.set(kITEmptyNoteMapSlotIgnoreCell); playBehaviour.set(kITOffsetWithInstrNumber); playBehaviour.set(kITDoublePortamentoSlides); playBehaviour.set(kITCarryAfterNoteOff); playBehaviour.set(kITNoteCutWithPorta); break; case MOD_TYPE_XM: playBehaviour.set(MSF_COMPATIBLE_PLAY); playBehaviour.set(kFT2VolumeRamping); playBehaviour.set(kTempoClamp); playBehaviour.set(kPerChannelGlobalVolSlide); playBehaviour.set(kPanOverride); playBehaviour.set(kITFT2PatternLoop); playBehaviour.set(kITFT2DontResetNoteOffOnPorta); playBehaviour.set(kFT2Arpeggio); playBehaviour.set(kFT2Retrigger); playBehaviour.set(kFT2VolColVibrato); playBehaviour.set(kFT2PortaNoNote); playBehaviour.set(kFT2KeyOff); playBehaviour.set(kFT2PanSlide); playBehaviour.set(kFT2ST3OffsetOutOfRange); playBehaviour.set(kFT2RestrictXCommand); playBehaviour.set(kFT2RetrigWithNoteDelay); playBehaviour.set(kFT2SetPanEnvPos); playBehaviour.set(kFT2PortaIgnoreInstr); playBehaviour.set(kFT2VolColMemory); playBehaviour.set(kFT2LoopE60Restart); playBehaviour.set(kFT2ProcessSilentChannels); playBehaviour.set(kFT2ReloadSampleSettings); playBehaviour.set(kFT2PortaDelay); playBehaviour.set(kFT2Transpose); playBehaviour.set(kFT2PatternLoopWithJumps); playBehaviour.set(kFT2PortaTargetNoReset); playBehaviour.set(kFT2EnvelopeEscape); playBehaviour.set(kFT2Tremor); playBehaviour.set(kFT2OutOfRangeDelay); playBehaviour.set(kFT2Periods); playBehaviour.set(kFT2PanWithDelayedNoteOff); playBehaviour.set(kFT2VolColDelay); playBehaviour.set(kFT2FinetunePrecision); playBehaviour.set(kFT2NoteOffFlags); playBehaviour.set(kRowDelayWithNoteDelay); playBehaviour.set(kFT2MODTremoloRampWaveform); playBehaviour.set(kFT2PortaUpDownMemory); playBehaviour.set(kFT2PanSustainRelease); playBehaviour.set(kFT2NoteDelayWithoutInstr); playBehaviour.set(kFT2PortaResetDirection); playBehaviour.set(kFT2AutoVibratoAbortSweep); playBehaviour.set(kFT2OffsetMemoryRequiresNote); break; case MOD_TYPE_S3M: playBehaviour.set(MSF_COMPATIBLE_PLAY); playBehaviour.set(kTempoClamp); playBehaviour.set(kPanOverride); playBehaviour.set(kITPanbrelloHold); playBehaviour.set(kFT2ST3OffsetOutOfRange); playBehaviour.set(kST3NoMutedChannels); playBehaviour.set(kST3PortaSampleChange); playBehaviour.set(kST3EffectMemory); playBehaviour.set(kST3VibratoMemory); playBehaviour.set(KST3PortaAfterArpeggio); playBehaviour.set(kRowDelayWithNoteDelay); playBehaviour.set(kST3OffsetWithoutInstrument); playBehaviour.set(kST3RetrigAfterNoteCut); playBehaviour.set(kST3SampleSwap); playBehaviour.set(kOPLNoteOffOnNoteChange); playBehaviour.set(kApplyUpperPeriodLimit); playBehaviour.set(kST3TonePortaWithAdlibNote); playBehaviour.set(kS3MIgnoreCombinedFineSlides); break; case MOD_TYPE_MOD: playBehaviour.set(kMODVBlankTiming); playBehaviour.set(kMODOneShotLoops); playBehaviour.set(kMODIgnorePanning); playBehaviour.set(kMODSampleSwap); playBehaviour.set(kMODOutOfRangeNoteDelay); playBehaviour.set(kMODTempoOnSecondTick); playBehaviour.set(kRowDelayWithNoteDelay); playBehaviour.set(kFT2MODTremoloRampWaveform); break; default: playBehaviour.set(MSF_COMPATIBLE_PLAY); playBehaviour.set(kPeriodsAreHertz); playBehaviour.set(kTempoClamp); playBehaviour.set(kPanOverride); break; } return playBehaviour; } PlayBehaviourSet CSoundFile::GetDefaultPlaybackBehaviour(MODTYPE type) { PlayBehaviourSet playBehaviour; switch(type) { case MOD_TYPE_MPT: playBehaviour.set(kPeriodsAreHertz); playBehaviour.set(kPerChannelGlobalVolSlide); playBehaviour.set(kPanOverride); playBehaviour.set(kITArpeggio); playBehaviour.set(kITPortaMemoryShare); playBehaviour.set(kITPatternLoopTargetReset); playBehaviour.set(kITFT2PatternLoop); playBehaviour.set(kITPingPongNoReset); playBehaviour.set(kITClearOldNoteAfterCut); playBehaviour.set(kITVibratoTremoloPanbrello); playBehaviour.set(kITMultiSampleBehaviour); playBehaviour.set(kITPortaTargetReached); playBehaviour.set(kITPatternLoopBreak); playBehaviour.set(kITSwingBehaviour); playBehaviour.set(kITSCxStopsSample); playBehaviour.set(kITEnvelopePositionHandling); playBehaviour.set(kITPingPongMode); playBehaviour.set(kITRealNoteMapping); playBehaviour.set(kITPortaNoNote); playBehaviour.set(kITVolColMemory); playBehaviour.set(kITFirstTickHandling); playBehaviour.set(kITClearPortaTarget); playBehaviour.set(kITSampleAndHoldPanbrello); playBehaviour.set(kITPanbrelloHold); playBehaviour.set(kITPanningReset); playBehaviour.set(kITInstrWithNoteOff); playBehaviour.set(kOPLFlexibleNoteOff); playBehaviour.set(kITDoNotOverrideChannelPan); playBehaviour.set(kITDCTBehaviour); playBehaviour.set(kOPLwithNNA); playBehaviour.set(kITPitchPanSeparation); break; case MOD_TYPE_S3M: playBehaviour = GetSupportedPlaybackBehaviour(type); // Default behaviour was chosen to follow GUS, so kST3PortaSampleChange is enabled and kST3SampleSwap is disabled. // For SoundBlaster behaviour, those two flags would need to be swapped. playBehaviour.reset(kST3SampleSwap); // Most trackers supporting the S3M format, including all OpenMPT versions up to now, support fine slides with Kxy / Lxy, so only enable this quirk for files made with ST3. playBehaviour.reset(kS3MIgnoreCombinedFineSlides); break; case MOD_TYPE_XM: playBehaviour = GetSupportedPlaybackBehaviour(type); // Only set this explicitely for FT2-made XMs. playBehaviour.reset(kFT2VolumeRamping); break; case MOD_TYPE_MOD: playBehaviour.set(kRowDelayWithNoteDelay); break; default: playBehaviour = GetSupportedPlaybackBehaviour(type); break; } return playBehaviour; } MODTYPE CSoundFile::GetBestSaveFormat() const { switch(GetType()) { case MOD_TYPE_MOD: case MOD_TYPE_S3M: case MOD_TYPE_XM: case MOD_TYPE_IT: case MOD_TYPE_MPT: return GetType(); case MOD_TYPE_AMF0: case MOD_TYPE_DIGI: case MOD_TYPE_SFX: case MOD_TYPE_STP: return MOD_TYPE_MOD; case MOD_TYPE_MED: if(!m_nInstruments) { for(const auto &pat : Patterns) { if(pat.IsValid() && pat.GetNumRows() != 64) return MOD_TYPE_XM; } return MOD_TYPE_MOD; } return MOD_TYPE_XM; case MOD_TYPE_PSM: if(Order.GetNumSequences() > 1) return MOD_TYPE_MPT; if(GetNumChannels() > 16) return MOD_TYPE_IT; for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { if(ChnSettings[i].dwFlags[CHN_SURROUND] || ChnSettings[i].nVolume != 64) { return MOD_TYPE_IT; break; } } return MOD_TYPE_S3M; case MOD_TYPE_669: case MOD_TYPE_FAR: case MOD_TYPE_STM: case MOD_TYPE_DSM: case MOD_TYPE_AMF: case MOD_TYPE_MTM: return MOD_TYPE_S3M; case MOD_TYPE_AMS: case MOD_TYPE_DMF: case MOD_TYPE_DBM: case MOD_TYPE_IMF: case MOD_TYPE_J2B: case MOD_TYPE_ULT: case MOD_TYPE_OKT: case MOD_TYPE_MT2: case MOD_TYPE_MDL: case MOD_TYPE_PTM: case MOD_TYPE_DTM: default: return MOD_TYPE_IT; case MOD_TYPE_MID: return MOD_TYPE_MPT; } } const char *CSoundFile::GetSampleName(SAMPLEINDEX nSample) const { MPT_ASSERT(nSample <= GetNumSamples()); if (nSample < MAX_SAMPLES) { return m_szNames[nSample].buf; } else { return ""; } } const char *CSoundFile::GetInstrumentName(INSTRUMENTINDEX nInstr) const { if((nInstr >= MAX_INSTRUMENTS) || (!Instruments[nInstr])) return ""; MPT_ASSERT(nInstr <= GetNumInstruments()); return Instruments[nInstr]->name.buf; } void CSoundFile::InitAmigaResampler() { if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga != Resampling::AmigaFilter::Off) { const Paula::State defaultState(GetSampleRate()); for(auto &chn : m_PlayState.Chn) { chn.paulaState = defaultState; } } } void CSoundFile::InitOPL() { if(!m_opl) m_opl = std::make_unique(m_MixerSettings.gdwMixingFreq); } // Detect samples that are referenced by an instrument, but actually not used in a song. // Only works in instrument mode. Unused samples are marked as false in the vector. SAMPLEINDEX CSoundFile::DetectUnusedSamples(std::vector &sampleUsed) const { sampleUsed.assign(GetNumSamples() + 1, false); if(GetNumInstruments() == 0) { return 0; } SAMPLEINDEX unused = 0; std::vector lastIns; for(const auto &pat : Patterns) if(pat.IsValid()) { lastIns.assign(GetNumChannels(), 0); auto p = pat.cbegin(); for(ROWINDEX row = 0; row < pat.GetNumRows(); row++) { for(CHANNELINDEX c = 0; c < GetNumChannels(); c++, p++) { if(p->IsNote()) { ModCommand::INSTR instr = p->instr; if(!p->instr) instr = lastIns[c]; INSTRUMENTINDEX minInstr = 1, maxInstr = GetNumInstruments(); if(instr > 0) { if(instr <= GetNumInstruments()) { minInstr = maxInstr = instr; } lastIns[c] = instr; } else { // No idea which instrument this note belongs to, so mark it used in any instruments. } for(INSTRUMENTINDEX i = minInstr; i <= maxInstr; i++) { if(const auto *pIns = Instruments[i]; pIns != nullptr) { SAMPLEINDEX n = pIns->Keyboard[p->note - NOTE_MIN]; if(n <= GetNumSamples()) sampleUsed[n] = true; } } } } } } for (SAMPLEINDEX ichk = GetNumSamples(); ichk >= 1; ichk--) { if ((!sampleUsed[ichk]) && (Samples[ichk].HasSampleData())) unused++; } return unused; } // Destroy samples where keepSamples index is false. First sample is keepSamples[1]! SAMPLEINDEX CSoundFile::RemoveSelectedSamples(const std::vector &keepSamples) { if(keepSamples.empty()) { return 0; } SAMPLEINDEX nRemoved = 0; for(SAMPLEINDEX nSmp = std::min(GetNumSamples(), static_cast(keepSamples.size() - 1)); nSmp >= 1; nSmp--) { if(!keepSamples[nSmp]) { CriticalSection cs; #ifdef MODPLUG_TRACKER if(GetpModDoc()) { GetpModDoc()->GetSampleUndo().PrepareUndo(nSmp, sundo_replace, "Remove Sample"); } #endif // MODPLUG_TRACKER if(DestroySample(nSmp)) { m_szNames[nSmp] = ""; nRemoved++; } if((nSmp == GetNumSamples()) && (nSmp > 1)) m_nSamples--; } } return nRemoved; } bool CSoundFile::DestroySample(SAMPLEINDEX nSample) { if(!nSample || nSample >= MAX_SAMPLES) { return false; } if(!Samples[nSample].HasSampleData()) { return true; } ModSample &sample = Samples[nSample]; for(auto &chn : m_PlayState.Chn) { if(chn.pModSample == &sample) { chn.position.Set(0); chn.nLength = 0; chn.pCurrentSample = nullptr; } } sample.FreeSample(); sample.nLength = 0; sample.uFlags.reset(CHN_16BIT | CHN_STEREO); sample.SetAdlib(false); #ifdef MODPLUG_TRACKER ResetSamplePath(nSample); #endif return true; } bool CSoundFile::DestroySampleThreadsafe(SAMPLEINDEX nSample) { CriticalSection cs; return DestroySample(nSample); } std::unique_ptr CSoundFile::CreateTuning12TET(const mpt::ustring &name) { std::unique_ptr pT = CTuning::CreateGeometric(name, 12, 2, 15); for(ModCommand::NOTE note = 0; note < 12; ++note) { pT->SetNoteName(note, mpt::ustring(NoteNamesSharp[note])); } return pT; } mpt::ustring CSoundFile::GetNoteName(const ModCommand::NOTE note, const INSTRUMENTINDEX inst, const NoteName *noteNames) const { // For MPTM instruments with custom tuning, find the appropriate note name. Else, use default note names. if(ModCommand::IsNote(note) && GetType() == MOD_TYPE_MPT && inst >= 1 && inst <= GetNumInstruments() && Instruments[inst] && Instruments[inst]->pTuning) { return Instruments[inst]->pTuning->GetNoteName(note - NOTE_MIDDLEC); } else { return GetNoteName(note, noteNames ? noteNames : m_NoteNames); } } mpt::ustring CSoundFile::GetNoteName(const ModCommand::NOTE note) const { return GetNoteName(note, m_NoteNames); } mpt::ustring CSoundFile::GetNoteName(const ModCommand::NOTE note, const NoteName *noteNames) { if(ModCommand::IsSpecialNote(note)) { // cppcheck false-positive // cppcheck-suppress constStatement const mpt::uchar specialNoteNames[][4] = { UL_("PCs"), UL_("PC "), UL_("~~~"), UL_("^^^"), UL_("===") }; static_assert(mpt::array_size::size == NOTE_MAX_SPECIAL - NOTE_MIN_SPECIAL + 1); return specialNoteNames[note - NOTE_MIN_SPECIAL]; } else if(ModCommand::IsNote(note)) { const int octave = (note - NOTE_MIN) / 12; return mpt::ustring() .append(noteNames[(note - NOTE_MIN) % 12]) .append(1, static_cast((octave <= 9 ? UC_('0') : UC_('A') - 10) + octave)) ; // e.g. "C#" + "5" } else if(note == NOTE_NONE) { return UL_("..."); } return UL_("???"); } #ifdef MODPLUG_TRACKER void CSoundFile::SetDefaultNoteNames() { m_NoteNames = TrackerSettings::Instance().accidentalFlats ? NoteNamesFlat : NoteNamesSharp; } const NoteName *CSoundFile::GetDefaultNoteNames() { return m_NoteNames; } #endif // MODPLUG_TRACKER const CModSpecifications &CSoundFile::GetModSpecifications(const MODTYPE type) { switch(type) { case MOD_TYPE_MPT: return ModSpecs::mptm; break; case MOD_TYPE_IT: return ModSpecs::itEx; break; case MOD_TYPE_XM: return ModSpecs::xmEx; break; case MOD_TYPE_S3M: return ModSpecs::s3mEx; break; case MOD_TYPE_MOD: default: return ModSpecs::mod; break; } } void CSoundFile::SetType(MODTYPE type) { m_nType = type; m_playBehaviour = GetDefaultPlaybackBehaviour(GetBestSaveFormat()); m_pModSpecs = &GetModSpecifications(GetBestSaveFormat()); } #ifdef MODPLUG_TRACKER void CSoundFile::ChangeModTypeTo(const MODTYPE newType, bool adjust) { const MODTYPE oldType = GetType(); m_nType = newType; m_pModSpecs = &GetModSpecifications(m_nType); if(oldType == newType || !adjust) return; SetupMODPanning(); // Setup LRRL panning scheme if needed // Only keep supported play behaviour flags PlayBehaviourSet oldAllowedFlags = GetSupportedPlaybackBehaviour(oldType); PlayBehaviourSet newAllowedFlags = GetSupportedPlaybackBehaviour(newType); PlayBehaviourSet newDefaultFlags = GetDefaultPlaybackBehaviour(newType); for(size_t i = 0; i < m_playBehaviour.size(); i++) { // If a flag is supported in both formats, keep its status if(m_playBehaviour[i]) m_playBehaviour.set(i, newAllowedFlags[i]); // Set allowed flags to their defaults if they were not supported in the old format if(!oldAllowedFlags[i]) m_playBehaviour.set(i, newDefaultFlags[i]); } // Special case for OPL behaviour when converting from S3M to MPTM to retain S3M-like note-off behaviour if(oldType == MOD_TYPE_S3M && newType == MOD_TYPE_MPT && m_opl) m_playBehaviour.reset(kOPLFlexibleNoteOff); Order.OnModTypeChanged(oldType); Patterns.OnModTypeChanged(oldType); m_modFormat.type = GetModSpecifications().GetFileExtension(); } #endif // MODPLUG_TRACKER ModMessageHeuristicOrder CSoundFile::GetMessageHeuristic() const { ModMessageHeuristicOrder result = ModMessageHeuristicOrder::Default; switch(GetType()) { case MOD_TYPE_MPT: result = ModMessageHeuristicOrder::Samples; break; case MOD_TYPE_IT: result = ModMessageHeuristicOrder::Samples; break; case MOD_TYPE_XM: result = ModMessageHeuristicOrder::InstrumentsSamples; break; case MOD_TYPE_MDL: result = ModMessageHeuristicOrder::InstrumentsSamples; break; case MOD_TYPE_IMF: result = ModMessageHeuristicOrder::InstrumentsSamples; break; default: result = ModMessageHeuristicOrder::Default; break; } return result; } bool CSoundFile::SetTitle(const std::string &newTitle) { if(m_songName != newTitle) { m_songName = newTitle; return true; } return false; } double CSoundFile::GetPlaybackTimeAt(ORDERINDEX ord, ROWINDEX row, bool updateVars, bool updateSamplePos) { const GetLengthType t = GetLength(updateVars ? (updateSamplePos ? eAdjustSamplePositions : eAdjust) : eNoAdjust, GetLengthTarget(ord, row)).back(); if(t.targetReached) return t.duration; else return -1; //Given position not found from play sequence. } std::vector CSoundFile::GetAllSubSongs() { std::vector subSongs; for(SEQUENCEINDEX seq = 0; seq < Order.GetNumSequences(); seq++) { const auto subSongsSeq = GetLength(eNoAdjust, GetLengthTarget(true).StartPos(seq, 0, 0)); subSongs.reserve(subSongs.size() + subSongsSeq.size()); for(const auto &song : subSongsSeq) { subSongs.push_back({song.duration, song.startRow, song.endRow, song.restartRow, song.startOrder, song.endOrder, song.restartOrder, seq}); } } return subSongs; } // Calculate the length of a tick, depending on the tempo mode. // This differs from GetTickDuration() by not accumulating errors // because this is not called once per tick but in unrelated // circumstances. So this should not update error accumulation. void CSoundFile::RecalculateSamplesPerTick() { switch(m_nTempoMode) { case TempoMode::Classic: default: m_PlayState.m_nSamplesPerTick = Util::muldiv(m_MixerSettings.gdwMixingFreq, 5 * TEMPO::fractFact, std::max(TEMPO::store_t(1), m_PlayState.m_nMusicTempo.GetRaw() << 1)); break; case TempoMode::Modern: m_PlayState.m_nSamplesPerTick = static_cast((Util::mul32to64_unsigned(m_MixerSettings.gdwMixingFreq, 60 * TEMPO::fractFact) / std::max(uint64(1), Util::mul32to64_unsigned(m_PlayState.m_nMusicSpeed, m_PlayState.m_nCurrentRowsPerBeat) * m_PlayState.m_nMusicTempo.GetRaw()))); break; case TempoMode::Alternative: m_PlayState.m_nSamplesPerTick = Util::muldiv(m_MixerSettings.gdwMixingFreq, TEMPO::fractFact, std::max(TEMPO::store_t(1), m_PlayState.m_nMusicTempo.GetRaw())); break; } #ifndef MODPLUG_TRACKER m_PlayState.m_nSamplesPerTick = Util::muldivr(m_PlayState.m_nSamplesPerTick, m_nTempoFactor, 65536); #endif // !MODPLUG_TRACKER if(!m_PlayState.m_nSamplesPerTick) m_PlayState.m_nSamplesPerTick = 1; } // Get length of a tick in sample, with tick-to-tick tempo correction in modern tempo mode. // This has to be called exactly once per tick because otherwise the error accumulation // goes wrong. uint32 CSoundFile::GetTickDuration(PlayState &playState) const { uint32 retval = 0; switch(m_nTempoMode) { case TempoMode::Classic: default: retval = Util::muldiv(m_MixerSettings.gdwMixingFreq, 5 * TEMPO::fractFact, std::max(TEMPO::store_t(1), playState.m_nMusicTempo.GetRaw() << 1)); break; case TempoMode::Alternative: retval = Util::muldiv(m_MixerSettings.gdwMixingFreq, TEMPO::fractFact, std::max(TEMPO::store_t(1), playState.m_nMusicTempo.GetRaw())); break; case TempoMode::Modern: { double accurateBufferCount = static_cast(m_MixerSettings.gdwMixingFreq) * (60.0 / (playState.m_nMusicTempo.ToDouble() * static_cast(Util::mul32to64_unsigned(playState.m_nMusicSpeed, playState.m_nCurrentRowsPerBeat)))); const TempoSwing &swing = (Patterns.IsValidPat(playState.m_nPattern) && Patterns[playState.m_nPattern].HasTempoSwing()) ? Patterns[playState.m_nPattern].GetTempoSwing() : m_tempoSwing; if(!swing.empty()) { // Apply current row's tempo swing factor TempoSwing::value_type swingFactor = swing[playState.m_nRow % swing.size()]; accurateBufferCount = accurateBufferCount * swingFactor / double(TempoSwing::Unity); } uint32 bufferCount = static_cast(accurateBufferCount); playState.m_dBufferDiff += accurateBufferCount - bufferCount; //tick-to-tick tempo correction: if(playState.m_dBufferDiff >= 1) { bufferCount++; playState.m_dBufferDiff--; } else if(m_PlayState.m_dBufferDiff <= -1) { bufferCount--; playState.m_dBufferDiff++; } MPT_ASSERT(std::abs(playState.m_dBufferDiff) < 1.0); retval = bufferCount; } break; } #ifndef MODPLUG_TRACKER // when the user modifies the tempo, we do not really care about accurate tempo error accumulation retval = Util::muldivr_unsigned(retval, m_nTempoFactor, 65536); #endif // !MODPLUG_TRACKER if(!retval) retval = 1; return retval; } // Get the duration of a row in milliseconds, based on the current rows per beat and given speed and tempo settings. double CSoundFile::GetRowDuration(TEMPO tempo, uint32 speed) const { switch(m_nTempoMode) { case TempoMode::Classic: default: return static_cast(2500 * speed) / tempo.ToDouble(); case TempoMode::Modern: // If there are any row delay effects, the row length factor compensates for those. return 60000.0 / tempo.ToDouble() / static_cast(m_PlayState.m_nCurrentRowsPerBeat); case TempoMode::Alternative: return static_cast(1000 * speed) / tempo.ToDouble(); } } ChannelFlags CSoundFile::GetChannelMuteFlag() { #ifdef MODPLUG_TRACKER return (TrackerSettings::Instance().patternSetup & PatternSetup::SyncMute) ? CHN_SYNCMUTE : CHN_MUTE; #else return CHN_SYNCMUTE; #endif } // Resolve note/instrument combination to real sample index. Return value is guaranteed to be in [0, GetNumSamples()]. SAMPLEINDEX CSoundFile::GetSampleIndex(ModCommand::NOTE note, uint32 instr) const noexcept { SAMPLEINDEX smp = 0; if(GetNumInstruments()) { if(ModCommand::IsNote(note) && instr <= GetNumInstruments() && Instruments[instr] != nullptr) smp = Instruments[instr]->Keyboard[note - NOTE_MIN]; } else { smp = static_cast(instr); } if(smp <= GetNumSamples()) return smp; else return 0; } // Find an unused sample slot. If it is going to be assigned to an instrument, targetInstrument should be specified. // SAMPLEINDEX_INVLAID is returned if no free sample slot could be found. SAMPLEINDEX CSoundFile::GetNextFreeSample(INSTRUMENTINDEX targetInstrument, SAMPLEINDEX start) const { // Find empty slot in two passes - in the first pass, we only search for samples with empty sample names, // in the second pass we check all samples with non-empty sample names. for(int passes = 0; passes < 2; passes++) { for(SAMPLEINDEX i = start; i <= GetModSpecifications().samplesMax; i++) { // Early exit for FM instruments if(Samples[i].uFlags[CHN_ADLIB] && (targetInstrument == INSTRUMENTINDEX_INVALID || !IsSampleReferencedByInstrument(i, targetInstrument))) continue; // When loading into an instrument, ignore non-empty sample names. Else, only use this slot if the sample name is empty or we're in second pass. if((i > GetNumSamples() && passes == 1) || (!Samples[i].HasSampleData() && (!m_szNames[i][0] || passes == 1 || targetInstrument != INSTRUMENTINDEX_INVALID)) || (targetInstrument != INSTRUMENTINDEX_INVALID && IsSampleReferencedByInstrument(i, targetInstrument))) // Not empty, but already used by this instrument. XXX this should only be done when replacing an instrument with a single sample! Otherwise it will use an inconsistent sample map! { // Empty slot, so it's a good candidate already. // In instrument mode, check whether any instrument references this sample slot. If that is the case, we won't use it as it could lead to unwanted conflicts. // If we are loading the sample *into* an instrument, we should also not consider that instrument's sample map, since it might be inconsistent at this time. bool isReferenced = false; for(INSTRUMENTINDEX ins = 1; ins <= GetNumInstruments(); ins++) { if(ins == targetInstrument) { continue; } if(IsSampleReferencedByInstrument(i, ins)) { isReferenced = true; break; } } if(!isReferenced) { return i; } } } } return SAMPLEINDEX_INVALID; } // Find an unused instrument slot. // INSTRUMENTINDEX_INVALID is returned if no free instrument slot could be found. INSTRUMENTINDEX CSoundFile::GetNextFreeInstrument(INSTRUMENTINDEX start) const { for(INSTRUMENTINDEX i = start; i <= GetModSpecifications().instrumentsMax; i++) { if(Instruments[i] == nullptr) { return i; } } return INSTRUMENTINDEX_INVALID; } // Check whether a given sample is used by a given instrument. bool CSoundFile::IsSampleReferencedByInstrument(SAMPLEINDEX sample, INSTRUMENTINDEX instr) const { if(instr < 1 || instr > GetNumInstruments()) return false; const ModInstrument *targetIns = Instruments[instr]; if(targetIns == nullptr) return false; return mpt::contains(mpt::as_span(targetIns->Keyboard).first(NOTE_MAX - NOTE_MIN + 1), sample); } ModInstrument *CSoundFile::AllocateInstrument(INSTRUMENTINDEX instr, SAMPLEINDEX assignedSample) { if(instr == 0 || instr >= MAX_INSTRUMENTS) { return nullptr; } ModInstrument *ins = Instruments[instr]; if(ins != nullptr) { // Re-initialize instrument *ins = ModInstrument(assignedSample); } else { // Create new instrument Instruments[instr] = ins = new (std::nothrow) ModInstrument(assignedSample); } if(ins != nullptr) { m_nInstruments = std::max(m_nInstruments, instr); } return ins; } void CSoundFile::PrecomputeSampleLoops(bool updateChannels) { for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++) { Samples[i].PrecomputeLoops(*this, updateChannels); } } #ifdef MPT_EXTERNAL_SAMPLES // Load external waveform, but keep sample properties like frequency, panning, etc... // Returns true if the file could be loaded. bool CSoundFile::LoadExternalSample(SAMPLEINDEX smp, const mpt::PathString &filename) { bool ok = false; mpt::IO::InputFile f(filename, SettingCacheCompleteFileBeforeLoading()); if(f.IsValid()) { const ModSample origSample = Samples[smp]; mpt::charbuf origName; origName = m_szNames[smp]; FileReader file = GetFileReader(f); ok = ReadSampleFromFile(smp, file, false); if(ok) { // Copy over old attributes, but keep new sample data ModSample &sample = GetSample(smp); SmpLength newLength = sample.nLength; void *newData = sample.samplev(); SampleFlags newFlags = sample.uFlags; sample = origSample; sample.nLength = newLength; sample.pData.pSample = newData; sample.uFlags.set(CHN_16BIT, newFlags[CHN_16BIT]); sample.uFlags.set(CHN_STEREO, newFlags[CHN_STEREO]); sample.uFlags.reset(SMP_MODIFIED); sample.SanitizeLoops(); } m_szNames[smp] = origName; } SetSamplePath(smp, filename); return ok; } #endif // MPT_EXTERNAL_SAMPLES // Set up channel panning suitable for MOD + similar files. If the current mod type is not MOD, forceSetup has to be set to true for this function to take effect. void CSoundFile::SetupMODPanning(bool forceSetup) { // Setup LRRL panning, max channel volume if(!(GetType() & MOD_TYPE_MOD) && !forceSetup) return; for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].dwFlags.reset(CHN_SURROUND); if(m_MixerSettings.MixerFlags & SNDMIX_MAXDEFAULTPAN) ChnSettings[chn].nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 256 : 0; else ChnSettings[chn].nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 0xC0 : 0x40; } } void CSoundFile::PropagateXMAutoVibrato(INSTRUMENTINDEX ins, VibratoType type, uint8 sweep, uint8 depth, uint8 rate) { if(ins > m_nInstruments || Instruments[ins] == nullptr) return; const std::set referencedSamples = Instruments[ins]->GetSamples(); // Propagate changes to all samples that belong to this instrument. for(auto sample : referencedSamples) { if(sample <= m_nSamples) { Samples[sample].nVibDepth = depth; Samples[sample].nVibType = type; Samples[sample].nVibRate = rate; Samples[sample].nVibSweep = sweep; } } } // Normalize the tempo swing coefficients so that they add up to exactly the specified tempo again void TempoSwing::Normalize() { if(empty()) return; uint64 sum = 0; for(auto &i : *this) { Limit(i, Unity / 4u, Unity * 4u); sum += i; } sum /= size(); MPT_ASSERT(sum > 0); // clang-analyzer false-positive int64 remain = Unity * size(); for(auto &i : *this) { i = Util::muldivr_unsigned(i, Unity, static_cast(sum)); remain -= i; } //MPT_ASSERT(static_cast(std::abs(static_cast(remain))) <= size()); at(0) += static_cast(remain); } void TempoSwing::Serialize(std::ostream &oStrm, const TempoSwing &swing) { mpt::IO::WriteIntLE(oStrm, static_cast(swing.size())); for(std::size_t i = 0; i < swing.size(); i++) { mpt::IO::WriteIntLE(oStrm, swing[i]); } } void TempoSwing::Deserialize(std::istream &iStrm, TempoSwing &swing, const size_t) { uint16 numEntries; mpt::IO::ReadIntLE(iStrm, numEntries); swing.resize(numEntries); for(uint16 i = 0; i < numEntries; i++) { mpt::IO::ReadIntLE(iStrm, swing[i]); } swing.Normalize(); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_med.cpp0000644000175000017500000015304315016552743020323 00000000000000/* * Load_med.cpp * ------------ * Purpose: OctaMED / MED Soundstudio module loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #ifdef MPT_WITH_VST #include "../mptrack/Vstplug.h" #include "plugins/PluginManager.h" #endif // MPT_WITH_VST #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_span.hpp" #include "mpt/io/io_stdstream.hpp" #include OPENMPT_NAMESPACE_BEGIN struct MMD0FileHeader { char mmd[3]; // "MMD" for the first song in file, "MCN" for the rest uint8be version; // '0'-'3' uint32be modLength; // Size of file uint32be songOffset; // Position in file for the first song uint16be playerSettings1[2]; // Internal variables for the play routine uint32be blockArrOffset; // Position in file for blocks (patterns) uint8be flags; uint8be reserved1[3]; uint32be sampleArrOffset; // Position in file for samples (should be identical between songs) uint32be reserved2; uint32be expDataOffset; // Absolute offset in file for ExpData (0 if not present) uint32be reserved3; char playerSettings2[11]; // Internal variables for the play routine uint8be extraSongs; // Number of songs - 1 }; MPT_BINARY_STRUCT(MMD0FileHeader, 52) struct MMD0Sample { uint16be loopStart; uint16be loopLength; uint8be midiChannel; uint8be midiPreset; uint8be sampleVolume; int8be sampleTranspose; }; MPT_BINARY_STRUCT(MMD0Sample, 8) // Song header for MMD0/MMD1 struct MMD0Song { uint8be sequence[256]; }; MPT_BINARY_STRUCT(MMD0Song, 256) // Song header for MMD2/MMD3 struct MMD2Song { enum Flags3 { FLAG3_STEREO = 0x01, // Mixing in stereo FLAG3_FREEPAN = 0x02, // Mixing flag: free pan }; uint32be playSeqTableOffset; uint32be sectionTableOffset; uint32be trackVolsOffset; uint16be numTracks; uint16be numPlaySeqs; uint32be trackPanOffset; // 0: all centered (according to docs, MED Soundstudio uses Amiga hard-panning instead) uint32be flags3; uint16be volAdjust; // Volume adjust (%) uint16be mixChannels; // Mixing channels, 0 means 4 uint8 mixEchoType; // 0 = nothing, 1 = normal, 2 = cross uint8 mixEchoDepth; // 1 - 6, 0 = default uint16be mixEchoLength; // Echo length in milliseconds int8 mixStereoSep; // Stereo separation char pad0[223]; }; MPT_BINARY_STRUCT(MMD2Song, 256) // Common song header struct MMDSong { enum Flags { FLAG_FILTERON = 0x01, // The hardware audio filter is on FLAG_JUMPINGON = 0x02, // Mouse pointer jumping on FLAG_JUMP8TH = 0x04, // Jump every 8th line (not in OctaMED Pro) FLAG_INSTRSATT = 0x08, // sng+samples indicator (not useful in MMDs) FLAG_VOLHEX = 0x10, // volumes are HEX FLAG_STSLIDE = 0x20, // use ST/NT/PT compatible sliding FLAG_8CHANNEL = 0x40, // this is OctaMED 5-8 channel song FLAG_SLOWHQ = 0x80, // HQ V2-4 compatibility mode }; enum Flags2 { FLAG2_BMASK = 0x1F, // (bits 0-4) BPM beat length (in lines) FLAG2_BPM = 0x20, // BPM mode on FLAG2_MIX = 0x80, // Module uses mixing }; uint16be numBlocks; // Number of blocks in current song uint16be songLength; // MMD0: Number of sequence numbers in the play sequence list, MMD2: Number of sections char song[256]; MMD0Song GetMMD0Song() const { static_assert(sizeof(MMD0Song) == sizeof(song)); return mpt::bit_cast(song); } MMD2Song GetMMD2Song() const { static_assert(sizeof(MMD2Song) == sizeof(song)); return mpt::bit_cast(song); } uint16be defaultTempo; int8be playTranspose; // The global play transpose value for current song uint8be flags; uint8be flags2; uint8be tempo2; // Timing pulses per line (ticks) uint8be trackVol[16]; // 1...64 in MMD0/MMD1, reserved in MMD2 uint8be masterVol; // 1...64 uint8be numSamples; }; MPT_BINARY_STRUCT(MMDSong, 284) struct MMD2PlaySeq { char name[32]; uint32be commandTableOffset; uint32be reserved; uint16be length; // Number of entries }; MPT_BINARY_STRUCT(MMD2PlaySeq, 42) struct MMD0PatternHeader { uint8be numTracks; uint8be numRows; }; MPT_BINARY_STRUCT(MMD0PatternHeader, 2) struct MMD1PatternHeader { uint16be numTracks; uint16be numRows; uint32be blockInfoOffset; }; MPT_BINARY_STRUCT(MMD1PatternHeader, 8) struct MMDPlaySeqCommand { enum Command { kStop = 1, kJump = 2, }; uint16be offset; // Offset within current play sequence, 0xFFFF = end of list uint8be command; // Stop = 1, Jump = 2 uint8be extraSize; }; MPT_BINARY_STRUCT(MMDPlaySeqCommand, 4) struct MMDBlockInfo { uint32be highlightMaskOffset; uint32be nameOffset; uint32be nameLength; uint32be pageTableOffset; // File offset of command page table uint32be cmdExtTableOffset; // File offset of command extension table (second parameter) uint32be reserved[4]; }; MPT_BINARY_STRUCT(MMDBlockInfo, 36) struct MMDInstrHeader { enum Types { VSTI = -4, HIGHLIFE = -3, HYBRID = -2, SYNTHETIC = -1, SAMPLE = 0, // an ordinary 1-octave sample (or MIDI) IFF5OCT = 1, // 5 octaves IFF3OCT = 2, // 3 octaves // The following ones are recognized by OctaMED Pro only IFF2OCT = 3, // 2 octaves IFF4OCT = 4, // 4 octaves IFF6OCT = 5, // 6 octaves IFF7OCT = 6, // 7 octaves // OctaMED Pro V5 + later EXTSAMPLE = 7, // two extra-low octaves TYPEMASK = 0x0F, S_16 = 0x10, STEREO = 0x20, DELTA = 0x40, PACKED = 0x80, // MMDPackedSampleHeader follows OBSOLETE_MD16 = 0x18, }; uint32be length; int16be type; }; MPT_BINARY_STRUCT(MMDInstrHeader, 6) struct MMDPackedSampleHeader { uint16be packType; // Only 1 = ADPCM is supported uint16be subType; // Packing subtype // ADPCM subtype // 1: g723_40 // 2: g721 // 3: g723_24 uint8be commonFlags; // flags common to all packtypes (none defined so far) uint8be packerFlags; // flags for the specific packtype uint32be leftChLen; // packed length of left channel in bytes uint32be rightChLen; // packed length of right channel in bytes (ONLY PRESENT IN STEREO SAMPLES) }; MPT_BINARY_STRUCT(MMDPackedSampleHeader, 14) struct MMDSynthInstr { uint8 defaultDecay; // Not used in modules char reserved[3]; uint16be loopStart; // Only for hybrid uint16be loopLength; uint16be volTableLen; uint16be waveTableLen; uint8 volSpeed; uint8 waveSpeed; uint16be numWaveforms; std::array volTable; std::array waveTable; bool IsValid() const { return volTableLen <= 128 && waveTableLen <= 128 && (numWaveforms <= 64 || numWaveforms == 0xFFFF); } }; MPT_BINARY_STRUCT(MMDSynthInstr, 272) struct MMDInstrExt { enum { SSFLG_LOOP = 0x01, // Loop On / Off SSFLG_EXTPSET = 0x02, // Ext.Preset SSFLG_DISABLED = 0x04, // Disabled SSFLG_PINGPONG = 0x08, // Ping-pong looping }; uint8be hold; // 0...127 uint8be decay; // 0...127 uint8be suppressMidiOff; int8be finetune; // Below fields saved by >= V5 uint8be defaultPitch; uint8be instrFlags; uint16be longMidiPreset; // Legacy MIDI program mode that doesn't use banks but a combination of two program change commands // Below fields saved by >= V5.02 uint8be outputDevice; uint8be reserved; // Below fields saved by >= V7 uint32be loopStart; uint32be loopLength; // Not sure which version starts saving those but they are saved by MED Soundstudio for Windows uint8 volume; // 0...127 uint8 outputPort; // Index into user-configurable device list (NOT WinAPI port index) uint16le midiBank; }; MPT_BINARY_STRUCT(MMDInstrExt, 22) struct MMDInstrInfo { char name[40]; }; MPT_BINARY_STRUCT(MMDInstrInfo, 40) struct MMD0Exp { uint32be nextModOffset; uint32be instrExtOffset; uint16be instrExtEntries; uint16be instrExtEntrySize; uint32be annoText; uint32be annoLength; uint32be instrInfoOffset; uint16be instrInfoEntries; uint16be instrInfoEntrySize; uint32be jumpMask; uint32be rgbTable; uint8be channelSplit[4]; uint32be notationInfoOffset; uint32be songNameOffset; uint32be songNameLength; uint32be midiDumpOffset; uint32be mmdInfoOffset; uint32be arexxOffset; uint32be midiCmd3xOffset; uint32be trackInfoOffset; // Pointer to song->numtracks pointers to tag lists uint32be effectInfoOffset; // Pointers to group pointers uint32be tagEnd; }; MPT_BINARY_STRUCT(MMD0Exp, 80) struct MMDTag { enum TagType { // Generic MMD tags MMDTAG_END = 0x00000000, MMDTAG_PTR = 0x80000000, // Data needs relocation MMDTAG_MUSTKNOW = 0x40000000, // Loader must fail if this isn't recognized MMDTAG_MUSTWARN = 0x20000000, // Loader must warn if this isn't recognized MMDTAG_MASK = 0x1FFFFFFF, // ExpData tags // # of effect groups, including the global group (will override settings in MMDSong struct), default = 1 MMDTAG_EXP_NUMFXGROUPS = 1, MMDTAG_TRK_FXGROUP = 3, MMDTAG_TRK_NAME = 1, // trackinfo tags MMDTAG_TRK_NAMELEN = 2, // namelen includes zero term. // effectinfo tags MMDTAG_FX_ECHOTYPE = 1, MMDTAG_FX_ECHOLEN = 2, MMDTAG_FX_ECHODEPTH = 3, MMDTAG_FX_STEREOSEP = 4, MMDTAG_FX_GROUPNAME = 5, // the Global Effects group shouldn't have name saved! MMDTAG_FX_GRPNAMELEN = 6, // namelen includes zero term. }; uint32be type; uint32be data; }; MPT_BINARY_STRUCT(MMDTag, 8) struct MMDDump { uint32be length; uint32be dataPointer; uint16be extLength; // If >= 20: name follows as char[20] }; MPT_BINARY_STRUCT(MMDDump, 10) static TEMPO MMDTempoToBPM(uint32 tempo, bool is8Ch, bool softwareMixing, bool bpmMode, uint8 rowsPerBeat) { if(bpmMode && !is8Ch) { // Observed in OctaMED 5 and MED SoundStudio 1.03 (bug?) if(tempo < 7) return TEMPO(111.5); // You would have thought that we could use modern tempo mode here. // Alas, the number of ticks per row still influences the tempo. :( return TEMPO((tempo * rowsPerBeat) / 4.0); } if(is8Ch && tempo > 0) { LimitMax(tempo, 10u); // MED Soundstudio uses these tempos when importing old files static constexpr uint8 tempos[10] = {179, 164, 152, 141, 131, 123, 116, 110, 104, 99}; return TEMPO(tempos[tempo - 1], 0); } else if(!softwareMixing && tempo > 0 && tempo <= 10) { // SoundTracker compatible tempo return TEMPO((6.0 * 1773447.0 / 14500.0) / tempo); } else if(softwareMixing && tempo < 8) { // Observed in MED SoundStudio 1.03 with 1-64ch mixing mode and SPD tempo mode (bug?) return TEMPO(157.86); } return TEMPO(tempo / 0.264); } struct TranslateMEDPatternContext { const int16 transpose; const CHANNELINDEX numTracks; const uint8 version; const uint8 rowsPerBeat; const bool is8Ch : 1; const bool softwareMixing : 1; const bool bpmMode : 1; const bool volHex : 1; const bool vol7bit : 1; }; static std::pair ConvertMEDEffect(ModCommand &m, const uint8 command, const uint8 param, const uint8 param2, const TranslateMEDPatternContext ctx) { const uint8 nibbleLo = std::min(param, uint8(0x0F)); switch(command) { case 0x01: // Portamento Up (avoid effect memory when importing as XM) if(param) m.SetEffectCommand(CMD_PORTAMENTOUP, param); break; case 0x02: // Portamento Down (avoid effect memory when importing as XM) if(param) m.SetEffectCommand(CMD_PORTAMENTODOWN, param); break; case 0x04: // Vibrato (twice as deep as in ProTracker) m.SetEffectCommand(CMD_VIBRATO, (param & 0xF0) | std::min((param & 0x0F) * 2, 0x0F)); break; case 0x05: // Tone Porta + Volume Slide (avoid effect memory when importing as XM) if(param) m.SetEffectCommand(CMD_TONEPORTAVOL, param); else m.SetEffectCommand(CMD_TONEPORTAMENTO, 0); break; case 0x06: // Vibrato + Volume Slide (avoid effect memory when importing as XM) if(param) m.SetEffectCommand(CMD_VIBRATOVOL, param); else m.SetEffectCommand(CMD_VIBRATO, 0); break; case 0x08: // Hold and decay break; case 0x09: // Set secondary speed if(param > 0 && param <= 0x20) m.SetEffectCommand(CMD_SPEED, param); break; case 0x0C: // Set Volume (note: parameters >= 0x80 (only in hex mode?) should set the default instrument volume, which we don't support) if(!ctx.volHex && param < 0x99) m.SetEffectCommand(CMD_VOLUME, static_cast((param >> 4) * 10 + (param & 0x0F))); else if(ctx.volHex && !ctx.vol7bit) m.SetEffectCommand(CMD_VOLUME, static_cast(std::min(param & 0x7F, 64))); else if(ctx.volHex) m.SetEffectCommand(CMD_VOLUME, static_cast(((param & 0x7F) + 1) / 2)); break; case 0x0D: if(param) m.SetEffectCommand(CMD_VOLUMESLIDE, param); break; case 0x0E: // Synth jump / MIDI panning m.SetEffectCommand(CMD_MED_SYNTH_JUMP, param); break; case 0x0F: // Misc if(param == 0) { m.SetEffectCommand(CMD_PATTERNBREAK, param); } else if(param <= 0xF0) { m.command = CMD_TEMPO; if(param < 0x03) { // This appears to be a bug in OctaMED which is not emulated in MED Soundstudio on Windows. m.param = 0x70; } else { uint16 tempo = mpt::saturate_round(MMDTempoToBPM(param, ctx.is8Ch, ctx.softwareMixing, ctx.bpmMode, ctx.rowsPerBeat).ToDouble()); if(tempo <= Util::MaxValueOfType(m.param)) { m.param = static_cast(tempo); } else { m.param = static_cast(tempo >> 8); return {CMD_XPARAM, static_cast(tempo & 0xFF)}; } } } else switch(param) { case 0xF1: // Play note twice m.SetEffectCommand(CMD_MODCMDEX, 0x93); break; case 0xF2: // Delay note m.SetEffectCommand(CMD_MODCMDEX, 0xD3); break; case 0xF3: // Play note three times m.SetEffectCommand(CMD_MODCMDEX, 0x92); break; case 0xF8: // Turn filter off case 0xF9: // Turn filter on m.SetEffectCommand(CMD_MODCMDEX, 0xF9 - param); break; case 0xFD: // Set pitch m.SetEffectCommand(CMD_TONEPORTA_DURATION, 0); break; case 0xFA: // MIDI pedal on case 0xFB: // MIDI pedal off case 0xFE: // End of song break; case 0xFF: // Turn note off if(!m.IsNote()) m.note = NOTE_NOTECUT; break; } break; case 0x10: // MIDI message m.SetEffectCommand(CMD_MIDI, 0x80 | param); break; case 0x11: // Slide pitch up m.SetEffectCommand(CMD_MODCMDEX, 0x10 | nibbleLo); break; case 0x12: // Slide pitch down m.SetEffectCommand(CMD_MODCMDEX, 0x20 | nibbleLo); break; case 0x14: // Vibrato (ProTracker compatible depth, but faster) m.SetEffectCommand(CMD_VIBRATO, param); break; case 0x15: // Set finetune m.SetEffectCommand(CMD_MODCMDEX, 0x50 | (param & 0x0F)); break; case 0x16: // Loop m.SetEffectCommand(CMD_MODCMDEX, 0x60 | nibbleLo); break; case 0x18: // Stop note m.SetEffectCommand(CMD_MODCMDEX, 0xC0 | nibbleLo); break; case 0x19: // Sample Offset m.SetEffectCommand(CMD_OFFSET, param); break; case 0x1A: // Slide volume up once m.SetEffectCommand(CMD_MODCMDEX, 0xA0 | nibbleLo); break; case 0x1B: // Slide volume down once m.SetEffectCommand(CMD_MODCMDEX, 0xB0 | nibbleLo); break; case 0x1C: // MIDI program if(param > 0 && param <= 128) m.SetEffectCommand(CMD_MIDI, param - 1); break; case 0x1D: // Pattern break (in hex) m.SetEffectCommand(CMD_PATTERNBREAK, param); break; case 0x1E: // Repeat row m.SetEffectCommand(CMD_MODCMDEX, 0xE0 | std::min(param, 0x0F)); break; case 0x1F: // Note delay and retrigger { if(param & 0xF0) m.SetEffectCommand(CMD_MODCMDEX, 0xD0 | (param >> 4)); else if(param & 0x0F) m.SetEffectCommand(CMD_MODCMDEX, 0x90 | param); break; } case 0x20: // Reverse sample + skip samples if(param == 0 && param2 == 0) { if(m.IsNote()) { m.SetEffectCommand(CMD_XFINEPORTAUPDOWN, 0x9F); } } else { // Skip given number of samples } break; case 0x29: // Relative sample offset if(param2 > 0) m.SetEffectCommand(CMD_OFFSETPERCENTAGE, mpt::saturate_cast(Util::muldiv_unsigned(param, 0x100, param2))); break; case 0x2E: // Set panning if(param <= 0x10 || param >= 0xF0) m.SetEffectCommand(CMD_PANNING8, mpt::saturate_cast(((param ^ 0x80) - 0x70) * 8)); break; default: if((command > 0 || param) && command < 0x10) CSoundFile::ConvertModCommand(m, command, param); break; } return std::make_pair(CMD_NONE, ModCommand::PARAM(0)); } static bool TranslateMEDPattern(FileReader &file, FileReader &cmdExt, CPattern &pattern, const TranslateMEDPatternContext ctx, const bool isExtraPage) { bool needInstruments = false; for(ROWINDEX row = 0; row < pattern.GetNumRows(); row++) { ModCommand *m = pattern.GetpModCommand(row, 0); for(CHANNELINDEX chn = 0; chn < ctx.numTracks; chn++, m++) { auto oldCmd = std::make_pair(m->command, m->param); int note = NOTE_NONE; uint8 cmd = 0, param1 = 0, param2 = 0; if(ctx.version < 1) { const auto [noteInstr, instrCmd, param] = file.ReadArray(); if(noteInstr & 0x3F) note = (noteInstr & 0x3F) + ctx.transpose; m->instr = (instrCmd >> 4) | ((noteInstr & 0x80) >> 3) | ((noteInstr & 0x40) >> 1); cmd = instrCmd & 0x0F; param1 = param; } else if(isExtraPage) { const auto [command, param] = file.ReadArray(); param2 = cmdExt.ReadUint8(); cmd = command; param1 = param; } else { const auto [noteVal, instr, command, param] = file.ReadArray(); param2 = cmdExt.ReadUint8(); if(noteVal & 0x7F) note = (noteVal & 0x7F) + ctx.transpose; else if(noteVal == 0x80) m->note = NOTE_NOTECUT; if(instr & 0x3F) m->instr = instr & 0x3F; cmd = command; param1 = param; } // Octave wrapping for 4-channel modules if(note >= NOTE_MIDDLEC + 2 * 12) needInstruments = true; // This doesn't happen in MED SoundStudio for Windows... closest we have to be able to identify it is the usage of 7-bit volume if(note > NOTE_MIN + 131 && !ctx.vol7bit) note -= 108; else if(note > NOTE_MAX) note -= mpt::align_down(note - (NOTE_MAX - 11), 12); if(note >= NOTE_MIN) m->note = static_cast(note); if(!cmd && !param1) continue; const auto extraCmd = ConvertMEDEffect(*m, cmd, param1, param2, ctx); if(oldCmd.first != CMD_NONE && m->command != oldCmd.first) { if(!ModCommand::CombineEffects(m->command, m->param, oldCmd.first, oldCmd.second) && m->volcmd == VOLCMD_NONE) m->FillInTwoCommands(m->command, m->param, oldCmd.first, oldCmd.second, true); // Reset X-Param to 8-bit value if this cell was overwritten with a "useful" effect if(row > 0 && oldCmd.first == CMD_XPARAM && m->command != CMD_XPARAM) pattern.GetpModCommand(row - 1, chn)->param = Util::MaxValueOfType(m->param); } if(extraCmd.first != CMD_NONE) { if(row < (pattern.GetNumRows() - 1)) pattern.GetpModCommand(row + 1, chn)->SetEffectCommand(extraCmd); else m->param = Util::MaxValueOfType(m->param); // No space :( } } } return needInstruments; } static void TranslateMEDSynthScript(std::array &arr, size_t numEntries, uint8 speed, uint8 hold, uint8 decay, InstrumentSynth::Events &events, bool isVolume) { events.push_back(InstrumentSynth::Event::SetStepSpeed(speed, true)); if(hold && isVolume) events.push_back(InstrumentSynth::Event::MED_HoldDecay(hold, decay)); std::map entryFromByte; FileReader chunk{mpt::as_span(arr).subspan(0, std::min(arr.size(), numEntries))}; while(chunk.CanRead(1)) { const uint16 scriptPos = static_cast(chunk.GetPosition()); entryFromByte[scriptPos] = static_cast(events.size()); events.push_back(InstrumentSynth::Event::JumpMarker(scriptPos)); uint8 b = chunk.ReadUint8(); switch(b) { case 0xFF: // END - End sequence case 0xFB: // HLT - Halt events.push_back(InstrumentSynth::Event::StopScript()); break; case 0xFE: // JMP - Jump events.push_back(InstrumentSynth::Event::Jump(chunk.ReadUint8())); break; case 0xFD: // ARE - End arpeggio definition break; case 0xFC: // ARP - Begin arpeggio definition { size_t firstEvent = events.size(); uint8 arpSize = 0; while(chunk.CanRead(1)) { b = chunk.ReadUint8(); if(b >= 0x80) break; events.push_back(InstrumentSynth::Event::MED_DefineArpeggio(b, 0)); arpSize++; } if(arpSize) events[firstEvent].u16 = arpSize; } break; case 0xFA: // JWV / JWS - Jump waveform / volume sequence events.push_back(InstrumentSynth::Event::MED_JumpScript(isVolume ? 1 : 0, chunk.ReadUint8())); break; case 0xF7: // - / VWF - Set vibrato waveform if(!isVolume) events.push_back(InstrumentSynth::Event::MED_SetEnvelope(chunk.ReadUint8(), true, false)); break; case 0xF6: // EST / RES - ? / reset pitch if(!isVolume) events.push_back(InstrumentSynth::Event::Puma_PitchRamp(0, 0, 0)); break; case 0xF5: // EN2 / VBS - Looping envelope / set vibrato speed if(isVolume) events.push_back(InstrumentSynth::Event::MED_SetEnvelope(chunk.ReadUint8(), true, true)); else events.push_back(InstrumentSynth::Event::MED_SetVibratoSpeed(chunk.ReadUint8())); break; case 0xF4: // EN1 - VBD - One shot envelope / set vibrato depth if(isVolume) events.push_back(InstrumentSynth::Event::MED_SetEnvelope(chunk.ReadUint8(), false, true)); else events.push_back(InstrumentSynth::Event::MED_SetVibratoDepth(chunk.ReadUint8())); break; case 0xF3: // CHU - Change volume / pitch up speed if(isVolume) events.push_back(InstrumentSynth::Event::MED_SetVolumeStep(chunk.ReadUint8())); else events.push_back(InstrumentSynth::Event::MED_SetPeriodStep(chunk.ReadUint8())); break; case 0xF2: // CHD - Change volume / pitch down speed if(isVolume) events.push_back(InstrumentSynth::Event::MED_SetVolumeStep(-static_cast(chunk.ReadUint8()))); else events.push_back(InstrumentSynth::Event::MED_SetPeriodStep(-static_cast(chunk.ReadUint8()))); break; case 0xF1: // WAI - Wait events.push_back(InstrumentSynth::Event::Delay(std::max(chunk.ReadUint8(), uint8(1)) - 1)); break; case 0xF0: // SPD - Set Speed events.push_back(InstrumentSynth::Event::SetStepSpeed(chunk.ReadUint8(), false)); break; default: if(isVolume && b <= 64) events.push_back(InstrumentSynth::Event::MED_SetVolume(b)); else if(!isVolume) events.push_back(InstrumentSynth::Event::MED_SetWaveform(b)); break; } } for(auto &event : events) { event.FixupJumpTarget(entryFromByte); } } #ifdef MPT_WITH_VST static std::wstring ReadMEDStringUTF16BE(FileReader &file) { FileReader chunk = file.ReadChunk(file.ReadUint32BE()); std::wstring s(chunk.GetLength() / 2u, L'\0'); for(auto &c : s) { c = chunk.ReadUint16BE(); } return s; } #endif // MPT_WITH_VST static void MEDReadNextSong(FileReader &file, MMD0FileHeader &fileHeader, MMD0Exp &expData, MMDSong &songHeader) { file.ReadStruct(fileHeader); file.Seek(fileHeader.songOffset + 63 * sizeof(MMD0Sample)); file.ReadStruct(songHeader); if(fileHeader.expDataOffset && file.Seek(fileHeader.expDataOffset)) file.ReadStruct(expData); else expData = {}; } static std::pair MEDScanNumChannels(FileReader &file, const uint8 version) { MMD0FileHeader fileHeader; MMD0Exp expData; MMDSong songHeader; file.Rewind(); uint32 songOffset = 0; MEDReadNextSong(file, fileHeader, expData, songHeader); SEQUENCEINDEX numSongs = std::min(MAX_SEQUENCES, mpt::saturate_cast(fileHeader.expDataOffset ? fileHeader.extraSongs + 1 : 1)); CHANNELINDEX numChannels = 4; // Scan patterns for max number of channels for(SEQUENCEINDEX song = 0; song < numSongs; song++) { const PATTERNINDEX numPatterns = songHeader.numBlocks; if(songHeader.numSamples > 63 || numPatterns > 0x7FFF) return {}; for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { if(!file.Seek(fileHeader.blockArrOffset + pat * 4u) || !file.Seek(file.ReadUint32BE())) { continue; } numChannels = std::max(numChannels, static_cast(version < 1 ? file.ReadUint8() : file.ReadUint16BE())); } // If song offsets are going backwards, reject the file if(expData.nextModOffset <= songOffset || !file.Seek(expData.nextModOffset)) { numSongs = song + 1; break; } songOffset = expData.nextModOffset; MEDReadNextSong(file, fileHeader, expData, songHeader); } return {numChannels, numSongs}; } static bool ValidateHeader(const MMD0FileHeader &fileHeader) { if(std::memcmp(fileHeader.mmd, "MMD", 3) || fileHeader.version < '0' || fileHeader.version > '3' || fileHeader.songOffset < sizeof(MMD0FileHeader) || fileHeader.songOffset > uint32_max - 63 * sizeof(MMD0Sample) - sizeof(MMDSong) || fileHeader.blockArrOffset < sizeof(MMD0FileHeader) || (fileHeader.sampleArrOffset > 0 && fileHeader.sampleArrOffset < sizeof(MMD0FileHeader)) || fileHeader.expDataOffset > uint32_max - sizeof(MMD0Exp)) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const MMD0FileHeader &fileHeader) { return std::max({ fileHeader.songOffset + 63 * sizeof(MMD0Sample) + sizeof(MMDSong), fileHeader.blockArrOffset, fileHeader.sampleArrOffset ? fileHeader.sampleArrOffset : sizeof(MMD0FileHeader), fileHeader.expDataOffset + sizeof(MMD0Exp) }) - sizeof(MMD0FileHeader); } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize) { MMD0FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!ValidateHeader(fileHeader)) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); MMD0FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return false; if(!ValidateHeader(fileHeader)) return false; if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) return false; if(loadFlags == onlyVerifyHeader) return true; file.Seek(fileHeader.songOffset); FileReader sampleHeaderChunk = file.ReadChunk(63 * sizeof(MMD0Sample)); MMDSong songHeader; file.ReadStruct(songHeader); if(songHeader.numSamples > 63 || songHeader.numBlocks > 0x7FFF) return false; const uint8 version = fileHeader.version - '0'; const auto [numChannels, numSongs] = MEDScanNumChannels(file, version); if(numChannels < 1 || numChannels > MAX_BASECHANNELS) return false; InitializeGlobals(MOD_TYPE_MED, numChannels); // Start with the instruments, as those are shared between songs std::vector instrOffsets; if(fileHeader.sampleArrOffset) { file.Seek(fileHeader.sampleArrOffset); file.ReadVector(instrOffsets, songHeader.numSamples); } else if(songHeader.numSamples > 0) { return false; } m_nInstruments = m_nSamples = songHeader.numSamples; MMD0Exp expData{}; if(fileHeader.expDataOffset && file.Seek(fileHeader.expDataOffset)) { file.ReadStruct(expData); } FileReader expDataChunk; if(expData.instrExtOffset != 0 && file.Seek(expData.instrExtOffset)) { const uint16 entries = std::min(expData.instrExtEntries, songHeader.numSamples); expDataChunk = file.ReadChunk(expData.instrExtEntrySize * entries); } FileReader instrInfoChunk; if(expData.instrInfoOffset != 0 && file.Seek(expData.instrInfoOffset)) { const uint16 entries = std::min(expData.instrInfoEntries, songHeader.numSamples); instrInfoChunk = file.ReadChunk(expData.instrInfoEntrySize * entries); } // In MMD0 / MMD1, octave wrapping is not done for synth instruments // - It's required e.g. for automatic terminated to.mmd0 and you got to let the music.mmd1 // - starkelsesirap.mmd0 (synth instruments) on the other hand don't need it // In MMD2 / MMD3, the mix flag is used instead. const bool hardwareMixSamples = (version < 2) || (version >= 2 && !(songHeader.flags2 & MMDSong::FLAG2_MIX)); m_nMinPeriod = hardwareMixSamples ? (113 * 4) : (55 * 4); bool needInstruments = false; #ifndef NO_PLUGINS PLUGINDEX numPlugins = 0; #endif // !NO_PLUGINS for(SAMPLEINDEX ins = 1, smp = 1; ins <= m_nInstruments; ins++) { if(!AllocateInstrument(ins, smp)) return false; ModInstrument &instr = *Instruments[ins]; MMDInstrExt instrExt{}; expDataChunk.ReadStructPartial(instrExt, expData.instrExtEntrySize); MMDInstrHeader instrHeader{}; FileReader sampleChunk; if(instrOffsets[ins - 1] != 0 && file.Seek(instrOffsets[ins - 1])) { file.ReadStruct(instrHeader); uint32 chunkLength = instrHeader.length; if(instrHeader.type > 0 && (instrHeader.type & MMDInstrHeader::STEREO)) chunkLength *= 2u; sampleChunk = file.ReadChunk(chunkLength); } std::vector waveformOffsets; // For synth instruments const bool isSynth = instrHeader.type < 0; const size_t maskedType = static_cast(instrHeader.type & MMDInstrHeader::TYPEMASK); #ifdef MPT_WITH_VST if(instrHeader.type == MMDInstrHeader::VSTI) { needInstruments = true; sampleChunk.Skip(6); // 00 00 const std::wstring type = ReadMEDStringUTF16BE(sampleChunk); const std::wstring name = ReadMEDStringUTF16BE(sampleChunk); if(type == L"VST") { auto &mixPlug = m_MixPlugins[numPlugins]; mpt::reconstruct(mixPlug); mixPlug.Info.dwPluginId1 = Vst::kEffectMagic; mixPlug.Info.gain = 10; mixPlug.Info.szName = mpt::ToCharset(mpt::Charset::Locale, name); mixPlug.Info.szLibraryName = mpt::ToCharset(mpt::Charset::UTF8, name); instr.nMixPlug = numPlugins + 1; instr.nMidiChannel = MidiFirstChannel; instr.Transpose(-24); instr.AssignSample(0); // TODO: Figure out patch and routing data numPlugins++; } } else #endif // MPT_WITH_VST if(instrHeader.type == MMDInstrHeader::SYNTHETIC || instrHeader.type == MMDInstrHeader::HYBRID) { needInstruments = true; MMDSynthInstr synthInstr; sampleChunk.ReadStruct(synthInstr); if(!synthInstr.IsValid()) return false; if(instrHeader.type == MMDInstrHeader::SYNTHETIC) instr.filename = "Synth"; else instr.filename = "Hybrid"; instr.AssignSample(smp); if(instrHeader.type == MMDInstrHeader::SYNTHETIC && version <= 2) instr.Transpose(-24); instr.synth.m_scripts.resize(2); TranslateMEDSynthScript(synthInstr.volTable, synthInstr.volTableLen, synthInstr.volSpeed, instrExt.hold, instrExt.decay, instr.synth.m_scripts[0], true); TranslateMEDSynthScript(synthInstr.waveTable, synthInstr.waveTableLen, synthInstr.waveSpeed, instrExt.hold, instrExt.decay, instr.synth.m_scripts[1], false); if(synthInstr.numWaveforms <= 64) file.ReadVector(waveformOffsets, synthInstr.numWaveforms); } else if(isSynth) { instr.AssignSample(0); } MMD0Sample sampleHeader; sampleHeaderChunk.ReadStruct(sampleHeader); int8 sampleTranspose = sampleHeader.sampleTranspose; uint8 numSamples = std::max(uint8(1), static_cast(waveformOffsets.size())); static constexpr uint8 SamplesPerType[] = {1, 5, 3, 2, 4, 6, 7}; if(!isSynth && maskedType < std::size(SamplesPerType)) numSamples = SamplesPerType[maskedType]; if(numSamples > 1) { if(!CanAddMoreSamples(numSamples - 1)) continue; m_nSamples += static_cast(numSamples - 1); needInstruments = true; static constexpr uint8 OctSampleMap[][8] = { {1, 1, 0, 0, 0, 0, 0, 0}, // 2 {2, 2, 1, 1, 0, 0, 0, 0}, // 3 {3, 3, 2, 2, 1, 0, 0, 0}, // 4 {4, 3, 2, 1, 1, 0, 0, 0}, // 5 {5, 4, 3, 2, 1, 0, 0, 0}, // 6 {6, 5, 4, 3, 2, 1, 0, 0}, // 7 }; static constexpr int8 OctTransposeMap[][8] = { { 0, 0, -12, -12, -24, -36, -48, -60}, // 2 { 0, 0, -12, -12, -24, -36, -48, -60}, // 3 { 0, 0, -12, -12, -24, -36, -48, -60}, // 4 {12, 0, -12, -24, -24, -36, -48, -60}, // 5 {12, 0, -12, -24, -36, -48, -48, -60}, // 6 {12, 0, -12, -24, -36, -48, -60, -72}, // 7 }; // TODO: Move octaves so that they align better (C-4 = lowest, we don't have access to the highest four octaves) if(!isSynth) { for(int i = 0; i < static_cast(instr.Keyboard.size()); i++) { int note = i + sampleTranspose; if(note < 0) note = -note % 12; int octave = std::clamp(note / 12 - 4, 0, static_cast(std::size(OctTransposeMap[0]) - 1)); instr.Keyboard[i] = smp + OctSampleMap[numSamples - 2][octave]; instr.NoteMap[i] = static_cast(NOTE_MIN + note + OctTransposeMap[numSamples - 2][octave]); } sampleTranspose = 0; } } else if(maskedType == MMDInstrHeader::EXTSAMPLE) { needInstruments = true; instr.Transpose(-24); } // midiChannel = 0xFF == midi instrument but with invalid channel, midiChannel = 0x00 == sample-based instrument? if(sampleHeader.midiChannel > 0 && sampleHeader.midiChannel <= 16) { instr.nMidiChannel = sampleHeader.midiChannel - 1 + MidiFirstChannel; needInstruments = true; #ifdef MPT_WITH_VST if(!isSynth) { auto &mixPlug = m_MixPlugins[numPlugins]; mpt::reconstruct(mixPlug); mixPlug.Info.dwPluginId1 = PLUGMAGIC('V', 's', 't', 'P'); mixPlug.Info.dwPluginId2 = PLUGMAGIC('M', 'M', 'I', 'D'); mixPlug.Info.gain = 10; mixPlug.Info.szName = "MIDI Input Output"; mixPlug.Info.szLibraryName = "MIDI Input Output"; instr.nMixPlug = numPlugins + 1; instr.Transpose(-24); numPlugins++; } #endif // MPT_WITH_VST } if(sampleHeader.midiPreset > 0 && sampleHeader.midiPreset <= 128) { instr.nMidiProgram = sampleHeader.midiPreset; } if(instr.nMidiChannel == MidiNoChannel) { int offset = NOTE_MIDDLEC + (hardwareMixSamples ? 24 : 36); for(auto ¬e : instr.NoteMap) { int realNote = note + sampleTranspose; if(realNote >= offset) note -= static_cast(mpt::align_down(realNote - offset + 12, 12)); } } for(SAMPLEINDEX i = 0; i < numSamples; i++) { ModSample &mptSmp = Samples[smp + i]; mptSmp.Initialize(MOD_TYPE_MED); mptSmp.nVolume = 4u * std::min(sampleHeader.sampleVolume, 64u); mptSmp.RelativeTone = sampleTranspose; } SampleIO sampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM); const bool hasLoop = sampleHeader.loopLength > 1; SmpLength loopStart = sampleHeader.loopStart * 2; SmpLength loopEnd = loopStart + sampleHeader.loopLength * 2; if(isSynth) { for(size_t i = 0; i < waveformOffsets.size(); i++) { const uint32 offset = waveformOffsets[i]; if(offset <= sizeof(MMDInstrHeader) + sizeof(MMDSynthInstr) || !file.Seek(instrOffsets[ins - 1] + offset)) continue; ModSample &mptSmp = Samples[smp + i]; if(instrHeader.type == MMDInstrHeader::SYNTHETIC || i > 0) { mptSmp.nLength = file.ReadUint16BE() * 2; mptSmp.nLoopStart = 0; mptSmp.nLoopEnd = mptSmp.nLength; mptSmp.uFlags.set(CHN_LOOP); m_szNames[smp + i] = "Synth"; } else { MMDInstrHeader hybridHeader; file.ReadStruct(hybridHeader); if(hybridHeader.type == MMDInstrHeader::SAMPLE) { mptSmp.nLength = hybridHeader.length; if(hasLoop) { mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; mptSmp.uFlags.set(CHN_LOOP); } } m_szNames[smp + i] = "Hybrid"; } if(loadFlags & loadSampleData) sampleIO.ReadSample(mptSmp, file); } } else { SmpLength length = mpt::saturate_cast(sampleChunk.GetLength()); if(instrHeader.type & MMDInstrHeader::S_16) { sampleIO |= SampleIO::_16bit; length /= 2; } if(instrHeader.type & MMDInstrHeader::STEREO) { sampleIO |= SampleIO::stereoSplit; length /= 2; m_SongFlags.reset(SONG_ISAMIGA); // Amiga resampler does not handle stereo samples } if(instrHeader.type & MMDInstrHeader::DELTA) { sampleIO |= SampleIO::deltaPCM; } if(numSamples > 1) length = length / ((1u << numSamples) - 1); for(SAMPLEINDEX i = 0; i < numSamples; i++) { ModSample &mptSmp = Samples[smp + i]; mptSmp.nLength = length; if(loadFlags & loadSampleData) sampleIO.ReadSample(mptSmp, sampleChunk); if(hasLoop) { mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; mptSmp.uFlags.set(CHN_LOOP); } length *= 2; loopStart *= 2; loopEnd *= 2; } } // On to the extended instrument info... if(expDataChunk.IsValid()) { const uint16 size = expData.instrExtEntrySize; if(instrExt.hold && !isSynth) { instr.VolEnv.assign({ EnvelopeNode{0u, ENVELOPE_MAX}, EnvelopeNode{static_cast(instrExt.hold - 1), ENVELOPE_MAX}, EnvelopeNode{static_cast(instrExt.hold + (instrExt.decay ? 64u / instrExt.decay : 0u)), ENVELOPE_MIN}, }); if(instrExt.hold == 1) instr.VolEnv.erase(instr.VolEnv.begin()); instr.nFadeOut = instrExt.decay ? (instrExt.decay * 512) : 32767; instr.VolEnv.dwFlags.set(ENV_ENABLED); needInstruments = true; } if(size > offsetof(MMDInstrExt, defaultPitch) && instrExt.defaultPitch != 0) { instr.NoteMap[24] = instrExt.defaultPitch + NOTE_MIN + 23; needInstruments = true; } if(size > offsetof(MMDInstrExt, volume)) instr.nGlobalVol = (instrExt.volume + 1u) / 2u; if(size > offsetof(MMDInstrExt, midiBank)) instr.wMidiBank = instrExt.midiBank; #ifdef MPT_WITH_VST if(instr.nMixPlug > 0) { PLUGINDEX plug = instr.nMixPlug - 1; auto &mixPlug = m_MixPlugins[plug]; if(mixPlug.Info.dwPluginId2 == PLUGMAGIC('M', 'M', 'I', 'D')) { float dev = (instrExt.outputDevice + 1) / 65536.0f; // Magic code from MidiInOut.h :( mixPlug.pluginData.resize(3 * sizeof(uint32)); auto memFile = std::make_pair(mpt::as_span(mixPlug.pluginData), mpt::IO::Offset(0)); mpt::IO::WriteIntLE(memFile, 0); // Plugin data type mpt::IO::Write(memFile, IEEE754binary32LE{0}); // Input device mpt::IO::Write(memFile, IEEE754binary32LE{dev}); // Output device // Check if we already have another plugin referencing this output device for(PLUGINDEX p = 0; p < plug; p++) { const auto &otherPlug = m_MixPlugins[p]; if(otherPlug.Info.dwPluginId1 == mixPlug.Info.dwPluginId1 && otherPlug.Info.dwPluginId2 == mixPlug.Info.dwPluginId2 && otherPlug.pluginData == mixPlug.pluginData) { instr.nMixPlug = p + 1; mixPlug = {}; break; } } } } #endif // MPT_WITH_VST loopStart = instrExt.loopStart; loopEnd = instrExt.loopStart + instrExt.loopLength; for(SAMPLEINDEX i = 0; i < numSamples; i++) { ModSample &sample = Samples[smp + i]; sample.nFineTune = MOD2XMFineTune(instrExt.finetune); if(!isSynth && size > offsetof(MMDInstrExt, loopLength)) { sample.nLoopStart = loopStart; sample.nLoopEnd = loopEnd; loopStart *= 2; loopEnd *= 2; } if(size > offsetof(MMDInstrExt, instrFlags)) { if(!isSynth) { sample.uFlags.set(CHN_LOOP, (instrExt.instrFlags & MMDInstrExt::SSFLG_LOOP) != 0); sample.uFlags.set(CHN_PINGPONGLOOP, (instrExt.instrFlags & MMDInstrExt::SSFLG_PINGPONG) != 0); } if(instrExt.instrFlags & MMDInstrExt::SSFLG_DISABLED) sample.nGlobalVol = 0; } } } // And even more optional data! if(instrInfoChunk.IsValid()) { MMDInstrInfo instrInfo; instrInfoChunk.ReadStructPartial(instrInfo, expData.instrInfoEntrySize); instr.name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, instrInfo.name); for(SAMPLEINDEX i = 0; i < numSamples; i++) { m_szNames[smp + i] = instr.name; } } smp += numSamples; } // Setup a program change macro for command 1C (even if MIDI plugin is disabled, as otherwise these commands may act as filter commands) m_MidiCfg.ClearZxxMacros(); m_MidiCfg.SFx[0] = "Cc z"; file.Rewind(); PATTERNINDEX basePattern = 0; for(SEQUENCEINDEX song = 0; song < numSongs; song++) { MEDReadNextSong(file, fileHeader, expData, songHeader); if(song != 0) { if(Order.AddSequence() == SEQUENCEINDEX_INVALID) return false; } ModSequence &order = Order(song); std::map jumpTargets; order.clear(); uint32 preamp = 32; if(version < 2) { if(songHeader.songLength > 256) return false; ReadOrderFromArray(order, songHeader.GetMMD0Song().sequence, songHeader.songLength); for(auto &ord : order) { ord += basePattern; } SetupMODPanning(true); // With MED SoundStudio 1.03 it's possible to create MMD1 files with more than 16 channels. const CHANNELINDEX numChannelVols = std::min(GetNumChannels(), CHANNELINDEX(16)); for(CHANNELINDEX chn = 0; chn < numChannelVols; chn++) { ChnSettings[chn].nVolume = std::min(songHeader.trackVol[chn], 64); } } else { const MMD2Song header = songHeader.GetMMD2Song(); if(header.numTracks < 1 || header.numTracks > 64 || GetNumChannels() > 64) return false; const bool freePan = !hardwareMixSamples && (header.flags3 & MMD2Song::FLAG3_FREEPAN); if(header.volAdjust) preamp = Util::muldivr_unsigned(preamp, std::min(header.volAdjust, 800), 100); if (freePan) preamp /= 2; if(file.Seek(header.trackVolsOffset)) { for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nVolume = std::min(file.ReadUint8(), 64); } } if((freePan || version > 2) && header.trackPanOffset && file.Seek(header.trackPanOffset)) { for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = static_cast((Clamp(file.ReadInt8(), -16, 16) + 16) * 8); } } else { SetupMODPanning(true); } #ifndef NO_PLUGINS if((header.mixEchoType == 1 || header.mixEchoType == 2) && numPlugins < MAX_MIXPLUGINS) { // Emulating MED echo using the DMO echo requires to compensate for the differences in initial feedback in the latter. const float feedback = 1.0f / (1 << std::clamp(header.mixEchoDepth, uint8(1), uint8(9))); // The feedback we want const float initialFeedback = std::sqrt(1.0f - (feedback * feedback)); // Actual strength of first delay's feedback const float wetFactor = feedback / initialFeedback; // Factor to compensate for this const float delay = (std::max(header.mixEchoLength.get(), uint16(1)) - 1) / 1999.0f; SNDMIXPLUGIN &mixPlug = m_MixPlugins[numPlugins]; mpt::reconstruct(mixPlug); memcpy(&mixPlug.Info.dwPluginId1, "OMXD", 4); memcpy(&mixPlug.Info.dwPluginId2, "\x2C\x93\x3E\xEF", 4); mixPlug.Info.routingFlags = SNDMIXPLUGININFO::irApplyToMaster | SNDMIXPLUGININFO::irAutoSuspend; mixPlug.fDryRatio = 1.0f - wetFactor / (wetFactor + 1.0f); mixPlug.Info.gain = 10; mixPlug.Info.szName = "Echo"; mixPlug.Info.szLibraryName = "Echo"; std::array params{}; params[1] = 1.0f; // WetDryMix params[2] = feedback; // Feedback params[3] = delay; // LeftDelay params[4] = delay; // RightDelay params[5] = header.mixEchoType - 1.0f; // PanDelay mixPlug.pluginData.resize(sizeof(params)); memcpy(mixPlug.pluginData.data(), params.data(), sizeof(params)); } #endif std::vector sections; if(!file.Seek(header.sectionTableOffset) || !file.CanRead(songHeader.songLength * 2) || !file.ReadVector(sections, songHeader.songLength)) continue; for(uint16 section : sections) { if(section > header.numPlaySeqs) continue; file.Seek(header.playSeqTableOffset + section * 4); if(!file.Seek(file.ReadUint32BE()) || !file.CanRead(sizeof(MMD2PlaySeq))) continue; MMD2PlaySeq playSeq; file.ReadStruct(playSeq); if(!order.empty()) order.push_back(PATTERNINDEX_SKIP); const size_t orderStart = order.size(); size_t readOrders = playSeq.length; if(!file.CanRead(readOrders)) LimitMax(readOrders, file.BytesLeft()); LimitMax(readOrders, ORDERINDEX_MAX); order.reserve(orderStart + readOrders); for(size_t ord = 0; ord < readOrders; ord++) { PATTERNINDEX pat = file.ReadUint16BE(); if(pat < 0x8000) { order.push_back(basePattern + pat); } } if(playSeq.name[0]) order.SetName(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, mpt::String::ReadAutoBuf(playSeq.name))); // Play commands (jump / stop) if(playSeq.commandTableOffset > 0 && file.Seek(playSeq.commandTableOffset)) { MMDPlaySeqCommand command; while(file.ReadStruct(command)) { FileReader chunk = file.ReadChunk(command.extraSize); ORDERINDEX ord = mpt::saturate_cast(orderStart + command.offset); if(command.offset == 0xFFFF || ord >= order.size()) break; if(command.command == MMDPlaySeqCommand::kStop) { order[ord] = PATTERNINDEX_INVALID; } else if(command.command == MMDPlaySeqCommand::kJump) { jumpTargets[ord] = chunk.ReadUint16BE(); order[ord] = PATTERNINDEX_SKIP; } } } } } const bool volHex = (songHeader.flags & MMDSong::FLAG_VOLHEX) != 0; const bool is8Ch = (songHeader.flags & MMDSong::FLAG_8CHANNEL) != 0; const bool bpmMode = (songHeader.flags2 & MMDSong::FLAG2_BPM) != 0; const bool softwareMixing = (songHeader.flags2 & MMDSong::FLAG2_MIX) != 0; const uint8 rowsPerBeat = 1 + (songHeader.flags2 & MMDSong::FLAG2_BMASK); order.SetDefaultTempo(MMDTempoToBPM(songHeader.defaultTempo, is8Ch, softwareMixing, bpmMode, rowsPerBeat)); order.SetDefaultSpeed(Clamp(songHeader.tempo2, 1, 32)); if(bpmMode) { m_nDefaultRowsPerBeat = rowsPerBeat; m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat * 4u; } if(songHeader.masterVol) m_nDefaultGlobalVolume = std::min(songHeader.masterVol, 64) * 4; m_nSamplePreAmp = m_nVSTiVolume = preamp; m_SongFlags.set(SONG_FASTVOLSLIDES, !(songHeader.flags & MMDSong::FLAG_STSLIDE)); m_SongFlags.set(SONG_FASTPORTAS, !(songHeader.flags& MMDSong::FLAG_STSLIDE)); m_playBehaviour.set(kST3OffsetWithoutInstrument); m_playBehaviour.set(kST3PortaSampleChange); m_playBehaviour.set(kFT2PortaNoNote); if(expData.songNameOffset && file.Seek(expData.songNameOffset)) { file.ReadString(m_songName, expData.songNameLength); if(numSongs > 1) order.SetName(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, m_songName)); } if(expData.annoLength > 1 && file.Seek(expData.annoText)) { m_songMessage.Read(file, expData.annoLength - 1, SongMessage::leAutodetect); } #ifdef MPT_WITH_VST // Read MIDI messages if(expData.midiDumpOffset && file.Seek(expData.midiDumpOffset) && file.CanRead(8)) { uint16 numDumps = std::min(file.ReadUint16BE(), static_cast(m_MidiCfg.Zxx.size())); file.Skip(6); if(file.CanRead(numDumps * 4)) { std::vector dumpPointers; file.ReadVector(dumpPointers, numDumps); for(uint16 dump = 0; dump < numDumps; dump++) { if(!file.Seek(dumpPointers[dump]) || !file.CanRead(sizeof(MMDDump))) continue; MMDDump dumpHeader; file.ReadStruct(dumpHeader); if(!file.Seek(dumpHeader.dataPointer) || !file.CanRead(dumpHeader.length)) continue; std::array macro{}; auto length = std::min(static_cast(dumpHeader.length), macro.size() / 2u); for(size_t i = 0; i < length; i++) { const uint8 byte = file.ReadUint8(), high = byte >> 4, low = byte & 0x0F; macro[i * 2] = high + (high < 0x0A ? '0' : 'A' - 0x0A); macro[i * 2 + 1] = low + (low < 0x0A ? '0' : 'A' - 0x0A); } m_MidiCfg.Zxx[dump] = std::string_view{macro.data(), length * 2}; } } } #endif // MPT_WITH_VST if(expData.mmdInfoOffset && file.Seek(expData.mmdInfoOffset) && file.CanRead(12)) { file.Skip(6); // Next info file (unused) + reserved if(file.ReadUint16BE() == 1) // ASCII text { uint32 length = file.ReadUint32BE(); if(length && file.CanRead(length)) { const auto oldMsg = std::move(m_songMessage); m_songMessage.Read(file, length, SongMessage::leAutodetect); if(!oldMsg.empty()) m_songMessage.SetRaw(oldMsg + std::string(2, SongMessage::InternalLineEnding) + m_songMessage); } } } // Track Names if(version >= 2 && expData.trackInfoOffset) { for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { if(file.Seek(expData.trackInfoOffset + chn * 4) && file.Seek(file.ReadUint32BE())) { uint32 nameOffset = 0, nameLength = 0; while(file.CanRead(sizeof(MMDTag))) { MMDTag tag; file.ReadStruct(tag); if(tag.type == MMDTag::MMDTAG_END) break; switch(tag.type & MMDTag::MMDTAG_MASK) { case MMDTag::MMDTAG_TRK_NAME: nameOffset = tag.data; break; case MMDTag::MMDTAG_TRK_NAMELEN: nameLength = tag.data; break; } } if(nameOffset > 0 && nameLength > 0 && file.Seek(nameOffset)) { file.ReadString(ChnSettings[chn].szName, nameLength); } } } } PATTERNINDEX numPatterns = songHeader.numBlocks; LimitMax(numPatterns, static_cast(PATTERNINDEX_INVALID - basePattern)); Patterns.ResizeArray(basePattern + numPatterns); for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !file.Seek(fileHeader.blockArrOffset + pat * 4u) || !file.Seek(file.ReadUint32BE())) { continue; } CHANNELINDEX numTracks; ROWINDEX numRows; std::string patName; int16 transpose = NOTE_MIN + 47 + songHeader.playTranspose; uint16 numPages = 0; FileReader cmdExt, commandPages; bool vol7bit = false; if(version < 1) { MMD0PatternHeader patHeader; file.ReadStruct(patHeader); numTracks = patHeader.numTracks; numRows = patHeader.numRows + 1; } else { if(version > 2) transpose -= 24; MMD1PatternHeader patHeader; file.ReadStruct(patHeader); numTracks = patHeader.numTracks; numRows = patHeader.numRows + 1; if(patHeader.blockInfoOffset) { auto offset = file.GetPosition(); file.Seek(patHeader.blockInfoOffset); MMDBlockInfo blockInfo; file.ReadStruct(blockInfo); if(blockInfo.nameLength && blockInfo.nameOffset && file.Seek(blockInfo.nameOffset)) { // We have now chased four pointers to get this far... lovely format. file.ReadString(patName, blockInfo.nameLength); } if(blockInfo.pageTableOffset && file.Seek(blockInfo.pageTableOffset) && file.CanRead(8)) { numPages = file.ReadUint16BE(); file.Skip(2); commandPages = file.ReadChunk(4 * numPages); } if(blockInfo.cmdExtTableOffset && file.Seek(blockInfo.cmdExtTableOffset) && file.Seek(file.ReadUint32BE())) { vol7bit = true; cmdExt = file.ReadChunk(numTracks * numRows * (1 + numPages)); } file.Seek(offset); } } if(!Patterns.Insert(basePattern + pat, numRows)) continue; CPattern &pattern = Patterns[basePattern + pat]; pattern.SetName(patName); LimitMax(numTracks, GetNumChannels()); TranslateMEDPatternContext context{transpose, numTracks, version, rowsPerBeat, is8Ch, softwareMixing, bpmMode, volHex, vol7bit}; needInstruments |= TranslateMEDPattern(file, cmdExt, pattern, context, false); for(uint16 page = 0; page < numPages; page++) { const uint32 pageOffset = commandPages.ReadUint32BE(); if(!pageOffset || !file.Seek(pageOffset)) continue; TranslateMEDPattern(file, cmdExt, pattern, context, true); } } // Fix jump order commands for(const auto &[from, to] : jumpTargets) { PATTERNINDEX pat; if(from > 0 && order.IsValidPat(from - 1)) { pat = order.EnsureUnique(from - 1); } else { if(to == from + 1) // No action required continue; pat = Patterns.InsertAny(1); if(pat == PATTERNINDEX_INVALID) continue; order[from] = pat; } Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, mpt::saturate_cast(to)).Row(Patterns[pat].GetNumRows() - 1).RetryPreviousRow()); if(pat >= basePattern && (pat - basePattern) >= numPatterns) numPatterns = static_cast(pat - basePattern + 1); } if(numSongs > 1) { PATTERNINDEX firstPat = order.EnsureUnique(order.GetFirstValidIndex()); if(firstPat != PATTERNINDEX_INVALID) { for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { Patterns[firstPat].WriteEffect(EffectWriter(CMD_CHANNELVOLUME, static_cast(ChnSettings[chn].nVolume)).Channel(chn).RetryNextRow()); Patterns[firstPat].WriteEffect(EffectWriter(CMD_PANNING8, mpt::saturate_cast(ChnSettings[chn].nPan)).Channel(chn).RetryNextRow()); } if(firstPat >= basePattern && (firstPat - basePattern) >= numPatterns) numPatterns = static_cast(firstPat - basePattern + 1); } } basePattern += numPatterns; if(!expData.nextModOffset || !file.Seek(expData.nextModOffset)) break; } Order.SetSequence(0); if(!needInstruments) { for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++) { delete Instruments[ins]; Instruments[ins] = nullptr; } m_nInstruments = 0; } const mpt::uchar *madeWithTracker = MPT_ULITERAL(""); switch(version) { case 0: madeWithTracker = GetNumChannels() > 4 ? MPT_ULITERAL("OctaMED v2.10 (MMD0)") : MPT_ULITERAL("MED v2 (MMD0)"); break; case 1: madeWithTracker = MPT_ULITERAL("OctaMED v4 (MMD1)"); break; case 2: madeWithTracker = MPT_ULITERAL("OctaMED v5 (MMD2)"); break; case 3: madeWithTracker = MPT_ULITERAL("OctaMED Soundstudio (MMD3)"); break; } m_modFormat.formatName = MPT_UFORMAT("OctaMED (MMD{})")(version); m_modFormat.type = MPT_USTRING("med"); m_modFormat.madeWithTracker = madeWithTracker; m_modFormat.charset = mpt::Charset::Amiga_no_C1; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_psm.cpp0000644000175000017500000011277114706260707020361 00000000000000/* * Load_psm.cpp * ------------ * Purpose: PSM16 and new PSM (ProTracker Studio / Epic MegaGames MASI) module loader * Notes : This is partly based on https://moddingwiki.shikadi.net/wiki/ProTracker_Studio_Module * and partly reverse-engineered. Also thanks to the author of foo_dumb, the source code gave me a few clues. :) * Authors: Johannes Schultz * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "mpt/parse/parse.hpp" OPENMPT_NAMESPACE_BEGIN //////////////////////////////////////////////////////////// // // New PSM support starts here. PSM16 structs are below. // // PSM File Header struct PSMFileHeader { char formatID[4]; // "PSM " (new format) uint32le fileSize; // Filesize - 12 char fileInfoID[4]; // "FILE" }; MPT_BINARY_STRUCT(PSMFileHeader, 12) // RIFF-style Chunk struct PSMChunk { // 32-Bit chunk identifiers enum ChunkIdentifiers { idTITL = MagicLE("TITL"), idSDFT = MagicLE("SDFT"), idPBOD = MagicLE("PBOD"), idSONG = MagicLE("SONG"), idDATE = MagicLE("DATE"), idOPLH = MagicLE("OPLH"), idPPAN = MagicLE("PPAN"), idPATT = MagicLE("PATT"), idDSAM = MagicLE("DSAM"), idDSMP = MagicLE("DSMP"), }; uint32le id; uint32le length; size_t GetLength() const { return length; } ChunkIdentifiers GetID() const { return static_cast(id.get()); } }; MPT_BINARY_STRUCT(PSMChunk, 8) // Song Information struct PSMSongHeader { char songType[9]; // Mostly "MAINSONG " (But not in Extreme Pinball!) uint8 compression; // 1 - uncompressed uint8 numChannels; // Number of channels }; MPT_BINARY_STRUCT(PSMSongHeader, 11) // Regular sample header struct PSMSampleHeader { uint8le flags; char fileName[8]; // Filename of the original module (without extension) char sampleID[4]; // Identifier like "INS0" (only last digit of sample ID, i.e. sample 1 and sample 11 are equal) or "I0 " char sampleName[33]; uint8le unknown1[6]; // 00 00 00 00 00 FF uint16le sampleNumber; uint32le sampleLength; uint32le loopStart; uint32le loopEnd; // FF FF FF FF = end of sample uint8le unknown3; uint8le finetune; // unused? always 0 uint8le defaultVolume; uint32le unknown4; uint32le c5Freq; // MASI ignores the high 16 bits char padding[19]; // Convert header data to OpenMPT's internal format void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileName); mptSmp.nC5Speed = c5Freq; mptSmp.nLength = sampleLength; mptSmp.nLoopStart = loopStart; // Note that we shouldn't add + 1 for MTM conversions here (e.g. the OMF 2097 music), // but I think there is no way to figure out the original format, and in the case of the OMF 2097 soundtrack // it doesn't make a huge audible difference anyway (no chip samples are used). // On the other hand, sample 8 of MUSIC_A.PSM from Extreme Pinball will sound detuned if we don't adjust the loop end here. if(loopEnd) mptSmp.nLoopEnd = loopEnd + 1; mptSmp.nVolume = static_cast((defaultVolume + 1) * 2); mptSmp.uFlags.set(CHN_LOOP, (flags & 0x80) != 0); LimitMax(mptSmp.nLoopEnd, mptSmp.nLength); LimitMax(mptSmp.nLoopStart, mptSmp.nLoopEnd); } }; MPT_BINARY_STRUCT(PSMSampleHeader, 96) // Sinaria sample header (and possibly other games) struct PSMSinariaSampleHeader { uint8le flags; char fileName[8]; // Filename of the original module (without extension) char sampleID[8]; // INS0...INS99999 char sampleName[33]; uint8le unknown1[6]; // 00 00 00 00 00 FF uint16le sampleNumber; uint32le sampleLength; uint32le loopStart; uint32le loopEnd; uint16le unknown3; uint8le finetune; // Appears to be unused uint8le defaultVolume; uint32le unknown4; uint16le c5Freq; char padding[16]; // Convert header data to OpenMPT's internal format void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileName); mptSmp.nC5Speed = c5Freq; mptSmp.nLength = sampleLength; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; mptSmp.nVolume = static_cast((defaultVolume + 1) * 2); mptSmp.uFlags.set(CHN_LOOP, (flags & 0x80) != 0); LimitMax(mptSmp.nLoopEnd, mptSmp.nLength); LimitMax(mptSmp.nLoopStart, mptSmp.nLoopEnd); } }; MPT_BINARY_STRUCT(PSMSinariaSampleHeader, 96) struct PSMSubSong // For internal use (pattern conversion) { std::vector channelPanning, channelVolume; std::vector channelSurround; char songName[10] = {}; PSMSubSong(CHANNELINDEX numChannels) : channelPanning(numChannels, 128) , channelVolume(numChannels, 64) , channelSurround(numChannels, false) { } void SetPanning(CHANNELINDEX chn, uint8 type, int16 pan, bool &subsongPanningDiffers, std::vector &subsongs) { if(chn >= channelPanning.size()) return; switch(type) { case 0: // use panning if(pan >= 0) channelPanning[chn] = static_cast(pan ^ 128); channelSurround[chn] = false; break; case 2: // surround channelPanning[chn] = 128; channelSurround[chn] = true; break; case 4: // center channelPanning[chn] = 128; channelSurround[chn] = false; break; } if(!subsongPanningDiffers && !subsongs.empty()) { if(subsongs.back().channelPanning[chn] != channelPanning[chn] || subsongs.back().channelSurround[chn] != channelSurround[chn]) subsongPanningDiffers = true; } } }; // Portamento effect conversion (depending on format version) static uint8 ConvertPSMPorta(uint8 param, bool sinariaFormat) { if(sinariaFormat) return param; if(param < 4) return (param | 0xF0); else return (param >> 2); } // Read a Pattern ID (something like "P0 " or "P13 ", or "PATT0 " in Sinaria) static PATTERNINDEX ReadPSMPatternIndex(FileReader &file, bool &sinariaFormat) { char patternID[5]; uint8 offset = 1; if(!file.ReadString(patternID, 4)) return 0; if(!memcmp(patternID, "PATT", 4)) { file.ReadString(patternID, 4); sinariaFormat = true; offset = 0; } return mpt::parse(&patternID[offset]); } static bool ValidateHeader(const PSMFileHeader &fileHeader) { if(!std::memcmp(fileHeader.formatID, "PSM ", 4) && !std::memcmp(fileHeader.fileInfoID, "FILE", 4)) { return true; } #ifdef MPT_PSM_DECRYPT if(!std::memcmp(fileHeader.formatID, "QUP$", 4) && !std::memcmp(fileHeader.fileInfoID, "OSWQ", 4)) { return true; } #endif return false; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPSM(MemoryFileReader file, const uint64 *pfilesize) { PSMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); PSMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } #ifdef MPT_PSM_DECRYPT // CONVERT.EXE /K - I don't think any game ever used this. std::vector decrypted; if(!memcmp(fileHeader.formatID, "QUP$", 4) && !memcmp(fileHeader.fileInfoID, "OSWQ", 4)) { if(loadFlags == onlyVerifyHeader) return true; file.Rewind(); decrypted.resize(file.GetLength()); file.ReadRaw(decrypted.data(), decrypted.size()); uint8 i = 0; for(auto &c : decrypted) { c -= ++i; } file = FileReader(mpt::as_span(decrypted)); file.ReadStruct(fileHeader); } #endif // MPT_PSM_DECRYPT // Check header if(!ValidateHeader(fileHeader)) { return false; } ChunkReader chunkFile(file); ChunkReader::ChunkList chunks; if(loadFlags == onlyVerifyHeader) chunks = chunkFile.ReadChunksUntil(1, PSMChunk::idSDFT); else chunks = chunkFile.ReadChunks(1); // "SDFT" - Format info (song data starts here) if(!chunks.GetChunk(PSMChunk::idSDFT).ReadMagic("MAINSONG")) return false; else if(loadFlags == onlyVerifyHeader) return true; auto songChunks = chunks.GetAllChunks(PSMChunk::idSONG); CHANNELINDEX numChannels = 0; for(FileReader chunk : songChunks) { PSMSongHeader songHeader; if(!chunk.ReadStruct(songHeader) || songHeader.compression != 0x01) // No compression for PSM files return false; // Subsongs *might* have different channel count numChannels = Clamp(static_cast(songHeader.numChannels), numChannels, MAX_BASECHANNELS); } if(!numChannels) return false; // Yep, this seems to be a valid file. InitializeGlobals(MOD_TYPE_PSM, numChannels); m_SongFlags = SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX; // "TITL" - Song Title FileReader titleChunk = chunks.GetChunk(PSMChunk::idTITL); titleChunk.ReadString(m_songName, titleChunk.GetLength()); Order().clear(); // Subsong setup std::vector subsongs; bool subsongPanningDiffers = false; // Do we have subsongs with different panning positions? bool sinariaFormat = false; // The game "Sinaria" uses a slightly modified PSM structure - in some ways it's more like PSM16 (e.g. effects). // "SONG" - Subsong information (channel count etc) for(ChunkReader chunk : songChunks) { PSMSongHeader songHeader; chunk.ReadStruct(songHeader); PSMSubSong subsong{GetNumChannels()}; mpt::String::WriteAutoBuf(subsong.songName) = mpt::String::ReadBuf(mpt::String::nullTerminated, songHeader.songType); if(!Order().empty()) { // Add a new sequence for this subsong if(Order.AddSequence() == SEQUENCEINDEX_INVALID) break; } Order().SetName(mpt::ToUnicode(mpt::Charset::CP437, subsong.songName)); // Read "Sub chunks" auto subChunks = chunk.ReadChunks(1); for(const auto &subChunkIter : subChunks.chunks) { FileReader subChunk(subChunkIter.GetData()); PSMChunk subChunkHead = subChunkIter.GetHeader(); switch(subChunkHead.GetID()) { #if 0 case PSMChunk::idDATE: // "DATE" - Conversion date (YYMMDD) if(subChunkHead.GetLength() == 6) { char cversion[7]; subChunk.ReadString(cversion, 6); uint32 version = mpt::parse(cversion); // Sinaria song dates (just to go sure...) if(version == 800211 || version == 940902 || version == 940903 || version == 940906 || version == 940914 || version == 941213) sinariaFormat = true; } break; #endif case PSMChunk::idOPLH: // "OPLH" - Order list, channel + module settings if(subChunkHead.GetLength() >= 9) { // First two bytes = Number of chunks that follow //uint16 totalChunks = subChunk.ReadUint16LE(); subChunk.Skip(2); // Now, the interesting part begins! uint16 chunkCount = 0, firstOrderChunk = uint16_max; // "Sub sub chunks" (grrrr, silly format) while(subChunk.CanRead(1)) { uint8 opcode = subChunk.ReadUint8(); if(!opcode) { // Last chunk was reached. break; } // Note: This is more like a playlist than a collection of global values. // In theory, a tempo item inbetween two order items should modify the // tempo when switching patterns. No module uses this feature in practice // though, so we can keep our loader simple. switch(opcode) { case 0x01: // Play order list item { PATTERNINDEX pat = ReadPSMPatternIndex(subChunk, sinariaFormat); if(pat == 0xFF) pat = PATTERNINDEX_INVALID; else if(pat == 0xFE) pat = PATTERNINDEX_SKIP; Order().push_back(pat); // Decide whether this is the first order chunk or not (for finding out the correct restart position) if(firstOrderChunk == uint16_max) firstOrderChunk = chunkCount; } break; case 0x02: // Play Range (xx from line yy to line zz). Three 16-bit parameters but it seems like the next opcode is parsed at the same position as the third parameter. subChunk.Skip(4); break; case 0x03: // Jump Loop (like Jump Line, but with a third, unknown byte following - nope, it does not appear to be a loop count) case 0x04: // Jump Line (Restart position) { uint16 restartChunk = subChunk.ReadUint16LE(); if(restartChunk >= firstOrderChunk) Order().SetRestartPos(static_cast(restartChunk - firstOrderChunk)); // Close enough - we assume that order list is continuous (like in any real-world PSM) if(opcode == 0x03) subChunk.Skip(1); } break; case 0x05: // Channel Flip (changes channel type without changing pan position) { const auto [chn, type] = subChunk.ReadArray(); subsong.SetPanning(chn, type, -1, subsongPanningDiffers, subsongs); } break; case 0x06: // Transpose (appears to be a no-op in MASI) subChunk.Skip(1); break; case 0x07: // Default Speed Order().SetDefaultSpeed(subChunk.ReadUint8()); break; case 0x08: // Default Tempo Order().SetDefaultTempoInt(subChunk.ReadUint8()); break; case 0x0C: // Sample map table // Never seems to be different, so... // This is probably a part of the never-implemented "mini programming language" mentioned in the PSM docs. // Output of PLAY.EXE: "SMapTabl from pos 0 to pos -1 starting at 0 and adding 1 to it each time" // It appears that this maps e.g. what is "I0" in the file to sample 1. // If we were being fancy, we could implement this, but in practice it won't matter. { uint8 mapTable[6]; if(!subChunk.ReadArray(mapTable) || mapTable[0] != 0x00 || mapTable[1] != 0xFF // "0 to -1" (does not seem to do anything) || mapTable[2] != 0x00 || mapTable[3] != 0x00 // "at 0" (actually this appears to be the adding part - changing this to 0x01 0x00 offsets all samples by 1) || mapTable[4] != 0x01 || mapTable[5] != 0x00) // "adding 1" (does not seem to do anything) { return false; } } break; case 0x0D: // Channel panning table - can be set using CONVERT.EXE /E { const auto [chn, pan, type] = subChunk.ReadArray(); subsong.SetPanning(chn, type, pan, subsongPanningDiffers, subsongs); } break; case 0x0E: // Channel volume table (0...255) - can be set using CONVERT.EXE /E, is 255 in all "official" PSMs except for some OMF 2097 tracks { const auto [chn, vol] = subChunk.ReadArray(); if(chn < subsong.channelVolume.size()) { subsong.channelVolume[chn] = (vol / 4u) + 1; } } break; default: // Non-existent opcode, MASI would just freeze in this case. return false; } chunkCount++; } } break; case PSMChunk::idPPAN: // PPAN - Channel panning table (used in Sinaria) // In some Sinaria tunes, this is actually longer than 2 * channels... MPT_ASSERT(subChunkHead.GetLength() >= GetNumChannels() * 2u); for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { if(!subChunk.CanRead(2)) break; const auto [type, pan] = subChunk.ReadArray(); subsong.SetPanning(chn, type, pan, subsongPanningDiffers, subsongs); } break; case PSMChunk::idPATT: // PATT - Pattern list // We don't really need this. break; case PSMChunk::idDSAM: // DSAM - Sample list // We don't need this either. break; default: break; } } // Attach this subsong to the subsong list - finally, all "sub sub sub ..." chunks are parsed. if(!Order().empty()) subsongs.push_back(subsong); } Order.SetSequence(0); if(subsongs.empty()) return false; // DSMP - Samples if(loadFlags & loadSampleData) { auto sampleChunks = chunks.GetAllChunks(PSMChunk::idDSMP); for(auto &chunk : sampleChunks) { SAMPLEINDEX smp; if(!sinariaFormat) { // Original header PSMSampleHeader sampleHeader; if(!chunk.ReadStruct(sampleHeader)) continue; smp = static_cast(sampleHeader.sampleNumber + 1); if(smp > 0 && smp < MAX_SAMPLES) { m_nSamples = std::max(m_nSamples, smp); sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::nullTerminated, sampleHeader.sampleName); } } else { // Sinaria uses a slightly different sample header PSMSinariaSampleHeader sampleHeader; if(!chunk.ReadStruct(sampleHeader)) continue; smp = static_cast(sampleHeader.sampleNumber + 1); if(smp > 0 && smp < MAX_SAMPLES) { m_nSamples = std::max(m_nSamples, smp); sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::nullTerminated, sampleHeader.sampleName); } } if(smp > 0 && smp < MAX_SAMPLES) { SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::deltaPCM).ReadSample(Samples[smp], chunk); } } } // Make the default variables of the first subsong global for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nVolume = subsongs[0].channelVolume[chn]; ChnSettings[chn].nPan = subsongs[0].channelPanning[chn]; ChnSettings[chn].dwFlags.set(CHN_SURROUND, subsongs[0].channelSurround[chn]); } m_modFormat.formatName = sinariaFormat ? UL_("Epic MegaGames MASI (New Version / Sinaria)") : UL_("Epic MegaGames MASI (New Version)"); m_modFormat.type = UL_("psm"); m_modFormat.charset = mpt::Charset::CP437; if(!(loadFlags & loadPatternData)) { return true; } // "PBOD" - Pattern data of a single pattern // Now that we know the number of channels, we can go through all the patterns. auto pattChunks = chunks.GetAllChunks(PSMChunk::idPBOD); Patterns.ResizeArray(static_cast(pattChunks.size())); for(auto &chunk : pattChunks) { if(chunk.GetLength() != chunk.ReadUint32LE() // Same value twice || !chunk.LengthIsAtLeast(8)) { continue; } PATTERNINDEX pat = ReadPSMPatternIndex(chunk, sinariaFormat); uint16 numRows = chunk.ReadUint16LE(); if(!Patterns.Insert(pat, numRows)) { continue; } enum { noteFlag = 0x80, instrFlag = 0x40, volFlag = 0x20, effectFlag = 0x10, }; // Read pattern. for(ROWINDEX row = 0; row < numRows; row++) { auto rowBase = Patterns[pat].GetRow(row); uint16 rowSize = chunk.ReadUint16LE(); if(rowSize <= 2) { continue; } FileReader rowChunk = chunk.ReadChunk(rowSize - 2); while(rowChunk.CanRead(3)) { const auto [flags, channel] = rowChunk.ReadArray(); // Point to the correct channel ModCommand &m = rowBase[std::min(static_cast(GetNumChannels() - 1), static_cast(channel))]; if(flags & noteFlag) { // Note present uint8 note = rowChunk.ReadUint8(); if(!sinariaFormat) { if(note == 0xFF) // Can be found in a few files but is apparently not supported by MASI note = NOTE_NOTECUT; else if(note < 129) note = static_cast((note & 0x0F) + 12 * (note >> 4) + 13); } else { if(note < 85) note += 36; } m.note = note; } if(flags & instrFlag) { // Instrument present m.instr = rowChunk.ReadUint8() + 1; } if(flags & volFlag) { // Volume present uint8 vol = rowChunk.ReadUint8(); m.SetVolumeCommand(VOLCMD_VOLUME, static_cast((std::min(vol, uint8(127)) + 1) / 2)); } if(flags & effectFlag) { // Effect present - convert const auto [command, param] = rowChunk.ReadArray(); m.param = param; // This list is annoyingly similar to PSM16, but not quite identical. switch(command) { // Volslides case 0x01: // fine volslide up m.command = CMD_VOLUMESLIDE; if (sinariaFormat) m.param = (m.param << 4) | 0x0F; else m.param = ((m.param & 0x1E) << 3) | 0x0F; break; case 0x02: // volslide up m.command = CMD_VOLUMESLIDE; if (sinariaFormat) m.param = 0xF0 & (m.param << 4); else m.param = 0xF0 & (m.param << 3); break; case 0x03: // fine volslide down m.command = CMD_VOLUMESLIDE; if (sinariaFormat) m.param |= 0xF0; else m.param = 0xF0 | (m.param >> 1); break; case 0x04: // volslide down m.command = CMD_VOLUMESLIDE; if (sinariaFormat) m.param &= 0x0F; else if(m.param < 2) m.param |= 0xF0; else m.param = (m.param >> 1) & 0x0F; break; // Portamento case 0x0B: // fine portamento up m.SetEffectCommand(CMD_PORTAMENTOUP, 0xF0 | ConvertPSMPorta(m.param, sinariaFormat)); break; case 0x0C: // portamento up m.SetEffectCommand(CMD_PORTAMENTOUP, ConvertPSMPorta(m.param, sinariaFormat)); break; case 0x0D: // fine portamento down m.SetEffectCommand(CMD_PORTAMENTODOWN, 0xF0 | ConvertPSMPorta(m.param, sinariaFormat)); break; case 0x0E: // portamento down m.SetEffectCommand(CMD_PORTAMENTODOWN, ConvertPSMPorta(m.param, sinariaFormat)); break; case 0x0F: // tone portamento m.command = CMD_TONEPORTAMENTO; if(!sinariaFormat) m.param >>= 2; break; case 0x11: // glissando control m.SetEffectCommand(CMD_S3MCMDEX, 0x10 | (m.param & 0x01)); break; case 0x10: // tone portamento + volslide up m.SetEffectCommand(CMD_TONEPORTAVOL, m.param & 0xF0); break; case 0x12: // tone portamento + volslide down m.SetEffectCommand(CMD_TONEPORTAVOL, (m.param >> 4) & 0x0F); break; case 0x13: // ScreamTracker command S - actually hangs / crashes MASI m.command = CMD_S3MCMDEX; break; // Vibrato case 0x15: // vibrato m.command = CMD_VIBRATO; break; case 0x16: // vibrato waveform m.SetEffectCommand(CMD_S3MCMDEX, 0x30 | (m.param & 0x0F)); break; case 0x17: // vibrato + volslide up m.SetEffectCommand(CMD_VIBRATOVOL, 0xF0 | m.param); break; case 0x18: // vibrato + volslide down m.command = CMD_VIBRATOVOL; break; // Tremolo case 0x1F: // tremolo m.command = CMD_TREMOLO; break; case 0x20: // tremolo waveform m.SetEffectCommand(CMD_S3MCMDEX, 0x40 | (m.param & 0x0F)); break; // Sample commands case 0x29: // 3-byte offset - we only support the middle byte. m.SetEffectCommand(CMD_OFFSET, rowChunk.ReadArray()[0]); break; case 0x2A: // retrigger m.command = CMD_RETRIG; break; case 0x2B: // note cut m.SetEffectCommand(CMD_S3MCMDEX, 0xC0 | (m.param & 0x0F)); break; case 0x2C: // note delay m.SetEffectCommand(CMD_S3MCMDEX, 0xD0 | (m.param & 0x0F)); break; // Position change case 0x33: // position jump - MASI seems to ignore this command, and CONVERT.EXE never writes it // Parameter actually is probably just an index into the order table m.SetEffectCommand(CMD_POSITIONJUMP, m.param / 2u); rowChunk.Skip(1); break; case 0x34: // pattern break // When converting from S3M, the parameter is double-BDC-encoded (wtf!) // When converting from MOD, it's in binary. // MASI ignores the parameter entirely, and so do we. m.SetEffectCommand(CMD_PATTERNBREAK, 0); break; case 0x35: // loop pattern m.SetEffectCommand(CMD_S3MCMDEX, 0xB0 | (m.param & 0x0F)); break; case 0x36: // pattern delay m.SetEffectCommand(CMD_S3MCMDEX, 0xE0 | (m.param & 0x0F)); break; // speed change case 0x3D: // set speed m.command = CMD_SPEED; break; case 0x3E: // set tempo m.command = CMD_TEMPO; break; // misc commands case 0x47: // arpeggio m.command = CMD_ARPEGGIO; break; case 0x48: // set finetune m.SetEffectCommand(CMD_S3MCMDEX, 0x20 | (m.param & 0x0F)); break; case 0x49: // set balance m.SetEffectCommand(CMD_S3MCMDEX, 0x80 | (m.param & 0x0F)); break; default: m.command = CMD_NONE; break; } } } } } if(subsongs.size() > 1) { // Write subsong "configuration" to patterns (only if there are multiple subsongs) for(size_t i = 0; i < subsongs.size(); i++) { const PSMSubSong &subsong = subsongs[i]; ModSequence &order = Order(static_cast(i)); const PATTERNINDEX startPattern = order.EnsureUnique(order.GetFirstValidIndex()); if(startPattern == PATTERNINDEX_INVALID) continue; // Subsongs with different panning setup -> write to pattern (MUSIC_C.PSM) // Don't write channel volume for now, as there is no real-world module which needs it. if(subsongPanningDiffers) { for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { if(subsong.channelSurround[chn]) Patterns[startPattern].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0x91).Row(0).Channel(chn).RetryNextRow()); else Patterns[startPattern].WriteEffect(EffectWriter(CMD_PANNING8, subsong.channelPanning[chn]).Row(0).Channel(chn).RetryNextRow()); } } } } return true; } //////////////////////////////// // // PSM16 support starts here. // struct PSM16FileHeader { char formatID[4]; // "PSM\xFE" (PSM16) char songName[59]; // Song title, padded with nulls uint8le lineEnd; // $1A uint8le songType; // Song Type bitfield uint8le formatVersion; // $10 uint8le patternVersion; // 0 or 1 uint8le songSpeed; // 1 ... 255 uint8le songTempo; // 32 ... 255 uint8le masterVolume; // 0 ... 255 uint16le songLength; // 0 ... 255 (number of patterns to play in the song) uint16le songOrders; // 0 ... 255 (same as previous value as no subsongs are present) uint16le numPatterns; // 1 ... 255 uint16le numSamples; // 1 ... 255 uint16le numChannelsPlay; // 0 ... 32 (max. number of channels to play) uint16le numChannelsReal; // 0 ... 32 (max. number of channels to process) uint32le orderOffset; // Pointer to order list uint32le panOffset; // Pointer to pan table uint32le patOffset; // Pointer to pattern data uint32le smpOffset; // Pointer to sample headers uint32le commentsOffset; // Pointer to song comment uint32le patSize; // Size of all patterns char filler[40]; }; MPT_BINARY_STRUCT(PSM16FileHeader, 146) struct PSM16SampleHeader { enum SampleFlags { smpMask = 0x7F, smp16Bit = 0x04, smpUnsigned = 0x08, smpDelta = 0x10, smpPingPong = 0x20, smpLoop = 0x80, }; char filename[13]; // null-terminated char name[24]; // ditto uint32le offset; // in file uint32le memoffset; // not used uint16le sampleNumber; // 1 ... 255 uint8le flags; // sample flag bitfield uint32le length; // in bytes uint32le loopStart; // in samples? uint32le loopEnd; // in samples? uint8le finetune; // Low nibble = MOD finetune, high nibble = transpose (7 = center) uint8le volume; // default volume uint16le c2freq; // Middle-C frequency, which has to be combined with the finetune and transpose. // Convert sample header to OpenMPT's internal format void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename); mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; // It seems like that finetune and transpose are added to the already given c2freq... That's a double WTF! // Why on earth would you want to use both systems at the same time? mptSmp.nC5Speed = c2freq; mptSmp.Transpose(((finetune ^ 0x08) - 0x78) / (12.0 * 16.0)); mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4u; mptSmp.uFlags.reset(); if(flags & PSM16SampleHeader::smp16Bit) { mptSmp.uFlags.set(CHN_16BIT); mptSmp.nLength /= 2u; } if(flags & PSM16SampleHeader::smpPingPong) { mptSmp.uFlags.set(CHN_PINGPONGLOOP); } if(flags & PSM16SampleHeader::smpLoop) { mptSmp.uFlags.set(CHN_LOOP); } } // Retrieve the internal sample format flags for this sample. SampleIO GetSampleFormat() const { SampleIO sampleIO( (flags & PSM16SampleHeader::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM); if(flags & PSM16SampleHeader::smpUnsigned) { sampleIO |= SampleIO::unsignedPCM; } else if((flags & PSM16SampleHeader::smpDelta) || (flags & PSM16SampleHeader::smpMask) == 0) { sampleIO |= SampleIO::deltaPCM; } return sampleIO; } }; MPT_BINARY_STRUCT(PSM16SampleHeader, 64) struct PSM16PatternHeader { uint16le size; // includes header bytes uint8le numRows; // 1 ... 64 uint8le numChans; // 1 ... 32 }; MPT_BINARY_STRUCT(PSM16PatternHeader, 4) static bool ValidateHeader(const PSM16FileHeader &fileHeader) { if(std::memcmp(fileHeader.formatID, "PSM\xFE", 4) || fileHeader.lineEnd != 0x1A || (fileHeader.formatVersion != 0x10 && fileHeader.formatVersion != 0x01) // why is this sometimes 0x01? || fileHeader.patternVersion != 0 // 255ch pattern version not supported (does it actually exist? The pattern format is not documented) || (fileHeader.songType & 3) != 0 || fileHeader.numChannelsPlay > 32 || fileHeader.numChannelsReal > 32 || std::max(fileHeader.numChannelsPlay, fileHeader.numChannelsReal) == 0) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPSM16(MemoryFileReader file, const uint64 *pfilesize) { PSM16FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); // Is it a valid PSM16 file? PSM16FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } // Seems to be valid! InitializeGlobals(MOD_TYPE_PSM, Clamp(CHANNELINDEX(fileHeader.numChannelsPlay), CHANNELINDEX(fileHeader.numChannelsReal), MAX_BASECHANNELS)); m_modFormat.formatName = UL_("Epic MegaGames MASI (Old Version)"); m_modFormat.type = UL_("psm"); m_modFormat.charset = mpt::Charset::CP437; m_nSamplePreAmp = fileHeader.masterVolume; if(m_nSamplePreAmp == 255) { // Most of the time, the master volume value makes sense... Just not when it's 255. m_nSamplePreAmp = 48; } Order().SetDefaultSpeed(fileHeader.songSpeed); Order().SetDefaultTempoInt(fileHeader.songTempo); m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songName); // Read orders if(fileHeader.orderOffset > 4 && file.Seek(fileHeader.orderOffset - 4) && file.ReadMagic("PORD")) { ReadOrderFromFile(Order(), file, fileHeader.songOrders); } // Read pan positions if(fileHeader.panOffset > 4 && file.Seek(fileHeader.panOffset - 4) && file.ReadMagic("PPAN")) { for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { ChnSettings[i].nPan = static_cast(((15 - (file.ReadUint8() & 0x0F)) * 256 + 8) / 15); // 15 seems to be left and 0 seems to be right... // ChnSettings[i].dwFlags = (i >= fileHeader.numChannelsPlay) ? CHN_MUTE : 0; // don't mute channels, as muted channels are completely ignored in S3M } } // Read samples if(fileHeader.smpOffset > 4 && file.Seek(fileHeader.smpOffset - 4) && file.ReadMagic("PSAH")) { FileReader sampleChunk = file.ReadChunk(fileHeader.numSamples * sizeof(PSM16SampleHeader)); for(SAMPLEINDEX fileSample = 0; fileSample < fileHeader.numSamples; fileSample++) { PSM16SampleHeader sampleHeader; if(!sampleChunk.ReadStruct(sampleHeader)) { break; } const SAMPLEINDEX smp = sampleHeader.sampleNumber; if(smp > 0 && smp < MAX_SAMPLES && !Samples[smp].HasSampleData()) { m_nSamples = std::max(m_nSamples, smp); sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::nullTerminated, sampleHeader.name); if(loadFlags & loadSampleData) { file.Seek(sampleHeader.offset); sampleHeader.GetSampleFormat().ReadSample(Samples[smp], file); } } } } // Read patterns if(!(loadFlags & loadPatternData)) { return true; } if(fileHeader.patOffset > 4 && file.Seek(fileHeader.patOffset - 4) && file.ReadMagic("PPAT")) { Patterns.ResizeArray(fileHeader.numPatterns); for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++) { PSM16PatternHeader patternHeader; if(!file.ReadStruct(patternHeader)) { break; } if(patternHeader.size < sizeof(PSM16PatternHeader)) { continue; } // Patterns are padded to 16 Bytes FileReader patternChunk = file.ReadChunk(((patternHeader.size + 15) & ~15) - sizeof(PSM16PatternHeader)); if(!Patterns.Insert(pat, patternHeader.numRows)) { continue; } enum { channelMask = 0x1F, noteFlag = 0x80, volFlag = 0x40, effectFlag = 0x20, }; ROWINDEX curRow = 0; while(patternChunk.CanRead(1) && curRow < patternHeader.numRows) { uint8 chnFlag = patternChunk.ReadUint8(); if(chnFlag == 0) { curRow++; continue; } ModCommand &m = *Patterns[pat].GetpModCommand(curRow, std::min(static_cast(chnFlag & channelMask), static_cast(GetNumChannels() - 1))); if(chnFlag & noteFlag) { // note + instr present const auto [note, instr] = patternChunk.ReadArray(); m.note = note + 36; m.instr = instr; } if(chnFlag & volFlag) { // volume present m.volcmd = VOLCMD_VOLUME; m.vol = std::min(patternChunk.ReadUint8(), uint8(64)); } if(chnFlag & effectFlag) { // effect present - convert const auto [command, param] = patternChunk.ReadArray(); m.param = param; switch(command) { // Volslides case 0x01: // fine volslide up m.SetEffectCommand(CMD_VOLUMESLIDE, (m.param << 4) | 0x0F); break; case 0x02: // volslide up m.SetEffectCommand(CMD_VOLUMESLIDE, (m.param << 4) & 0xF0); break; case 0x03: // fine voslide down m.SetEffectCommand(CMD_VOLUMESLIDE, 0xF0 | m.param); break; case 0x04: // volslide down m.SetEffectCommand(CMD_VOLUMESLIDE, m.param & 0x0F); break; // Portamento case 0x0A: // fine portamento up m.SetEffectCommand(CMD_PORTAMENTOUP, 0xF0 | m.param); break; case 0x0B: // portamento down m.command = CMD_PORTAMENTOUP; break; case 0x0C: // fine portamento down m.SetEffectCommand(CMD_PORTAMENTODOWN, m.param | 0xF0); break; case 0x0D: // portamento down m.command = CMD_PORTAMENTODOWN; break; case 0x0E: // tone portamento m.command = CMD_TONEPORTAMENTO; break; case 0x0F: // glissando control (note: this can be found in the Odyssey music from Silverball but it seems like it was actually a literal translation from MOD effect F) m.SetEffectCommand(CMD_S3MCMDEX, 0x10 | (m.param & 0x0F)); break; case 0x10: // tone portamento + volslide up m.SetEffectCommand(CMD_TONEPORTAVOL, m.param << 4); break; case 0x11: // tone portamento + volslide down m.SetEffectCommand(CMD_TONEPORTAVOL, m.param & 0x0F); break; // Vibrato case 0x14: // vibrato m.command = CMD_VIBRATO; break; case 0x15: // vibrato waveform m.SetEffectCommand(CMD_S3MCMDEX, 0x30 | (m.param & 0x0F)); break; case 0x16: // vibrato + volslide up m.SetEffectCommand(CMD_VIBRATOVOL, m.param << 4); break; case 0x17: // vibrato + volslide down m.SetEffectCommand(CMD_VIBRATOVOL, m.param & 0x0F); break; // Tremolo case 0x1E: // tremolo m.command = CMD_TREMOLO; break; case 0x1F: // tremolo waveform m.SetEffectCommand(CMD_S3MCMDEX, 0x40 | (m.param & 0x0F)); break; // Sample commands case 0x28: // 3-byte offset - we only support the middle byte. m.SetEffectCommand(CMD_OFFSET, patternChunk.ReadArray()[0]); break; case 0x29: // retrigger m.SetEffectCommand(CMD_RETRIG, m.param & 0x0F); break; case 0x2A: // note cut m.command = CMD_S3MCMDEX; #ifdef MODPLUG_TRACKER if(m.param == 0) // in S3M mode, SC0 is ignored, so we convert it to a note cut. { if(m.note == NOTE_NONE) { m.note = NOTE_NOTECUT; m.command = CMD_NONE; } else { m.param = 1; } } #endif // MODPLUG_TRACKER m.param |= 0xC0; break; case 0x2B: // note delay m.SetEffectCommand(CMD_S3MCMDEX, 0xD0 | (m.param & 0x0F)); break; // Position change case 0x32: // position jump m.command = CMD_POSITIONJUMP; break; case 0x33: // pattern break m.command = CMD_PATTERNBREAK; break; case 0x34: // loop pattern m.SetEffectCommand(CMD_S3MCMDEX, 0xB0 | (m.param & 0x0F)); break; case 0x35: // pattern delay m.SetEffectCommand(CMD_S3MCMDEX, 0xE0 | (m.param & 0x0F)); break; // speed change case 0x3C: // set speed m.command = CMD_SPEED; break; case 0x3D: // set tempo m.command = CMD_TEMPO; break; // misc commands case 0x46: // arpeggio m.command = CMD_ARPEGGIO; break; case 0x47: // set finetune m.SetEffectCommand(CMD_S3MCMDEX, 0x20 | (m.param & 0x0F)); break; case 0x48: // set balance (panning?) m.SetEffectCommand(CMD_S3MCMDEX, 0x80 | (m.param & 0x0F)); break; default: m.command = CMD_NONE; break; } } } } } if(fileHeader.commentsOffset != 0) { file.Seek(fileHeader.commentsOffset); m_songMessage.Read(file, file.ReadUint16LE(), SongMessage::leAutodetect); } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/XMTools.h0000644000175000017500000001626514726400214017625 00000000000000/* * XMTools.h * --------- * Purpose: Definition of XM file structures and helper functions * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/base/Endian.hpp" #include "Snd_defs.h" OPENMPT_NAMESPACE_BEGIN struct InstrumentEnvelope; struct ModInstrument; struct ModSample; class SampleIO; // XM File Header struct XMFileHeader { enum XMHeaderFlags { linearSlides = 0x01, extendedFilterRange = 0x1000, }; char signature[17]; // "Extended Module: " char songName[20]; // Song Name, space-padded uint8le eof; // DOS EOF Character (0x1A) char trackerName[20]; // Software that was used to create the XM file uint16le version; // File version (1.02 - 1.04 are supported) uint32le size; // Header Size uint16le orders; // Number of Orders uint16le restartPos; // Restart Position uint16le channels; // Number of Channels uint16le patterns; // Number of Patterns uint16le instruments; // Number of Unstruments uint16le flags; // Song Flags uint16le speed; // Default Speed uint16le tempo; // Default Tempo }; MPT_BINARY_STRUCT(XMFileHeader, 80) // XM Instrument Data struct XMInstrument { // Envelope Flags enum XMEnvelopeFlags { envEnabled = 0x01, envSustain = 0x02, envLoop = 0x04, }; uint8le sampleMap[96]; // Note -> Sample assignment uint16le volEnv[24]; // Volume envelope nodes / values (0...64) uint16le panEnv[24]; // Panning envelope nodes / values (0...63) uint8le volPoints; // Volume envelope length uint8le panPoints; // Panning envelope length uint8le volSustain; // Volume envelope sustain point uint8le volLoopStart; // Volume envelope loop start point uint8le volLoopEnd; // Volume envelope loop end point uint8le panSustain; // Panning envelope sustain point uint8le panLoopStart; // Panning envelope loop start point uint8le panLoopEnd; // Panning envelope loop end point uint8le volFlags; // Volume envelope flags uint8le panFlags; // Panning envelope flags uint8le vibType; // Sample Auto-Vibrato Type uint8le vibSweep; // Sample Auto-Vibrato Sweep uint8le vibDepth; // Sample Auto-Vibrato Depth uint8le vibRate; // Sample Auto-Vibrato Rate uint16le volFade; // Volume Fade-Out uint8le midiEnabled; // MIDI Out Enabled (0 / 1) uint8le midiChannel; // MIDI Channel (0...15) uint16le midiProgram; // MIDI Program (0...127) uint16le pitchWheelRange; // MIDI Pitch Wheel Range (0...36 halftones) uint8le muteComputer; // Mute instrument if MIDI is enabled (0 / 1) uint8le reserved[15]; // Reserved enum EnvType { EnvTypeVol, EnvTypePan, }; // Convert OpenMPT's internal envelope representation to XM envelope data. void ConvertEnvelopeToXM(const InstrumentEnvelope &mptEnv, uint8le &numPoints, uint8le &flags, uint8le &sustain, uint8le &loopStart, uint8le &loopEnd, EnvType env); // Convert XM envelope data to an OpenMPT's internal envelope representation. void ConvertEnvelopeToMPT(InstrumentEnvelope &mptEnv, uint8 numPoints, uint8 flags, uint8 sustain, uint8 loopStart, uint8 loopEnd, EnvType env) const; struct SampleList { std::vector samples; // The list of samples to write to the file bool tooManySamples = false; // Does the source instrument contain more samples than what we can write? }; // Convert OpenMPT's internal sample representation to an XMInstrument. SampleList ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport); // Convert an XMInstrument to OpenMPT's internal instrument representation. void ConvertToMPT(ModInstrument &mptIns) const; // Apply auto-vibrato settings from sample to file. void ApplyAutoVibratoToXM(const ModSample &mptSmp, MODTYPE fromType); // Apply auto-vibrato settings from file to a sample. void ApplyAutoVibratoToMPT(ModSample &mptSmp) const; // Get a list of samples that should be written to the file. SampleList GetSampleList(const ModInstrument &mptIns, bool compatibilityExport) const; }; MPT_BINARY_STRUCT(XMInstrument, 230) // XM Instrument Header struct XMInstrumentHeader { uint32le size; // Size of XMInstrumentHeader + XMInstrument char name[22]; // Instrument Name, space-padded uint8le type; // Instrument Type (FT2 does not initialize this field properly, so it contains a random value, but it's the same random value for all instruments of the same module!) uint16le numSamples; // Number of Samples associated with instrument uint32le sampleHeaderSize; // Size of XMSample XMInstrument instrument; // Write stuff to the header that's always necessary (also for empty instruments) void Finalise(); // Convert OpenMPT's internal sample representation to an XMInstrument. XMInstrument::SampleList ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport); // Convert an XMInstrument to OpenMPT's internal instrument representation. void ConvertToMPT(ModInstrument &mptIns) const; }; MPT_BINARY_STRUCT(XMInstrumentHeader, 263) // XI Instrument Header struct XIInstrumentHeader { enum { fileVersion = 0x102, }; char signature[21]; // "Extended Instrument: " char name[22]; // Instrument Name, space-padded uint8le eof; // DOS EOF Character (0x1A) char trackerName[20]; // Software that was used to create the XI file uint16le version; // File Version (1.02) XMInstrument instrument; uint16le numSamples; // Number of embedded sample headers + samples // Convert OpenMPT's internal sample representation to an XIInstrumentHeader. XMInstrument::SampleList ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport); // Convert an XIInstrumentHeader to OpenMPT's internal instrument representation. void ConvertToMPT(ModInstrument &mptIns) const; }; MPT_BINARY_STRUCT(XIInstrumentHeader, 298) // XM Sample Header struct XMSample { enum XMSampleFlags { sampleLoop = 0x01, sampleBidiLoop = 0x02, sample16Bit = 0x10, sampleStereo = 0x20, sampleADPCM = 0xAD, // MODPlugin :( }; uint32le length; // Sample Length (in bytes) uint32le loopStart; // Loop Start (in bytes) uint32le loopLength; // Loop Length (in bytes) uint8le vol; // Default Volume int8le finetune; // Sample Finetune uint8le flags; // Sample Flags uint8le pan; // Sample Panning int8le relnote; // Sample Transpose uint8le reserved; // Reserved (abused for ModPlug's ADPCM compression) char name[22]; // Sample Name, space-padded // Convert OpenMPT's internal sample representation to an XMSample. void ConvertToXM(const ModSample &mptSmp, MODTYPE fromType, bool compatibilityExport); // Convert an XMSample to OpenMPT's internal sample representation. void ConvertToMPT(ModSample &mptSmp) const; // Retrieve the internal sample format flags for this instrument. SampleIO GetSampleFormat() const; }; MPT_BINARY_STRUCT(XMSample, 40) OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/0000755000175000017500000000000015023302362017632 500000000000000libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/0000755000175000017500000000000015023302362020411 500000000000000libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Chorus.h0000644000175000017500000000722214722730163021761 00000000000000/* * Chorus.h * -------- * Purpose: Implementation of the DMO Chorus DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #ifndef NO_PLUGINS #include "../PlugInterface.h" OPENMPT_NAMESPACE_BEGIN namespace DMO { class Chorus : public IMixPlugin { protected: enum Parameters { kChorusWetDryMix = 0, kChorusDepth, kChorusFrequency, kChorusWaveShape, kChorusPhase, kChorusFeedback, kChorusDelay, kChorusNumParameters }; std::array m_param; // Calculated parameters float m_waveShapeMin, m_waveShapeMax, m_waveShapeVal; float m_depthDelay; float m_frequency; int32 m_delayOffset; const bool m_isFlanger = false; // State std::vector m_bufferL, m_bufferR; // Only m_bufferL is used in case of !m_isFlanger std::array m_DryBufferL, m_DryBufferR; int32 m_bufPos = 0, m_bufSize = 0; int32 m_delayL = 0, m_delayR = 0; int32 m_dryWritePos = 0; public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); Chorus(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, bool stereoBuffers = false); int32 GetUID() const override { return 0xEFE6629C; } int32 GetVersion() const override { return 0; } void Idle() override { } uint32 GetLatency() const override { return 0; } void Process(float *pOutL, float *pOutR, uint32 numFrames) override; float RenderSilence(uint32) override { return 0.0f; } int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } void SetCurrentProgram(int32) override { } PlugParamIndex GetNumParameters() const override { return kChorusNumParameters; } PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override { m_isResumed = false; } void PositionChanged() override; bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("Chorus"); } CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; CString GetCurrentProgramName() override { return CString(); } void SetCurrentProgramName(const CString &) override { } CString GetProgramName(int32) override { return CString(); } bool HasEditor() const override { return false; } #endif void BeginSetProgram(int32) override { } void EndSetProgram() override { } int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } protected: int32 GetBufferIntOffset(int32 fpOffset) const; virtual float WetDryMix() const { return m_param[kChorusWetDryMix]; } virtual bool IsSquare() const { return m_param[kChorusWaveShape] < 1; } virtual float Depth() const { return m_param[kChorusDepth]; } virtual float Feedback() const { return -99.0f + m_param[kChorusFeedback] * 198.0f; } virtual float Delay() const { return m_param[kChorusDelay] * 20.0f; } virtual float FrequencyInHertz() const { return m_param[kChorusFrequency] * 10.0f; } virtual int Phase() const { return mpt::saturate_round(m_param[kChorusPhase] * 4.0f); } void RecalculateChorusParams(); }; } // namespace DMO OPENMPT_NAMESPACE_END #endif // !NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/DMOPlugin.cpp0000644000175000017500000002563014722730163022652 00000000000000/* * DMOPlugin.h * ----------- * Purpose: DirectX Media Object plugin handling / processing. * Notes : Some default plugins only have the same output characteristics in the floating point code path (compared to integer PCM) * if we feed them input in the range [-32768, +32768] rather than the more usual [-1, +1]. * Hence, OpenMPT uses this range for both the floating-point and integer path. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "mpt/base/aligned_array.hpp" #if defined(MPT_WITH_DMO) #include "DMOPlugin.h" #include "mpt/uuid/guid.hpp" #include "../../Sndfile.h" #include "../PluginManager.h" #include #include #include #endif // MPT_WITH_DMO OPENMPT_NAMESPACE_BEGIN #if defined(MPT_WITH_DMO) #ifdef MPT_ALL_LOGGING #define DMO_LOG #else #define DMO_LOG #endif IMixPlugin* DMOPlugin::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { CLSID clsid; if(mpt::VerifyStringToCLSID(factory.dllPath.AsNative(), clsid)) { IMediaObject *pMO = nullptr; IMediaObjectInPlace *pMOIP = nullptr; if ((CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, IID_IMediaObject, (VOID **)&pMO) == S_OK) && (pMO)) { if (pMO->QueryInterface(IID_IMediaObjectInPlace, (void **)&pMOIP) != S_OK) pMOIP = nullptr; } else pMO = nullptr; if ((pMO) && (pMOIP)) { DWORD dwInputs = 0, dwOutputs = 0; pMO->GetStreamCount(&dwInputs, &dwOutputs); if (dwInputs == 1 && dwOutputs == 1) { DMOPlugin *p = new (std::nothrow) DMOPlugin(factory, sndFile, mixStruct, pMO, pMOIP, clsid.Data1); return p; } #ifdef DMO_LOG MPT_LOG_GLOBAL(LogDebug, "DMO", factory.libraryName.ToUnicode() + U_(": Unable to use this DMO")); #endif } #ifdef DMO_LOG else MPT_LOG_GLOBAL(LogDebug, "DMO", factory.libraryName.ToUnicode() + U_(": Failed to get IMediaObject & IMediaObjectInPlace interfaces")); #endif if (pMO) pMO->Release(); if (pMOIP) pMOIP->Release(); } return nullptr; } DMOPlugin::DMOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, IMediaObject *pMO, IMediaObjectInPlace *pMOIP, uint32 uid) : IMixPlugin(factory, sndFile, mixStruct) , m_pMediaObject(pMO) , m_pMediaProcess(pMOIP) , m_pParamInfo(nullptr) , m_pMediaParams(nullptr) , m_nSamplesPerSec(sndFile.GetSampleRate()) , m_uid(uid) { if(FAILED(m_pMediaObject->QueryInterface(IID_IMediaParamInfo, (void **)&m_pParamInfo))) m_pParamInfo = nullptr; if (FAILED(m_pMediaObject->QueryInterface(IID_IMediaParams, (void **)&m_pMediaParams))) m_pMediaParams = nullptr; m_alignedBuffer.f32 = mpt::align_bytes<16, MIXBUFFERSIZE * 2>(m_interleavedBuffer.f32); m_mixBuffer.Initialize(2, 2); } DMOPlugin::~DMOPlugin() { if(m_pMediaParams) { m_pMediaParams->Release(); m_pMediaParams = nullptr; } if(m_pParamInfo) { m_pParamInfo->Release(); m_pParamInfo = nullptr; } if(m_pMediaProcess) { m_pMediaProcess->Release(); m_pMediaProcess = nullptr; } if(m_pMediaObject) { m_pMediaObject->Release(); m_pMediaObject = nullptr; } } uint32 DMOPlugin::GetLatency() const { REFERENCE_TIME time; // Unit 100-nanoseconds if(m_pMediaProcess->GetLatency(&time) == S_OK) { return static_cast(time * m_nSamplesPerSec / (10 * 1000 * 1000)); } return 0; } static constexpr float _f2si = 32768.0f; static constexpr float _si2f = 1.0f / 32768.0f; static void InterleaveStereo(const float * MPT_RESTRICT inputL, const float * MPT_RESTRICT inputR, float * MPT_RESTRICT output, uint32 numFrames) { while(numFrames--) { *(output++) = *(inputL++) * _f2si; *(output++) = *(inputR++) * _f2si; } } static void DeinterleaveStereo(const float * MPT_RESTRICT input, float * MPT_RESTRICT outputL, float * MPT_RESTRICT outputR, uint32 numFrames) { while(numFrames--) { *(outputL++) = *(input++) * _si2f; *(outputR++) = *(input++) * _si2f; } } // Interleave two float streams into one int16 stereo stream. static void InterleaveFloatToInt16(const float * MPT_RESTRICT inputL, const float * MPT_RESTRICT inputR, int16 * MPT_RESTRICT output, uint32 numFrames) { while(numFrames--) { *(output++) = static_cast(Clamp(*(inputL++) * _f2si, static_cast(int16_min), static_cast(int16_max))); *(output++) = static_cast(Clamp(*(inputR++) * _f2si, static_cast(int16_min), static_cast(int16_max))); } } // Deinterleave an int16 stereo stream into two float streams. static void DeinterleaveInt16ToFloat(const int16 * MPT_RESTRICT input, float * MPT_RESTRICT outputL, float * MPT_RESTRICT outputR, uint32 numFrames) { while(numFrames--) { *outputL++ += _si2f * static_cast(*input++); *outputR++ += _si2f * static_cast(*input++); } } void DMOPlugin::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(!numFrames || !m_mixBuffer.Ok()) return; m_mixBuffer.ClearOutputBuffers(numFrames); REFERENCE_TIME startTime = Util::muldiv(m_SndFile.GetTotalSampleCount(), 10000000, m_nSamplesPerSec); if(m_useFloat) { InterleaveStereo(m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1), m_alignedBuffer.f32, numFrames); m_pMediaProcess->Process(numFrames * 2 * sizeof(float), reinterpret_cast(m_alignedBuffer.f32), startTime, DMO_INPLACE_NORMAL); DeinterleaveStereo(m_alignedBuffer.f32, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } else { InterleaveFloatToInt16(m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1), m_alignedBuffer.i16, numFrames); m_pMediaProcess->Process(numFrames * 2 * sizeof(int16), reinterpret_cast(m_alignedBuffer.i16), startTime, DMO_INPLACE_NORMAL); DeinterleaveInt16ToFloat(m_alignedBuffer.i16, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } PlugParamIndex DMOPlugin::GetNumParameters() const { DWORD dwParamCount = 0; m_pParamInfo->GetParamCount(&dwParamCount); return dwParamCount; } PlugParamValue DMOPlugin::GetParameter(PlugParamIndex index) { if(index < GetNumParameters() && m_pParamInfo != nullptr && m_pMediaParams != nullptr) { MP_PARAMINFO mpi{}; MP_DATA md = 0; if (m_pParamInfo->GetParamInfo(index, &mpi) == S_OK && m_pMediaParams->GetParam(index, &md) == S_OK) { float fValue = md; float fMin = mpi.mpdMinValue; float fMax = mpi.mpdMaxValue; //float fDefault = mpi.mpdNeutralValue; if (mpi.mpType == MPT_BOOL) { fMin = 0; fMax = 1; } fValue -= fMin; if (fMax > fMin) fValue /= (fMax - fMin); return fValue; } } return 0; } void DMOPlugin::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < GetNumParameters() && m_pParamInfo != nullptr && m_pMediaParams != nullptr) { MP_PARAMINFO mpi{}; if (m_pParamInfo->GetParamInfo(index, &mpi) == S_OK) { float fMin = mpi.mpdMinValue; float fMax = mpi.mpdMaxValue; if (mpi.mpType == MPT_BOOL) { fMin = 0; fMax = 1; value = (value > 0.5f) ? 1.0f : 0.0f; } if (fMax > fMin) value *= (fMax - fMin); value += fMin; value = mpt::safe_clamp(value, fMin, fMax); if (mpi.mpType != MPT_FLOAT) value = mpt::round(value); m_pMediaParams->SetParam(index, value); } } } void DMOPlugin::Resume() { m_nSamplesPerSec = m_SndFile.GetSampleRate(); m_isResumed = true; DMO_MEDIA_TYPE mt; WAVEFORMATEX wfx; mt.majortype = MEDIATYPE_Audio; mt.subtype = MEDIASUBTYPE_PCM; mt.bFixedSizeSamples = TRUE; mt.bTemporalCompression = FALSE; mt.formattype = FORMAT_WaveFormatEx; mt.pUnk = nullptr; mt.pbFormat = (LPBYTE)&wfx; mt.cbFormat = sizeof(WAVEFORMATEX); mt.lSampleSize = 2 * sizeof(float); wfx.wFormatTag = 3; // WAVE_FORMAT_IEEE_FLOAT; wfx.nChannels = 2; wfx.nSamplesPerSec = m_nSamplesPerSec; wfx.wBitsPerSample = sizeof(float) * 8; wfx.nBlockAlign = wfx.nChannels * (wfx.wBitsPerSample / 8); wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; wfx.cbSize = 0; // First try 32-bit float (DirectX 9+) m_useFloat = true; if(FAILED(m_pMediaObject->SetInputType(0, &mt, 0)) || FAILED(m_pMediaObject->SetOutputType(0, &mt, 0))) { m_useFloat = false; // Try again with 16-bit PCM mt.lSampleSize = 2 * sizeof(int16); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.wBitsPerSample = sizeof(int16) * 8; wfx.nBlockAlign = wfx.nChannels * (wfx.wBitsPerSample / 8); wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; if(FAILED(m_pMediaObject->SetInputType(0, &mt, 0)) || FAILED(m_pMediaObject->SetOutputType(0, &mt, 0))) { #ifdef DMO_LOG MPT_LOG_GLOBAL(LogDebug, "DMO", U_("DMO: Failed to set I/O media type")); #endif } } } void DMOPlugin::PositionChanged() { m_pMediaObject->Discontinuity(0); m_pMediaObject->Flush(); } void DMOPlugin::Suspend() { m_isResumed = false; m_pMediaObject->Flush(); m_pMediaObject->SetInputType(0, nullptr, DMO_SET_TYPEF_CLEAR); m_pMediaObject->SetOutputType(0, nullptr, DMO_SET_TYPEF_CLEAR); } #ifdef MODPLUG_TRACKER CString DMOPlugin::GetParamName(PlugParamIndex param) { if(param < GetNumParameters() && m_pParamInfo != nullptr) { MP_PARAMINFO mpi; mpi.mpType = MPT_INT; mpi.szUnitText[0] = 0; mpi.szLabel[0] = 0; if(m_pParamInfo->GetParamInfo(param, &mpi) == S_OK) { return mpt::ToCString(mpi.szLabel); } } return CString(); } CString DMOPlugin::GetParamLabel(PlugParamIndex param) { if(param < GetNumParameters() && m_pParamInfo != nullptr) { MP_PARAMINFO mpi; mpi.mpType = MPT_INT; mpi.szUnitText[0] = 0; mpi.szLabel[0] = 0; if(m_pParamInfo->GetParamInfo(param, &mpi) == S_OK) { return mpt::ToCString(mpi.szUnitText); } } return CString(); } CString DMOPlugin::GetParamDisplay(PlugParamIndex param) { if(param < GetNumParameters() && m_pParamInfo != nullptr && m_pMediaParams != nullptr) { MP_PARAMINFO mpi; mpi.mpType = MPT_INT; mpi.szUnitText[0] = 0; mpi.szLabel[0] = 0; if (m_pParamInfo->GetParamInfo(param, &mpi) == S_OK) { MP_DATA md; if(m_pMediaParams->GetParam(param, &md) == S_OK) { switch(mpi.mpType) { case MPT_FLOAT: { CString s; s.Format(_T("%.2f"), md); return s; } break; case MPT_BOOL: return ((int)md) ? _T("Yes") : _T("No"); break; case MPT_ENUM: { WCHAR *text = nullptr; m_pParamInfo->GetParamText(param, &text); const int nValue = mpt::saturate_round(md * (mpi.mpdMaxValue - mpi.mpdMinValue)); // Always skip first two strings (param name, unit name) for(int i = 0; i < nValue + 2; i++) { text += wcslen(text) + 1; } return mpt::ToCString(text); } break; case MPT_INT: default: { CString s; s.Format(_T("%d"), mpt::saturate_round(md)); return s; } break; } } } } return CString(); } #endif // MODPLUG_TRACKER #else // !MPT_WITH_DMO MPT_MSVC_WORKAROUND_LNK4221(DMOPlugin) #endif // MPT_WITH_DMO OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/DMOPlugin.h0000644000175000017500000000566614722730163022326 00000000000000/* * DMOPlugin.h * ----------- * Purpose: DirectX Media Object plugin handling / processing. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #if defined(MPT_WITH_DMO) #include "../PlugInterface.h" #include #include typedef interface IMediaObject IMediaObject; typedef interface IMediaObjectInPlace IMediaObjectInPlace; typedef interface IMediaParamInfo IMediaParamInfo; typedef interface IMediaParams IMediaParams; OPENMPT_NAMESPACE_BEGIN class DMOPlugin final : public IMixPlugin { protected: IMediaObject *m_pMediaObject; IMediaObjectInPlace *m_pMediaProcess; IMediaParamInfo *m_pParamInfo; IMediaParams *m_pMediaParams; uint32 m_nSamplesPerSec; const uint32 m_uid; union { int16 *i16; float *f32; } m_alignedBuffer; union { int16 i16[MIXBUFFERSIZE * 2 + 16]; // 16-bit PCM Stereo interleaved float f32[MIXBUFFERSIZE * 2 + 16]; // 32-bit Float Stereo interleaved } m_interleavedBuffer; bool m_useFloat; public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); protected: DMOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, IMediaObject *pMO, IMediaObjectInPlace *pMOIP, uint32 uid); ~DMOPlugin(); public: int32 GetUID() const override { return m_uid; } int32 GetVersion() const override { return 2; } void Idle() override { } uint32 GetLatency() const override; void Process(float *pOutL, float *pOutR, uint32 numFrames) override; int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } void SetCurrentProgram(int32 /*nIndex*/) override { } PlugParamIndex GetNumParameters() const override; PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override; void PositionChanged() override; bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return CString(); } CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex param) override; CString GetParamDisplay(PlugParamIndex param) override; // TODO we could simply add our own preset mechanism. But is it really useful for these plugins? CString GetCurrentProgramName() override { return CString(); } void SetCurrentProgramName(const CString &) override { } CString GetProgramName(int32) override { return CString(); } bool HasEditor() const override { return false; } #endif int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } }; OPENMPT_NAMESPACE_END #endif // MPT_WITH_DMO libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/I3DL2Reverb.h0000644000175000017500000001202314722730163022434 00000000000000/* * I3DL2Reverb.h * ------------- * Purpose: Implementation of the DMO I3DL2Reverb DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #ifndef NO_PLUGINS #include "../PlugInterface.h" OPENMPT_NAMESPACE_BEGIN namespace DMO { class I3DL2Reverb final : public IMixPlugin { protected: enum Parameters { kI3DL2ReverbRoom = 0, kI3DL2ReverbRoomHF, kI3DL2ReverbRoomRolloffFactor, // Doesn't actually do anything :) kI3DL2ReverbDecayTime, kI3DL2ReverbDecayHFRatio, kI3DL2ReverbReflections, kI3DL2ReverbReflectionsDelay, kI3DL2ReverbReverb, kI3DL2ReverbReverbDelay, kI3DL2ReverbDiffusion, kI3DL2ReverbDensity, kI3DL2ReverbHFReference, kI3DL2ReverbQuality, kI3DL2ReverbNumParameters }; enum QualityFlags { kMoreDelayLines = 0x01, kFullSampleRate = 0x02, }; class DelayLine : private std::vector { int32 m_length = 0; int32 m_position = 0; int32 m_delayPosition = 0; public: void Init(int32 ms, int32 padding, uint32 sampleRate, int32 delayTap = 0); void SetDelayTap(int32 delayTap); void Advance(); void Set(float value); float Get(int32 offset) const; float Get() const; }; std::array m_param; int32 m_program = 0; // Calculated parameters uint32 m_quality; float m_effectiveSampleRate; float m_diffusion; float m_roomFilter; float m_ERLevel; float m_ReverbLevelL; float m_ReverbLevelR; int32 m_delayTaps[15]; // 6*L + 6*R + LR + Early L + Early R int32 m_earlyTaps[2][6]; float m_delayCoeffs[13][2]; // State DelayLine m_delayLines[19]; float m_filterHist[19]; // Remaining frame for downsampled reverb float m_prevL; float m_prevR; bool m_remain = false; bool m_ok = false, m_recalcParams = true; public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); I3DL2Reverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); int32 GetUID() const override { return 0xEF985E71; } int32 GetVersion() const override { return 0; } void Idle() override { } uint32 GetLatency() const override { return 0; } void Process(float *pOutL, float *pOutR, uint32 numFrames) override; float RenderSilence(uint32) override { return 0.0f; } int32 GetNumPrograms() const override; int32 GetCurrentProgram() override { return m_program; } // cppcheck-suppress virtualCallInConstructor void SetCurrentProgram(int32) override; PlugParamIndex GetNumParameters() const override { return kI3DL2ReverbNumParameters; } PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override { m_isResumed = false; } void PositionChanged() override; bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("I3DL2Reverb"); } CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; CString GetCurrentProgramName() override; void SetCurrentProgramName(const CString &) override { } CString GetProgramName(int32 program) override; bool HasEditor() const override { return false; } #endif void BeginSetProgram(int32) override { } void EndSetProgram() override { } int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } protected: float Room() const { return -10000.0f + m_param[kI3DL2ReverbRoom] * 10000.0f; } float RoomHF() const { return -10000.0f + m_param[kI3DL2ReverbRoomHF] * 10000.0f; } float RoomRolloffFactor() const { return m_param[kI3DL2ReverbRoomRolloffFactor] * 10.0f; } float DecayTime() const { return 0.1f + m_param[kI3DL2ReverbDecayTime] * 19.9f; } float DecayHFRatio() const { return 0.1f + m_param[kI3DL2ReverbDecayHFRatio] * 1.9f; } float Reflections() const { return -10000.0f + m_param[kI3DL2ReverbReflections] * 11000.0f; } float ReflectionsDelay() const { return m_param[kI3DL2ReverbReflectionsDelay] * 0.3f; } float Reverb() const { return -10000.0f + m_param[kI3DL2ReverbReverb] * 12000.0f; } float ReverbDelay() const { return m_param[kI3DL2ReverbReverbDelay] * 0.1f; } float Diffusion() const { return m_param[kI3DL2ReverbDiffusion] * 100.0f; } float Density() const { return m_param[kI3DL2ReverbDensity] * 100.0f; } float HFReference() const { return 20.0f + m_param[kI3DL2ReverbHFReference] * 19980.0f; } uint32 Quality() const { return mpt::saturate_round(m_param[kI3DL2ReverbQuality] * 3.0f); } void RecalculateI3DL2ReverbParams(); void SetDelayTaps(); void SetDecayCoeffs(); float CalcDecayCoeffs(int32 index); }; } // namespace DMO OPENMPT_NAMESPACE_END #endif // !NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Compressor.cpp0000644000175000017500000001313715016303107023176 00000000000000/* * Compressor.cpp * --------------- * Purpose: Implementation of the DMO Compressor DSP (for non-Windows platforms) * Notes : The original plugin's integer and floating point code paths only * behave identically when feeding floating point numbers in range * [-32768, +32768] rather than the usual [-1, +1] into the plugin. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "../../Sndfile.h" #include "Compressor.h" #include "DMOUtils.h" #include "mpt/base/numbers.hpp" #endif // !NO_PLUGINS OPENMPT_NAMESPACE_BEGIN #ifndef NO_PLUGINS namespace DMO { IMixPlugin* Compressor::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Compressor(factory, sndFile, mixStruct); } Compressor::Compressor(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) { m_param[kCompGain] = 0.5f; m_param[kCompAttack] = 0.02f; m_param[kCompRelease] = 150.0f / 2950.0f; m_param[kCompThreshold] = 2.0f / 3.0f; m_param[kCompRatio] = 0.02f; m_param[kCompPredelay] = 1.0f; m_mixBuffer.Initialize(2, 2); } void Compressor::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(!m_bufSize || !m_mixBuffer.Ok()) return; const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) }; float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) }; for(uint32 i = numFrames; i != 0; i--) { float leftIn = *(in[0])++; float rightIn = *(in[1])++; m_buffer[m_bufPos * 2] = leftIn; m_buffer[m_bufPos * 2 + 1] = rightIn; leftIn = std::abs(leftIn); rightIn = std::abs(rightIn); float mono = (leftIn + rightIn) * (0.5f * 32768.0f * 32768.0f); float monoLog = std::abs(logGain(mono, 31, 5)) * (1.0f / float(1u << 31)); float newPeak = monoLog + (m_peak - monoLog) * ((m_peak <= monoLog) ? m_attack : m_release); m_peak = newPeak; if(newPeak < m_threshold) newPeak = m_threshold; float compGain = (m_threshold - newPeak) * m_ratio + 0.9999999f; // Computes 2 ^ (2 ^ (log2(x) - 26) - 1) (x = 0...2^31) uint32 compGainInt = static_cast(compGain * 2147483648.0f); uint32 compGainPow = compGainInt << 5; compGainInt >>= 26; if(compGainInt) // compGainInt >= 2^26 { compGainPow |= 0x80000000u; compGainInt--; } compGainPow >>= (31 - compGainInt); int32 readOffset = m_predelay + m_bufSize - 1; readOffset /= 4096; readOffset = (readOffset + m_bufPos) % m_bufSize; float outGain = (static_cast(compGainPow) * (1.0f / 2147483648.0f)) * m_gain; *(out[0])++ = m_buffer[readOffset * 2] * outGain; *(out[1])++ = m_buffer[readOffset * 2 + 1] * outGain; if(m_bufPos-- == 0) m_bufPos += m_bufSize; } ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } PlugParamValue Compressor::GetParameter(PlugParamIndex index) { if(index < kCompNumParameters) { return m_param[index]; } return 0; } void Compressor::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < kCompNumParameters) { value = mpt::safe_clamp(value, 0.0f, 1.0f); m_param[index] = value; RecalculateCompressorParams(); } } void Compressor::Resume() { m_isResumed = true; PositionChanged(); RecalculateCompressorParams(); } void Compressor::PositionChanged() { m_bufSize = Util::muldiv(m_SndFile.GetSampleRate(), 200, 1000); try { m_buffer.assign(m_bufSize * 2, 0.0f); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); m_bufSize = 0; } m_bufPos = 0; m_peak = 0.0f; } #ifdef MODPLUG_TRACKER CString Compressor::GetParamName(PlugParamIndex param) { switch(param) { case kCompGain: return _T("Gain"); case kCompAttack: return _T("Attack"); case kCompRelease: return _T("Release"); case kCompThreshold: return _T("Threshold"); case kCompRatio: return _T("Ratio"); case kCompPredelay: return _T("Predelay"); } return CString(); } CString Compressor::GetParamLabel(PlugParamIndex param) { switch(param) { case kCompGain: case kCompThreshold: return _T("dB"); case kCompAttack: case kCompRelease: case kCompPredelay: return _T("ms"); case kCompRatio: return _T(": 1"); } return CString(); } CString Compressor::GetParamDisplay(PlugParamIndex param) { float value = m_param[param]; switch(param) { case kCompGain: value = GainInDecibel(); break; case kCompAttack: value = AttackTime(); break; case kCompRelease: value = ReleaseTime(); break; case kCompThreshold: value = ThresholdInDecibel(); break; case kCompRatio: value = CompressorRatio(); break; case kCompPredelay: value = PreDelay(); break; } CString s; s.Format(_T("%.2f"), value); return s; } #endif // MODPLUG_TRACKER void Compressor::RecalculateCompressorParams() { const float sampleRate = static_cast(m_SndFile.GetSampleRate()) / 1000.0f; m_gain = std::pow(10.0f, GainInDecibel() / 20.0f); m_attack = std::pow(10.0f, -1.0f / (AttackTime() * sampleRate)); m_release = std::pow(10.0f, -1.0f / (ReleaseTime() * sampleRate)); const float _2e31 = float(1u << 31); const float _2e26 = float(1u << 26); m_threshold = std::min((_2e31 - 1.0f), (std::log(std::pow(10.0f, ThresholdInDecibel() / 20.0f) * _2e31) * _2e26) / mpt::numbers::ln2_v + _2e26) * (1.0f / _2e31); m_ratio = 1.0f - (1.0f / CompressorRatio()); m_predelay = static_cast((PreDelay() * sampleRate) + 2.0f); } } // namespace DMO #else MPT_MSVC_WORKAROUND_LNK4221(Compressor) #endif // !NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Gargle.h0000644000175000017500000000477714722730163021733 00000000000000/* * Gargle.h * -------- * Purpose: Implementation of the DMO Gargle DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef NO_PLUGINS #include "../PlugInterface.h" OPENMPT_NAMESPACE_BEGIN namespace DMO { class Gargle final : public IMixPlugin { protected: enum Parameters { kGargleRate = 0, kGargleWaveShape, kGargleNumParameters }; std::array m_param; uint32 m_period, m_periodHalf, m_counter; // In frames public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); Gargle(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); int32 GetUID() const override { return 0xDAFD8210; } int32 GetVersion() const override { return 0; } void Idle() override { } uint32 GetLatency() const override { return 0; } void Process(float *pOutL, float *pOutR, uint32 numFrames) override; float RenderSilence(uint32) override { return 0.0f; } int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } void SetCurrentProgram(int32) override { } PlugParamIndex GetNumParameters() const override { return kGargleNumParameters; } PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override { m_isResumed = false; } void PositionChanged() override { m_counter = 0; } bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("Gargle"); } CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; CString GetCurrentProgramName() override { return CString(); } void SetCurrentProgramName(const CString &) override { } CString GetProgramName(int32) override { return CString(); } bool HasEditor() const override { return false; } #endif int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } protected: uint32 RateInHertz() const; void RecalculateGargleParams(); }; } // namespace DMO OPENMPT_NAMESPACE_END #endif // !NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/ParamEq.cpp0000644000175000017500000001041514722730163022375 00000000000000/* * ParamEq.cpp * ----------- * Purpose: Implementation of the DMO Parametric Equalizer DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "ParamEq.h" #include "../../Sndfile.h" #include "mpt/base/numbers.hpp" #endif // !NO_PLUGINS OPENMPT_NAMESPACE_BEGIN #ifndef NO_PLUGINS namespace DMO { IMixPlugin* ParamEq::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) ParamEq(factory, sndFile, mixStruct); } ParamEq::ParamEq(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_maxFreqParam(1.0f) { m_param[kEqCenter] = (8000.0f - 80.0f) / 15920.0f; m_param[kEqBandwidth] = 0.314286f; m_param[kEqGain] = 0.5f; m_mixBuffer.Initialize(2, 2); } void ParamEq::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(!m_mixBuffer.Ok()) return; const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) }; float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) }; if(m_param[kEqGain] == 0.5f) { memcpy(out[0], in[0], numFrames * sizeof(float)); memcpy(out[1], in[1], numFrames * sizeof(float)); } else { for(uint32 i = numFrames; i != 0; i--) { for(uint8 channel = 0; channel < 2; channel++) { float x = *(in[channel])++; float y = b0DIVa0 * x + b1DIVa0 * x1[channel] + b2DIVa0 * x2[channel] - a1DIVa0 * y1[channel] - a2DIVa0 * y2[channel]; x2[channel] = x1[channel]; x1[channel] = x; y2[channel] = y1[channel]; y1[channel] = y; *(out[channel])++ = y; } } } ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } PlugParamValue ParamEq::GetParameter(PlugParamIndex index) { if(index < kEqNumParameters) { return m_param[index]; } return 0; } void ParamEq::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < kEqNumParameters) { value = mpt::safe_clamp(value, 0.0f, 1.0f); m_param[index] = value; RecalculateEqParams(); } } void ParamEq::Resume() { m_isResumed = true; // Limit center frequency to a third of the sampling rate. m_maxFreqParam = Clamp((static_cast(m_SndFile.GetSampleRate()) / 3.0f - 80.0f) / 15920.0f, 0.0f, 1.0f); RecalculateEqParams(); PositionChanged(); } void ParamEq::PositionChanged() { // Reset filter state x1[0] = x2[0] = 0; x1[1] = x2[1] = 0; y1[0] = y2[0] = 0; y1[1] = y2[1] = 0; } #ifdef MODPLUG_TRACKER CString ParamEq::GetParamName(PlugParamIndex param) { switch(param) { case kEqCenter: return _T("Center"); case kEqBandwidth: return _T("Bandwidth"); case kEqGain: return _T("Gain"); } return CString(); } CString ParamEq::GetParamLabel(PlugParamIndex param) { switch(param) { case kEqCenter: return _T("Hz"); case kEqBandwidth: return _T("Semitones"); case kEqGain: return _T("dB"); } return CString(); } CString ParamEq::GetParamDisplay(PlugParamIndex param) { float value = 0.0f; switch(param) { case kEqCenter: value = FreqInHertz(); break; case kEqBandwidth: value = BandwidthInSemitones(); break; case kEqGain: value = GainInDecibel(); break; } CString s; s.Format(_T("%.2f"), value); return s; } #endif // MODPLUG_TRACKER void ParamEq::RecalculateEqParams() { LimitMax(m_param[kEqCenter], m_maxFreqParam); const float freq = FreqInHertz() / static_cast(m_SndFile.GetSampleRate()); const float a = std::pow(10.0f, GainInDecibel() / 40.0f); const float w0 = 2.0f * mpt::numbers::pi_v * freq; const float sinW0 = std::sin(w0); const float cosW0 = std::cos(w0); const float alpha = sinW0 * std::sinh((BandwidthInSemitones() * (mpt::numbers::ln2_v / 24.0f)) * w0 / sinW0); const float b0 = 1.0f + alpha * a; const float b1 = -2.0f * cosW0; const float b2 = 1.0f - alpha * a; const float a0 = 1.0f + alpha / a; const float a1 = -2.0f * cosW0; const float a2 = 1.0f - alpha / a; b0DIVa0 = b0 / a0; b1DIVa0 = b1 / a0; b2DIVa0 = b2 / a0; a1DIVa0 = a1 / a0; a2DIVa0 = a2 / a0; } } // namespace DMO #else MPT_MSVC_WORKAROUND_LNK4221(ParamEq) #endif // !NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/I3DL2Reverb.cpp0000644000175000017500000005010714722730163022774 00000000000000/* * I3DL2Reverb.cpp * --------------- * Purpose: Implementation of the DMO I3DL2Reverb DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "I3DL2Reverb.h" #include "../../Sndfile.h" #ifdef MODPLUG_TRACKER #include "../../../sounddsp/Reverb.h" #endif // MODPLUG_TRACKER #include "mpt/base/numbers.hpp" #endif // !NO_PLUGINS OPENMPT_NAMESPACE_BEGIN #ifndef NO_PLUGINS namespace DMO { void I3DL2Reverb::DelayLine::Init(int32 ms, int32 padding, uint32 sampleRate, int32 delayTap) { m_length = Util::muldiv(sampleRate, ms, 1000) + padding; m_position = 0; SetDelayTap(delayTap); assign(m_length, 0.0f); } void I3DL2Reverb::DelayLine::SetDelayTap(int32 delayTap) { if(m_length > 0) m_delayPosition = (delayTap + m_position + m_length) % m_length; } void I3DL2Reverb::DelayLine::Advance() { if(--m_position < 0) m_position += m_length; if(--m_delayPosition < 0) m_delayPosition += m_length; } MPT_FORCEINLINE void I3DL2Reverb::DelayLine::Set(float value) { at(m_position) = value; } float I3DL2Reverb::DelayLine::Get(int32 offset) const { offset = (offset + m_position) % m_length; if(offset < 0) offset += m_length; return at(offset); } MPT_FORCEINLINE float I3DL2Reverb::DelayLine::Get() const { return at(m_delayPosition); } IMixPlugin* I3DL2Reverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) I3DL2Reverb(factory, sndFile, mixStruct); } I3DL2Reverb::I3DL2Reverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) { m_param[kI3DL2ReverbRoom] = 0.9f; m_param[kI3DL2ReverbRoomHF] = 0.99f; m_param[kI3DL2ReverbRoomRolloffFactor] = 0.0f; m_param[kI3DL2ReverbDecayTime] = 0.07f; m_param[kI3DL2ReverbDecayHFRatio] = 0.3842105f; m_param[kI3DL2ReverbReflections] = 0.672545433f; m_param[kI3DL2ReverbReflectionsDelay] = 0.233333333f; m_param[kI3DL2ReverbReverb] = 0.85f; m_param[kI3DL2ReverbReverbDelay] = 0.11f; m_param[kI3DL2ReverbDiffusion] = 1.0f; m_param[kI3DL2ReverbDensity] = 1.0f; m_param[kI3DL2ReverbHFReference] = (5000.0f - 20.0f) / 19980.0f; m_param[kI3DL2ReverbQuality] = 2.0f / 3.0f; SetCurrentProgram(m_program); m_mixBuffer.Initialize(2, 2); } void I3DL2Reverb::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(m_recalcParams) { auto sampleRate = m_effectiveSampleRate; RecalculateI3DL2ReverbParams(); // Resize and clear delay lines if quality has changed if(sampleRate != m_effectiveSampleRate) PositionChanged(); } if(!m_ok || !m_mixBuffer.Ok()) return; const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) }; float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) }; uint32 frames = numFrames; if(!(m_quality & kFullSampleRate) && m_remain && frames > 0) { // Remaining frame from previous render call frames--; *(out[0]++) = m_prevL; *(out[1]++) = m_prevR; in[0]++; in[1]++; m_remain = false; } while(frames > 0) { // Apply room filter and insert into early reflection delay lines const float inL = *(in[0]++); const float inRoomL = (m_filterHist[12] - inL) * m_roomFilter + inL; m_filterHist[12] = inRoomL; m_delayLines[15].Set(inRoomL); const float inR = *(in[1]++); const float inRoomR = (m_filterHist[13] - inR) * m_roomFilter + inR; m_filterHist[13] = inRoomR; m_delayLines[16].Set(inRoomR); // Early reflections (left) float earlyL = m_delayLines[15].Get(m_earlyTaps[0][1]) * 0.68f - m_delayLines[15].Get(m_earlyTaps[0][2]) * 0.5f - m_delayLines[15].Get(m_earlyTaps[0][3]) * 0.62f - m_delayLines[15].Get(m_earlyTaps[0][4]) * 0.5f - m_delayLines[15].Get(m_earlyTaps[0][5]) * 0.62f; if(m_quality & kMoreDelayLines) { float earlyL2 = earlyL; earlyL = m_delayLines[13].Get() + earlyL * 0.618034f; m_delayLines[13].Set(earlyL2 - earlyL * 0.618034f); } const float earlyRefOutL = earlyL * m_ERLevel; m_filterHist[15] = m_delayLines[15].Get(m_earlyTaps[0][0]) + m_filterHist[15]; m_filterHist[16] = m_delayLines[16].Get(m_earlyTaps[1][0]) + m_filterHist[16]; // Lots of slightly different copy-pasta ahead float reverbL1, reverbL2, reverbL3, reverbR1, reverbR2, reverbR3; reverbL1 = -m_filterHist[15] * 0.707f; reverbL2 = m_filterHist[16] * 0.707f + reverbL1; reverbR2 = reverbL1 - m_filterHist[16] * 0.707f; m_filterHist[5] = (m_filterHist[5] - m_delayLines[5].Get()) * m_delayCoeffs[5][1] + m_delayLines[5].Get(); reverbL1 = m_filterHist[5] * m_delayCoeffs[5][0] + reverbL2 * m_diffusion; m_delayLines[5].Set(reverbL2 - reverbL1 * m_diffusion); reverbL2 = reverbL1; reverbL3 = -0.15f * reverbL1; m_filterHist[4] = (m_filterHist[4] - m_delayLines[4].Get()) * m_delayCoeffs[4][1] + m_delayLines[4].Get(); reverbL1 = m_filterHist[4] * m_delayCoeffs[4][0] + reverbL2 * m_diffusion; m_delayLines[4].Set(reverbL2 - reverbL1 * m_diffusion); reverbL2 = reverbL1; reverbL3 -= reverbL1 * 0.2f; if(m_quality & kMoreDelayLines) { m_filterHist[3] = (m_filterHist[3] - m_delayLines[3].Get()) * m_delayCoeffs[3][1] + m_delayLines[3].Get(); reverbL1 = m_filterHist[3] * m_delayCoeffs[3][0] + reverbL2 * m_diffusion; m_delayLines[3].Set(reverbL2 - reverbL1 * m_diffusion); reverbL2 = reverbL1; reverbL3 += 0.35f * reverbL1; m_filterHist[2] = (m_filterHist[2] - m_delayLines[2].Get()) * m_delayCoeffs[2][1] + m_delayLines[2].Get(); reverbL1 = m_filterHist[2] * m_delayCoeffs[2][0] + reverbL2 * m_diffusion; m_delayLines[2].Set(reverbL2 - reverbL1 * m_diffusion); reverbL2 = reverbL1; reverbL3 -= reverbL1 * 0.38f; } m_delayLines[17].Set(reverbL2); reverbL1 = m_delayLines[17].Get() * m_delayCoeffs[12][0]; m_filterHist[17] = (m_filterHist[17] - reverbL1) * m_delayCoeffs[12][1] + reverbL1; m_filterHist[1] = (m_filterHist[1] - m_delayLines[1].Get()) * m_delayCoeffs[1][1] + m_delayLines[1].Get(); reverbL1 = m_filterHist[17] * m_diffusion + m_filterHist[1] * m_delayCoeffs[1][0]; m_delayLines[1].Set(m_filterHist[17] - reverbL1 * m_diffusion); reverbL2 = reverbL1; float reverbL4 = reverbL1 * 0.38f; m_filterHist[0] = (m_filterHist[0] - m_delayLines[0].Get()) * m_delayCoeffs[0][1] + m_delayLines[0].Get(); reverbL1 = m_filterHist[0] * m_delayCoeffs[0][0] + reverbL2 * m_diffusion; m_delayLines[0].Set(reverbL2 - reverbL1 * m_diffusion); reverbL3 -= reverbL1 * 0.38f; m_filterHist[15] = reverbL1; // Early reflections (right) float earlyR = m_delayLines[16].Get(m_earlyTaps[1][1]) * 0.707f - m_delayLines[16].Get(m_earlyTaps[1][2]) * 0.6f - m_delayLines[16].Get(m_earlyTaps[1][3]) * 0.5f - m_delayLines[16].Get(m_earlyTaps[1][4]) * 0.6f - m_delayLines[16].Get(m_earlyTaps[1][5]) * 0.5f; if(m_quality & kMoreDelayLines) { float earlyR2 = earlyR; earlyR = m_delayLines[14].Get() + earlyR * 0.618034f; m_delayLines[14].Set(earlyR2 - earlyR * 0.618034f); } const float earlyRefOutR = earlyR * m_ERLevel; m_filterHist[11] = (m_filterHist[11] - m_delayLines[11].Get()) * m_delayCoeffs[11][1] + m_delayLines[11].Get(); reverbR1 = m_filterHist[11] * m_delayCoeffs[11][0] + reverbR2 * m_diffusion; m_delayLines[11].Set(reverbR2 - reverbR1 * m_diffusion); reverbR2 = reverbR1; m_filterHist[10] = (m_filterHist[10] - m_delayLines[10].Get()) * m_delayCoeffs[10][1] + m_delayLines[10].Get(); reverbR1 = m_filterHist[10] * m_delayCoeffs[10][0] + reverbR2 * m_diffusion; m_delayLines[10].Set(reverbR2 - reverbR1 * m_diffusion); reverbR3 = reverbL4 - reverbR2 * 0.15f - reverbR1 * 0.2f; reverbR2 = reverbR1; if(m_quality & kMoreDelayLines) { m_filterHist[9] = (m_filterHist[9] - m_delayLines[9].Get()) * m_delayCoeffs[9][1] + m_delayLines[9].Get(); reverbR1 = m_filterHist[9] * m_delayCoeffs[9][0] + reverbR2 * m_diffusion; m_delayLines[9].Set(reverbR2 - reverbR1 * m_diffusion); reverbR2 = reverbR1; reverbR3 += reverbR1 * 0.35f; m_filterHist[8] = (m_filterHist[8] - m_delayLines[8].Get()) * m_delayCoeffs[8][1] + m_delayLines[8].Get(); reverbR1 = m_filterHist[8] * m_delayCoeffs[8][0] + reverbR2 * m_diffusion; m_delayLines[8].Set(reverbR2 - reverbR1 * m_diffusion); reverbR2 = reverbR1; reverbR3 -= reverbR1 * 0.38f; } m_delayLines[18].Set(reverbR2); reverbR1 = m_delayLines[18].Get() * m_delayCoeffs[12][0]; m_filterHist[18] = (m_filterHist[18] - reverbR1) * m_delayCoeffs[12][1] + reverbR1; m_filterHist[7] = (m_filterHist[7] - m_delayLines[7].Get()) * m_delayCoeffs[7][1] + m_delayLines[7].Get(); reverbR1 = m_filterHist[18] * m_diffusion + m_filterHist[7] * m_delayCoeffs[7][0]; m_delayLines[7].Set(m_filterHist[18] - reverbR1 * m_diffusion); reverbR2 = reverbR1; float lateRevOutL = (reverbL3 + reverbR1 * 0.38f) * m_ReverbLevelL; m_filterHist[6] = (m_filterHist[6] - m_delayLines[6].Get()) * m_delayCoeffs[6][1] + m_delayLines[6].Get(); reverbR1 = m_filterHist[6] * m_delayCoeffs[6][0] + reverbR2 * m_diffusion; m_delayLines[6].Set(reverbR2 - reverbR1 * m_diffusion); m_filterHist[16] = reverbR1; float lateRevOutR = (reverbR3 - reverbR1 * 0.38f) * m_ReverbLevelR; float outL = earlyRefOutL + lateRevOutL; float outR = earlyRefOutR + lateRevOutR; for(auto &line : m_delayLines) line.Advance(); if(!(m_quality & kFullSampleRate)) { *(out[0]++) = (outL + m_prevL) * 0.5f; *(out[1]++) = (outR + m_prevR) * 0.5f; m_prevL = outL; m_prevR = outR; in[0]++; in[1]++; if(frames-- == 1) { m_remain = true; break; } } *(out[0]++) = outL; *(out[1]++) = outR; frames--; } ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } int32 I3DL2Reverb::GetNumPrograms() const { #ifdef MODPLUG_TRACKER return NUM_REVERBTYPES; #else return 0; #endif } void I3DL2Reverb::SetCurrentProgram(int32 program) { #ifdef MODPLUG_TRACKER if(program < static_cast(NUM_REVERBTYPES)) { m_program = program; const auto &preset = *GetReverbPreset(m_program); m_param[kI3DL2ReverbRoom] = (preset.lRoom + 10000) / 10000.0f; m_param[kI3DL2ReverbRoomHF] = (preset.lRoomHF + 10000) / 10000.0f; m_param[kI3DL2ReverbRoomRolloffFactor] = 0.0f; m_param[kI3DL2ReverbDecayTime] = (preset.flDecayTime - 0.1f) / 19.9f; m_param[kI3DL2ReverbDecayHFRatio] = (preset.flDecayHFRatio - 0.1f) / 1.9f; m_param[kI3DL2ReverbReflections] = (preset.lReflections + 10000) / 11000.0f; m_param[kI3DL2ReverbReflectionsDelay] = preset.flReflectionsDelay / 0.3f; m_param[kI3DL2ReverbReverb] = (preset.lReverb + 10000) / 12000.0f; m_param[kI3DL2ReverbReverbDelay] = preset.flReverbDelay / 0.1f; m_param[kI3DL2ReverbDiffusion] = preset.flDiffusion / 100.0f; m_param[kI3DL2ReverbDensity] = preset.flDensity / 100.0f; m_param[kI3DL2ReverbHFReference] = (5000.0f - 20.0f) / 19980.0f; RecalculateI3DL2ReverbParams(); } #else MPT_UNUSED_VARIABLE(program); #endif } PlugParamValue I3DL2Reverb::GetParameter(PlugParamIndex index) { if(index < kI3DL2ReverbNumParameters) { return m_param[index]; } return 0; } void I3DL2Reverb::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < kI3DL2ReverbNumParameters) { value = mpt::safe_clamp(value, 0.0f, 1.0f); if(index == kI3DL2ReverbQuality) value = mpt::round(value * 3.0f) / 3.0f; m_param[index] = value; m_recalcParams = true; } } void I3DL2Reverb::Resume() { RecalculateI3DL2ReverbParams(); PositionChanged(); m_isResumed = true; } void I3DL2Reverb::PositionChanged() { MemsetZero(m_filterHist); m_prevL = 0; m_prevR = 0; m_remain = false; try { uint32 sampleRate = static_cast(m_effectiveSampleRate); m_delayLines[0].Init(67, 5, sampleRate, m_delayTaps[0]); m_delayLines[1].Init(62, 5, sampleRate, m_delayTaps[1]); m_delayLines[2].Init(53, 5, sampleRate, m_delayTaps[2]); m_delayLines[3].Init(43, 5, sampleRate, m_delayTaps[3]); m_delayLines[4].Init(32, 5, sampleRate, m_delayTaps[4]); m_delayLines[5].Init(22, 5, sampleRate, m_delayTaps[5]); m_delayLines[6].Init(75, 5, sampleRate, m_delayTaps[6]); m_delayLines[7].Init(69, 5, sampleRate, m_delayTaps[7]); m_delayLines[8].Init(60, 5, sampleRate, m_delayTaps[8]); m_delayLines[9].Init(48, 5, sampleRate, m_delayTaps[9]); m_delayLines[10].Init(36, 5, sampleRate, m_delayTaps[10]); m_delayLines[11].Init(25, 5, sampleRate, m_delayTaps[11]); m_delayLines[12].Init(0, 0, 0); // Dummy for array index consistency with both tap and coefficient arrays m_delayLines[13].Init(3, 0, sampleRate, m_delayTaps[13]); m_delayLines[14].Init(3, 0, sampleRate, m_delayTaps[14]); m_delayLines[15].Init(407, 1, sampleRate); m_delayLines[16].Init(400, 1, sampleRate); m_delayLines[17].Init(10, 0, sampleRate, -1); m_delayLines[18].Init(10, 0, sampleRate, -1); m_ok = true; } catch(mpt::out_of_memory e) { m_ok = false; mpt::delete_out_of_memory(e); } } #ifdef MODPLUG_TRACKER CString I3DL2Reverb::GetParamName(PlugParamIndex param) { switch(param) { case kI3DL2ReverbRoom: return _T("Room"); case kI3DL2ReverbRoomHF: return _T("RoomHF"); case kI3DL2ReverbRoomRolloffFactor: return _T("RoomRolloffFactor"); case kI3DL2ReverbDecayTime: return _T("DecayTime"); case kI3DL2ReverbDecayHFRatio: return _T("DecayHFRatio"); case kI3DL2ReverbReflections: return _T("Reflections"); case kI3DL2ReverbReflectionsDelay: return _T("ReflectionsDelay"); case kI3DL2ReverbReverb: return _T("Reverb"); case kI3DL2ReverbReverbDelay: return _T("ReverbDelay"); case kI3DL2ReverbDiffusion: return _T("Diffusion"); case kI3DL2ReverbDensity: return _T("Density"); case kI3DL2ReverbHFReference: return _T("HFRefrence"); case kI3DL2ReverbQuality: return _T("Quality"); } return CString(); } CString I3DL2Reverb::GetParamLabel(PlugParamIndex param) { switch(param) { case kI3DL2ReverbRoom: case kI3DL2ReverbRoomHF: case kI3DL2ReverbReflections: case kI3DL2ReverbReverb: return _T("dB"); case kI3DL2ReverbDecayTime: case kI3DL2ReverbReflectionsDelay: case kI3DL2ReverbReverbDelay: return _T("s"); case kI3DL2ReverbDiffusion: case kI3DL2ReverbDensity: return _T("%"); case kI3DL2ReverbHFReference: return _T("Hz"); } return CString(); } CString I3DL2Reverb::GetParamDisplay(PlugParamIndex param) { static constexpr const TCHAR * const modes[] = { _T("LQ"), _T("LQ+"), _T("HQ"), _T("HQ+") }; float value = m_param[param]; switch(param) { case kI3DL2ReverbRoom: value = Room() * 0.01f; break; case kI3DL2ReverbRoomHF: value = RoomHF() * 0.01f; break; case kI3DL2ReverbRoomRolloffFactor: value = RoomRolloffFactor(); break; case kI3DL2ReverbDecayTime: value = DecayTime(); break; case kI3DL2ReverbDecayHFRatio: value = DecayHFRatio(); break; case kI3DL2ReverbReflections: value = Reflections() * 0.01f; break; case kI3DL2ReverbReflectionsDelay: value = ReflectionsDelay(); break; case kI3DL2ReverbReverb: value = Reverb() * 0.01f; break; case kI3DL2ReverbReverbDelay: value = ReverbDelay(); break; case kI3DL2ReverbDiffusion: value = Diffusion(); break; case kI3DL2ReverbDensity: value = Density(); break; case kI3DL2ReverbHFReference: value = HFReference(); break; case kI3DL2ReverbQuality: return modes[Quality() % 4u]; } CString s; s.Format(_T("%.2f"), value); return s; } CString I3DL2Reverb::GetCurrentProgramName() { return GetProgramName(m_program); } CString I3DL2Reverb::GetProgramName(int32 program) { return mpt::ToCString(GetReverbPresetName(program)); } #endif // MODPLUG_TRACKER void I3DL2Reverb::RecalculateI3DL2ReverbParams() { m_quality = Quality(); m_effectiveSampleRate = static_cast(m_SndFile.GetSampleRate() / ((m_quality & kFullSampleRate) ? 1u : 2u)); // Diffusion m_diffusion = Diffusion() * (0.618034f / 100.0f); // Early Reflection Level m_ERLevel = std::min(std::pow(10.0f, (Room() + Reflections()) / (100.0f * 20.0f)), 1.0f) * 0.761f; // Room Filter float roomHF = std::pow(10.0f, RoomHF() / 100.0f / 10.0f); if(roomHF == 1.0f) { m_roomFilter = 0.0f; } else { float freq = std::min(std::cos(HFReference() * (2.0f * mpt::numbers::pi_v) / m_effectiveSampleRate), 0.9999f); float roomFilter = (freq * (roomHF + roomHF) - 2.0f + std::sqrt(freq * (roomHF * roomHF * freq * 4.0f) + roomHF * 8.0f - roomHF * roomHF * 4.0f - roomHF * freq * 8.0f)) / (roomHF + roomHF - 2.0f); m_roomFilter = Clamp(roomFilter, 0.0f, 1.0f); } SetDelayTaps(); SetDecayCoeffs(); m_recalcParams = false; } void I3DL2Reverb::SetDelayTaps() { // Early reflections static constexpr float delays[] = { 1.0000f, 1.0000f, 0.0000f, 0.1078f, 0.1768f, 0.2727f, 0.3953f, 0.5386f, 0.6899f, 0.8306f, 0.9400f, 0.9800f, }; const float sampleRate = m_effectiveSampleRate; const float reflectionsDelay = ReflectionsDelay(); const float reverbDelay = std::max(ReverbDelay(), 5.0f / 1000.0f); m_earlyTaps[0][0] = static_cast((reverbDelay + reflectionsDelay + 7.0f / 1000.0f) * sampleRate); for(uint32 i = 1; i < 12; i++) { m_earlyTaps[i % 2u][i / 2u] = static_cast((reverbDelay * delays[i] + reflectionsDelay) * sampleRate); } // Late reflections float density = std::min((Density() / 100.0f + 0.1f) * 0.9091f, 1.0f); float delayL = density * 67.0f / 1000.0f * sampleRate; float delayR = density * 75.0f / 1000.0f * sampleRate; for(int i = 0, power = 0; i < 6; i++) { power += i; float factor = std::pow(0.93f, static_cast(power)); m_delayTaps[i + 0] = static_cast(delayL * factor); m_delayTaps[i + 6] = static_cast(delayR * factor); } m_delayTaps[12] = static_cast(10.0f / 1000.0f * sampleRate); // Early reflections (extra delay lines) m_delayTaps[13] = static_cast(3.25f / 1000.0f * sampleRate); m_delayTaps[14] = static_cast(3.53f / 1000.0f * sampleRate); for(std::size_t d = 0; d < std::size(m_delayTaps); d++) m_delayLines[d].SetDelayTap(m_delayTaps[d]); } void I3DL2Reverb::SetDecayCoeffs() { float levelLtmp = 1.0f, levelRtmp = 1.0f; float levelL = 0.0f, levelR = 0.0f; levelLtmp *= CalcDecayCoeffs(5); levelRtmp *= CalcDecayCoeffs(11); levelL += levelLtmp * 0.0225f; levelR += levelRtmp * 0.0225f; levelLtmp *= CalcDecayCoeffs(4); levelRtmp *= CalcDecayCoeffs(10); levelL += levelLtmp * 0.04f; levelR += levelRtmp * 0.04f; if(m_quality & kMoreDelayLines) { levelLtmp *= CalcDecayCoeffs(3); levelRtmp *= CalcDecayCoeffs(9); levelL += levelLtmp * 0.1225f; levelR += levelRtmp * 0.1225f; levelLtmp *= CalcDecayCoeffs(2); levelRtmp *= CalcDecayCoeffs(8); levelL += levelLtmp * 0.1444f; levelR += levelRtmp * 0.1444f; } CalcDecayCoeffs(12); levelLtmp *= m_delayCoeffs[12][0] * m_delayCoeffs[12][0]; levelRtmp *= m_delayCoeffs[12][0] * m_delayCoeffs[12][0]; levelLtmp *= CalcDecayCoeffs(1); levelRtmp *= CalcDecayCoeffs(7); levelL += levelRtmp * 0.1444f; levelR += levelLtmp * 0.1444f; levelLtmp *= CalcDecayCoeffs(0); levelRtmp *= CalcDecayCoeffs(6); levelL += levelLtmp * 0.1444f; levelR += levelRtmp * 0.1444f; // Final Reverb Level float level = std::min(std::pow(10.0f, (Room() + Reverb()) / (100.0f * 20.0f)), 1.0f); float monoInv = 1.0f - ((levelLtmp + levelRtmp) * 0.5f); m_ReverbLevelL = level * std::sqrt(monoInv / levelL); m_ReverbLevelR = level * std::sqrt(monoInv / levelR); } float I3DL2Reverb::CalcDecayCoeffs(int32 index) { float hfRef = (2.0f * mpt::numbers::pi_v) / m_effectiveSampleRate * HFReference(); float decayHFRatio = DecayHFRatio(); if(decayHFRatio > 1.0f) hfRef = mpt::numbers::pi_v; float c1 = std::pow(10.0f, ((static_cast(m_delayTaps[index]) / m_effectiveSampleRate) * -60.0f / DecayTime()) / 20.0f); float c2 = 0.0f; float c21 = (std::pow(c1, 2.0f - 2.0f / decayHFRatio) - 1.0f) / (1.0f - std::cos(hfRef)); if(c21 != 0 && std::isfinite(c21)) { float c22 = -2.0f * c21 - 2.0f; float c23sq = c22 * c22 - c21 * c21 * 4.0f; float c23 = c23sq > 0.0f ? std::sqrt(c23sq) : 0.0f; c2 = (c23 - c22) / (c21 + c21); if(std::abs(c2) > 1.0f) c2 = (-c22 - c23) / (c21 + c21); c2 = mpt::sanitize_nan(c2); } m_delayCoeffs[index][0] = c1; m_delayCoeffs[index][1] = c2; c1 *= c1; float diff2 = m_diffusion * m_diffusion; return diff2 + c1 / (1.0f - diff2 * c1) * (1.0f - diff2) * (1.0f - diff2); } } // namespace DMO #else MPT_MSVC_WORKAROUND_LNK4221(I3DL2Reverb) #endif // !NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/WavesReverb.cpp0000644000175000017500000001716214722730163023310 00000000000000/* * WavesReverb.cpp * --------------- * Purpose: Implementation of the DMO WavesReverb DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "WavesReverb.h" #include "../../Sndfile.h" #endif // !NO_PLUGINS OPENMPT_NAMESPACE_BEGIN #ifndef NO_PLUGINS namespace DMO { IMixPlugin* WavesReverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) WavesReverb(factory, sndFile, mixStruct); } WavesReverb::WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) { m_param[kRvbInGain] = 1.0f; m_param[kRvbReverbMix] = 1.0f; m_param[kRvbReverbTime] = 1.0f / 3.0f; m_param[kRvbHighFreqRTRatio] = 0.0f; m_mixBuffer.Initialize(2, 2); } void WavesReverb::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(!m_mixBuffer.Ok()) return; const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) }; float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) }; uint32 combPos = m_state.combPos, allpassPos = m_state.allpassPos; uint32 delay0 = (m_delay[0] + combPos + 1) & 0xFFF; uint32 delay1 = (m_delay[1] + combPos + 1) & 0xFFF; uint32 delay2 = (m_delay[2] + combPos + 1) & 0xFFF; uint32 delay3 = (m_delay[3] + combPos + 1) & 0xFFF; uint32 delay4 = (m_delay[4] + allpassPos) & 0x3FF; uint32 delay5 = (m_delay[5] + allpassPos) & 0x3FF; float delay0old = m_state.comb[delay0][0]; float delay1old = m_state.comb[delay1][1]; float delay2old = m_state.comb[delay2][2]; float delay3old = m_state.comb[delay3][3]; for(uint32 i = numFrames; i != 0; i--) { const float leftIn = *(in[0])++ + 1e-30f; // Prevent denormals const float rightIn = *(in[1])++ + 1e-30f; // Prevent denormals // Advance buffer index for the four comb filters delay0 = (delay0 - 1) & 0xFFF; delay1 = (delay1 - 1) & 0xFFF; delay2 = (delay2 - 1) & 0xFFF; delay3 = (delay3 - 1) & 0xFFF; float &delay0new = m_state.comb[delay0][0]; float &delay1new = m_state.comb[delay1][1]; float &delay2new = m_state.comb[delay2][2]; float &delay3new = m_state.comb[delay3][3]; float r1, r2; r1 = delay1new * 0.61803401f + m_state.allpass1[delay4][0] * m_coeffs[0]; r2 = m_state.allpass1[delay4][1] * m_coeffs[0] - delay0new * 0.61803401f; m_state.allpass1[allpassPos][0] = r2 * 0.61803401f + delay0new; m_state.allpass1[allpassPos][1] = delay1new - r1 * 0.61803401f; delay0new = r1; delay1new = r2; r1 = delay3new * 0.61803401f + m_state.allpass2[delay5][0] * m_coeffs[1]; r2 = m_state.allpass2[delay5][1] * m_coeffs[1] - delay2new * 0.61803401f; m_state.allpass2[allpassPos][0] = r2 * 0.61803401f + delay2new; m_state.allpass2[allpassPos][1] = delay3new - r1 * 0.61803401f; delay2new = r1; delay3new = r2; *(out[0])++ = (leftIn * m_dryFactor) + delay0new + delay2new; *(out[1])++ = (rightIn * m_dryFactor) + delay1new + delay3new; const float leftWet = leftIn * m_wetFactor; const float rightWet = rightIn * m_wetFactor; m_state.comb[combPos][0] = (delay0new * m_coeffs[2]) + (delay0old * m_coeffs[3]) + leftWet; m_state.comb[combPos][1] = (delay1new * m_coeffs[4]) + (delay1old * m_coeffs[5]) + rightWet; m_state.comb[combPos][2] = (delay2new * m_coeffs[6]) + (delay2old * m_coeffs[7]) - rightWet; m_state.comb[combPos][3] = (delay3new * m_coeffs[8]) + (delay3old * m_coeffs[9]) + leftWet; delay0old = delay0new; delay1old = delay1new; delay2old = delay2new; delay3old = delay3new; // Advance buffer index combPos = (combPos - 1) & 0xFFF; allpassPos = (allpassPos - 1) & 0x3FF; delay4 = (delay4 - 1) & 0x3FF; delay5 = (delay5 - 1) & 0x3FF; } m_state.combPos = combPos; m_state.allpassPos = allpassPos; ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } PlugParamValue WavesReverb::GetParameter(PlugParamIndex index) { if(index < kRvbNumParameters) { return m_param[index]; } return 0; } void WavesReverb::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < kRvbNumParameters) { value = mpt::safe_clamp(value, 0.0f, 1.0f); m_param[index] = value; RecalculateWavesReverbParams(); } } void WavesReverb::Resume() { m_isResumed = true; // Recalculate delays uint32 delay0 = mpt::saturate_round(static_cast(m_SndFile.GetSampleRate()) * 0.045f); uint32 delay1 = mpt::saturate_round(static_cast(delay0) * 1.18920707f); // 2^0.25 uint32 delay2 = mpt::saturate_round(static_cast(delay1) * 1.18920707f); uint32 delay3 = mpt::saturate_round(static_cast(delay2) * 1.18920707f); uint32 delay4 = mpt::saturate_round(static_cast(delay0 + delay2) * 0.11546667f); uint32 delay5 = mpt::saturate_round(static_cast(delay1 + delay3) * 0.11546667f); // Comb delays m_delay[0] = delay0 - delay4; m_delay[1] = delay2 - delay4; m_delay[2] = delay1 - delay5; m_delay[3] = delay3 - delay5; // Allpass delays m_delay[4] = delay4; m_delay[5] = delay5; RecalculateWavesReverbParams(); PositionChanged(); } void WavesReverb::PositionChanged() { MemsetZero(m_state); } #ifdef MODPLUG_TRACKER CString WavesReverb::GetParamName(PlugParamIndex param) { switch(param) { case kRvbInGain: return _T("InGain"); case kRvbReverbMix: return _T("ReverbMix"); case kRvbReverbTime: return _T("ReverbTime"); case kRvbHighFreqRTRatio: return _T("HighFreqRTRatio"); } return CString(); } CString WavesReverb::GetParamLabel(PlugParamIndex param) { switch(param) { case kRvbInGain: case kRvbReverbMix: return _T("dB"); case kRvbReverbTime: return _T("ms"); } return CString(); } CString WavesReverb::GetParamDisplay(PlugParamIndex param) { float value = m_param[param]; switch(param) { case kRvbInGain: case kRvbReverbMix: value = GainInDecibel(value); break; case kRvbReverbTime: value = ReverbTime(); break; case kRvbHighFreqRTRatio: value = HighFreqRTRatio(); break; } CString s; s.Format(_T("%.2f"), value); return s; } #endif // MODPLUG_TRACKER void WavesReverb::RecalculateWavesReverbParams() { // Recalculate filters const double ReverbTimeSmp = -3000.0 / (static_cast(m_SndFile.GetSampleRate()) * static_cast(ReverbTime())); const double ReverbTimeSmpHF = ReverbTimeSmp * (1.0 / static_cast(HighFreqRTRatio()) - 1.0); m_coeffs[0] = static_cast(std::pow(10.0, m_delay[4] * ReverbTimeSmp)); m_coeffs[1] = static_cast(std::pow(10.0, m_delay[5] * ReverbTimeSmp)); double sum = 0.0; for(uint32 pair = 0; pair < 4; pair++) { double gain1 = std::pow(10.0, m_delay[pair] * ReverbTimeSmp); double gain2 = (1.0 - std::pow(10.0, (m_delay[pair] + m_delay[4 + pair / 2]) * ReverbTimeSmpHF)) * 0.5; double gain3 = gain1 * static_cast(m_coeffs[pair / 2]); double gain4 = gain3 * (((gain3 + 1.0) * gain3 + 1.0) * gain3 + 1.0) + 1.0; m_coeffs[2 + pair * 2] = static_cast(gain1 * (1.0 - gain2)); m_coeffs[3 + pair * 2] = static_cast(gain1 * gain2); sum += gain4 * gain4; } double inGain = std::pow(10.0, static_cast(GainInDecibel(m_param[kRvbInGain])) * 0.05); double reverbMix = std::pow(10.0, static_cast(GainInDecibel(m_param[kRvbReverbMix])) * 0.1); m_dryFactor = static_cast(std::sqrt(1.0 - reverbMix) * inGain); m_wetFactor = static_cast(std::sqrt(reverbMix) * (4.0 / std::sqrt(sum) * inGain)); } } // namespace DMO #else MPT_MSVC_WORKAROUND_LNK4221(WavesReverb) #endif // !NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Gargle.cpp0000644000175000017500000001015514722730163022251 00000000000000/* * Gargle.cpp * ---------- * Purpose: Implementation of the DMO Gargle DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "Gargle.h" #include "../../Sndfile.h" #endif // !NO_PLUGINS OPENMPT_NAMESPACE_BEGIN #ifndef NO_PLUGINS namespace DMO { IMixPlugin* Gargle::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Gargle(factory, sndFile, mixStruct); } Gargle::Gargle(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) { m_param[kGargleRate] = 0.02f; m_param[kGargleWaveShape] = 0.0f; m_mixBuffer.Initialize(2, 2); } void Gargle::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(!m_mixBuffer.Ok()) return; const float *inL = m_mixBuffer.GetInputBuffer(0), *inR = m_mixBuffer.GetInputBuffer(1); float *outL = m_mixBuffer.GetOutputBuffer(0), *outR = m_mixBuffer.GetOutputBuffer(1); const bool triangle = m_param[kGargleWaveShape] < 1.0f; for(uint32 frame = numFrames; frame != 0;) { if(m_counter < m_periodHalf) { // First half of gargle period const uint32 remain = std::min(frame, m_periodHalf - m_counter); if(triangle) { const uint32 stop = m_counter + remain; const float factor = 1.0f / static_cast(m_periodHalf); for(uint32 i = m_counter; i < stop; i++) { *outL++ = *inL++ * static_cast(i) * factor; *outR++ = *inR++ * static_cast(i) * factor; } } else { for(uint32 i = 0; i < remain; i++) { *outL++ = *inL++; *outR++ = *inR++; } } frame -= remain; m_counter += remain; } else { // Second half of gargle period const uint32 remain = std::min(frame, m_period - m_counter); if(triangle) { const uint32 stop = m_period - m_counter - remain; const float factor = 1.0f / static_cast(m_periodHalf); for(uint32 i = m_period - m_counter; i > stop; i--) { *outL++ = *inL++ * static_cast(i) * factor; *outR++ = *inR++ * static_cast(i) * factor; } } else { for(uint32 i = 0; i < remain; i++) { *outL++ = 0; *outR++ = 0; } inL += remain; inR += remain; } frame -= remain; m_counter += remain; if(m_counter >= m_period) m_counter = 0; } } ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } PlugParamValue Gargle::GetParameter(PlugParamIndex index) { if(index < kGargleNumParameters) { return m_param[index]; } return 0; } void Gargle::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < kGargleNumParameters) { value = mpt::safe_clamp(value, 0.0f, 1.0f); if(index == kGargleWaveShape) value = mpt::round(value); m_param[index] = value; RecalculateGargleParams(); } } void Gargle::Resume() { RecalculateGargleParams(); m_counter = 0; m_isResumed = true; } #ifdef MODPLUG_TRACKER CString Gargle::GetParamName(PlugParamIndex param) { switch(param) { case kGargleRate: return _T("Rate"); case kGargleWaveShape: return _T("WaveShape"); } return CString(); } CString Gargle::GetParamLabel(PlugParamIndex param) { switch(param) { case kGargleRate: return _T("Hz"); } return CString(); } CString Gargle::GetParamDisplay(PlugParamIndex param) { CString s; switch(param) { case kGargleRate: s.Format(_T("%u"), RateInHertz()); break; case kGargleWaveShape: return (m_param[param] < 0.5) ? _T("Triangle") : _T("Square"); } return s; } #endif // MODPLUG_TRACKER uint32 Gargle::RateInHertz() const { return static_cast(mpt::round(std::clamp(m_param[kGargleRate], 0.0f, 1.0f) * 999.0f)) + 1; } void Gargle::RecalculateGargleParams() { m_period = m_SndFile.GetSampleRate() / RateInHertz(); if(m_period < 2) m_period = 2; m_periodHalf = m_period / 2; LimitMax(m_counter, m_period); } } // namespace DMO #else MPT_MSVC_WORKAROUND_LNK4221(Gargle) #endif // !NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/WavesReverb.h0000644000175000017500000000576214722730163022760 00000000000000/* * WavesReverb.h * ------------- * Purpose: Implementation of the DMO WavesReverb DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef NO_PLUGINS #include "../PlugInterface.h" OPENMPT_NAMESPACE_BEGIN namespace DMO { class WavesReverb final : public IMixPlugin { protected: enum Parameters { kRvbInGain = 0, kRvbReverbMix, kRvbReverbTime, kRvbHighFreqRTRatio, kRvbNumParameters }; std::array m_param; // Parameters and coefficients float m_dryFactor; float m_wetFactor; std::array m_coeffs; std::array m_delay; // State struct ReverbState { uint32 combPos, allpassPos; float comb[4096][4]; float allpass1[1024][2]; float allpass2[1024][2]; } m_state; public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); int32 GetUID() const override { return 0x87FC0268; } int32 GetVersion() const override { return 0; } void Idle() override { } uint32 GetLatency() const override { return 0; } void Process(float *pOutL, float *pOutR, uint32 numFrames) override; float RenderSilence(uint32) override { return 0.0f; } int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } void SetCurrentProgram(int32) override { } PlugParamIndex GetNumParameters() const override { return kRvbNumParameters; } PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override { m_isResumed = false; } void PositionChanged() override; bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("WavesReverb"); } CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; CString GetCurrentProgramName() override { return CString(); } void SetCurrentProgramName(const CString &) override { } CString GetProgramName(int32) override { return CString(); } bool HasEditor() const override { return false; } #endif int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } protected: static float GainInDecibel(float param) { return -96.0f + param * 96.0f; } float ReverbTime() const { return 0.001f + m_param[kRvbReverbTime] * 2999.999f; } float HighFreqRTRatio() const { return 0.001f + m_param[kRvbHighFreqRTRatio] * 0.998f; } void RecalculateWavesReverbParams(); }; } // namespace DMO OPENMPT_NAMESPACE_END #endif // !NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Echo.cpp0000644000175000017500000001116414722730163021727 00000000000000/* * Echo.cpp * -------- * Purpose: Implementation of the DMO Echo DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "Echo.h" #include "../../Sndfile.h" #endif // !NO_PLUGINS OPENMPT_NAMESPACE_BEGIN #ifndef NO_PLUGINS namespace DMO { IMixPlugin* Echo::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Echo(factory, sndFile, mixStruct); } Echo::Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_bufferSize(0) , m_writePos(0) , m_sampleRate(sndFile.GetSampleRate()) , m_initialFeedback(0.0f) { m_param[kEchoWetDry] = 0.5f; m_param[kEchoFeedback] = 0.5f; m_param[kEchoLeftDelay] = (500.0f - 1.0f) / 1999.0f; m_param[kEchoRightDelay] = (500.0f - 1.0f) / 1999.0f; m_param[kEchoPanDelay] = 0.0f; m_mixBuffer.Initialize(2, 2); } void Echo::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(!m_bufferSize || !m_mixBuffer.Ok()) return; const float wetMix = m_param[kEchoWetDry], dryMix = 1 - wetMix; const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) }; float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) }; for(uint32 i = numFrames; i != 0; i--) { for(uint8 channel = 0; channel < 2; channel++) { const uint8 readChannel = (m_crossEcho ? (1 - channel) : channel); int readPos = m_writePos - m_delayTime[readChannel]; if(readPos < 0) readPos += m_bufferSize; float chnInput = *(in[channel])++; float chnDelay = m_delayLine[readPos * 2 + readChannel]; // Calculate the delay float chnOutput = chnInput * m_initialFeedback; chnOutput += chnDelay * m_param[kEchoFeedback]; // Prevent denormals if(std::abs(chnOutput) < 1e-24f) chnOutput = 0.0f; m_delayLine[m_writePos * 2 + channel] = chnOutput; // Output samples now *(out[channel])++ = (chnInput * dryMix + chnDelay * wetMix); } m_writePos++; if(m_writePos == m_bufferSize) m_writePos = 0; } ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } PlugParamValue Echo::GetParameter(PlugParamIndex index) { if(index < kEchoNumParameters) { return m_param[index]; } return 0; } void Echo::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < kEchoNumParameters) { value = mpt::safe_clamp(value, 0.0f, 1.0f); if(index == kEchoPanDelay) value = mpt::round(value); m_param[index] = value; RecalculateEchoParams(); } } void Echo::Resume() { m_isResumed = true; m_sampleRate = m_SndFile.GetSampleRate(); RecalculateEchoParams(); PositionChanged(); } void Echo::PositionChanged() { m_bufferSize = m_sampleRate * 2u; try { m_delayLine.assign(m_bufferSize * 2, 0); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); m_bufferSize = 0; } m_writePos = 0; } #ifdef MODPLUG_TRACKER CString Echo::GetParamName(PlugParamIndex param) { switch(param) { case kEchoWetDry: return _T("WetDryMix"); case kEchoFeedback: return _T("Feedback"); case kEchoLeftDelay: return _T("LeftDelay"); case kEchoRightDelay: return _T("RightDelay"); case kEchoPanDelay: return _T("PanDelay"); } return CString(); } CString Echo::GetParamLabel(PlugParamIndex param) { switch(param) { case kEchoFeedback: return _T("%"); case kEchoLeftDelay: case kEchoRightDelay: return _T("ms"); default: return CString{}; } } CString Echo::GetParamDisplay(PlugParamIndex param) { CString s; switch(param) { case kEchoWetDry: s.Format(_T("%.1f : %.1f"), m_param[param] * 100.0f, 100.0f - m_param[param] * 100.0f); break; case kEchoFeedback: s.Format(_T("%.2f"), m_param[param] * 100.0f); break; case kEchoLeftDelay: case kEchoRightDelay: s.Format(_T("%.2f"), 1.0f + m_param[param] * 1999.0f); break; case kEchoPanDelay: s = (m_param[param] <= 0.5) ? _T("No") : _T("Yes"); } return s; } #endif // MODPLUG_TRACKER void Echo::RecalculateEchoParams() { m_initialFeedback = std::sqrt(1.0f - (m_param[kEchoFeedback] * m_param[kEchoFeedback])); m_delayTime[0] = static_cast((1.0f + m_param[kEchoLeftDelay] * 1999.0f) / 1000.0f * static_cast(m_sampleRate)); m_delayTime[1] = static_cast((1.0f + m_param[kEchoRightDelay] * 1999.0f) / 1000.0f * static_cast(m_sampleRate)); m_crossEcho = (m_param[kEchoPanDelay]) > 0.5f; } } // namespace DMO #else MPT_MSVC_WORKAROUND_LNK4221(Echo) #endif // !NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/DMOUtils.cpp0000644000175000017500000000251014575403626022513 00000000000000/* * DMOUtils.cpp * ------------ * Purpose: Utility functions shared by DMO plugins * Notes : none * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "DMOUtils.h" #ifndef NO_PLUGINS #include "../../Sndfile.h" #endif // !NO_PLUGINS OPENMPT_NAMESPACE_BEGIN #ifndef NO_PLUGINS namespace DMO { // Computes (log2(x) + 1) * 2 ^ (shiftL - shiftR) (x = -2^31...2^31) float logGain(float x, int32 shiftL, int32 shiftR) { uint32 intSample; if(x <= static_cast(int32_min) || x > static_cast(int32_max)) intSample = static_cast(int32_min); else intSample = static_cast(static_cast(x)); const uint32 sign = intSample & 0x80000000; if(sign) intSample = (~intSample) + 1; // Multiply until overflow (or edge shift factor is reached) while(shiftL > 0 && intSample < 0x80000000) { intSample += intSample; shiftL--; } // Unsign clipped sample if(intSample >= 0x80000000) { intSample &= 0x7FFFFFFF; shiftL++; } intSample = (shiftL << (31 - shiftR)) | (intSample >> shiftR); if(sign) intSample = ~intSample | sign; return static_cast(static_cast(intSample)); } } // namespace DMO #else MPT_MSVC_WORKAROUND_LNK4221(Distortion) #endif // !NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Chorus.cpp0000644000175000017500000001666414722730163022326 00000000000000/* * Chorus.cpp * ---------- * Purpose: Implementation of the DMO Chorus DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "Chorus.h" #include "../../Sndfile.h" #include "mpt/base/numbers.hpp" #endif // !NO_PLUGINS OPENMPT_NAMESPACE_BEGIN #ifndef NO_PLUGINS namespace DMO { IMixPlugin* Chorus::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Chorus(factory, sndFile, mixStruct); } Chorus::Chorus(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, bool isFlanger) : IMixPlugin(factory, sndFile, mixStruct) , m_isFlanger(isFlanger) { m_param[kChorusWetDryMix] = 0.5f; m_param[kChorusDepth] = 0.1f; m_param[kChorusFrequency] = 0.11f; m_param[kChorusWaveShape] = 1.0f; m_param[kChorusPhase] = 0.75f; m_param[kChorusFeedback] = (25.0f + 99.0f) / 198.0f; m_param[kChorusDelay] = 0.8f; m_mixBuffer.Initialize(2, 2); } // Integer part of buffer position int32 Chorus::GetBufferIntOffset(int32 fpOffset) const { if(fpOffset < 0) fpOffset += m_bufSize * 4096; MPT_ASSERT(fpOffset >= 0); return (m_bufPos + (fpOffset / 4096)) % m_bufSize; } void Chorus::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(!m_bufSize || !m_mixBuffer.Ok()) return; const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) }; float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) }; const bool isSquare = IsSquare(); const float feedback = Feedback() / 100.0f; const float wetDryMix = WetDryMix(); const uint32 phase = Phase(); const auto &bufferR = m_isFlanger ? m_bufferR : m_bufferL; for(uint32 i = numFrames; i != 0; i--) { const float leftIn = *(in[0])++; const float rightIn = *(in[1])++; const int32 readOffset = GetBufferIntOffset(m_delayOffset); const int32 writeOffset = m_bufPos; if(m_isFlanger) { m_DryBufferL[m_dryWritePos] = leftIn; m_DryBufferR[m_dryWritePos] = rightIn; m_bufferL[writeOffset] = (m_bufferL[readOffset] * feedback) + leftIn; m_bufferR[writeOffset] = (m_bufferR[readOffset] * feedback) + rightIn; } else { m_bufferL[writeOffset] = (m_bufferL[readOffset] * feedback) + (leftIn + rightIn) * 0.5f; } float waveMin; float waveMax; if(isSquare) { m_waveShapeMin += m_waveShapeVal; m_waveShapeMax += m_waveShapeVal; if(m_waveShapeMin > 1) m_waveShapeMin -= 2; if(m_waveShapeMax > 1) m_waveShapeMax -= 2; waveMin = std::abs(m_waveShapeMin) * 2 - 1; waveMax = std::abs(m_waveShapeMax) * 2 - 1; } else { m_waveShapeMin = m_waveShapeMax * m_waveShapeVal + m_waveShapeMin; m_waveShapeMax = m_waveShapeMax - m_waveShapeMin * m_waveShapeVal; waveMin = m_waveShapeMin; waveMax = m_waveShapeMax; } const float leftDelayIn = m_isFlanger ? m_DryBufferL[(m_dryWritePos + 2) % 3] : leftIn; const float rightDelayIn = m_isFlanger ? m_DryBufferR[(m_dryWritePos + 2) % 3] : rightIn; float left1 = m_bufferL[GetBufferIntOffset(m_delayL)]; float left2 = m_bufferL[GetBufferIntOffset(m_delayL + 4096)]; float fracPos = static_cast(m_delayL & 0xFFF) * (1.0f / 4096.0f); float leftOut = (left2 - left1) * fracPos + left1; *(out[0])++ = leftDelayIn + (leftOut - leftDelayIn) * wetDryMix; float right1 = bufferR[GetBufferIntOffset(m_delayR)]; float right2 = bufferR[GetBufferIntOffset(m_delayR + 4096)]; fracPos = static_cast(m_delayR & 0xFFF) * (1.0f / 4096.0f); float rightOut = (right2 - right1) * fracPos + right1; *(out[1])++ = rightDelayIn + (rightOut - rightDelayIn) * wetDryMix; // Increment delay positions if(m_dryWritePos <= 0) m_dryWritePos += 3; m_dryWritePos--; m_delayL = m_delayOffset + (phase < 4 ? 1 : -1) * static_cast(waveMin * m_depthDelay); m_delayR = m_delayOffset + (phase < 2 ? -1 : 1) * static_cast(((phase % 2u) ? waveMax : waveMin) * m_depthDelay); if(m_bufPos <= 0) m_bufPos += m_bufSize; m_bufPos--; } ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } PlugParamValue Chorus::GetParameter(PlugParamIndex index) { if(index < kChorusNumParameters) { return m_param[index]; } return 0; } void Chorus::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < kChorusNumParameters) { value = mpt::safe_clamp(value, 0.0f, 1.0f); if(index == kChorusWaveShape) { value = mpt::round(value); if(m_param[index] != value) { m_waveShapeMin = 0.0f; m_waveShapeMax = 0.5f + value * 0.5f; } } else if(index == kChorusPhase) { value = mpt::round(value * 4.0f) / 4.0f; } m_param[index] = value; RecalculateChorusParams(); } } void Chorus::Resume() { PositionChanged(); RecalculateChorusParams(); m_isResumed = true; m_waveShapeMin = 0.0f; m_waveShapeMax = IsSquare() ? 0.5f : 1.0f; m_delayL = m_delayR = m_delayOffset; m_dryWritePos = 0; } void Chorus::PositionChanged() { m_bufSize = Util::muldiv(m_SndFile.GetSampleRate(), 3840, 1000); m_bufPos = 0; try { m_bufferL.assign(m_bufSize, 0.0f); if(m_isFlanger) m_bufferR.assign(m_bufSize, 0.0f); m_DryBufferL.fill(0.0f); m_DryBufferR.fill(0.0f); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); m_bufSize = 0; } } #ifdef MODPLUG_TRACKER CString Chorus::GetParamName(PlugParamIndex param) { switch(param) { case kChorusWetDryMix: return _T("WetDryMix"); case kChorusDepth: return _T("Depth"); case kChorusFrequency: return _T("Frequency"); case kChorusWaveShape: return _T("WaveShape"); case kChorusPhase: return _T("Phase"); case kChorusFeedback: return _T("Feedback"); case kChorusDelay: return _T("Delay"); } return CString(); } CString Chorus::GetParamLabel(PlugParamIndex param) { switch(param) { case kChorusWetDryMix: case kChorusDepth: case kChorusFeedback: return _T("%"); case kChorusFrequency: return _T("Hz"); case kChorusPhase: return mpt::ToCString(MPT_UTF8("\xC2\xB0")); // U+00B0 DEGREE SIGN case kChorusDelay: return _T("ms"); } return CString(); } CString Chorus::GetParamDisplay(PlugParamIndex param) { CString s; float value = m_param[param]; switch(param) { case kChorusWetDryMix: case kChorusDepth: value *= 100.0f; break; case kChorusFrequency: value = FrequencyInHertz(); break; case kChorusWaveShape: return (value < 1) ? _T("Square") : _T("Sine"); break; case kChorusPhase: switch(Phase()) { case 0: return _T("-180"); case 1: return _T("-90"); case 2: return _T("0"); case 3: return _T("90"); case 4: return _T("180"); } break; case kChorusFeedback: value = Feedback(); break; case kChorusDelay: value = Delay(); } s.Format(_T("%.2f"), value); return s; } #endif // MODPLUG_TRACKER void Chorus::RecalculateChorusParams() { const float sampleRate = static_cast(m_SndFile.GetSampleRate()); float delaySamples = Delay() * sampleRate / 1000.0f; m_depthDelay = Depth() * delaySamples * 2048.0f; m_delayOffset = mpt::saturate_round(4096.0f * (delaySamples + 2.0f)); m_frequency = FrequencyInHertz(); const float frequencySamples = m_frequency / sampleRate; if(IsSquare()) m_waveShapeVal = frequencySamples * 2.0f; else m_waveShapeVal = std::sin(frequencySamples * mpt::numbers::pi_v) * 2.0f; } } // namespace DMO #else MPT_MSVC_WORKAROUND_LNK4221(Chorus) #endif // !NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Compressor.h0000644000175000017500000000624114722730163022652 00000000000000/* * Compressor.h * ------------- * Purpose: Implementation of the DMO Compressor DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef NO_PLUGINS #include "../PlugInterface.h" OPENMPT_NAMESPACE_BEGIN namespace DMO { class Compressor final : public IMixPlugin { protected: enum Parameters { kCompGain = 0, kCompAttack, kCompRelease, kCompThreshold, kCompRatio, kCompPredelay, kCompNumParameters }; std::array m_param; // Calculated parameters and coefficients float m_gain; float m_attack; float m_release; float m_threshold; float m_ratio; int32 m_predelay; // State std::vector m_buffer; int32 m_bufPos, m_bufSize; float m_peak; public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); Compressor(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); int32 GetUID() const override { return 0xEF011F79; } int32 GetVersion() const override { return 0; } void Idle() override { } uint32 GetLatency() const override { return 0; } void Process(float *pOutL, float *pOutR, uint32 numFrames) override; float RenderSilence(uint32) override { return 0.0f; } int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } void SetCurrentProgram(int32) override { } PlugParamIndex GetNumParameters() const override { return kCompNumParameters; } PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override { m_isResumed = false; } void PositionChanged() override; bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("Compressor"); } CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; CString GetCurrentProgramName() override { return CString(); } void SetCurrentProgramName(const CString &) override { } CString GetProgramName(int32) override { return CString(); } bool HasEditor() const override { return false; } #endif int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } protected: float GainInDecibel() const { return -60.0f + m_param[kCompGain] * 120.0f; } float AttackTime() const { return 0.01f + m_param[kCompAttack] * 499.99f; } float ReleaseTime() const { return 50.0f + m_param[kCompRelease] * 2950.0f; } float ThresholdInDecibel() const { return -60.0f + m_param[kCompThreshold] * 60.0f; } float CompressorRatio() const { return 1.0f + m_param[kCompRatio] * 99.0f; } float PreDelay() const { return m_param[kCompPredelay] * 4.0f; } void RecalculateCompressorParams(); }; } // namespace DMO OPENMPT_NAMESPACE_END #endif // !NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Distortion.cpp0000644000175000017500000001261114722730163023205 00000000000000/* * Distortion.cpp * -------------- * Purpose: Implementation of the DMO Distortion DSP (for non-Windows platforms) * Notes : The original plugin's integer and floating point code paths only * behave identically when feeding floating point numbers in range * [-32768, +32768] rather than the usual [-1, +1] into the plugin. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "Distortion.h" #include "../../Sndfile.h" #include "DMOUtils.h" #include "mpt/base/numbers.hpp" #endif // !NO_PLUGINS OPENMPT_NAMESPACE_BEGIN #ifndef NO_PLUGINS namespace DMO { IMixPlugin* Distortion::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Distortion(factory, sndFile, mixStruct); } Distortion::Distortion(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) { m_param[kDistGain] = 0.7f; m_param[kDistEdge] = 0.15f; m_param[kDistPreLowpassCutoff] = 1.0f; m_param[kDistPostEQCenterFrequency] = 0.291f; m_param[kDistPostEQBandwidth] = 0.291f; m_mixBuffer.Initialize(2, 2); } void Distortion::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(!m_mixBuffer.Ok()) return; const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) }; float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) }; for(uint32 i = numFrames; i != 0; i--) { for(uint8 channel = 0; channel < 2; channel++) { float x = *(in[channel])++; // Pre EQ float z = x * m_preEQa0 + m_preEQz1[channel] * m_preEQb1; m_preEQz1[channel] = z; z *= 1073741824.0f; // 32768^2 // The actual distortion z = logGain(z, m_edge, m_shift); // Post EQ / Gain z = (z * m_postEQa0) - m_postEQz1[channel] * m_postEQb1 - m_postEQz2[channel] * m_postEQb0; m_postEQz1[channel] = z * m_postEQb0 + m_postEQz2[channel]; m_postEQz2[channel] = z; z *= (1.0f / 1073741824.0f); // 32768^2 *(out[channel])++ = z; } } ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } PlugParamValue Distortion::GetParameter(PlugParamIndex index) { if(index < kDistNumParameters) { return m_param[index]; } return 0; } void Distortion::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < kDistNumParameters) { value = mpt::safe_clamp(value, 0.0f, 1.0f); m_param[index] = value; RecalculateDistortionParams(); } } void Distortion::Resume() { m_isResumed = true; RecalculateDistortionParams(); PositionChanged(); } void Distortion::PositionChanged() { // Reset filter state m_preEQz1[0] = m_preEQz1[1] = 0; m_postEQz1[0] = m_postEQz2[0] = 0; m_postEQz1[1] = m_postEQz2[1] = 0; } #ifdef MODPLUG_TRACKER CString Distortion::GetParamName(PlugParamIndex param) { switch(param) { case kDistGain: return _T("Gain"); case kDistEdge: return _T("Edge"); case kDistPreLowpassCutoff: return _T("PreLowpassCutoff"); case kDistPostEQCenterFrequency: return _T("PostEQCenterFrequency"); case kDistPostEQBandwidth: return _T("PostEQBandwidth"); } return CString(); } CString Distortion::GetParamLabel(PlugParamIndex param) { switch(param) { case kDistGain: return _T("dB"); case kDistPreLowpassCutoff: case kDistPostEQCenterFrequency: case kDistPostEQBandwidth: return _T("Hz"); } return CString(); } CString Distortion::GetParamDisplay(PlugParamIndex param) { float value = m_param[param]; switch(param) { case kDistGain: value = GainInDecibel(); break; case kDistEdge: value *= 100.0f; break; case kDistPreLowpassCutoff: case kDistPostEQCenterFrequency: case kDistPostEQBandwidth: value = FreqInHertz(value); break; } CString s; s.Format(_T("%.2f"), value); return s; } #endif // MODPLUG_TRACKER void Distortion::RecalculateDistortionParams() { // Pre-EQ m_preEQb1 = std::sqrt((2.0f * std::cos(2.0f * mpt::numbers::pi_v * std::min(FreqInHertz(m_param[kDistPreLowpassCutoff]) / static_cast(m_SndFile.GetSampleRate()), 0.5f)) + 3.0f) / 5.0f); m_preEQa0 = std::sqrt(1.0f - m_preEQb1 * m_preEQb1); // Distortion float edge = 2.0f + m_param[kDistEdge] * 29.0f; m_edge = static_cast(edge); // 2...31 shifted bits m_shift = static_cast(mpt::bit_width(m_edge)); static constexpr float LogNorm[32] = { 1.00f, 1.00f, 1.50f, 1.00f, 1.75f, 1.40f, 1.17f, 1.00f, 1.88f, 1.76f, 1.50f, 1.36f, 1.25f, 1.15f, 1.07f, 1.00f, 1.94f, 1.82f, 1.72f, 1.63f, 1.55f, 1.48f, 1.41f, 1.35f, 1.29f, 1.24f, 1.19f, 1.15f, 1.11f, 1.07f, 1.03f, 1.00f, }; // Post-EQ const float gain = std::pow(10.0f, GainInDecibel() / 20.0f); const float postFreq = 2.0f * mpt::numbers::pi_v * std::min(FreqInHertz(m_param[kDistPostEQCenterFrequency]) / static_cast(m_SndFile.GetSampleRate()), 0.5f); const float postBw = 2.0f * mpt::numbers::pi_v * std::min(FreqInHertz(m_param[kDistPostEQBandwidth]) / static_cast(m_SndFile.GetSampleRate()), 0.5f); const float t = std::tan(5.0e-1f * postBw); m_postEQb1 = ((1.0f - t) / (1.0f + t)); m_postEQb0 = -std::cos(postFreq); m_postEQa0 = gain * std::sqrt(1.0f - m_postEQb0 * m_postEQb0) * std::sqrt(1.0f - m_postEQb1 * m_postEQb1) * LogNorm[m_edge]; } } // namespace DMO #else MPT_MSVC_WORKAROUND_LNK4221(Distortion) #endif // !NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/DMOUtils.h0000644000175000017500000000071113744301561022151 00000000000000/* * DMOUtils.h * ---------- * Purpose: Utility functions shared by DMO plugins * Notes : none * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ OPENMPT_NAMESPACE_BEGIN #ifndef NO_PLUGINS namespace DMO { // Computes (log2(x) + 1) * 2 ^ (shiftL - shiftR) (x = -2^31...2^31) float logGain(float x, int32 shiftL, int32 shiftR); } #endif // !NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Echo.h0000644000175000017500000000534414722730163021377 00000000000000/* * Echo.h * ------ * Purpose: Implementation of the DMO Echo DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef NO_PLUGINS #include "../PlugInterface.h" OPENMPT_NAMESPACE_BEGIN namespace DMO { class Echo final : public IMixPlugin { protected: enum Parameters { kEchoWetDry = 0, kEchoFeedback, kEchoLeftDelay, kEchoRightDelay, kEchoPanDelay, kEchoNumParameters }; std::vector m_delayLine; // Echo delay line float m_param[kEchoNumParameters]; uint32 m_bufferSize; // Delay line length in frames uint32 m_writePos; // Current write position in the delay line uint32 m_delayTime[2]; // In frames uint32 m_sampleRate; // Echo calculation coefficients float m_initialFeedback; bool m_crossEcho; public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); int32 GetUID() const override { return 0xEF3E932C; } int32 GetVersion() const override { return 0; } void Idle() override { } uint32 GetLatency() const override { return 0; } void Process(float *pOutL, float *pOutR, uint32 numFrames)override; float RenderSilence(uint32) override { return 0.0f; } int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } void SetCurrentProgram(int32) override { } PlugParamIndex GetNumParameters() const override { return kEchoNumParameters; } PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override { m_isResumed = false; } void PositionChanged() override; bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("Echo"); } CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; CString GetCurrentProgramName() override { return CString(); } void SetCurrentProgramName(const CString &) override { } CString GetProgramName(int32) override { return CString(); } bool HasEditor() const override { return false; } #endif int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } protected: void RecalculateEchoParams(); }; } // namespace DMO OPENMPT_NAMESPACE_END #endif // !NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/ParamEq.h0000644000175000017500000000546214722730163022050 00000000000000/* * ParamEq.h * --------- * Purpose: Implementation of the DMO Parametric Equalizer DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef NO_PLUGINS #include "../PlugInterface.h" OPENMPT_NAMESPACE_BEGIN namespace DMO { class ParamEq final : public IMixPlugin { protected: enum Parameters { kEqCenter = 0, kEqBandwidth, kEqGain, kEqNumParameters }; std::array m_param; // Equalizer coefficients float b0DIVa0, b1DIVa0, b2DIVa0, a1DIVa0, a2DIVa0; // Equalizer memory float x1[2], x2[2]; float y1[2], y2[2]; float m_maxFreqParam; public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); ParamEq(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); int32 GetUID() const override { return 0x120CED89; } int32 GetVersion() const override { return 0; } void Idle() override { } uint32 GetLatency() const override { return 0; } void Process(float *pOutL, float *pOutR, uint32 numFrames) override; float RenderSilence(uint32) override { return 0.0f; } int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } void SetCurrentProgram(int32) override { } PlugParamIndex GetNumParameters() const override { return kEqNumParameters; } PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override { m_isResumed = false; } void PositionChanged() override; bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("ParamEq"); } CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; CString GetCurrentProgramName() override { return CString(); } void SetCurrentProgramName(const CString &) override { } CString GetProgramName(int32) override { return CString(); } bool HasEditor() const override { return false; } #endif int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } protected: float BandwidthInSemitones() const { return 1.0f + m_param[kEqBandwidth] * 35.0f; } float FreqInHertz() const { return 80.0f + m_param[kEqCenter] * 15920.0f; } float GainInDecibel() const { return (m_param[kEqGain] - 0.5f) * 30.0f; } void RecalculateEqParams(); }; } // namespace DMO OPENMPT_NAMESPACE_END #endif // !NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Flanger.h0000644000175000017500000000415514722730163022076 00000000000000/* * Flanger.h * --------- * Purpose: Implementation of the DMO Flanger DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #ifndef NO_PLUGINS #include "Chorus.h" OPENMPT_NAMESPACE_BEGIN namespace DMO { class Flanger final : public Chorus { protected: enum Parameters { kFlangerWetDryMix = 0, kFlangerWaveShape, kFlangerFrequency, kFlangerDepth, kFlangerPhase, kFlangerFeedback, kFlangerDelay, kFlangerNumParameters }; public: // cppcheck-suppress duplInheritedMember static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); static IMixPlugin* CreateLegacy(VSTPluginLib& factory, CSoundFile& sndFile, SNDMIXPLUGIN &mixStruct); Flanger(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, const bool legacy); int32 GetUID() const override { return 0xEFCA3D92; } PlugParamIndex GetNumParameters() const override { return kFlangerNumParameters; } void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("Flanger"); } CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; #endif protected: float WetDryMix() const override { return m_param[kFlangerWetDryMix]; } bool IsSquare() const override { return m_param[kFlangerWaveShape] < 1; } float Depth() const override { return m_param[kFlangerDepth]; } float Feedback() const override { return -99.0f + m_param[kFlangerFeedback] * 198.0f; } float Delay() const override { return m_param[kFlangerDelay] * 4.0f; } float FrequencyInHertz() const override { return m_param[kFlangerFrequency] * 10.0f; } int Phase() const override { return mpt::saturate_round(m_param[kFlangerPhase] * 4.0f); } }; } // namespace DMO OPENMPT_NAMESPACE_END #endif // !NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Distortion.h0000644000175000017500000000551114722730163022653 00000000000000/* * Distortion.h * ------------ * Purpose: Implementation of the DMO Distortion DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef NO_PLUGINS #include "../PlugInterface.h" OPENMPT_NAMESPACE_BEGIN namespace DMO { class Distortion final : public IMixPlugin { protected: enum Parameters { kDistGain = 0, kDistEdge, kDistPreLowpassCutoff, kDistPostEQCenterFrequency, kDistPostEQBandwidth, kDistNumParameters }; std::array m_param; // Pre-EQ coefficients float m_preEQz1[2], m_preEQb1, m_preEQa0; // Post-EQ coefficients float m_postEQz1[2], m_postEQz2[2], m_postEQa0, m_postEQb0, m_postEQb1; uint8 m_edge, m_shift; public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); Distortion(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); int32 GetUID() const override { return 0xEF114C90; } int32 GetVersion() const override { return 0; } void Idle() override { } uint32 GetLatency() const override { return 0; } void Process(float *pOutL, float *pOutR, uint32 numFrames) override; float RenderSilence(uint32) override { return 0.0f; } int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } void SetCurrentProgram(int32) override { } PlugParamIndex GetNumParameters() const override { return kDistNumParameters; } PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override { m_isResumed = false; } void PositionChanged() override; bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("Distortion"); } CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; CString GetCurrentProgramName() override { return CString(); } void SetCurrentProgramName(const CString &) override { } CString GetProgramName(int32) override { return CString(); } bool HasEditor() const override { return false; } #endif int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } protected: static float FreqInHertz(float param) { return 100.0f + param * 7900.0f; } float GainInDecibel() const { return -60.0f + m_param[kDistGain] * 60.0f; } void RecalculateDistortionParams(); }; } // namespace DMO OPENMPT_NAMESPACE_END #endif // !NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/dmo/Flanger.cpp0000644000175000017500000000657215016303107022425 00000000000000/* * Flanger.cpp * ----------- * Purpose: Implementation of the DMO Flanger DSP (for non-Windows platforms) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "Flanger.h" #include "../../Sndfile.h" #endif // !NO_PLUGINS OPENMPT_NAMESPACE_BEGIN #ifndef NO_PLUGINS namespace DMO { // cppcheck-suppress duplInheritedMember IMixPlugin* Flanger::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Flanger(factory, sndFile, mixStruct, false); } IMixPlugin* Flanger::CreateLegacy(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new(std::nothrow) Flanger(factory, sndFile, mixStruct, true); } Flanger::Flanger(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, const bool legacy) : Chorus(factory, sndFile, mixStruct, !legacy) { m_param[kFlangerWetDryMix] = 0.5f; m_param[kFlangerWaveShape] = 1.0f; m_param[kFlangerFrequency] = 0.025f; m_param[kFlangerDepth] = 1.0f; m_param[kFlangerPhase] = 0.5f; m_param[kFlangerFeedback] = (-50.0f + 99.0f) / 198.0f; m_param[kFlangerDelay] = 0.5f; // Already done in Chorus constructor //m_mixBuffer.Initialize(2, 2); } void Flanger::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < kFlangerNumParameters) { value = mpt::safe_clamp(value, 0.0f, 1.0f); if(index == kFlangerWaveShape) { value = mpt::round(value); if(m_param[index] != value) { m_waveShapeMin = 0.0f; m_waveShapeMax = 0.5f + value * 0.5f; } } else if(index == kFlangerPhase) { value = mpt::round(value * 4.0f) / 4.0f; } m_param[index] = value; RecalculateChorusParams(); } } #ifdef MODPLUG_TRACKER CString Flanger::GetParamName(PlugParamIndex param) { switch(param) { case kFlangerWetDryMix: return _T("WetDryMix"); case kFlangerWaveShape: return _T("WaveShape"); case kFlangerFrequency: return _T("Frequency"); case kFlangerDepth: return _T("Depth"); case kFlangerPhase: return _T("Phase"); case kFlangerFeedback: return _T("Feedback"); case kFlangerDelay: return _T("Delay"); } return CString(); } CString Flanger::GetParamLabel(PlugParamIndex param) { switch(param) { case kFlangerWetDryMix: case kFlangerDepth: case kFlangerFeedback: return _T("%"); case kFlangerFrequency: return _T("Hz"); case kFlangerPhase: return mpt::ToCString(MPT_UTF8("\xC2\xB0")); // U+00B0 DEGREE SIGN case kFlangerDelay: return _T("ms"); } return CString(); } CString Flanger::GetParamDisplay(PlugParamIndex param) { CString s; float value = m_param[param]; switch(param) { case kFlangerWetDryMix: case kFlangerDepth: value *= 100.0f; break; case kFlangerFrequency: value = FrequencyInHertz(); break; case kFlangerWaveShape: return (value < 1) ? _T("Square") : _T("Sine"); break; case kFlangerPhase: switch(Phase()) { case 0: return _T("-180"); case 1: return _T("-90"); case 2: return _T("0"); case 3: return _T("90"); case 4: return _T("180"); } break; case kFlangerFeedback: value = Feedback(); break; case kFlangerDelay: value = Delay(); } s.Format(_T("%.2f"), value); return s; } #endif // MODPLUG_TRACKER } // namespace DMO #else MPT_MSVC_WORKAROUND_LNK4221(Flanger) #endif // !NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/SymMODEcho.cpp0000644000175000017500000001461314722730163022203 00000000000000/* * SymMODEcho.cpp * -------------- * Purpose: Implementation of the SymMOD Echo DSP * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "SymMODEcho.h" #include "../Sndfile.h" OPENMPT_NAMESPACE_BEGIN IMixPlugin *SymMODEcho::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) SymMODEcho(factory, sndFile, mixStruct); } SymMODEcho::SymMODEcho(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_chunk(PluginChunk::Default()) { m_mixBuffer.Initialize(2, 2); RecalculateEchoParams(); } void SymMODEcho::Process(float* pOutL, float* pOutR, uint32 numFrames) { const float *srcL = m_mixBuffer.GetInputBuffer(0), *srcR = m_mixBuffer.GetInputBuffer(1); float *outL = m_mixBuffer.GetOutputBuffer(0), *outR = m_mixBuffer.GetOutputBuffer(1); const uint32 delayTime = m_SndFile.m_PlayState.m_nSamplesPerTick * m_chunk.param[kEchoDelay]; // SymMODs don't have a variable tempo so the tick duration should never change... but if someone loads an instance into an MPTM file we have to account for this. if(m_delayLine.size() < delayTime * 2) m_delayLine.resize(delayTime * 2); const auto dspType = GetDSPType(); if(dspType == DSPType::Off) { // Toggling the echo while it's running keeps its delay line untouched std::copy(srcL, srcL + numFrames, outL); std::copy(srcR, srcR + numFrames, outR); } else { for(uint32 i = 0; i < numFrames; i++) { if(m_writePos >= delayTime) m_writePos = 0; int readPos = m_writePos - delayTime; if(readPos < 0) readPos += delayTime; const float lDry = *srcL++, rDry = *srcR++; const float lDelay = m_delayLine[readPos * 2], rDelay = m_delayLine[readPos * 2 + 1]; // Output samples *outL++ = (lDry + lDelay); *outR++ = (rDry + rDelay); // Compute new delay line values float lOut = 0.0f, rOut = 0.0f; switch(dspType) { case DSPType::Off: break; case DSPType::Normal: lOut = (lDelay + lDry) * m_feedback; rOut = (rDelay + rDry) * m_feedback; break; case DSPType::Cross: case DSPType::Cross2: lOut = (rDelay + rDry) * m_feedback; rOut = (lDelay + lDry) * m_feedback; break; case DSPType::Center: lOut = (lDelay + (lDry + rDry) * 0.5f) * m_feedback; rOut = lOut; break; case DSPType::NumTypes: break; } // Prevent denormals if(std::abs(lOut) < 1e-24f) lOut = 0.0f; if(std::abs(rOut) < 1e-24f) rOut = 0.0f; m_delayLine[m_writePos * 2 + 0] = lOut; m_delayLine[m_writePos * 2 + 1] = rOut; m_writePos++; } } ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } void SymMODEcho::SaveAllParameters() { m_pMixStruct->defaultProgram = -1; try { const auto pluginData = mpt::as_raw_memory(m_chunk); m_pMixStruct->pluginData.assign(pluginData.begin(), pluginData.end()); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); m_pMixStruct->pluginData.clear(); } } void SymMODEcho::RestoreAllParameters(int32 program) { if(m_pMixStruct->pluginData.size() == sizeof(m_chunk) && !memcmp(m_pMixStruct->pluginData.data(), "Echo", 4)) { std::copy(m_pMixStruct->pluginData.begin(), m_pMixStruct->pluginData.end(), mpt::as_raw_memory(m_chunk).begin()); } else { IMixPlugin::RestoreAllParameters(program); } RecalculateEchoParams(); } PlugParamValue SymMODEcho::GetParameter(PlugParamIndex index) { if(index < kEchoNumParameters) { return m_chunk.param[index] / 127.0f; } return 0; } void SymMODEcho::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < kEchoNumParameters) { m_chunk.param[index] = mpt::saturate_round(mpt::safe_clamp(value, 0.0f, 1.0f) * 127.0f); RecalculateEchoParams(); } } void SymMODEcho::Resume() { m_isResumed = true; PositionChanged(); } void SymMODEcho::PositionChanged() { try { m_delayLine.assign(127 * 2 * m_SndFile.m_PlayState.m_nSamplesPerTick, 0.0f); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); } m_writePos = 0; } #ifdef MODPLUG_TRACKER std::pair SymMODEcho::GetParamUIRange(PlugParamIndex param) { if(param == kEchoType) return {0.0f, (static_cast(DSPType::NumTypes) - 1) / 127.0f}; else return {0.0f, 1.0f}; } CString SymMODEcho::GetParamName(PlugParamIndex param) { switch (param) { case kEchoType: return _T("Type"); case kEchoDelay: return _T("Delay"); case kEchoFeedback: return _T("Feedback"); case kEchoNumParameters: break; } return {}; } CString SymMODEcho::GetParamLabel(PlugParamIndex param) { if(param == kEchoDelay) return _T("Ticks"); if(param == kEchoFeedback) return _T("%"); return {}; } CString SymMODEcho::GetParamDisplay(PlugParamIndex param) { switch(static_cast(param)) { case kEchoType: switch(GetDSPType()) { case DSPType::Off: return _T("Off"); case DSPType::Normal: return _T("Normal"); case DSPType::Cross: return _T("Cross"); case DSPType::Cross2: return _T("Cross 2"); case DSPType::Center: return _T("Center"); case DSPType::NumTypes: break; } break; case kEchoDelay: return mpt::cfmt::val(m_chunk.param[kEchoDelay]); case kEchoFeedback: return mpt::cfmt::flt(m_feedback * 100.0f, 4); case kEchoNumParameters: break; } return {}; } #endif // MODPLUG_TRACKER IMixPlugin::ChunkData SymMODEcho::GetChunk(bool) { auto data = reinterpret_cast(&m_chunk); return ChunkData(data, sizeof(m_chunk)); } void SymMODEcho::SetChunk(const ChunkData& chunk, bool) { auto data = chunk.data(); if(chunk.size() == sizeof(chunk) && !memcmp(data, "Echo", 4)) { memcpy(&m_chunk, data, chunk.size()); RecalculateEchoParams(); } } void SymMODEcho::RecalculateEchoParams() { if(m_chunk.param[kEchoType] >= static_cast(DSPType::NumTypes)) m_chunk.param[kEchoType] = 0; if(m_chunk.param[kEchoDelay] > 127) m_chunk.param[kEchoDelay] = 127; if(m_chunk.param[kEchoFeedback] > 127) m_chunk.param[kEchoFeedback] = 127; if(GetDSPType() == DSPType::Cross2) m_feedback = 1.0f - std::pow(2.0f, -static_cast(m_chunk.param[kEchoFeedback] + 1)); else m_feedback = std::pow(2.0f, -static_cast(m_chunk.param[kEchoFeedback])); } OPENMPT_NAMESPACE_END #endif // NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/DigiBoosterEcho.h0000644000175000017500000000717114722730163022753 00000000000000/* * DigiBoosterEcho.h * ----------------- * Purpose: Implementation of the DigiBooster Pro Echo DSP * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef NO_PLUGINS #include "PlugInterface.h" OPENMPT_NAMESPACE_BEGIN class DigiBoosterEcho final : public IMixPlugin { public: enum Parameters { kEchoDelay = 0, kEchoFeedback, kEchoMix, kEchoCross, kEchoNumParameters }; // Our settings chunk for file I/O, as it will be written to files struct PluginChunk { char id[4]; uint8 param[kEchoNumParameters]; static PluginChunk Create(uint8 delay, uint8 feedback, uint8 mix, uint8 cross) { static_assert(sizeof(PluginChunk) == 8); PluginChunk result; memcpy(result.id, "Echo", 4); result.param[kEchoDelay] = delay; result.param[kEchoFeedback] = feedback; result.param[kEchoMix] = mix; result.param[kEchoCross] = cross; return result; } static PluginChunk Default() { return Create(80, 150, 80, 255); } }; protected: std::vector m_delayLine; // Echo delay line uint32 m_bufferSize = 0; // Delay line length in frames uint32 m_writePos = 0; // Current write position in the delay line uint32 m_delayTime = 0; // In frames uint32 m_sampleRate = 0; // Echo calculation coefficients float m_PMix, m_NMix; float m_PCrossPBack, m_PCrossNBack; float m_NCrossPBack, m_NCrossNBack; // Settings chunk for file I/O PluginChunk m_chunk; public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); DigiBoosterEcho(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); void SaveAllParameters() override; void RestoreAllParameters(int32 program) override; int32 GetUID() const override { int32le id; memcpy(&id, "Echo", 4); return id; } int32 GetVersion() const override { return 0; } void Idle() override { } uint32 GetLatency() const override { return 0; } void Process(float *pOutL, float *pOutR, uint32 numFrames) override; float RenderSilence(uint32) override { return 0.0f; } int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } void SetCurrentProgram(int32) override { } PlugParamIndex GetNumParameters() const override { return kEchoNumParameters; } PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override { m_isResumed = false; } void PositionChanged() override; bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("Echo"); } CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; CString GetCurrentProgramName() override { return CString(); } void SetCurrentProgramName(const CString &) override { } CString GetProgramName(int32) override { return CString(); } bool HasEditor() const override { return false; } #endif int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } bool ProgramsAreChunks() const override { return true; } ChunkData GetChunk(bool) override; void SetChunk(const ChunkData &chunk, bool) override; protected: void RecalculateEchoParams(); }; OPENMPT_NAMESPACE_END #endif // NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/PluginMixBuffer.h0000644000175000017500000000747514155422765023025 00000000000000/* * PluginMixBuffer.h * ----------------- * Purpose: Helper class for managing plugin audio input and output buffers. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include #include #if defined(MPT_ENABLE_ARCH_INTRINSICS) || defined(MPT_WITH_VST) #include "mpt/base/aligned_array.hpp" #endif // MPT_ENABLE_ARCH_INTRINSICS || MPT_WITH_VST OPENMPT_NAMESPACE_BEGIN // At least this part of the code is ready for double-precision rendering... :> // buffer_t: Sample buffer type (float, double, ...) // bufferSize: Buffer size in samples template class PluginMixBuffer { private: #if defined(MPT_ENABLE_ARCH_INTRINSICS) || defined(MPT_WITH_VST) static constexpr std::align_val_t alignment = std::align_val_t{16}; static_assert(sizeof(mpt::aligned_array) == sizeof(std::array)); static_assert(alignof(mpt::aligned_array) == static_cast(alignment)); #endif // MPT_ENABLE_ARCH_INTRINSICS || MPT_WITH_VST protected: #if defined(MPT_ENABLE_ARCH_INTRINSICS) || defined(MPT_WITH_VST) std::vector> inputs; std::vector> outputs; #else // !(MPT_ENABLE_ARCH_INTRINSICS || MPT_WITH_VST) std::vector> inputs; std::vector> outputs; #endif // MPT_ENABLE_ARCH_INTRINSICS || MPT_WITH_VST std::vector inputsarray; std::vector outputsarray; public: // Allocate input and output buffers bool Initialize(uint32 numInputs, uint32 numOutputs) { // Short cut - we do not need to recreate the buffers. if(inputs.size() == numInputs && outputs.size() == numOutputs) { return true; } try { inputs.resize(numInputs); outputs.resize(numOutputs); inputsarray.resize(numInputs); outputsarray.resize(numOutputs); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); inputs.clear(); inputs.shrink_to_fit(); outputs.clear(); outputs.shrink_to_fit(); inputsarray.clear(); inputsarray.shrink_to_fit(); outputsarray.clear(); outputsarray.shrink_to_fit(); return false; } for(uint32 i = 0; i < numInputs; i++) { inputsarray[i] = inputs[i].data(); } for(uint32 i = 0; i < numOutputs; i++) { outputsarray[i] = outputs[i].data(); } return true; } // Silence all input buffers. void ClearInputBuffers(uint32 numSamples) { MPT_ASSERT(numSamples <= bufferSize); for(size_t i = 0; i < inputs.size(); i++) { std::fill(inputs[i].data(), inputs[i].data() + numSamples, buffer_t{0}); } } // Silence all output buffers. void ClearOutputBuffers(uint32 numSamples) { MPT_ASSERT(numSamples <= bufferSize); for(size_t i = 0; i < outputs.size(); i++) { std::fill(outputs[i].data(), outputs[i].data() + numSamples, buffer_t{0}); } } PluginMixBuffer() { Initialize(2, 0); } // Return pointer to a given input or output buffer const buffer_t *GetInputBuffer(uint32 index) const { return inputs[index].data(); } const buffer_t *GetOutputBuffer(uint32 index) const { return outputs[index].data(); } buffer_t *GetInputBuffer(uint32 index) { return inputs[index].data(); } buffer_t *GetOutputBuffer(uint32 index) { return outputs[index].data(); } // Return pointer array to all input or output buffers buffer_t **GetInputBufferArray() { return inputs.empty() ? nullptr : inputsarray.data(); } buffer_t **GetOutputBufferArray() { return outputs.empty() ? nullptr : outputsarray.data(); } bool Ok() const { return (inputs.size() + outputs.size()) > 0; } }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/LFOPlugin.h0000644000175000017500000001147514722730163021543 00000000000000/* * LFOPlugin.h * ----------- * Purpose: Plugin for automating other plugins' parameters * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #ifndef NO_PLUGINS #include "PlugInterface.h" #include "../../common/mptRandom.h" OPENMPT_NAMESPACE_BEGIN class LFOPlugin final : public IMixPlugin { friend class LFOPluginEditor; protected: enum Parameters { kAmplitude = 0, kOffset, kFrequency, kTempoSync, kWaveform, kPolarity, kBypassed, kLoopMode, kCurrentPhase, kLFONumParameters }; enum LFOWaveform { kSine = 0, kTriangle, kSaw, kSquare, kSHNoise, kSmoothNoise, kNumWaveforms }; std::vector m_chunkData; static constexpr PlugParamIndex INVALID_OUTPUT_PARAM = uint32_max; // LFO parameters float m_amplitude = 0.5f, m_offset = 0.5f, m_frequency = 0.290241f; LFOWaveform m_waveForm = kSine; PlugParamIndex m_outputParam = INVALID_OUTPUT_PARAM; bool m_tempoSync = false, m_polarity = false, m_bypassed = false, m_outputToCC = false, m_oneshot = false; // LFO state double m_computedFrequency = 0.0; double m_phase = 0.0, m_increment = 0.0; double m_random = 0.0, m_nextRandom = 0.0; double m_tempo = 0.0; mpt::fast_prng m_PRNG; #ifdef MODPLUG_TRACKER static constexpr int WM_PARAM_UDPATE = WM_USER + 500; #endif public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); LFOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); int32 GetUID() const override { int32 id; memcpy(&id, "LFO ", 4); return id; } int32 GetVersion() const override { return 0; } void Idle() override { } uint32 GetLatency() const override { return 0; } void Process(float *pOutL, float *pOutR, uint32 numFrames) override; float RenderSilence(uint32) override { return 0.0f; } // MIDI event handling (mostly passing it through to the follow-up plugin) bool MidiSend(mpt::const_byte_span midiData) override; void MidiCC(MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) override; void MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackChannel) override; void MidiTonePortamento(int32 increment, uint8 newNote, int8 pwd, CHANNELINDEX trackChannel) override; void MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackChannel) override; void MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) override; void HardAllNotesOff() override; bool IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) override; int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } void SetCurrentProgram(int32) override { } PlugParamIndex GetNumParameters() const override { return kLFONumParameters; } PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override { m_isResumed = false; } void PositionChanged() override; bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("LFO"); } std::pair GetParamUIRange(PlugParamIndex param) override; CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; CString GetCurrentProgramName() override { return CString(); } void SetCurrentProgramName(const CString &) override { } CString GetProgramName(int32) override { return CString(); } bool HasEditor() const override { return true; } protected: CAbstractVstEditor *OpenEditor() override; #endif public: int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } bool ProgramsAreChunks() const override { return true; } // Save parameters for storing them in a module file void SaveAllParameters() override; // Restore parameters from module file void RestoreAllParameters(int32 program) override; ChunkData GetChunk(bool) override; void SetChunk(const ChunkData &chunk, bool) override; protected: void NextRandom(); void RecalculateFrequency(); void RecalculateIncrement(); IMixPlugin *GetOutputPlugin() const; public: static LFOWaveform ParamToWaveform(float param) { return static_cast(std::clamp(mpt::saturate_round(param * 32.0f), 0, kNumWaveforms - 1)); } static float WaveformToParam(LFOWaveform waveform) { return static_cast(static_cast(waveform)) / 32.0f; } }; OPENMPT_NAMESPACE_END #endif // NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/LFOPlugin.cpp0000644000175000017500000003041014722730163022064 00000000000000/* * LFOPlugin.cpp * ------------- * Purpose: Plugin for automating other plugins' parameters * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "LFOPlugin.h" #include "../Sndfile.h" #include "../../common/FileReader.h" #ifdef MODPLUG_TRACKER #include "../../mptrack/plugins/LFOPluginEditor.h" #endif // MODPLUG_TRACKER #include "mpt/base/numbers.hpp" #include "mpt/random/seed.hpp" OPENMPT_NAMESPACE_BEGIN IMixPlugin* LFOPlugin::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) LFOPlugin(factory, sndFile, mixStruct); } LFOPlugin::LFOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_PRNG(mpt::make_prng(mpt::global_prng())) { RecalculateFrequency(); RecalculateIncrement(); m_mixBuffer.Initialize(2, 2); } // Processing (we do not process audio, just send out parameters) void LFOPlugin::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(!m_bypassed) { ResetSilence(); if(m_tempoSync) { double tempo = m_SndFile.GetCurrentBPM(); if(tempo != m_tempo) { m_tempo = tempo; RecalculateIncrement(); } } if(m_oneshot) { LimitMax(m_phase, 1.0); } else { int intPhase = static_cast(m_phase); if(intPhase > 0 && (m_waveForm == kSHNoise || m_waveForm == kSmoothNoise)) { // Phase wrap-around happened NextRandom(); } m_phase -= intPhase; } double value = 0; switch(m_waveForm) { case kSine: value = std::sin(m_phase * (2.0 * mpt::numbers::pi)); break; case kTriangle: value = 1.0 - 4.0 * std::abs(m_phase - 0.5); break; case kSaw: value = 2.0 * m_phase - 1.0; break; case kSquare: value = m_phase < 0.5 ? -1.0 : 1.0; break; case kSHNoise: value = m_random; break; case kSmoothNoise: value = m_phase * m_phase * m_phase * (m_phase * (m_phase * 6 - 15) + 10); // Smootherstep value = m_nextRandom * value + m_random * (1.0 - value); break; default: break; } if(m_polarity) value = -value; // Transform value from -1...+1 to 0...1 range and apply offset/amplitude value = value * static_cast(m_amplitude) + static_cast(m_offset); Limit(value, 0.0, 1.0); IMixPlugin *plugin = GetOutputPlugin(); if(plugin != nullptr) { if(m_outputToCC) { plugin->MidiSend(MIDIEvents::CC(static_cast(m_outputParam & 0x7F), static_cast((m_outputParam >> 8) & 0x0F), mpt::saturate_round(value * 127.0))); } else { plugin->SetParameter(m_outputParam, static_cast(value)); } } m_phase += m_increment * numFrames; } ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1), numFrames); } PlugParamValue LFOPlugin::GetParameter(PlugParamIndex index) { switch(index) { case kAmplitude: return m_amplitude; case kOffset: return m_offset; case kFrequency: return m_frequency; case kTempoSync: return m_tempoSync ? 1.0f : 0.0f; case kWaveform: return WaveformToParam(m_waveForm); case kPolarity: return m_polarity ? 1.0f : 0.0f; case kBypassed: return m_bypassed ? 1.0f : 0.0f; case kLoopMode: return m_oneshot ? 1.0f : 0.0f; default: return 0; } } void LFOPlugin::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { ResetSilence(); value = mpt::safe_clamp(value, 0.0f, 1.0f); switch(index) { case kAmplitude: m_amplitude = value; break; case kOffset: m_offset = value; break; case kFrequency: m_frequency = value; RecalculateFrequency(); break; case kTempoSync: m_tempoSync = (value >= 0.5f); RecalculateFrequency(); break; case kWaveform: m_waveForm = ParamToWaveform(value); break; case kPolarity: m_polarity = (value >= 0.5f); break; case kBypassed: m_bypassed = (value >= 0.5f); break; case kLoopMode: m_oneshot = (value >= 0.5f); break; case kCurrentPhase: if(value == 0) { // Enforce next random value for random LFOs NextRandom(); } m_phase = static_cast(value); return; default: return; } #ifdef MODPLUG_TRACKER if(GetEditor() != nullptr) { GetEditor()->PostMessage(WM_PARAM_UDPATE, GetSlot(), index); } #endif } void LFOPlugin::Resume() { m_isResumed = true; RecalculateIncrement(); NextRandom(); PositionChanged(); } void LFOPlugin::PositionChanged() { // TODO Changing tempo (with tempo sync enabled), parameter automation over time and setting the LFO phase manually is not considered here. m_phase = m_increment * m_SndFile.GetTotalSampleCount(); m_phase -= static_cast(m_phase); } bool LFOPlugin::MidiSend(mpt::const_byte_span midiData) { if(IMixPlugin *plugin = GetOutputPlugin()) return plugin->MidiSend(midiData); else return true; } void LFOPlugin::MidiCC(MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) { if(IMixPlugin *plugin = GetOutputPlugin()) { plugin->MidiCC(nController, nParam, trackChannel); } } void LFOPlugin::MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackChannel) { if(IMixPlugin *plugin = GetOutputPlugin()) { plugin->MidiPitchBend(increment, pwd, trackChannel); } } void LFOPlugin::MidiTonePortamento(int32 increment, uint8 newNote, int8 pwd, CHANNELINDEX trackChannel) { if(IMixPlugin *plugin = GetOutputPlugin()) { plugin->MidiTonePortamento(increment, newNote, pwd, trackChannel); } } void LFOPlugin::MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackChannel) { if(IMixPlugin *plugin = GetOutputPlugin()) { plugin->MidiVibrato(depth, pwd, trackChannel); } } void LFOPlugin::MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) { if(ModCommand::IsNote(static_cast(note)) && vol > 0) { SetParameter(kCurrentPhase, 0); } if(IMixPlugin *plugin = GetOutputPlugin()) { plugin->MidiCommand(instr, note, vol, trackChannel); } } void LFOPlugin::HardAllNotesOff() { if(IMixPlugin *plugin = GetOutputPlugin()) { plugin->HardAllNotesOff(); } } bool LFOPlugin::IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) { if(IMixPlugin *plugin = GetOutputPlugin()) return plugin->IsNotePlaying(note, trackerChn); else return false; } void LFOPlugin::SaveAllParameters() { auto chunk = GetChunk(false); if(chunk.empty()) return; m_pMixStruct->defaultProgram = -1; m_pMixStruct->pluginData.assign(chunk.begin(), chunk.end()); } void LFOPlugin::RestoreAllParameters(int32 /*program*/) { SetChunk(mpt::as_span(m_pMixStruct->pluginData), false); } struct PluginData { char magic[4]; uint32le version; uint32le amplitude; // float uint32le offset; // float uint32le frequency; // float uint32le waveForm; uint32le outputParam; uint8le tempoSync; uint8le polarity; uint8le bypassed; uint8le outputToCC; uint8le loopMode; }; MPT_BINARY_STRUCT(PluginData, 33) IMixPlugin::ChunkData LFOPlugin::GetChunk(bool) { PluginData chunk; memcpy(chunk.magic, "LFO ", 4); chunk.version = 0; chunk.amplitude = IEEE754binary32LE(m_amplitude).GetInt32(); chunk.offset = IEEE754binary32LE(m_offset).GetInt32(); chunk.frequency = IEEE754binary32LE(m_frequency).GetInt32(); chunk.waveForm = m_waveForm; chunk.outputParam = m_outputParam; chunk.tempoSync = m_tempoSync ? 1 : 0; chunk.polarity = m_polarity ? 1 : 0; chunk.bypassed = m_bypassed ? 1 : 0; chunk.outputToCC = m_outputToCC ? 1 : 0; chunk.loopMode = m_oneshot ? 1 : 0; m_chunkData.resize(sizeof(chunk)); memcpy(m_chunkData.data(), &chunk, sizeof(chunk)); return mpt::as_span(m_chunkData); } void LFOPlugin::SetChunk(const ChunkData &chunk, bool) { FileReader file(chunk); PluginData data; if(file.ReadStructPartial(data, mpt::saturate_cast(file.BytesLeft())) && !memcmp(data.magic, "LFO ", 4) && data.version == 0) { const float amplitude = IEEE754binary32LE().SetInt32(data.amplitude); m_amplitude = mpt::safe_clamp(amplitude, 0.0f, 1.0f); const float offset = IEEE754binary32LE().SetInt32(data.offset); m_offset = mpt::safe_clamp(offset, 0.0f, 1.0f); const float frequency = IEEE754binary32LE().SetInt32(data.frequency); m_frequency = mpt::safe_clamp(frequency, 0.0f, 1.0f); if(data.waveForm < kNumWaveforms) m_waveForm = static_cast(data.waveForm.get()); m_outputParam = data.outputParam; m_tempoSync = data.tempoSync != 0; m_polarity = data.polarity != 0; m_bypassed = data.bypassed != 0; m_outputToCC = data.outputToCC != 0; m_oneshot = data.loopMode != 0; RecalculateFrequency(); } } #ifdef MODPLUG_TRACKER std::pair LFOPlugin::GetParamUIRange(PlugParamIndex param) { if(param == kWaveform) return {0.0f, WaveformToParam(static_cast(kNumWaveforms - 1))}; else return {0.0f, 1.0f}; } CString LFOPlugin::GetParamName(PlugParamIndex param) { switch(param) { case kAmplitude: return _T("Amplitude"); case kOffset: return _T("Offset"); case kFrequency: return _T("Frequency"); case kTempoSync: return _T("Tempo Sync"); case kWaveform: return _T("Waveform"); case kPolarity: return _T("Polarity"); case kBypassed: return _T("Bypassed"); case kLoopMode: return _T("Loop Mode"); case kCurrentPhase: return _T("Set LFO Phase"); } return CString(); } CString LFOPlugin::GetParamLabel(PlugParamIndex param) { if(param == kFrequency) { if(m_tempoSync && m_computedFrequency > 0.0 && m_computedFrequency < 1.0) return _T("Beats Per Cycle"); else if(m_tempoSync) return _T("Cycles Per Beat"); else return _T("Hz"); } return CString(); } CString LFOPlugin::GetParamDisplay(PlugParamIndex param) { CString s; if(param == kPolarity) { return m_polarity ? _T("Inverted") : _T("Normal"); } else if(param == kTempoSync) { return m_tempoSync ? _T("Yes") : _T("No"); } else if(param == kBypassed) { return m_bypassed ? _T("Yes") : _T("No"); } else if(param == kWaveform) { static constexpr const TCHAR * const waveforms[] = { _T("Sine"), _T("Triangle"), _T("Saw"), _T("Square"), _T("Noise"), _T("Smoothed Noise") }; if(m_waveForm < static_cast(std::size(waveforms))) return waveforms[m_waveForm]; } else if(param == kLoopMode) { return m_oneshot ? _T("One-Shot") : _T("Looped"); } else if(param == kCurrentPhase) { return _T("Write-Only"); } else if(param < kLFONumParameters) { auto val = GetParameter(param); if(param == kOffset) val = 2.0f * val - 1.0f; if(param == kFrequency) { val = static_cast(m_computedFrequency); if(m_tempoSync && val > 0.0f && val < 1.0f) val = static_cast(1.0 / m_computedFrequency); } s.Format(_T("%.3f"), val); } return s; } CAbstractVstEditor *LFOPlugin::OpenEditor() { try { return new LFOPluginEditor(*this); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); return nullptr; } } #endif // MODPLUG_TRACKER void LFOPlugin::NextRandom() { m_random = m_nextRandom; m_nextRandom = mpt::random(m_PRNG) / static_cast(int32_min); } void LFOPlugin::RecalculateFrequency() { m_computedFrequency = 0.25 * std::pow(2.0, static_cast(m_frequency) * 8.0) - 0.25; if(m_tempoSync) { if(m_computedFrequency > 0.00045) { double freqLog = std::log(m_computedFrequency) / mpt::numbers::ln2; double freqFrac = freqLog - std::floor(freqLog); freqLog -= freqFrac; // Lock to powers of two and 1.5 times or 1.333333... times the powers of two if(freqFrac < 0.20751874963942190927313052802609) freqFrac = 0.0; else if(freqFrac < 0.5) freqFrac = 0.41503749927884381854626105605218; else if(freqFrac < 0.79248125036057809072686947197391) freqFrac = 0.58496250072115618145373894394782; else freqFrac = 1.0; m_computedFrequency = std::pow(2.0, freqLog + freqFrac) * 0.5; } else { m_computedFrequency = 0; } } RecalculateIncrement(); } void LFOPlugin::RecalculateIncrement() { m_increment = m_computedFrequency / m_SndFile.GetSampleRate(); if(m_tempoSync) { m_increment *= m_tempo / 60.0; } } IMixPlugin *LFOPlugin::GetOutputPlugin() const { PLUGINDEX outPlug = m_pMixStruct->GetOutputPlugin(); if(outPlug > m_nSlot && outPlug < MAX_MIXPLUGINS) return m_SndFile.m_MixPlugins[outPlug].pMixPlugin; else return nullptr; } OPENMPT_NAMESPACE_END #else MPT_MSVC_WORKAROUND_LNK4221(LFOPlugin) #endif // !NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/PlugInterface.cpp0000644000175000017500000007370414763553373023045 00000000000000/* * PlugInterface.cpp * ----------------- * Purpose: Default plugin interface implementation * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "PlugInterface.h" #include "../../common/FileReader.h" #include "../Sndfile.h" #include "PluginManager.h" #ifdef MODPLUG_TRACKER #include "../../mptrack/AbstractVstEditor.h" #include "../../mptrack/DefaultVstEditor.h" #include "../../mptrack/InputHandler.h" #include "../../mptrack/Mainfrm.h" #include "../../mptrack/Moddoc.h" #include "../../mptrack/Reporting.h" #include "../../mptrack/TrackerSettings.h" #include "../../mptrack/WindowMessages.h" // LoadProgram/SaveProgram #include "../mod_specifications.h" #include "../../common/mptFileIO.h" #include "../../mptrack/FileDialog.h" #include "../../mptrack/VstPresets.h" #include "mpt/io_file/inputfile.hpp" #include "mpt/io_file_read/inputfile_filecursor.hpp" #include "mpt/io_file/outputfile.hpp" #include "mpt/fs/fs.hpp" #endif // MODPLUG_TRACKER #include "../../soundlib/AudioCriticalSection.h" #include "mpt/base/aligned_array.hpp" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_span.hpp" #include #ifndef NO_PLUGINS OPENMPT_NAMESPACE_BEGIN #ifdef MODPLUG_TRACKER CModDoc *IMixPlugin::GetModDoc() { return m_SndFile.GetpModDoc(); } const CModDoc *IMixPlugin::GetModDoc() const { return m_SndFile.GetpModDoc(); } #endif // MODPLUG_TRACKER IMixPlugin::IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : m_Factory(factory) , m_SndFile(sndFile) , m_pMixStruct(&mixStruct) { m_SndFile.m_loadedPlugins++; m_MixState.pMixBuffer = mpt::align_bytes<8, MIXBUFFERSIZE * 2>(m_MixBuffer); while(m_pMixStruct != &(m_SndFile.m_MixPlugins[m_nSlot]) && m_nSlot < MAX_MIXPLUGINS - 1) { m_nSlot++; } } IMixPlugin::~IMixPlugin() { #ifdef MODPLUG_TRACKER CloseEditor(); CriticalSection cs; #endif // MODPLUG_TRACKER m_pMixStruct->pMixPlugin = nullptr; m_SndFile.m_loadedPlugins--; m_pMixStruct = nullptr; } #ifdef MODPLUG_TRACKER void IMixPlugin::SetSlot(PLUGINDEX slot) { m_nSlot = slot; m_pMixStruct = &m_SndFile.m_MixPlugins[slot]; } PlugParamValue IMixPlugin::GetScaledUIParam(PlugParamIndex param) { const auto [paramMin, paramMax] = GetParamUIRange(param); return (std::clamp(GetParameter(param), paramMin, paramMax) - paramMin) / (paramMax - paramMin); } void IMixPlugin::SetScaledUIParam(PlugParamIndex param, PlugParamValue value) { const auto [paramMin, paramMax] = GetParamUIRange(param); const auto scaledVal = paramMin + std::clamp(value, 0.0f, 1.0f) * (paramMax - paramMin); SetParameter(param, scaledVal); } CString IMixPlugin::GetFormattedParamName(PlugParamIndex param) { CString paramName = GetParamName(param); CString name; if(paramName.IsEmpty()) { name = MPT_CFORMAT("{}: Parameter {}")(mpt::cfmt::dec0<2>(param), mpt::cfmt::dec0<2>(param)); } else { name = MPT_CFORMAT("{}: {}")(mpt::cfmt::dec0<2>(param), paramName); } return name; } // Get a parameter's current value, represented by the plugin. CString IMixPlugin::GetFormattedParamValue(PlugParamIndex param) { CString paramDisplay = GetParamDisplay(param); CString paramUnits = GetParamLabel(param); paramDisplay.Trim(); paramUnits.Trim(); paramDisplay += _T(" ") + paramUnits; return paramDisplay; } CString IMixPlugin::GetFormattedProgramName(int32 index) { CString rawname = GetProgramName(index); // Let's start counting at 1 for the program name (as most MIDI hardware / software does) index++; CString formattedName; if(rawname[0] >= 0 && rawname[0] < _T(' ')) formattedName = MPT_CFORMAT("{} - Program {}")(mpt::cfmt::dec0<2>(index), index); else formattedName = MPT_CFORMAT("{} - {}")(mpt::cfmt::dec0<2>(index), rawname); return formattedName; } void IMixPlugin::SetEditorPos(int32 x, int32 y) { m_pMixStruct->editorX = x; m_pMixStruct->editorY = y; } void IMixPlugin::GetEditorPos(int32 &x, int32 &y) const { x = m_pMixStruct->editorX; y = m_pMixStruct->editorY; } #endif // MODPLUG_TRACKER bool IMixPlugin::IsBypassed() const { return m_pMixStruct != nullptr && m_pMixStruct->IsBypassed(); } void IMixPlugin::RecalculateGain() { float gain = 0.1f * static_cast(m_pMixStruct ? m_pMixStruct->GetGain() : 10); if(gain < 0.1f) gain = 1.0f; if(IsInstrument()) { gain /= m_SndFile.GetPlayConfig().getVSTiAttenuation(); gain = gain * (static_cast(m_SndFile.m_nVSTiVolume) / m_SndFile.GetPlayConfig().getNormalVSTiVol()); } m_fGain = gain; } void IMixPlugin::SetDryRatio(float dryRatio) { m_pMixStruct->fDryRatio = std::clamp(dryRatio, 0.0f, 1.0f); #ifdef MODPLUG_TRACKER m_SndFile.m_pluginDryWetRatioChanged.set(m_nSlot); #endif // MODPLUG_TRACKER } void IMixPlugin::Bypass(bool bypass) { m_pMixStruct->Info.SetBypass(bypass); #ifdef MODPLUG_TRACKER if(m_SndFile.GetpModDoc()) m_SndFile.GetpModDoc()->UpdateAllViews(PluginHint(m_nSlot + 1).Info()); #endif // MODPLUG_TRACKER } double IMixPlugin::GetOutputLatency() const { if(GetSoundFile().IsRenderingToDisc()) return 0; else return GetSoundFile().m_TimingInfo.OutputLatency; } void IMixPlugin::ProcessMixOps(float * MPT_RESTRICT pOutL, float * MPT_RESTRICT pOutR, float * MPT_RESTRICT leftPlugOutput, float * MPT_RESTRICT rightPlugOutput, uint32 numFrames) { /* float *leftPlugOutput; float *rightPlugOutput; if(m_Effect.numOutputs == 1) { // If there was just the one plugin output we copy it into our 2 outputs leftPlugOutput = rightPlugOutput = mixBuffer.GetOutputBuffer(0); } else if(m_Effect.numOutputs > 1) { // Otherwise we actually only cater for two outputs max (outputs > 2 have been mixed together already). leftPlugOutput = mixBuffer.GetOutputBuffer(0); rightPlugOutput = mixBuffer.GetOutputBuffer(1); } else { return; }*/ // -> mixop == 0 : normal processing // -> mixop == 1 : MIX += DRY - WET * wetRatio // -> mixop == 2 : MIX += WET - DRY * dryRatio // -> mixop == 3 : MIX -= WET - DRY * wetRatio // -> mixop == 4 : MIX -= middle - WET * wetRatio + middle - DRY // -> mixop == 5 : MIX_L += wetRatio * (WET_L - DRY_L) + dryRatio * (DRY_R - WET_R) // MIX_R += dryRatio * (WET_L - DRY_L) + wetRatio * (DRY_R - WET_R) // -> mixop == 6: same as normal, but forces dry ratio to 1 const PluginMixMode mixop = m_pMixStruct->GetMixMode(); float wetRatio = 1.f - m_pMixStruct->fDryRatio; float dryRatio = (mixop == PluginMixMode::Instrument) ? 1.f : m_pMixStruct->fDryRatio; // Wet / Dry range expansion [0,1] -> [-1,1] if(m_pMixStruct->IsExpandedMix()) { wetRatio = 2.0f * wetRatio - 1.0f; dryRatio = -wetRatio; } wetRatio *= m_fGain; dryRatio *= m_fGain; float * MPT_RESTRICT plugInputL = m_mixBuffer.GetInputBuffer(0); float * MPT_RESTRICT plugInputR = m_mixBuffer.GetInputBuffer(1); // Mix operation switch(mixop) { // Default mix case PluginMixMode::Default: case PluginMixMode::Instrument: for(uint32 i = 0; i < numFrames; i++) { pOutL[i] += leftPlugOutput[i] * wetRatio + plugInputL[i] * dryRatio; pOutR[i] += rightPlugOutput[i] * wetRatio + plugInputR[i] * dryRatio; } break; // Wet subtract case PluginMixMode::WetSubtract: for(uint32 i = 0; i < numFrames; i++) { pOutL[i] += plugInputL[i] - leftPlugOutput[i] * wetRatio; pOutR[i] += plugInputR[i] - rightPlugOutput[i] * wetRatio; } break; // Dry subtract case PluginMixMode::DrySubtract: for(uint32 i = 0; i < numFrames; i++) { pOutL[i] += leftPlugOutput[i] - plugInputL[i] * dryRatio; pOutR[i] += rightPlugOutput[i] - plugInputR[i] * dryRatio; } break; // Mix subtract case PluginMixMode::MixSubtract: for(uint32 i = 0; i < numFrames; i++) { pOutL[i] -= leftPlugOutput[i] - plugInputL[i] * wetRatio; pOutR[i] -= rightPlugOutput[i] - plugInputR[i] * wetRatio; } break; // Middle subtract case PluginMixMode::MiddleSubtract: for(uint32 i = 0; i < numFrames; i++) { float middle = (pOutL[i] + plugInputL[i] + pOutR[i] + plugInputR[i]) * 0.5f; pOutL[i] -= middle - leftPlugOutput[i] * wetRatio + middle - plugInputL[i]; pOutR[i] -= middle - rightPlugOutput[i] * wetRatio + middle - plugInputR[i]; } break; // Left / Right balance case PluginMixMode::LRBalance: if(m_pMixStruct->IsExpandedMix()) { wetRatio /= 2.0f; dryRatio /= 2.0f; } for(uint32 i = 0; i < numFrames; i++) { pOutL[i] += wetRatio * (leftPlugOutput[i] - plugInputL[i]) + dryRatio * (plugInputR[i] - rightPlugOutput[i]); pOutR[i] += dryRatio * (leftPlugOutput[i] - plugInputL[i]) + wetRatio * (plugInputR[i] - rightPlugOutput[i]); } break; } // If dry mix is ticked, we add the unprocessed buffer, // except with the instrument mixop as it has already been done: if(m_pMixStruct->IsDryMix() && mixop != PluginMixMode::Instrument) { for(uint32 i = 0; i < numFrames; i++) { pOutL[i] += plugInputL[i]; pOutR[i] += plugInputR[i]; } } } // Render some silence and return maximum level returned by the plugin. float IMixPlugin::RenderSilence(uint32 numFrames) { // The JUCE framework doesn't like processing while being suspended. const bool wasSuspended = !IsResumed(); if(wasSuspended) { Resume(); } float out[2][MIXBUFFERSIZE]; // scratch buffers float maxVal = 0.0f; m_mixBuffer.ClearInputBuffers(MIXBUFFERSIZE); while(numFrames > 0) { uint32 renderSamples = numFrames; LimitMax(renderSamples, mpt::saturate_cast(std::size(out[0]))); MemsetZero(out); Process(out[0], out[1], renderSamples); for(size_t i = 0; i < renderSamples; i++) { maxVal = std::max(maxVal, std::fabs(out[0][i])); maxVal = std::max(maxVal, std::fabs(out[1][i])); } numFrames -= renderSamples; } if(wasSuspended) { Suspend(); } return maxVal; } bool IMixPlugin::MidiSend(uint32 midiCode) { std::array midiData; memcpy(midiData.data(), &midiCode, 4); return MidiSend(mpt::as_span(midiData.data(), std::min(static_cast(midiData.size()), MIDIEvents::GetEventLength(mpt::byte_cast(midiData[0]))))); } // Get list of plugins to which output is sent. A nullptr indicates master output. size_t IMixPlugin::GetOutputPlugList(std::vector &list) { // At the moment we know there will only be 1 output. // Returning nullptr means plugin outputs directly to master. list.clear(); IMixPlugin *outputPlug = nullptr; if(!m_pMixStruct->IsOutputToMaster()) { PLUGINDEX nOutput = m_pMixStruct->GetOutputPlugin(); if(nOutput > m_nSlot && nOutput != PLUGINDEX_INVALID) { outputPlug = m_SndFile.m_MixPlugins[nOutput].pMixPlugin; } } list.push_back(outputPlug); return 1; } // Get a list of plugins that send data to this plugin. size_t IMixPlugin::GetInputPlugList(std::vector &list) { std::vector candidatePlugOutputs; list.clear(); for(PLUGINDEX plug = 0; plug < MAX_MIXPLUGINS; plug++) { IMixPlugin *candidatePlug = m_SndFile.m_MixPlugins[plug].pMixPlugin; if(candidatePlug) { candidatePlug->GetOutputPlugList(candidatePlugOutputs); for(auto &outPlug : candidatePlugOutputs) { if(outPlug == this) { list.push_back(candidatePlug); break; } } } } return list.size(); } // Get a list of instruments that send data to this plugin. size_t IMixPlugin::GetInputInstrumentList(std::vector &list) { list.clear(); const PLUGINDEX nThisMixPlug = m_nSlot + 1; //m_nSlot is position in mixplug array. for(INSTRUMENTINDEX ins = 0; ins <= m_SndFile.GetNumInstruments(); ins++) { if(m_SndFile.Instruments[ins] != nullptr && m_SndFile.Instruments[ins]->nMixPlug == nThisMixPlug) { list.push_back(ins); } } return list.size(); } size_t IMixPlugin::GetInputChannelList(std::vector &list) { list.clear(); PLUGINDEX nThisMixPlug = m_nSlot + 1; //m_nSlot is position in mixplug array. const CHANNELINDEX chnCount = m_SndFile.GetNumChannels(); for(CHANNELINDEX nChn=0; nChndefaultProgram = -1; // Default implementation: Save all parameter values PlugParamIndex numParams = std::min(GetNumParameters(), static_cast((std::numeric_limits::max() - sizeof(uint32)) / sizeof(IEEE754binary32LE))); uint32 nLen = numParams * sizeof(IEEE754binary32LE); if (!nLen) return; nLen += sizeof(uint32); try { m_pMixStruct->pluginData.resize(nLen); auto memFile = std::make_pair(mpt::as_span(m_pMixStruct->pluginData), mpt::IO::Offset(0)); mpt::IO::WriteIntLE(memFile, 0); // Plugin data type BeginGetProgram(); for(PlugParamIndex i = 0; i < numParams; i++) { mpt::IO::Write(memFile, IEEE754binary32LE(GetParameter(i))); } EndGetProgram(); } catch(mpt::out_of_memory e) { m_pMixStruct->pluginData.clear(); mpt::delete_out_of_memory(e); } } void IMixPlugin::RestoreAllParameters(int32 /*program*/) { if(m_pMixStruct != nullptr && m_pMixStruct->pluginData.size() >= sizeof(uint32)) { FileReader memFile(mpt::as_span(m_pMixStruct->pluginData)); uint32 type = memFile.ReadUint32LE(); if(type == 0) { const uint32 numParams = GetNumParameters(); if((m_pMixStruct->pluginData.size() - sizeof(uint32)) >= (numParams * sizeof(IEEE754binary32LE))) { BeginSetProgram(); for(uint32 i = 0; i < numParams; i++) { const auto value = memFile.ReadFloatLE(); SetParameter(i, std::isfinite(value) ? value : 0.0f); } EndSetProgram(); } } } } #ifdef MODPLUG_TRACKER void IMixPlugin::ToggleEditor() { // We only really need this mutex for bridged plugins, as we may be processing window messages (in the same thread) while the editor opens. // The user could press the toggle button while the editor is loading and thus close the editor while still being initialized. // Note that this does not protect against closing the module while the editor is still loading. static bool initializing = false; if(initializing) return; initializing = true; if (m_pEditor) { CloseEditor(); } else { m_pEditor = OpenEditor(); if (m_pEditor) m_pEditor->OpenEditor(CMainFrame::GetMainFrame()); } initializing = false; } // Provide default plugin editor CAbstractVstEditor *IMixPlugin::OpenEditor() { try { return new CDefaultVstEditor(*this); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); return nullptr; } } void IMixPlugin::CloseEditor() { if(m_pEditor) { if (m_pEditor->m_hWnd) m_pEditor->DoClose(); delete m_pEditor; m_pEditor = nullptr; } } // Automate a parameter from the plugin GUI (both custom and default plugin GUI) void IMixPlugin::AutomateParameter(PlugParamIndex param) { CModDoc *modDoc = GetModDoc(); if(modDoc == nullptr) { return; } // TODO: Check if any params are actually automatable, and if there are but this one isn't, chicken out if(m_recordAutomation) { // Record parameter change modDoc->RecordParamChange(GetSlot(), param); } modDoc->SendNotifyMessageToAllViews(WM_MOD_PLUGPARAMAUTOMATE, m_nSlot, param); if(auto *vstEditor = GetEditor(); vstEditor && vstEditor->m_hWnd) { // Mark track modified if GUI is open and format supports plugins SetModified(); // Do not use InputHandler in case we are coming from a bridged plugin editor if((GetAsyncKeyState(VK_SHIFT) & 0x8000) && TrackerSettings::Instance().midiMappingInPluginEditor) { // Shift pressed -> Open MIDI mapping dialog CMainFrame::GetMainFrame()->PostMessage(WM_MOD_MIDIMAPPING, m_nSlot, param); } // Learn macro int macroToLearn = vstEditor->GetLearnMacro(); if (macroToLearn > -1) { modDoc->LearnMacro(macroToLearn, param); vstEditor->SetLearnMacro(-1); } } } void IMixPlugin::SetModified() { CModDoc *modDoc = GetModDoc(); if(modDoc != nullptr && m_SndFile.GetModSpecifications().supportsPlugins) { modDoc->SetModified(); } } bool IMixPlugin::SaveProgram() { mpt::PathString defaultDir = TrackerSettings::Instance().PathPluginPresets.GetWorkingDir(); const bool useDefaultDir = !defaultDir.empty(); if(!useDefaultDir && mpt::native_fs{}.is_file(m_Factory.dllPath)) { defaultDir = m_Factory.dllPath.GetDirectoryWithDrive(); } CString progName = m_Factory.libraryName.ToCString() + _T(" - ") + GetCurrentProgramName(); progName = mpt::SanitizePathComponent(progName); FileDialog dlg = SaveFileDialog() .DefaultExtension("fxb") .DefaultFilename(progName) .ExtensionFilter("VST Plugin Programs (*.fxp)|*.fxp|" "VST Plugin Banks (*.fxb)|*.fxb||") .WorkingDirectory(defaultDir); if(!dlg.Show(m_pEditor)) return false; if(useDefaultDir) { TrackerSettings::Instance().PathPluginPresets.SetWorkingDir(dlg.GetWorkingDirectory()); } const bool isBank = (dlg.GetExtension() == P_("fxb")); try { mpt::IO::SafeOutputFile sf(dlg.GetFirstFile(), std::ios::binary, mpt::IO::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave)); mpt::IO::ofstream &f = sf; f.exceptions(f.exceptions() | std::ios::badbit | std::ios::failbit); if(f.good() && VSTPresets::SaveFile(f, *this, isBank)) return true; } catch(const std::exception &) { } Reporting::Error("Error saving preset.", m_pEditor); return false; } bool IMixPlugin::LoadProgram(mpt::PathString fileName) { mpt::PathString defaultDir = TrackerSettings::Instance().PathPluginPresets.GetWorkingDir(); bool useDefaultDir = !defaultDir.empty(); if(!useDefaultDir && mpt::native_fs{}.is_file(m_Factory.dllPath)) { defaultDir = m_Factory.dllPath.GetDirectoryWithDrive(); } if(fileName.empty()) { FileDialog dlg = OpenFileDialog() .DefaultExtension("fxp") .ExtensionFilter("VST Plugin Programs and Banks (*.fxp,*.fxb)|*.fxp;*.fxb|" "VST Plugin Programs (*.fxp)|*.fxp|" "VST Plugin Banks (*.fxb)|*.fxb|" "All Files|*.*||") .WorkingDirectory(defaultDir); if(!dlg.Show(m_pEditor)) return false; if(useDefaultDir) { TrackerSettings::Instance().PathPluginPresets.SetWorkingDir(dlg.GetWorkingDirectory()); } fileName = dlg.GetFirstFile(); } const char *errorStr = nullptr; mpt::IO::InputFile f(fileName, SettingCacheCompleteFileBeforeLoading()); if(f.IsValid()) { FileReader file = GetFileReader(f); errorStr = VSTPresets::GetErrorMessage(VSTPresets::LoadFile(file, *this)); } else { errorStr = "Can't open file."; } if(errorStr == nullptr) { if(GetModDoc() != nullptr && GetSoundFile().GetModSpecifications().supportsPlugins) { GetModDoc()->SetModified(); } return true; } else { Reporting::Error(errorStr, m_pEditor); return false; } } #endif // MODPLUG_TRACKER //////////////////////////////////////////////////////////////////// // IMidiPlugin: Default implementation of plugins with MIDI input // //////////////////////////////////////////////////////////////////// IMidiPlugin::IMidiPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_MidiCh{{}} { for(auto &chn : m_MidiCh) { chn.midiPitchBendPos = EncodePitchBendParam(MIDIEvents::pitchBendCentre); // centre pitch bend on all channels chn.ResetProgram(sndFile.m_playBehaviour[kPluginDefaultProgramAndBank1]); } } void IMidiPlugin::ApplyPitchWheelDepth(int32 &value, int8 pwd) { if(pwd != 0) { value = (value * ((MIDIEvents::pitchBendMax - MIDIEvents::pitchBendCentre + 1) / 64)) / pwd; } else { value = 0; } } // Get the MIDI channel currently associated with a given tracker channel uint8 IMidiPlugin::GetMidiChannel(const ModChannel &chn, CHANNELINDEX trackChannel) const { if(auto ins = chn.pModInstrument; ins != nullptr) return ins->GetMIDIChannel(chn, trackChannel); else return 0; } uint8 IMidiPlugin::GetMidiChannel(CHANNELINDEX trackChannel) const { if(trackChannel < std::size(m_SndFile.m_PlayState.Chn)) return GetMidiChannel(m_SndFile.m_PlayState.Chn[trackChannel], trackChannel); else return 0; } void IMidiPlugin::MidiCC(MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) { //Error checking LimitMax(nController, MIDIEvents::MIDICC_end); LimitMax(nParam, uint8(127)); const auto midiCh = GetMidiChannel(trackChannel); if(m_SndFile.m_playBehaviour[kMIDICCBugEmulation]) MidiSend(MIDIEvents::Event(MIDIEvents::evControllerChange, midiCh, nParam, static_cast(nController))); // param and controller are swapped (old broken implementation) else MidiSend(MIDIEvents::CC(nController, midiCh, nParam)); } // Set MIDI pitch for given MIDI channel to the specified raw 14-bit position void IMidiPlugin::MidiPitchBendRaw(int32 pitchbend, CHANNELINDEX trackerChn) { SendMidiPitchBend(GetMidiChannel(trackerChn), EncodePitchBendParam(Clamp(pitchbend, MIDIEvents::pitchBendMin, MIDIEvents::pitchBendMax))); } // Bend MIDI pitch for given MIDI channel using fine tracker param (one unit = 1/64th of a note step) void IMidiPlugin::MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackerChn) { const auto midiCh = GetMidiChannel(trackerChn); if(m_SndFile.m_playBehaviour[kOldMIDIPitchBends]) { // OpenMPT Legacy: Old pitch slides never were really accurate, but setting the PWD to 13 in plugins would give the closest results. increment = (increment * 0x800 * 13) / (0xFF * pwd); increment = EncodePitchBendParam(increment); } else { increment = EncodePitchBendParam(increment); ApplyPitchWheelDepth(increment, pwd); } int32 newPitchBendPos = (increment + m_MidiCh[midiCh].midiPitchBendPos) & kPitchBendMask; Limit(newPitchBendPos, EncodePitchBendParam(MIDIEvents::pitchBendMin), EncodePitchBendParam(MIDIEvents::pitchBendMax)); SendMidiPitchBend(midiCh, newPitchBendPos); } void IMidiPlugin::MidiTonePortamento(int32 increment, uint8 newNote, int8 pwd, CHANNELINDEX trackerChn) { const auto midiCh = GetMidiChannel(trackerChn); int32 targetBend = EncodePitchBendParam(64 * (newNote - static_cast(m_MidiCh[midiCh].lastNote))); ApplyPitchWheelDepth(targetBend, pwd); targetBend += EncodePitchBendParam(MIDIEvents::pitchBendCentre); if(targetBend < m_MidiCh[midiCh].midiPitchBendPos) increment = -increment; increment = EncodePitchBendParam(increment); ApplyPitchWheelDepth(increment, pwd); int32 newPitchBendPos = (increment + m_MidiCh[midiCh].midiPitchBendPos) & kPitchBendMask; if((newPitchBendPos > targetBend && increment > 0) || (newPitchBendPos < targetBend && increment < 0)) newPitchBendPos = targetBend; Limit(newPitchBendPos, EncodePitchBendParam(MIDIEvents::pitchBendMin), EncodePitchBendParam(MIDIEvents::pitchBendMax)); SendMidiPitchBend(midiCh, newPitchBendPos); } // Set MIDI pitch for given MIDI channel using fixed point pitch bend value (converted back to 0-16383 MIDI range) void IMidiPlugin::SendMidiPitchBend(uint8 midiCh, int32 newPitchBendPos) { MPT_ASSERT(EncodePitchBendParam(MIDIEvents::pitchBendMin) <= newPitchBendPos && newPitchBendPos <= EncodePitchBendParam(MIDIEvents::pitchBendMax)); m_MidiCh[midiCh].midiPitchBendPos = newPitchBendPos; MidiSend(MIDIEvents::PitchBend(midiCh, DecodePitchBendParam(newPitchBendPos))); } // Apply vibrato effect through pitch wheel commands on a given MIDI channel. void IMidiPlugin::MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackerChn) { const auto midiCh = GetMidiChannel(trackerChn); depth = EncodePitchBendParam(depth); if(depth != 0 || (m_MidiCh[midiCh].midiPitchBendPos & kVibratoFlag)) { ApplyPitchWheelDepth(depth, pwd); // Temporarily add vibrato offset to current pitch int32 newPitchBendPos = (depth + m_MidiCh[midiCh].midiPitchBendPos) & kPitchBendMask; Limit(newPitchBendPos, EncodePitchBendParam(MIDIEvents::pitchBendMin), EncodePitchBendParam(MIDIEvents::pitchBendMax)); MidiSend(MIDIEvents::PitchBend(midiCh, DecodePitchBendParam(newPitchBendPos))); } // Update vibrato status if(depth != 0) m_MidiCh[midiCh].midiPitchBendPos |= kVibratoFlag; else m_MidiCh[midiCh].midiPitchBendPos &= ~kVibratoFlag; } void IMidiPlugin::MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) { if(trackChannel >= MAX_CHANNELS) return; const auto midiCh = GetMidiChannel(trackChannel); PlugInstrChannel &channel = m_MidiCh[midiCh]; uint8 rawNote = static_cast(note & MIDI_NOTE_MASK); uint16 midiBank = instr.wMidiBank - 1; uint8 midiProg = instr.nMidiProgram - 1; bool bankChanged = (channel.currentBank != midiBank) && (midiBank < 0x4000); bool progChanged = (channel.currentProgram != midiProg) && (midiProg < 0x80); //get vol in [0,128[ uint8 volume = static_cast(std::min((vol + 1u) / 2u, 127u)); // Bank change if(bankChanged) { uint8 high = static_cast(midiBank >> 7); uint8 low = static_cast(midiBank & 0x7F); //m_SndFile.ProcessMIDIMacro(trackChannel, false, m_SndFile.m_MidiCfg.Global[MIDIOUT_BANKSEL], 0, m_nSlot + 1); MidiSend(MIDIEvents::CC(MIDIEvents::MIDICC_BankSelect_Coarse, midiCh, high)); MidiSend(MIDIEvents::CC(MIDIEvents::MIDICC_BankSelect_Fine, midiCh, low)); channel.currentBank = midiBank; } // Program change // According to the MIDI specs, a bank change alone doesn't have to change the active program - it will only change the bank of subsequent program changes. // Thus we send program changes also if only the bank has changed. if(progChanged || (midiProg < 0x80 && bankChanged)) { channel.currentProgram = midiProg; //m_SndFile.ProcessMIDIMacro(trackChannel, false, m_SndFile.m_MidiCfg.Global[MIDIOUT_PROGRAM], 0, m_nSlot + 1); MidiSend(MIDIEvents::ProgramChange(midiCh, midiProg)); } // Specific Note Off if(note & MIDI_NOTE_OFF) { uint8 i = rawNote - NOTE_MIN; if(i < mpt::array_size::size && channel.noteOnMap[i][trackChannel]) { channel.noteOnMap[i][trackChannel]--; MidiSend(MIDIEvents::NoteOff(midiCh, i, 0)); } } // "Hard core" All Sounds Off on this midi and tracker channel // This one doesn't check the note mask - just one note off per note. // Also less likely to cause a VST event buffer overflow. else if(note == NOTE_NOTECUT) // ^^ { MidiSend(MIDIEvents::CC(MIDIEvents::MIDICC_AllNotesOff, midiCh, 0)); MidiSend(MIDIEvents::CC(MIDIEvents::MIDICC_AllSoundOff, midiCh, 0)); // Turn off all notes for(uint8 i = 0; i < std::size(channel.noteOnMap); i++) { channel.noteOnMap[i][trackChannel] = 0; MidiSend(MIDIEvents::NoteOff(midiCh, i, volume)); } } // All "active" notes off on this midi and tracker channel // using note mask. else if(note == NOTE_KEYOFF || note == NOTE_FADE) // ==, ~~ { for(uint8 i = 0; i < std::size(channel.noteOnMap); i++) { // Some VSTis need a note off for each instance of a note on, e.g. fabfilter. while(channel.noteOnMap[i][trackChannel]) { MidiSend(MIDIEvents::NoteOff(midiCh, i, volume)); channel.noteOnMap[i][trackChannel]--; } } } // Note On else if(rawNote >= NOTE_MIN && rawNote < NOTE_MIN + mpt::array_size::size) { if(!(note & MIDI_NOTE_ARPEGGIO)) { m_MidiCh[midiCh].lastNote = rawNote; m_SndFile.m_PlayState.Chn[trackChannel].lastMidiNoteWithoutArp = rawNote; // Reset pitch bend on each new note, tracker style. // This is done if the pitch wheel has been moved or there was a vibrato on the previous row (in which case the "vstVibratoFlag" bit of the pitch bend memory is set) auto newPitchBendPos = EncodePitchBendParam(Clamp(m_SndFile.m_PlayState.Chn[trackChannel].GetMIDIPitchBend(), MIDIEvents::pitchBendMin, MIDIEvents::pitchBendMax)); if(m_MidiCh[midiCh].midiPitchBendPos != newPitchBendPos) { SendMidiPitchBend(midiCh, newPitchBendPos); } } // count instances of active notes. // This is to send a note off for each instance of a note, for plugs like Fabfilter. // Problem: if a note dies out naturally and we never send a note off, this counter // will block at max until note off. Is this a problem? // Safe to assume we won't need more than 255 note offs max on a given note? rawNote -= NOTE_MIN; if(channel.noteOnMap[rawNote][trackChannel] < uint8_max) { channel.noteOnMap[rawNote][trackChannel]++; } MidiSend(MIDIEvents::NoteOn(midiCh, rawNote, volume)); } } bool IMidiPlugin::IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) { if(!ModCommand::IsNote(note) || trackerChn >= std::size(m_MidiCh[GetMidiChannel(trackerChn)].noteOnMap[note])) return false; note -= NOTE_MIN; return (m_MidiCh[GetMidiChannel(trackerChn)].noteOnMap[note][trackerChn] != 0); } void IMidiPlugin::MoveChannel(CHANNELINDEX from, CHANNELINDEX to) { if(from >= std::size(m_MidiCh[GetMidiChannel(from)].noteOnMap[0]) || to >= std::size(m_MidiCh[GetMidiChannel(from)].noteOnMap[0])) return; for(auto ¬eOnMap : m_MidiCh[GetMidiChannel(from)].noteOnMap) { noteOnMap[to] = noteOnMap[from]; noteOnMap[from] = 0; } } void IMidiPlugin::ReceiveMidi(mpt::const_byte_span midiData) { if(midiData.empty()) return; ResetSilence(); // I think we should only route events to plugins that are explicitely specified as output plugins of the current plugin. // This should probably use GetOutputPlugList here if we ever get to support multiple output plugins. PLUGINDEX receiver; if(m_pMixStruct != nullptr && (receiver = m_pMixStruct->GetOutputPlugin()) != PLUGINDEX_INVALID) { IMixPlugin *plugin = m_SndFile.m_MixPlugins[receiver].pMixPlugin; // Add all events to the plugin's queue. plugin->MidiSend(midiData); } #ifdef MODPLUG_TRACKER if(m_recordMIDIOut && midiData[0] != std::byte{0xF0}) { // Spam MIDI data to all views uint32 midiCode = 0; memcpy(&midiCode, midiData.data(), std::min(sizeof(midiCode), midiData.size())); ::PostMessage(CMainFrame::GetMainFrame()->GetMidiRecordWnd(), WM_MOD_MIDIMSG, midiCode, reinterpret_cast(this)); } #endif // MODPLUG_TRACKER } // SNDMIXPLUGIN functions void SNDMIXPLUGIN::SetGain(uint8 gain) { Info.gain = gain; if(pMixPlugin != nullptr) pMixPlugin->RecalculateGain(); } void SNDMIXPLUGIN::SetBypass(bool bypass) { if(pMixPlugin != nullptr) pMixPlugin->Bypass(bypass); else Info.SetBypass(bypass); } void SNDMIXPLUGIN::Destroy() { if(pMixPlugin) { CriticalSection cs; pMixPlugin->GetPluginFactory().RemovePluginInstanceFromList(*pMixPlugin); pMixPlugin->Release(); pMixPlugin = nullptr; } pluginData.clear(); pluginData.shrink_to_fit(); } OPENMPT_NAMESPACE_END #endif // NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/PluginManager.cpp0000644000175000017500000006100514763542673023036 00000000000000/* * PluginManager.cpp * ----------------- * Purpose: Implementation of the plugin manager, which keeps a list of known plugins and instantiates them. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "PluginManager.h" #include "PlugInterface.h" #include "../../common/version.h" #if defined(MPT_WITH_DMO) #include "mpt/uuid/guid.hpp" #endif // MPT_WITH_DMO #include "mpt/uuid/uuid.hpp" // Built-in plugins #include "DigiBoosterEcho.h" #include "LFOPlugin.h" #include "SymMODEcho.h" #include "dmo/DMOPlugin.h" #include "dmo/Chorus.h" #include "dmo/Compressor.h" #include "dmo/Distortion.h" #include "dmo/Echo.h" #include "dmo/Flanger.h" #include "dmo/Gargle.h" #include "dmo/I3DL2Reverb.h" #include "dmo/ParamEq.h" #include "dmo/WavesReverb.h" #ifdef MODPLUG_TRACKER #include "../../mptrack/plugins/MidiInOut.h" #endif // MODPLUG_TRACKER #include "../../common/mptStringBuffer.h" #include "../Sndfile.h" #include "../Loaders.h" #ifdef MPT_WITH_VST #include "../../mptrack/Vstplug.h" #include "../../pluginBridge/BridgeWrapper.h" #ifdef MODPLUG_TRACKER #include "mpt/fs/fs.hpp" #endif // MODPLUG_TRACKER #endif // MPT_WITH_VST #if defined(MPT_WITH_DMO) #include #include #include #endif // MPT_WITH_DMO #ifdef MODPLUG_TRACKER #include "../../mptrack/Mptrack.h" #include "../../mptrack/Reporting.h" #include "../../mptrack/TrackerSettings.h" #include "../../mptrack/AbstractVstEditor.h" #include "../../soundlib/AudioCriticalSection.h" #include "../mptrack/ExceptionHandler.h" #include "mpt/crc/crc.hpp" #endif // MODPLUG_TRACKER OPENMPT_NAMESPACE_BEGIN using namespace mpt::uuid_literals; #ifdef MPT_ALL_LOGGING #define VST_LOG #define DMO_LOG #endif #ifdef MODPLUG_TRACKER static constexpr const mpt::uchar *cacheSection = UL_("PluginCache"); #endif // MODPLUG_TRACKER #ifdef MPT_WITH_VST uint8 VSTPluginLib::GetNativePluginArch() { uint8 result = 0; switch(mpt::OS::Windows::GetProcessArchitecture()) { case mpt::OS::Windows::Architecture::x86: result = PluginArch_x86; break; case mpt::OS::Windows::Architecture::amd64: result = PluginArch_amd64; break; case mpt::OS::Windows::Architecture::arm: result = PluginArch_arm; break; case mpt::OS::Windows::Architecture::arm64: result = PluginArch_arm64; break; default: result = 0; break; } return result; } mpt::ustring VSTPluginLib::GetPluginArchName(uint8 arch) { mpt::ustring result; switch(arch) { case PluginArch_x86: result = U_("x86"); break; case PluginArch_amd64: result = U_("amd64"); break; case PluginArch_arm: result = U_("arm"); break; case PluginArch_arm64: result = U_("arm64"); break; default: result = U_(""); break; } return result; } uint8 VSTPluginLib::GetDllArch(bool fromCache) const { // Built-in plugins are always native. if(dllPath.empty()) return GetNativePluginArch(); #ifdef MPT_WITH_VST if(!dllArch || !fromCache) { dllArch = static_cast(BridgeWrapper::GetPluginBinaryType(dllPath)); } #else // !MPT_WITH_VST MPT_UNREFERENCED_PARAMETER(fromCache); #endif // MPT_WITH_VST return dllArch; } mpt::ustring VSTPluginLib::GetDllArchName(bool fromCache) const { return GetPluginArchName(GetDllArch(fromCache)); } mpt::ustring VSTPluginLib::GetDllArchNameUser(bool fromCache) const { return GetPluginArchName(GetDllArch(fromCache)); } bool VSTPluginLib::IsNative(bool fromCache) const { return GetDllArch(fromCache) == GetNativePluginArch(); } bool VSTPluginLib::IsNativeFromCache() const { return dllArch == GetNativePluginArch() || dllArch == 0; } #endif // MPT_WITH_VST // PluginCache format: // FullDllPath = (hex-encoded) // .Flags = Plugin Flags (see VSTPluginLib::DecodeCacheFlags). // .Vendor = Plugin Vendor String. #ifdef MODPLUG_TRACKER void VSTPluginLib::WriteToCache() const { SettingsContainer &cacheFile = theApp.GetPluginCache(); mpt::ustring pathStr; if(theApp.IsPortableMode()) pathStr = theApp.PathAbsoluteToInstallRelative(dllPath).ToUnicode(); else pathStr = dllPath.ToUnicode(); if(shellPluginID) pathStr += U_("|") + mpt::ufmt::HEX0<8>(shellPluginID); // CRC is used to distinguish plugins sharing the same IDs const std::string crcName = mpt::ToCharset(mpt::Charset::UTF8, pathStr); const mpt::crc32 crc(crcName); const mpt::ustring IDs = mpt::ufmt::HEX0<8>(static_cast(pluginId1)) + mpt::ufmt::HEX0<8>(static_cast(pluginId2)) + mpt::ufmt::HEX0<8>(crc.result()); cacheFile.Write(cacheSection, pathStr, IDs); cacheFile.Write(cacheSection, IDs + U_(".Vendor"), vendor); cacheFile.Write(cacheSection, IDs + U_(".Flags"), EncodeCacheFlags()); } #endif // MODPLUG_TRACKER void VSTPluginLib::InsertPluginInstanceIntoList(IMixPlugin &pluginInstance) { pluginInstance.m_pNext = pPluginsList; if(pPluginsList) { pPluginsList->m_pPrev = &pluginInstance; } pPluginsList = &pluginInstance; } void VSTPluginLib::RemovePluginInstanceFromList(IMixPlugin &pluginInstance) { if(pPluginsList == &pluginInstance) { pPluginsList = pluginInstance.m_pNext; } if(pluginInstance.m_pNext) { pluginInstance.m_pNext->m_pPrev = pluginInstance.m_pPrev; } if(pluginInstance.m_pPrev) { pluginInstance.m_pPrev->m_pNext = pluginInstance.m_pNext; } pluginInstance.m_pPrev = nullptr; pluginInstance.m_pNext = nullptr; } bool CreateMixPluginProc(SNDMIXPLUGIN &mixPlugin, CSoundFile &sndFile) { #ifdef MODPLUG_TRACKER CVstPluginManager *that = theApp.GetPluginManager(); if(that) { return that->CreateMixPlugin(mixPlugin, sndFile); } return false; #else if(!sndFile.m_PluginManager) { sndFile.m_PluginManager = std::make_unique(); } return sndFile.m_PluginManager->CreateMixPlugin(mixPlugin, sndFile); #endif // MODPLUG_TRACKER } CVstPluginManager::CVstPluginManager() { #if defined(MPT_WITH_DMO) HRESULT COMinit = CoInitializeEx(NULL, COINIT_MULTITHREADED); if(COMinit == S_OK || COMinit == S_FALSE) { MustUnInitilizeCOM = true; } #endif // Hard-coded "plugins" static constexpr struct { VSTPluginLib::CreateProc createProc; const char *filename, *name; uint32 pluginId1, pluginId2; PluginCategory category; bool isInstrument, isOurs; } BuiltInPlugins[] = { // DirectX Media Objects Emulation { DMO::Chorus::Create, "{EFE6629C-81F7-4281-BD91-C9D604A95AF6}", "Chorus", kDmoMagic, 0xEFE6629C, PluginCategory::DMO, false, false }, { DMO::Compressor::Create, "{EF011F79-4000-406D-87AF-BFFB3FC39D57}", "Compressor", kDmoMagic, 0xEF011F79, PluginCategory::DMO, false, false }, { DMO::Distortion::Create, "{EF114C90-CD1D-484E-96E5-09CFAF912A21}", "Distortion", kDmoMagic, 0xEF114C90, PluginCategory::DMO, false, false }, { DMO::Echo::Create, "{EF3E932C-D40B-4F51-8CCF-3F98F1B29D5D}", "Echo", kDmoMagic, 0xEF3E932C, PluginCategory::DMO, false, false }, { DMO::Flanger::Create, "{EFCA3D92-DFD8-4672-A603-7420894BAD98}", "Flanger", kDmoMagic, 0xEFCA3D92, PluginCategory::DMO, false, false }, { DMO::Gargle::Create, "{DAFD8210-5711-4B91-9FE3-F75B7AE279BF}", "Gargle", kDmoMagic, 0xDAFD8210, PluginCategory::DMO, false, false }, { DMO::I3DL2Reverb::Create, "{EF985E71-D5C7-42D4-BA4D-2D073E2E96F4}", "I3DL2Reverb", kDmoMagic, 0xEF985E71, PluginCategory::DMO, false, false }, { DMO::ParamEq::Create, "{120CED89-3BF4-4173-A132-3CB406CF3231}", "ParamEq", kDmoMagic, 0x120CED89, PluginCategory::DMO, false, false }, { DMO::WavesReverb::Create, "{87FC0268-9A55-4360-95AA-004A1D9DE26C}", "WavesReverb", kDmoMagic, 0x87FC0268, PluginCategory::DMO, false, false }, // First (inaccurate) Flanger implementation (will be chosen based on library name, shares ID1 and ID2 with regular Flanger) { DMO::Flanger::CreateLegacy, "{EFCA3D92-DFD8-4672-A603-7420894BAD98}", "Flanger (Legacy)", kDmoMagic, 0xEFCA3D92, PluginCategory::Hidden, false, false }, // DigiBooster Pro Echo DSP { DigiBoosterEcho::Create, "", "DigiBooster Pro Echo", MagicLE("DBM0"), MagicLE("Echo"), PluginCategory::RoomFx, false, true }, // LFO { LFOPlugin::Create, "", "LFO", MagicLE("OMPT"), MagicLE("LFO "), PluginCategory::Generator, false, true }, // SymMOD Echo { SymMODEcho::Create, "", "SymMOD Echo", MagicLE("SymM"), MagicLE("Echo"), PluginCategory::RoomFx, false, true }, #ifdef MODPLUG_TRACKER { MidiInOut::Create, "", "MIDI Input Output", PLUGMAGIC('V','s','t','P'), PLUGMAGIC('M','M','I','D'), PluginCategory::Synth, true, true }, #endif // MODPLUG_TRACKER }; pluginList.reserve(std::size(BuiltInPlugins)); for(const auto &plugin : BuiltInPlugins) { auto &plug = pluginList.emplace_back(std::make_unique(plugin.createProc, true, mpt::PathString::FromUTF8(plugin.filename), mpt::PathString::FromUTF8(plugin.name))); plug->pluginId1 = plugin.pluginId1; plug->pluginId2 = plugin.pluginId2; plug->category = plugin.category; plug->isInstrument = plugin.isInstrument; #ifdef MODPLUG_TRACKER if(plugin.isOurs) plug->vendor = _T("OpenMPT Project"); #endif // MODPLUG_TRACKER } #ifdef MODPLUG_TRACKER // For security reasons, we do not load untrusted DMO plugins in libopenmpt. EnumerateDirectXDMOs(); #endif } CVstPluginManager::~CVstPluginManager() { for(auto &plug : pluginList) { while(plug->pPluginsList != nullptr) { IMixPlugin *pluginInstance = plug->pPluginsList; plug->RemovePluginInstanceFromList(*pluginInstance); pluginInstance->Release(); } } #if defined(MPT_WITH_DMO) if(MustUnInitilizeCOM) { CoUninitialize(); MustUnInitilizeCOM = false; } #endif } bool CVstPluginManager::IsValidPlugin(const VSTPluginLib *pLib) const { return std::find_if(pluginList.begin(), pluginList.end(), [pLib](const std::unique_ptr &value) { return value.get() == pLib; }) != pluginList.end(); } void CVstPluginManager::EnumerateDirectXDMOs() { #if defined(MPT_WITH_DMO) static constexpr mpt::UUID knownDMOs[] = { "745057C7-F353-4F2D-A7EE-58434477730E"_uuid, // AEC (Acoustic echo cancellation, not usable) "EFE6629C-81F7-4281-BD91-C9D604A95AF6"_uuid, // Chorus "EF011F79-4000-406D-87AF-BFFB3FC39D57"_uuid, // Compressor "EF114C90-CD1D-484E-96E5-09CFAF912A21"_uuid, // Distortion "EF3E932C-D40B-4F51-8CCF-3F98F1B29D5D"_uuid, // Echo "EFCA3D92-DFD8-4672-A603-7420894BAD98"_uuid, // Flanger "DAFD8210-5711-4B91-9FE3-F75B7AE279BF"_uuid, // Gargle "EF985E71-D5C7-42D4-BA4D-2D073E2E96F4"_uuid, // I3DL2Reverb "120CED89-3BF4-4173-A132-3CB406CF3231"_uuid, // ParamEq "87FC0268-9A55-4360-95AA-004A1D9DE26C"_uuid, // WavesReverb "F447B69E-1884-4A7E-8055-346F74D6EDB3"_uuid, // Resampler DMO (not usable) "A8122FF4-9E52-4374-B3D9-B4063E77109D"_uuid, // XnaVisualizerDmo (not usable) }; HKEY hkEnum; TCHAR keyname[128]; LONG cr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("software\\classes\\DirectShow\\MediaObjects\\Categories\\f3602b3f-0592-48df-a4cd-674721e7ebeb"), 0, KEY_READ, &hkEnum); DWORD index = 0; while (cr == ERROR_SUCCESS) { if ((cr = RegEnumKey(hkEnum, index, keyname, mpt::saturate_cast(std::size(keyname)))) == ERROR_SUCCESS) { CLSID clsid; mpt::winstring formattedKey = mpt::winstring(_T("{")) + mpt::winstring(keyname) + mpt::winstring(_T("}")); if(mpt::VerifyStringToCLSID(formattedKey, clsid)) { if(!mpt::contains(knownDMOs, clsid)) { HKEY hksub; formattedKey = mpt::winstring(_T("software\\classes\\DirectShow\\MediaObjects\\")) + mpt::winstring(keyname); if (RegOpenKey(HKEY_LOCAL_MACHINE, formattedKey.c_str(), &hksub) == ERROR_SUCCESS) { TCHAR name[64]; DWORD datatype = REG_SZ; DWORD datasize = sizeof(name); if(ERROR_SUCCESS == RegQueryValueEx(hksub, nullptr, 0, &datatype, (LPBYTE)name, &datasize)) { auto &plug = pluginList.emplace_back(std::make_unique(DMOPlugin::Create, true, mpt::PathString::FromNative(mpt::GUIDToString(clsid)), mpt::PathString::FromNative(ParseMaybeNullTerminatedStringFromBufferWithSizeInBytes(name, datasize)))); plug->pluginId1 = kDmoMagic; plug->pluginId2 = clsid.Data1; plug->category = PluginCategory::DMO; #ifdef DMO_LOG MPT_LOG_GLOBAL(LogDebug, "DMO", MPT_UFORMAT("Found \"{}\" clsid={}\n")(plug->libraryName, plug->dllPath)); #endif } RegCloseKey(hksub); } } } } index++; } if (hkEnum) RegCloseKey(hkEnum); #endif // MPT_WITH_DMO } #ifdef MPT_WITH_VST // Convert CVstPlugin::LoadResult into a collection of VSTPluginLibs. static std::vector GetPluginInformation(VSTPluginLib plug, const CVstPlugin::LoadResult &loadResult) { plug.pluginId1 = loadResult.magic; plug.pluginId2 = loadResult.uniqueID; plug.isInstrument = CVstPlugin::IsInstrument(*loadResult.effect); std::vector containedPlugins; if(loadResult.shellPlugins.empty()) { #ifdef MODPLUG_TRACKER plug.WriteToCache(); #endif // MODPLUG_TRACKER containedPlugins.push_back(std::move(plug)); } else { for(auto &shellPlug : loadResult.shellPlugins) { plug.shellPluginID = shellPlug.shellPluginID; plug.libraryName = mpt::PathString::FromLocale(shellPlug.name); #ifdef MODPLUG_TRACKER plug.WriteToCache(); #endif // MODPLUG_TRACKER containedPlugins.push_back(plug); } } return containedPlugins; } #endif // !NO_VST #ifdef MODPLUG_TRACKER // Add a plugin to the list of known plugins. std::vector CVstPluginManager::AddPlugin(const mpt::PathString &dllPath, bool maskCrashes, bool fromCache, bool *fileFound, uint32 shellPluginID) { const mpt::PathString fileName = dllPath.GetFilenameBase(); // Check if this is already a known plugin for(const auto &dupePlug : pluginList) { if(shellPluginID == dupePlug->shellPluginID && !mpt::PathCompareNoCase(dllPath, dupePlug->dllPath)) return {dupePlug.get()}; } if(fileFound != nullptr) { *fileFound = mpt::native_fs{}.is_file(dllPath); } // Look if the plugin info is stored in the PluginCache if(fromCache) { mpt::ustring shellStr; if(shellPluginID) shellStr = UL_("|") + mpt::ufmt::HEX0<8>(shellPluginID); SettingsContainer &cacheFile = theApp.GetPluginCache(); // First try finding the full path mpt::ustring IDs = cacheFile.Read(cacheSection, dllPath.ToUnicode() + shellStr, U_("")); if(IDs.length() < 16) { // If that didn't work out, find relative path mpt::PathString relPath = theApp.PathAbsoluteToInstallRelative(dllPath); IDs = cacheFile.Read(cacheSection, relPath.ToUnicode() + shellStr, U_("")); } if(IDs.length() >= 16) { auto &plug = pluginList.emplace_back(std::make_unique(nullptr, false, dllPath, fileName)); // Extract plugin IDs uint32 id1 = 0, id2 = 0; for(int i = 0; i < 16; i++) { uint32 n = IDs[i] - '0'; if(n > 9) n = IDs[i] + 10 - 'A'; n &= 0x0F; if (i < 8) id1 = (id1 << 4) | n; else id2 = (id2 << 4) | n; } plug->pluginId1 = id1; plug->pluginId2 = id2; const mpt::ustring flagKey = IDs + U_(".Flags"); plug->DecodeCacheFlags(cacheFile.Read(cacheSection, flagKey, 0)); plug->vendor = cacheFile.Read(cacheSection, IDs + U_(".Vendor"), CString()); plug->shellPluginID = shellPluginID; #ifdef VST_LOG MPT_LOG_GLOBAL(LogDebug, "VST", MPT_UFORMAT("Plugin \"{}\" found in PluginCache")(plug->libraryName)); #endif // VST_LOG return {plug.get()}; } else { #ifdef VST_LOG MPT_LOG_GLOBAL(LogDebug, "VST", MPT_UFORMAT("Plugin mismatch in PluginCache: \"{}\" [{}]")(dllPath, IDs)); #endif // VST_LOG } } // If this key contains a file name on program launch, a plugin previously crashed OpenMPT. theApp.GetSettings().Write(U_("VST Plugins"), U_("FailedPlugin"), dllPath, SettingWriteThrough); std::vector foundPlugins; #ifdef MPT_WITH_VST unsigned long exception = 0; // Always scan plugins in a separate process { ExceptionHandler::Context ectx{ MPT_UFORMAT("VST Plugin: {}")(dllPath.ToUnicode()) }; ExceptionHandler::ContextSetter ectxguard{&ectx}; VSTPluginLib plug{nullptr, false, dllPath, fileName}; auto loadResult = CVstPlugin::LoadPlugin(maskCrashes, plug, CVstPlugin::BridgeMode::DetectRequiredBridgeMode, exception); Vst::AEffect *pEffect = loadResult.effect; if(pEffect) { foundPlugins = AddPluginsToList(GetPluginInformation(std::move(plug), loadResult), [&](VSTPluginLib &library, bool updateExisting) { if(updateExisting) return; if(library.shellPluginID) { if(!CVstPlugin::SelectShellPlugin(maskCrashes, loadResult, library)) return; } CVstPlugin::GetPluginMetadata(maskCrashes, loadResult, library); }); CVstPlugin::DispatchSEH(maskCrashes, *pEffect, Vst::effClose, 0, 0, 0, 0, exception); } if(loadResult.library) { FreeLibrary(loadResult.library); } } if(exception != 0) { CVstPluginManager::ReportPlugException(MPT_UFORMAT("Exception {} while trying to load plugin \"{}\"!\n")(mpt::ufmt::HEX0<8>(exception), fileName)); } #endif // MPT_WITH_VST // Now it should be safe to assume that this plugin loaded properly. :) theApp.GetSettings().Remove(U_("VST Plugins"), U_("FailedPlugin")); return foundPlugins; } // Remove a plugin from the list of known plugins and release any remaining instances of it. bool CVstPluginManager::RemovePlugin(VSTPluginLib *pFactory) { for(const_iterator p = begin(); p != end(); p++) { VSTPluginLib *plug = p->get(); if(plug == pFactory) { // Kill all instances of this plugin CriticalSection cs; while(plug->pPluginsList != nullptr) { IMixPlugin *pluginInstance = plug->pPluginsList; plug->RemovePluginInstanceFromList(*pluginInstance); pluginInstance->Release(); } pluginList.erase(p); return true; } } return false; } #endif // MODPLUG_TRACKER // Create an instance of a plugin. bool CVstPluginManager::CreateMixPlugin(SNDMIXPLUGIN &mixPlugin, CSoundFile &sndFile) { VSTPluginLib *pFound = nullptr; // Find plugin in library enum PlugMatchQuality { kNoMatch, kMatchName, kMatchId, kMatchNameAndId, }; PlugMatchQuality match = kNoMatch; // "Match quality" of found plugin. Higher value = better match. #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT const mpt::PathString libraryName = mpt::PathString::FromUnicode(mixPlugin.GetLibraryName()); #else const std::string libraryName = mpt::ToCharset(mpt::Charset::UTF8, mixPlugin.GetLibraryName()); #endif for(const auto &plug : pluginList) { const bool matchID = (plug->pluginId1 == mixPlugin.Info.dwPluginId1) && (plug->pluginId2 == mixPlugin.Info.dwPluginId2) && (plug->shellPluginID == mixPlugin.Info.shellPluginID); #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT const bool matchName = !mpt::PathCompareNoCase(plug->libraryName, libraryName); #else const bool matchName = !mpt::CompareNoCaseAscii(plug->libraryName.ToUTF8(), libraryName); #endif if(matchID && matchName) { pFound = plug.get(); #ifdef MPT_WITH_VST if(plug->IsNative(false)) { break; } #endif // MPT_WITH_VST // If the plugin isn't native, first check if a native version can be found. match = kMatchNameAndId; } else if(matchID && match < kMatchId) { pFound = plug.get(); match = kMatchId; } else if(matchName && match < kMatchName) { pFound = plug.get(); match = kMatchName; } } if(!pFound) return false; IMixPlugin *plugin = nullptr; if(pFound->Create != nullptr) { plugin = pFound->Create(*pFound, sndFile, mixPlugin); } #ifdef MPT_WITH_VST // Note: we don't check if dwPluginId1 matches Vst::kEffectMagic here, even if it should. // I have an old file I made with OpenMPT 1.17 where the primary plugin ID has an unexpected value. // No idea how that could happen, apart from some plugin.cache corruption (back then, the IDs were not re-checked // after instantiating a plugin and the cached plugin ID was blindly written to the module file) else { bool maskCrashes = TrackerSettings::Instance().BrokenPluginsWorkaroundVSTMaskAllCrashes; unsigned long exception = 0; auto loadResult = CVstPlugin::LoadPlugin(maskCrashes, *pFound, TrackerSettings::Instance().bridgeAllPlugins ? CVstPlugin::BridgeMode::ForceBridgeWithFallback : CVstPlugin::BridgeMode::Automatic, exception); Vst::AEffect *pEffect = loadResult.effect; if(pEffect != nullptr) { // If filename matched during load but plugin ID didn't (or vice versa), make sure it's updated. pFound->pluginId1 = loadResult.magic; pFound->pluginId2 = loadResult.uniqueID; plugin = new (std::nothrow) CVstPlugin(maskCrashes, loadResult.library, *pFound, mixPlugin, *pEffect, sndFile); #ifdef MODPLUG_TRACKER AddPluginsToList(GetPluginInformation(*pFound, loadResult), [&](VSTPluginLib &library, bool updateExisting) { if(&library == pFound && updateExisting) CVstPlugin::GetPluginMetadata(maskCrashes, loadResult, library); }); #endif } if(!plugin && loadResult.library) { FreeLibrary(loadResult.library); CVstPluginManager::ReportPlugException(MPT_UFORMAT("Unable to create plugin \"{}\"!\n")(pFound->libraryName)); } } #endif // MPT_WITH_VST #ifdef MODPLUG_TRACKER CriticalSection cs; #endif if(plugin) pFound->InsertPluginInstanceIntoList(*plugin); mixPlugin.pMixPlugin = plugin; // If filename matched during load but plugin ID didn't (or vice versa), make sure it's updated. mixPlugin.Info.dwPluginId1 = pFound->pluginId1; mixPlugin.Info.dwPluginId2 = pFound->pluginId2; mixPlugin.Info.szLibraryName = pFound->libraryName.ToUTF8(); return plugin != nullptr; } #ifdef MPT_WITH_VST std::vector CVstPluginManager::AddPluginsToList(std::vector containedPlugins, std::function updateFunc) { std::vector newPlugins; if(containedPlugins.empty()) return newPlugins; // Find existing shell plugins belonging to the same file first, so that we don't have to iterate through the whole plugin list again and again std::map existingCandidates; for(size_t i = 0; i < pluginList.size(); i++) { const auto &plug = pluginList[i]; if(plug->pluginId1 == containedPlugins.front().pluginId1 && plug->pluginId2 == containedPlugins.front().pluginId2) { if(!mpt::PathCompareNoCase(plug->dllPath, containedPlugins.front().dllPath)) existingCandidates[plug->shellPluginID] = i; } } // Add found plugins to list or update them if they already exist std::set containedIDs; VSTPluginLib *first = nullptr; for(auto &containedPlug : containedPlugins) { containedIDs.insert(containedPlug.shellPluginID); VSTPluginLib *found = nullptr; if(auto it = existingCandidates.find(containedPlug.shellPluginID); it != existingCandidates.end()) { auto &plug = pluginList[it->second]; MPT_ASSERT(plug->pluginId1 == containedPlug.pluginId1 && plug->pluginId2 == containedPlug.pluginId2); if(plug->shellPluginID == containedPlug.shellPluginID) found = plug.get(); } const bool updateExisting = found != nullptr; if(updateExisting) { found->libraryName = containedPlug.libraryName; } else { auto &plug = pluginList.emplace_back(std::make_unique(std::move(containedPlug))); found = plug.get(); newPlugins.push_back(found); } updateFunc(*found, updateExisting); if(!first) first = found; #ifdef MODPLUG_TRACKER found->WriteToCache(); #endif // MODPLUG_TRACKER } // Are there any shell plugins in our list that are no longer part of the shell plugin? if(containedPlugins.size() > 1) { size_t deleted = 0; for(const auto &[id, i] : existingCandidates) { if(!mpt::contains(containedIDs, id) && !pluginList[i - deleted]->pPluginsList) { MPT_ASSERT(pluginList[i - deleted]->shellPluginID == id); pluginList.erase(pluginList.begin() + i - deleted); deleted++; } } } if(newPlugins.empty() && first) newPlugins.push_back(first); return newPlugins; } #endif // MPT_WITH_VST #ifdef MODPLUG_TRACKER void CVstPluginManager::OnIdle() { for(auto &factory : pluginList) { // Note: bridged plugins won't receive these messages and generate their own idle messages. IMixPlugin *p = factory->pPluginsList; while (p) { //rewbs. VSTCompliance: A specific plug has requested indefinite periodic processing time. p->Idle(); //We need to update all open editors CAbstractVstEditor *editor = p->GetEditor(); if (editor && editor->m_hWnd) { editor->UpdateParamDisplays(); } //end rewbs. VSTCompliance: p = p->GetNextInstance(); } } } void CVstPluginManager::ReportPlugException(const mpt::ustring &msg) { Reporting::Notification(msg); #ifdef VST_LOG MPT_LOG_GLOBAL(LogDebug, "VST", mpt::ToUnicode(msg)); #endif } #endif // MODPLUG_TRACKER OPENMPT_NAMESPACE_END #endif // NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/PluginManager.h0000644000175000017500000001474214677051450022501 00000000000000/* * PluginManager.h * --------------- * Purpose: Plugin management * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include OPENMPT_NAMESPACE_BEGIN constexpr int32 PLUGMAGIC(char a, char b, char c, char d) noexcept { return static_cast((static_cast(a) << 24) | (static_cast(b) << 16) | (static_cast(c) << 8) | (static_cast(d) << 0)); } //#define kBuzzMagic PLUGMAGIC('B', 'u', 'z', 'z') inline constexpr int32 kDmoMagic = PLUGMAGIC('D', 'X', 'M', 'O'); class CSoundFile; class IMixPlugin; struct SNDMIXPLUGIN; enum PluginArch : int; enum class PluginCategory : uint8 { // Same plugin categories as defined in VST SDK Unknown = 0, Effect, // Simple Effect Synth, // VST Instrument (Synths, samplers,...) Analysis, // Scope, Tuner, ... Mastering, // Dynamics, ... Spacializer, // Panners, ... RoomFx, // Delays and Reverbs SurroundFx, // Dedicated surround processor Restoration, // Denoiser, ... OfflineProcess, // Offline Process Shell, // Plug-in is container of other plug-ins Generator, // Tone Generator, ... // Custom categories DMO, // DirectX media object plugin Hidden, // For internal plugins that should not be visible to the user (e.g. because they only exist for legacy reasons) NumCategories }; struct VSTPluginLib { public: using CreateProc = IMixPlugin *(*)(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); IMixPlugin *pPluginsList = nullptr; // Pointer to first plugin instance (this instance carries pointers to other instances) void InsertPluginInstanceIntoList(IMixPlugin &pluginInstance); void RemovePluginInstanceFromList(IMixPlugin &pluginInstance); CreateProc Create; // Factory to call for this plugin mpt::PathString libraryName; // Display name mpt::PathString dllPath; // Full path name #ifdef MODPLUG_TRACKER mpt::ustring tags; // User tags CString vendor; #endif // MODPLUG_TRACKER int32 pluginId1 = 0; // Plugin type (kEffectMagic, kDmoMagic, ...) int32 pluginId2 = 0; // Plugin unique ID uint32 shellPluginID = 0; // ID of shell child plugin PluginCategory category = PluginCategory::Unknown; const bool isBuiltIn : 1; bool isInstrument : 1; bool useBridge : 1, shareBridgeInstance : 1, modernBridge : 1; protected: mutable uint8 dllArch = 0; public: VSTPluginLib(CreateProc factoryProc, bool isBuiltIn, mpt::PathString dllPath, mpt::PathString libraryName) : Create(factoryProc) , libraryName(std::move(libraryName)), dllPath(std::move(dllPath)) , category(PluginCategory::Unknown) , isBuiltIn(isBuiltIn), isInstrument(false) , useBridge(false), shareBridgeInstance(true), modernBridge(true) { } VSTPluginLib(VSTPluginLib &&) = default; VSTPluginLib(const VSTPluginLib &other) : Create(other.Create) , libraryName(other.libraryName), dllPath(other.dllPath) #ifdef MODPLUG_TRACKER , tags(other.tags), vendor(other.vendor) #endif // MODPLUG_TRACKER , pluginId1(other.pluginId1), pluginId2(other.pluginId2), shellPluginID(other.shellPluginID) , category(other.category) , isBuiltIn(other.isBuiltIn), isInstrument(other.isInstrument) , useBridge(other.useBridge), shareBridgeInstance(other.shareBridgeInstance), modernBridge(other.modernBridge) , dllArch(other.dllArch) { } #ifdef MPT_WITH_VST // Get native phost process arch encoded as plugin arch static uint8 GetNativePluginArch(); static mpt::ustring GetPluginArchName(uint8 arch); // Check whether a plugin can be hosted inside OpenMPT or requires bridging uint8 GetDllArch(bool fromCache = true) const; mpt::ustring GetDllArchName(bool fromCache = true) const; mpt::ustring GetDllArchNameUser(bool fromCache = true) const; bool IsNative(bool fromCache = true) const; // Check if a plugin is native, and if it is currently unknown, assume that it is native. Use this function only for performance reasons // (e.g. if tons of unscanned plugins would slow down generation of the plugin selection dialog) bool IsNativeFromCache() const; #endif // MPT_WITH_VST void WriteToCache() const; uint32 EncodeCacheFlags() const { // Format: 00000000.0000000M.AAAAAASB.CCCCCCCI return (isInstrument ? 1 : 0) | (static_cast(category) << 1) | (useBridge ? 0x100 : 0) | (shareBridgeInstance ? 0x200 : 0) | ((dllArch / 8) << 10) | (modernBridge ? 0x10000 : 0) ; } void DecodeCacheFlags(uint32 flags) { category = static_cast((flags & 0xFF) >> 1); if(category >= PluginCategory::NumCategories) { category = PluginCategory::Unknown; } if(flags & 1) { isInstrument = true; category = PluginCategory::Synth; } useBridge = (flags & 0x100) != 0; shareBridgeInstance = (flags & 0x200) != 0; dllArch = ((flags >> 10) & 0x3F) * 8; modernBridge = (flags & 0x10000) != 0; } }; class CVstPluginManager { #ifndef NO_PLUGINS protected: #if defined(MPT_WITH_DMO) bool MustUnInitilizeCOM = false; #endif std::vector> pluginList; public: CVstPluginManager(); ~CVstPluginManager(); using iterator = decltype(pluginList)::iterator; using const_iterator = decltype(pluginList)::const_iterator; iterator begin() { return pluginList.begin(); } const_iterator begin() const { return pluginList.begin(); } iterator end() { return pluginList.end(); } const_iterator end() const { return pluginList.end(); } void reserve(size_t num) { pluginList.reserve(num); } size_t size() const { return pluginList.size(); } bool IsValidPlugin(const VSTPluginLib *pLib) const; std::vector AddPlugin(const mpt::PathString &dllPath, bool maskCrashes, bool fromCache = true, bool *fileFound = nullptr, uint32 shellPluginID = 0); bool RemovePlugin(VSTPluginLib *); bool CreateMixPlugin(SNDMIXPLUGIN &, CSoundFile &); void OnIdle(); static void ReportPlugException(const mpt::ustring &msg); protected: void EnumerateDirectXDMOs(); std::vector AddPluginsToList(std::vector containedPlugins, std::function updateFunc); #else // NO_PLUGINS public: const VSTPluginLib **begin() const { return nullptr; } const VSTPluginLib **end() const { return nullptr; } void reserve(size_t) { } size_t size() const { return 0; } void OnIdle() {} #endif // NO_PLUGINS }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/PluginStructs.h0000644000175000017500000001217614722674176022604 00000000000000/* * PluginStructs.h * --------------- * Purpose: Basic plugin structs for CSoundFile. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "../Snd_defs.h" #ifndef NO_PLUGINS #include "openmpt/base/Endian.hpp" #endif // NO_PLUGINS OPENMPT_NAMESPACE_BEGIN //////////////////////////////////////////////////////////////////// // Mix Plugins struct SNDMIXPLUGINSTATE; struct SNDMIXPLUGIN; class IMixPlugin; class CSoundFile; #ifndef NO_PLUGINS enum class PluginMixMode : uint8 { Default = 0, WetSubtract = 1, DrySubtract = 2, MixSubtract = 3, MiddleSubtract = 4, LRBalance = 5, Instrument = 6, }; struct SNDMIXPLUGININFO { // dwInputRouting flags enum RoutingFlags { irApplyToMaster = 0x01, // Apply to master mix irBypass = 0x02, // Bypass effect irDryMix = 0x04, // Wet Mix (dry added) irExpandMix = 0x08, // [0%,100%] -> [-200%,200%] irAutoSuspend = 0x10, // Plugin will automatically suspend on silence }; int32le dwPluginId1; // Plugin type (kEffectMagic, kDmoMagic or custom for built-in plugins) int32le dwPluginId2; // Plugin unique ID uint8le routingFlags; // See RoutingFlags uint8le mixMode; uint8le gain; // Divide by 10 to get real gain uint8le reserved; uint32le dwOutputRouting; // 0 = send to master 0x80 + x = send to plugin x uint32le shellPluginID; // For shell plugins: The child plugin to load uint32le dwReserved[3]; // Reserved for routing info mpt::modecharbuf<32, mpt::String::nullTerminated> szName; // User-chosen plugin display name - this is locale ANSI! mpt::modecharbuf<64, mpt::String::nullTerminated> szLibraryName; // original DLL name (shell plugins: child plugin name) - this is UTF-8! // Should only be called from SNDMIXPLUGIN::SetBypass() and IMixPlugin::Bypass() void SetBypass(bool bypass = true) { if(bypass) routingFlags |= irBypass; else routingFlags &= uint8(~irBypass); } }; MPT_BINARY_STRUCT(SNDMIXPLUGININFO, 128) // this is directly written to files, so the size must be correct! struct SNDMIXPLUGIN { IMixPlugin *pMixPlugin = nullptr; std::vector pluginData; SNDMIXPLUGININFO Info = {}; float fDryRatio = 0; int32 defaultProgram = 0; int32 editorX = 0, editorY = 0; #if defined(MPT_ENABLE_CHARSET_LOCALE) const char * GetNameLocale() const { return Info.szName.buf; } mpt::ustring GetName() const { return mpt::ToUnicode(mpt::Charset::Locale, Info.szName); } #endif // MPT_ENABLE_CHARSET_LOCALE mpt::ustring GetLibraryName() const { return mpt::ToUnicode(mpt::Charset::UTF8, Info.szLibraryName); } // Check if a plugin is loaded into this slot (also returns true if the plugin in this slot has not been found) bool IsValidPlugin() const { return (Info.dwPluginId1 | Info.dwPluginId2) != 0; } // Input routing getters uint8 GetGain() const { return Info.gain; } PluginMixMode GetMixMode() const { return static_cast(Info.mixMode.get()); } bool IsMasterEffect() const { return (Info.routingFlags & SNDMIXPLUGININFO::irApplyToMaster) != 0; } bool IsDryMix() const { return (Info.routingFlags & SNDMIXPLUGININFO::irDryMix) != 0; } bool IsExpandedMix() const { return (Info.routingFlags & SNDMIXPLUGININFO::irExpandMix) != 0; } bool IsBypassed() const { return (Info.routingFlags & SNDMIXPLUGININFO::irBypass) != 0; } bool IsAutoSuspendable() const { return (Info.routingFlags & SNDMIXPLUGININFO::irAutoSuspend) != 0; } // Input routing setters void SetGain(uint8 gain); void SetMixMode(PluginMixMode mixMode) { Info.mixMode = static_cast(mixMode); } void SetMasterEffect(bool master = true) { if(master) Info.routingFlags |= SNDMIXPLUGININFO::irApplyToMaster; else Info.routingFlags &= uint8(~SNDMIXPLUGININFO::irApplyToMaster); } void SetDryMix(bool wetMix = true) { if(wetMix) Info.routingFlags |= SNDMIXPLUGININFO::irDryMix; else Info.routingFlags &= uint8(~SNDMIXPLUGININFO::irDryMix); } void SetExpandedMix(bool expanded = true) { if(expanded) Info.routingFlags |= SNDMIXPLUGININFO::irExpandMix; else Info.routingFlags &= uint8(~SNDMIXPLUGININFO::irExpandMix); } void SetBypass(bool bypass = true); void SetAutoSuspend(bool suspend = true) { if(suspend) Info.routingFlags |= SNDMIXPLUGININFO::irAutoSuspend; else Info.routingFlags &= uint8(~SNDMIXPLUGININFO::irAutoSuspend); } // Output routing getters bool IsOutputToMaster() const { return Info.dwOutputRouting == 0; } PLUGINDEX GetOutputPlugin() const { return Info.dwOutputRouting >= 0x80 ? static_cast(Info.dwOutputRouting - 0x80) : PLUGINDEX_INVALID; } // Output routing setters void SetOutputToMaster() { Info.dwOutputRouting = 0; } void SetOutputPlugin(PLUGINDEX plugin) { if(plugin < MAX_MIXPLUGINS) Info.dwOutputRouting = plugin + 0x80; else Info.dwOutputRouting = 0; } void Destroy(); }; bool CreateMixPluginProc(SNDMIXPLUGIN &mixPlugin, CSoundFile &sndFile); #endif // NO_PLUGINS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/plugins/DigiBoosterEcho.cpp0000644000175000017500000001355314722730163023307 00000000000000/* * DigiBoosterEcho.cpp * ------------------- * Purpose: Implementation of the DigiBooster Pro Echo DSP * Notes : (currently none) * Authors: OpenMPT Devs, based on original code by Grzegorz Kraszewski (BSD 2-clause) * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_PLUGINS #include "DigiBoosterEcho.h" #include "../Sndfile.h" OPENMPT_NAMESPACE_BEGIN IMixPlugin* DigiBoosterEcho::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) DigiBoosterEcho(factory, sndFile, mixStruct); } DigiBoosterEcho::DigiBoosterEcho(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_sampleRate(sndFile.GetSampleRate()) , m_chunk(PluginChunk::Default()) { m_mixBuffer.Initialize(2, 2); } void DigiBoosterEcho::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(!m_bufferSize) return; const float *srcL = m_mixBuffer.GetInputBuffer(0), *srcR = m_mixBuffer.GetInputBuffer(1); float *outL = m_mixBuffer.GetOutputBuffer(0), *outR = m_mixBuffer.GetOutputBuffer(1); for(uint32 i = numFrames; i != 0; i--) { int readPos = m_writePos - m_delayTime; if(readPos < 0) readPos += m_bufferSize; float l = *srcL++, r = *srcR++; float lDelay = m_delayLine[readPos * 2], rDelay = m_delayLine[readPos * 2 + 1]; // Calculate the delay float al = l * m_NCrossNBack; al += r * m_PCrossNBack; al += lDelay * m_NCrossPBack; al += rDelay * m_PCrossPBack; float ar = r * m_NCrossNBack; ar += l * m_PCrossNBack; ar += rDelay * m_NCrossPBack; ar += lDelay * m_PCrossPBack; // Prevent denormals if(std::abs(al) < 1e-24f) al = 0.0f; if(std::abs(ar) < 1e-24f) ar = 0.0f; m_delayLine[m_writePos * 2] = al; m_delayLine[m_writePos * 2 + 1] = ar; m_writePos++; if(m_writePos == m_bufferSize) m_writePos = 0; // Output samples now *outL++ = (l * m_NMix + lDelay * m_PMix); *outR++ = (r * m_NMix + rDelay * m_PMix); } ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames); } void DigiBoosterEcho::SaveAllParameters() { m_pMixStruct->defaultProgram = -1; try { m_pMixStruct->pluginData.resize(sizeof(m_chunk)); memcpy(m_pMixStruct->pluginData.data(), &m_chunk, sizeof(m_chunk)); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); m_pMixStruct->pluginData.clear(); } } void DigiBoosterEcho::RestoreAllParameters(int32 program) { if(m_pMixStruct->pluginData.size() == sizeof(m_chunk) && !memcmp(m_pMixStruct->pluginData.data(), "Echo", 4)) { memcpy(&m_chunk, m_pMixStruct->pluginData.data(), sizeof(m_chunk)); } else { IMixPlugin::RestoreAllParameters(program); } RecalculateEchoParams(); } PlugParamValue DigiBoosterEcho::GetParameter(PlugParamIndex index) { if(index < kEchoNumParameters) { return m_chunk.param[index] / 255.0f; } return 0; } void DigiBoosterEcho::SetParameter(PlugParamIndex index, PlugParamValue value, PlayState *, CHANNELINDEX) { if(index < kEchoNumParameters) { m_chunk.param[index] = mpt::saturate_round(mpt::safe_clamp(value, 0.0f, 1.0f) * 255.0f); RecalculateEchoParams(); } } void DigiBoosterEcho::Resume() { m_isResumed = true; m_sampleRate = m_SndFile.GetSampleRate(); RecalculateEchoParams(); PositionChanged(); } void DigiBoosterEcho::PositionChanged() { m_bufferSize = (m_sampleRate >> 1) + (m_sampleRate >> 6); try { m_delayLine.assign(m_bufferSize * 2, 0); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); m_bufferSize = 0; } m_writePos = 0; } #ifdef MODPLUG_TRACKER CString DigiBoosterEcho::GetParamName(PlugParamIndex param) { switch(param) { case kEchoDelay: return _T("Delay"); case kEchoFeedback: return _T("Feedback"); case kEchoMix: return _T("Wet / Dry Ratio"); case kEchoCross: return _T("Cross Echo"); } return CString(); } CString DigiBoosterEcho::GetParamLabel(PlugParamIndex param) { if(param == kEchoDelay) return _T("ms"); return CString(); } CString DigiBoosterEcho::GetParamDisplay(PlugParamIndex param) { CString s; if(param == kEchoMix) { int wet = (m_chunk.param[kEchoMix] * 100) / 255; s.Format(_T("%d%% / %d%%"), wet, 100 - wet); } else if(param < kEchoNumParameters) { int val = m_chunk.param[param]; if(param == kEchoDelay) { if(val == 0) val = 167; val *= 2; } s.Format(_T("%d"), val); } return s; } #endif // MODPLUG_TRACKER IMixPlugin::ChunkData DigiBoosterEcho::GetChunk(bool) { auto data = reinterpret_cast(&m_chunk); return ChunkData(data, sizeof(m_chunk)); } void DigiBoosterEcho::SetChunk(const ChunkData &chunk, bool) { auto data = chunk.data(); if(chunk.size() == sizeof(chunk) && !memcmp(data, "Echo", 4)) { memcpy(&m_chunk, data, chunk.size()); RecalculateEchoParams(); } } void DigiBoosterEcho::RecalculateEchoParams() { // The fallback value when the delay is 0 was determined experimentally from DBPro 2.21 output. // The C implementation of libdigibooster3 has no specific handling of this value and thus produces a delay with maximum length. m_delayTime = ((m_chunk.param[kEchoDelay] ? m_chunk.param[kEchoDelay] : 167u) * m_sampleRate + 250u) / 500u; m_PMix = static_cast(m_chunk.param[kEchoMix]) * (1.0f / 256.0f); m_NMix = static_cast(256 - m_chunk.param[kEchoMix]) * (1.0f / 256.0f); m_PCrossPBack = static_cast(m_chunk.param[kEchoCross] * m_chunk.param[kEchoFeedback]) * (1.0f / 65536.0f); m_PCrossNBack = static_cast(m_chunk.param[kEchoCross] * (256 - m_chunk.param[kEchoFeedback])) * (1.0f / 65536.0f); m_NCrossPBack = static_cast((m_chunk.param[kEchoCross] - 256) * m_chunk.param[kEchoFeedback]) * (1.0f / 65536.0f); m_NCrossNBack = static_cast((m_chunk.param[kEchoCross] - 256) * (m_chunk.param[kEchoFeedback] - 256)) * (1.0f / 65536.0f); } OPENMPT_NAMESPACE_END #endif // NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/SymMODEcho.h0000644000175000017500000000707614722730163021655 00000000000000/* * SymMODEcho.h * ------------ * Purpose: Implementation of the SymMOD Echo DSP * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef NO_PLUGINS #include "PlugInterface.h" OPENMPT_NAMESPACE_BEGIN class SymMODEcho final : public IMixPlugin { public: enum class DSPType : uint8 { Off = 0, Normal, Cross, Cross2, Center, NumTypes }; enum Parameters { kEchoType = 0, kEchoDelay, kEchoFeedback, kEchoNumParameters }; // Our settings chunk for file I/O, as it will be written to files struct PluginChunk { char id[4]; uint8 param[kEchoNumParameters]; static PluginChunk Create(uint8 type, uint8 delay, uint8 feedback) { static_assert(sizeof(PluginChunk) == 7); PluginChunk result; memcpy(result.id, "Echo", 4); result.param[kEchoType] = type; result.param[kEchoDelay] = delay; result.param[kEchoFeedback] = feedback; return result; } static PluginChunk Default() { return Create(0, 4, 1); } }; std::vector m_delayLine; uint32 m_writePos = 0; // Current write position in the delay line float m_feedback = 0.5f; // Settings chunk for file I/O PluginChunk m_chunk; public: static IMixPlugin* Create(VSTPluginLib& factory, CSoundFile& sndFile, SNDMIXPLUGIN &mixStruct); SymMODEcho(VSTPluginLib& factory, CSoundFile& sndFile, SNDMIXPLUGIN &mixStruct); void SaveAllParameters() override; void RestoreAllParameters(int32 program) override; int32 GetUID() const override { int32le id; memcpy(&id, "Echo", 4); return id; } int32 GetVersion() const override { return 0; } void Idle() override { } uint32 GetLatency() const override { return 0; } void Process(float* pOutL, float* pOutR, uint32 numFrames) override; float RenderSilence(uint32) override { return 0.0f; } int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } void SetCurrentProgram(int32) override { } PlugParamIndex GetNumParameters() const override { return kEchoNumParameters; } PlugParamValue GetParameter(PlugParamIndex index) override; void SetParameter(PlugParamIndex index, PlugParamValue value, PlayState * = nullptr, CHANNELINDEX = CHANNELINDEX_INVALID) override; void Resume() override; void Suspend() override { m_isResumed = false; } void PositionChanged() override; bool IsInstrument() const override { return false; } bool CanRecieveMidiEvents() override { return false; } bool ShouldProcessSilence() override { return true; } #ifdef MODPLUG_TRACKER CString GetDefaultEffectName() override { return _T("Echo"); } std::pair GetParamUIRange(PlugParamIndex param) override; CString GetParamName(PlugParamIndex param) override; CString GetParamLabel(PlugParamIndex) override; CString GetParamDisplay(PlugParamIndex param) override; CString GetCurrentProgramName() override { return CString(); } void SetCurrentProgramName(const CString&) override { } CString GetProgramName(int32) override { return CString(); } bool HasEditor() const override { return false; } #endif int GetNumInputChannels() const override { return 2; } int GetNumOutputChannels() const override { return 2; } bool ProgramsAreChunks() const override { return true; } ChunkData GetChunk(bool) override; void SetChunk(const ChunkData& chunk, bool) override; protected: DSPType GetDSPType() const { return static_cast(m_chunk.param[kEchoType]); } void RecalculateEchoParams(); }; MPT_BINARY_STRUCT(SymMODEcho::PluginChunk, 7) OPENMPT_NAMESPACE_END #endif // NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/plugins/PlugInterface.h0000644000175000017500000002745614731624663022511 00000000000000/* * PlugInterface.h * --------------- * Purpose: Interface class for plugin handling * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #ifndef NO_PLUGINS #include "../../soundlib/Snd_defs.h" #include "../../soundlib/MIDIEvents.h" #include "../../soundlib/Mixer.h" #include "PluginMixBuffer.h" #include "PluginStructs.h" OPENMPT_NAMESPACE_BEGIN struct VSTPluginLib; struct SNDMIXPLUGIN; struct ModInstrument; struct ModChannel; struct PlayState; class CSoundFile; class CModDoc; class CAbstractVstEditor; struct SNDMIXPLUGINSTATE { // dwFlags flags enum PluginStateFlags { psfMixReady = 0x01, // Set when cleared psfHasInput = 0x02, // Set when plugin has non-silent input psfSilenceBypass = 0x04, // Bypass because of silence detection }; mixsample_t *pMixBuffer = nullptr; // Stereo effect send buffer uint32 dwFlags = 0; // PluginStateFlags uint32 inputSilenceCount = 0; // How much silence has been processed? (for plugin auto-turnoff) mixsample_t nVolDecayL = 0, nVolDecayR = 0; // End of sample click removal void ResetSilence() { dwFlags |= psfHasInput; dwFlags &= ~psfSilenceBypass; inputSilenceCount = 0; } }; class IMixPlugin { friend class CAbstractVstEditor; friend struct VSTPluginLib; protected: IMixPlugin *m_pNext = nullptr, *m_pPrev = nullptr; VSTPluginLib &m_Factory; CSoundFile &m_SndFile; SNDMIXPLUGIN *m_pMixStruct; #ifdef MODPLUG_TRACKER CAbstractVstEditor *m_pEditor = nullptr; #endif // MODPLUG_TRACKER public: SNDMIXPLUGINSTATE m_MixState; PluginMixBuffer m_mixBuffer; // Float buffers (input and output) for plugins protected: mixsample_t m_MixBuffer[MIXBUFFERSIZE * 2 + 2]; // Stereo interleaved input (sample mixer renders here) float m_fGain = 1.0f; PLUGINDEX m_nSlot = 0; bool m_isSongPlaying = false; bool m_isResumed = false; public: bool m_recordAutomation = false; bool m_passKeypressesToPlug = false; bool m_recordMIDIOut = false; // Combine with note value sent to IMixPlugin::MidiCommand enum MidiNoteFlag : uint16 { MIDI_NOTE_MASK = 0x0FF, MIDI_NOTE_OFF = 0x100, // Send note-off for a specific note MIDI_NOTE_ARPEGGIO = 0x200, // Note is part of an arpeggio, don't store it as the last triggered note }; protected: virtual ~IMixPlugin(); public: // Non-virtual part of the interface IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); inline CSoundFile &GetSoundFile() { return m_SndFile; } inline const CSoundFile &GetSoundFile() const { return m_SndFile; } #ifdef MODPLUG_TRACKER CModDoc *GetModDoc(); const CModDoc *GetModDoc() const; void SetSlot(PLUGINDEX slot); inline PLUGINDEX GetSlot() const { return m_nSlot; } #endif // MODPLUG_TRACKER inline VSTPluginLib &GetPluginFactory() const { return m_Factory; } // Returns the next instance of the same plugin inline IMixPlugin *GetNextInstance() const { return m_pNext; } void SetDryRatio(float dryRatio); bool IsBypassed() const; void RecalculateGain(); // Query output latency from host (in seconds) double GetOutputLatency() const; // Destroy the plugin virtual void Release() { delete this; } virtual int32 GetUID() const = 0; virtual int32 GetVersion() const = 0; virtual void Idle() = 0; // Plugin latency in samples virtual uint32 GetLatency() const = 0; virtual int32 GetNumPrograms() const = 0; virtual int32 GetCurrentProgram() = 0; virtual void SetCurrentProgram(int32 nIndex) = 0; virtual PlugParamIndex GetNumParameters() const = 0; virtual PlugParamIndex GetNumVisibleParameters() const { return GetNumParameters(); } virtual PlugParamValue GetParameter(PlugParamIndex nIndex) = 0; virtual void SetParameter(PlugParamIndex paramIndex, PlugParamValue paramValue, PlayState *playState = nullptr, CHANNELINDEX chn = CHANNELINDEX_INVALID) = 0; // Save parameters for storing them in a module file virtual void SaveAllParameters(); // Restore parameters from module file virtual void RestoreAllParameters(int32 program); virtual void Process(float *pOutL, float *pOutR, uint32 numFrames) = 0; void ProcessMixOps(float *pOutL, float *pOutR, float *leftPlugOutput, float *rightPlugOutput, uint32 numFrames); // Render silence and return the highest resulting output level virtual float RenderSilence(uint32 numSamples); // MIDI event handling bool MidiSend(uint32 midiCode); virtual bool MidiSend(mpt::const_byte_span /*midiData*/) { return true; } virtual void MidiCC(MIDIEvents::MidiCC /*nController*/, uint8 /*nParam*/, CHANNELINDEX /*trackChannel*/) { } virtual void MidiPitchBendRaw(int32 /*pitchbend*/, CHANNELINDEX /*trackChannel*/) {} virtual void MidiPitchBend(int32 /*increment*/, int8 /*pwd*/, CHANNELINDEX /*trackChannel*/) { } virtual void MidiTonePortamento(int32 /*increment*/, uint8 /*newNote*/, int8 /*pwd*/, CHANNELINDEX /*trackChannel*/) { } virtual void MidiVibrato(int32 /*depth*/, int8 /*pwd*/, CHANNELINDEX /*trackerChn*/) { } virtual void MidiCommand(const ModInstrument &/*instr*/, uint16 /*note*/, uint16 /*vol*/, CHANNELINDEX /*trackChannel*/) { } virtual void HardAllNotesOff() { } virtual bool IsNotePlaying(uint8 /*note*/, CHANNELINDEX /*trackerChn*/) { return false; } virtual void MoveChannel(CHANNELINDEX /*from*/, CHANNELINDEX /*to*/) { } // Modify parameter by given amount. Only needs to be re-implemented if plugin architecture allows this to be performed atomically. virtual void ModifyParameter(PlugParamIndex nIndex, PlugParamValue diff, PlayState &playState, CHANNELINDEX chn); virtual void NotifySongPlaying(bool playing) { m_isSongPlaying = playing; } virtual bool IsSongPlaying() const { return m_isSongPlaying; } virtual bool IsResumed() const { return m_isResumed; } virtual void Resume() = 0; virtual void Suspend() = 0; // Tell the plugin that there is a discontinuity between the previous and next render call (e.g. aftert jumping around in the module) virtual void PositionChanged() = 0; virtual void Bypass(bool = true); bool ToggleBypass() { Bypass(!IsBypassed()); return IsBypassed(); } virtual bool IsInstrument() const = 0; virtual bool CanRecieveMidiEvents() = 0; // If false is returned, mixing this plugin can be skipped if its input are currently completely silent. virtual bool ShouldProcessSilence() = 0; virtual void ResetSilence() { m_MixState.ResetSilence(); } size_t GetOutputPlugList(std::vector &list); size_t GetInputPlugList(std::vector &list); size_t GetInputInstrumentList(std::vector &list); size_t GetInputChannelList(std::vector &list); #ifdef MODPLUG_TRACKER bool SaveProgram(); bool LoadProgram(mpt::PathString fileName = mpt::PathString()); virtual CString GetDefaultEffectName() = 0; // Cache a range of names, in case one-by-one retrieval would be slow (e.g. when using plugin bridge) virtual void CacheProgramNames(int32 /*firstProg*/, int32 /*lastProg*/) { } virtual void CacheParameterNames(int32 /*firstParam*/, int32 /*lastParam*/) { } // Allowed value range for a parameter virtual std::pair GetParamUIRange(PlugParamIndex /*param*/) { return {0.0f, 1.0f}; } // Scale allowed value range of a parameter to/from [0,1] PlugParamValue GetScaledUIParam(PlugParamIndex param); void SetScaledUIParam(PlugParamIndex param, PlugParamValue value); virtual CString GetParamName(PlugParamIndex param) = 0; virtual CString GetParamLabel(PlugParamIndex param) = 0; virtual CString GetParamDisplay(PlugParamIndex param) = 0; CString GetFormattedParamName(PlugParamIndex param); CString GetFormattedParamValue(PlugParamIndex param); virtual CString GetCurrentProgramName() = 0; virtual void SetCurrentProgramName(const CString &name) = 0; virtual CString GetProgramName(int32 program) = 0; CString GetFormattedProgramName(int32 index); virtual bool HasEditor() const = 0; protected: virtual CAbstractVstEditor *OpenEditor(); public: // Get the plugin's editor window CAbstractVstEditor *GetEditor() { return m_pEditor; } const CAbstractVstEditor *GetEditor() const { return m_pEditor; } void ToggleEditor(); void CloseEditor(); void SetEditorPos(int32 x, int32 y); void GetEditorPos(int32 &x, int32 &y) const; // Notify OpenMPT that a plugin parameter has changed and set document as modified void AutomateParameter(PlugParamIndex param); // Plugin state changed, set document as modified. void SetModified(); #endif virtual int GetNumInputChannels() const = 0; virtual int GetNumOutputChannels() const = 0; using ChunkData = mpt::const_byte_span; virtual bool ProgramsAreChunks() const { return false; } virtual ChunkData GetChunk(bool /*isBank*/) { return ChunkData(); } virtual void SetChunk(const ChunkData &/*chunk*/, bool /*isBank*/) { } virtual void BeginSetProgram(int32 /*program*/ = -1) {} virtual void EndSetProgram() {} virtual void BeginGetProgram(int32 /*program*/ = -1) {} virtual void EndGetProgram() {} }; inline void IMixPlugin::ModifyParameter(PlugParamIndex nIndex, PlugParamValue diff, PlayState &playState, CHANNELINDEX chn) { PlugParamValue val = GetParameter(nIndex) + diff; Limit(val, PlugParamValue(0), PlugParamValue(1)); SetParameter(nIndex, val, &playState, chn); } // IMidiPlugin: Default implementation of plugins with MIDI input class IMidiPlugin : public IMixPlugin { protected: enum { // Pitch wheel constants kPitchBendShift = 12, // Use lowest 12 bits for fractional part and vibrato flag => 16.11 fixed point precision kPitchBendMask = (~1), kVibratoFlag = 1, }; struct PlugInstrChannel { int32 midiPitchBendPos = 0; // Current Pitch Wheel position, in 16.11 fixed point format. Lowest bit is used for indicating that vibrato was applied. Vibrato offset itself is not stored in this value. uint16 currentProgram = uint16_max; uint16 currentBank = uint16_max; uint8 lastNote = 0 /* NOTE_NONE */; uint8 noteOnMap[128][MAX_CHANNELS]; void ResetProgram(bool oldBehaviour) { currentProgram = oldBehaviour ? 0 : uint16_max; currentBank = oldBehaviour ? 0 : uint16_max; } }; std::array m_MidiCh; // MIDI channel state public: IMidiPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); void MidiCC(MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) override; void MidiPitchBendRaw(int32 pitchbend, CHANNELINDEX trackerChn) override; void MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackerChn) override; void MidiTonePortamento(int32 increment, uint8 newNote, int8 pwd, CHANNELINDEX trackerChn) override; void MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackerChn) override; void MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) override; bool IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) override; void MoveChannel(CHANNELINDEX from, CHANNELINDEX to) override; // Get the MIDI channel currently associated with a given tracker channel virtual uint8 GetMidiChannel(const ModChannel &chn, CHANNELINDEX trackChannel) const; protected: uint8 GetMidiChannel(CHANNELINDEX trackChannel) const; // Plugin wants to send MIDI to OpenMPT virtual void ReceiveMidi(mpt::const_byte_span midiData); // Converts a 14-bit MIDI pitch bend position to our internal pitch bend position representation static constexpr int32 EncodePitchBendParam(int32 position) { return (position << kPitchBendShift); } // Converts the internal pitch bend position to a 14-bit MIDI pitch bend position static constexpr int16 DecodePitchBendParam(int32 position) { return static_cast(position >> kPitchBendShift); } // Apply Pitch Wheel Depth (PWD) to some MIDI pitch bend value. static inline void ApplyPitchWheelDepth(int32 &value, int8 pwd); void SendMidiPitchBend(uint8 midiCh, int32 newPitchBendPos); }; OPENMPT_NAMESPACE_END #endif // NO_PLUGINS libopenmpt-0.8.1+release.autotools/soundlib/SoundFilePlayConfig.h0000644000175000017500000000622114052666041022117 00000000000000/* * SoundFilePlayConfig.h * --------------------- * Purpose: Configuration of sound levels, pan laws, etc... for various mix configurations. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" OPENMPT_NAMESPACE_BEGIN enum class TempoMode : uint8 { Classic = 0, Alternative = 1, Modern = 2, NumModes }; enum class MixLevels : uint8 { Original = 0, v1_17RC1 = 1, v1_17RC2 = 2, v1_17RC3 = 3, Compatible = 4, CompatibleFT2 = 5, NumMixLevels }; enum class PanningMode : uint8 { Undetermined, SoftPanning, NoSoftPanning, FT2Panning, }; // Class used to store settings for a song file. class CSoundFilePlayConfig { public: CSoundFilePlayConfig(); void SetMixLevels(MixLevels mixLevelType); //getters/setters bool getGlobalVolumeAppliesToMaster() const { return m_globalVolumeAppliesToMaster; } void setGlobalVolumeAppliesToMaster(bool inGlobalVolumeAppliesToMaster) { m_globalVolumeAppliesToMaster=inGlobalVolumeAppliesToMaster; } // user-controllable VSTi gain factor. float getVSTiVolume() const { return m_VSTiVolume; } void setVSTiVolume(float inVSTiVolume) { m_VSTiVolume = inVSTiVolume; } // default VSTi gain factor, different depending on the MPT version we're "emulating" float getVSTiAttenuation() const { return m_VSTiAttenuation; } void setVSTiAttenuation(float inVSTiAttenuation) { m_VSTiAttenuation = inVSTiAttenuation; } float getIntToFloat() const { return m_IntToFloat; } void setIntToFloat(float inIntToFloat) { m_IntToFloat = inIntToFloat; } float getFloatToInt() const { return m_FloatToInt; } void setFloatToInt(float inFloatToInt) { m_FloatToInt = inFloatToInt; } bool getUseGlobalPreAmp() const { return m_ignorePreAmp; } void setUseGlobalPreAmp(bool inUseGlobalPreAmp) { m_ignorePreAmp = inUseGlobalPreAmp; } PanningMode getPanningMode() const { return m_forceSoftPanning; } void setPanningMode(PanningMode inForceSoftPanning) { m_forceSoftPanning = inForceSoftPanning; } bool getDisplayDBValues() const { return m_displayDBValues; } void setDisplayDBValues(bool in) { m_displayDBValues = in; } // Values at which volumes are unchanged float getNormalSamplePreAmp() const { return m_normalSamplePreAmp; } void setNormalSamplePreAmp(float in) { m_normalSamplePreAmp = in; } float getNormalVSTiVol() const { return m_normalVSTiVol; } void setNormalVSTiVol(float in) { m_normalVSTiVol = in; } float getNormalGlobalVol() const { return m_normalGlobalVol; } void setNormalGlobalVol(float in) { m_normalGlobalVol = in; } // Extra sample attenuation in bits int getExtraSampleAttenuation() const { return m_extraAttenuation; } void setExtraSampleAttenuation(int attn) { m_extraAttenuation = attn; } protected: float m_IntToFloat; float m_FloatToInt; float m_VSTiAttenuation; float m_VSTiVolume; float m_normalSamplePreAmp; float m_normalVSTiVol; float m_normalGlobalVol; int m_extraAttenuation; PanningMode m_forceSoftPanning; bool m_globalVolumeAppliesToMaster; bool m_ignorePreAmp; bool m_displayDBValues; }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/RowVisitor.h0000644000175000017500000000764414052666041020414 00000000000000/* * RowVisitor.h * ------------ * Purpose: Class for recording which rows of a song has already been visited, used for detecting when a module starts to loop. * Notes : See implementation file. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/span.hpp" #include "Snd_defs.h" #include OPENMPT_NAMESPACE_BEGIN #if defined(MPT_BUILD_DEBUG) || defined(MPT_BUILD_FUZZER) #define MPT_VERIFY_ROWVISITOR_LOOPSTATE #endif // MPT_BUILD_DEBUG || MPT_BUILD_FUZZER class CSoundFile; class ModSequence; struct ModChannel; class RowVisitor { protected: using ChannelStates = mpt::span; class LoopState { static constexpr uint64 FNV1a_BASIS = 14695981039346656037ull; static constexpr uint64 FNV1a_PRIME = 1099511628211ull; uint64 m_hash = FNV1a_BASIS; #ifdef MPT_VERIFY_ROWVISITOR_LOOPSTATE std::vector> m_counts; // Actual loop counts to verify equality of hash-based implementation #endif public: LoopState() = default; LoopState(const ChannelStates &chnState, const bool ignoreRow); LoopState(const LoopState &) = default; LoopState(LoopState&&) = default; LoopState &operator=(const LoopState &) = default; LoopState &operator=(LoopState&&) = default; [[nodiscard]] bool operator==(const LoopState &other) const noexcept { #ifdef MPT_VERIFY_ROWVISITOR_LOOPSTATE if((m_counts == other.m_counts) != (m_hash == other.m_hash)) std::abort(); #endif return m_hash == other.m_hash; } [[nodiscard]] bool HasLoops() const noexcept { #ifdef MPT_VERIFY_ROWVISITOR_LOOPSTATE if(m_counts.empty() != (m_hash == FNV1a_BASIS)) std::abort(); #endif return m_hash != FNV1a_BASIS; } }; using LoopStateSet = std::vector; // Stores for every (order, row) combination in the sequence if it has been visited or not. std::vector> m_visitedRows; // Map for each row that's part of a pattern loop which loop states have been visited. Held in a separate data structure because it is sparse data in typical modules. std::map, LoopStateSet> m_visitedLoopStates; const CSoundFile &m_sndFile; ROWINDEX m_rowsSpentInLoops = 0; const SEQUENCEINDEX m_sequence; public: RowVisitor(const CSoundFile &sndFile, SEQUENCEINDEX sequence = SEQUENCEINDEX_INVALID); void MoveVisitedRowsFrom(RowVisitor &other) noexcept; // Resize / Clear the row vector. // If reset is true, the vector is not only resized to the required dimensions, but also completely cleared (i.e. all visited rows are unset). void Initialize(bool reset); // Mark an order/row combination as visited and returns true if it was visited before. bool Visit(ORDERINDEX ord, ROWINDEX row, const ChannelStates &chnState, bool ignoreRow); // Find the first row that has not been played yet. // The order and row is stored in the order and row variables on success, on failure they contain invalid values. // If onlyUnplayedPatterns is true (default), only completely unplayed patterns are considered, otherwise a song can start anywhere. // Function returns true on success. [[nodiscard]] bool GetFirstUnvisitedRow(ORDERINDEX &order, ROWINDEX &row, bool onlyUnplayedPatterns) const; // Pattern loops can stack up exponentially, which can cause an effectively infinite amount of time to be spent on evaluating them. // If this function returns true, module evaluation should be aborted because the pattern loops appear to be too complex. [[nodiscard]] bool ModuleTooComplex(ROWINDEX threshold) const noexcept { return m_rowsSpentInLoops >= threshold; } void ResetComplexity() { m_rowsSpentInLoops = 0; } protected: // Get the needed vector size for a given pattern. [[nodiscard]] ROWINDEX VisitedRowsVectorSize(PATTERNINDEX pattern) const noexcept; [[nodiscard]] const ModSequence &Order() const; }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ContainerPP20.cpp0000644000175000017500000001055114502511125021123 00000000000000/* * ContainerPP20.cpp * ----------------- * Purpose: Handling of PowerPack PP20 compressed modules * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "../common/FileReader.h" #include "Container.h" #include "Sndfile.h" #include OPENMPT_NAMESPACE_BEGIN #if !defined(MPT_WITH_ANCIENT) struct PPBITBUFFER { uint32 bitcount = 0; uint32 bitbuffer = 0; const uint8 *pStart = nullptr; const uint8 *pSrc = nullptr; uint32 GetBits(uint32 n); }; uint32 PPBITBUFFER::GetBits(uint32 n) { uint32 result = 0; for(uint32 i = 0; i < n; i++) { if(!bitcount) { bitcount = 8; if(pSrc != pStart) pSrc--; bitbuffer = *pSrc; } result = (result << 1) | (bitbuffer & 1); bitbuffer >>= 1; bitcount--; } return result; } static bool PP20_DoUnpack(mpt::span src, uint8 *pDst, uint32 dstLen) { const std::array modeTable{src[0], src[1], src[2], src[3]}; PPBITBUFFER BitBuffer; BitBuffer.pStart = src.data(); BitBuffer.pSrc = src.data() + src.size() - 4; BitBuffer.GetBits(src.data()[src.size() - 1]); uint32 bytesLeft = dstLen; while(bytesLeft > 0) { if(!BitBuffer.GetBits(1)) { uint32 count = 1, countAdd; do { countAdd = BitBuffer.GetBits(2); count += countAdd; } while(countAdd == 3); LimitMax(count, bytesLeft); for(uint32 i = 0; i < count; i++) { pDst[--bytesLeft] = (uint8)BitBuffer.GetBits(8); } if(!bytesLeft) break; } { uint32 modeIndex = BitBuffer.GetBits(2); MPT_CHECKER_ASSUME(modeIndex < 4); uint32 count = modeIndex + 2, offset; if(modeIndex == 3) { offset = BitBuffer.GetBits((BitBuffer.GetBits(1)) ? modeTable[modeIndex] : 7); uint32 countAdd = 7; do { countAdd = BitBuffer.GetBits(3); count += countAdd; } while(countAdd == 7); } else { offset = BitBuffer.GetBits(modeTable[modeIndex]); } LimitMax(count, bytesLeft); for(uint32 i = 0; i < count; i++) { pDst[bytesLeft - 1] = (bytesLeft + offset < dstLen) ? pDst[bytesLeft + offset] : 0; --bytesLeft; } } } return true; } struct PP20header { char magic[4]; // "PP20" uint8 efficiency[4]; }; MPT_BINARY_STRUCT(PP20header, 8) static bool ValidateHeader(const PP20header &hdr) { if(std::memcmp(hdr.magic, "PP20", 4) != 0) { return false; } if(hdr.efficiency[0] < 9 || hdr.efficiency[0] > 15 || hdr.efficiency[1] < 9 || hdr.efficiency[1] > 15 || hdr.efficiency[2] < 9 || hdr.efficiency[2] > 15 || hdr.efficiency[3] < 9 || hdr.efficiency[3] > 15) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPP20(MemoryFileReader file, const uint64 *pfilesize) { PP20header hdr; if(!file.ReadStruct(hdr)) { return ProbeWantMoreData; } if(!ValidateHeader(hdr)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool UnpackPP20(std::vector &containerItems, FileReader &file, ContainerLoadingFlags loadFlags) { file.Rewind(); containerItems.clear(); PP20header hdr; if(!file.ReadStruct(hdr)) { return false; } if(!ValidateHeader(hdr)) { return false; } if(loadFlags == ContainerOnlyVerifyHeader) { return true; } if(!file.CanRead(4)) { return false; } containerItems.emplace_back(); containerItems.back().data_cache = std::make_unique >(); std::vector & unpackedData = *(containerItems.back().data_cache); FileReader::pos_type length = file.GetLength(); if(!mpt::in_range(length)) return false; // Length word must be aligned if((length % 2u) != 0) return false; file.Seek(length - 4); uint32 dstLen = file.ReadUint24BE(); if(dstLen == 0) return false; try { unpackedData.resize(dstLen); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); return false; } file.Seek(4); FileReader::PinnedView compressedData = file.GetPinnedView(mpt::saturate_cast(length - 4)); bool result = PP20_DoUnpack(mpt::byte_cast>(compressedData.span()), mpt::byte_cast(unpackedData.data()), dstLen); if(result) { containerItems.back().file = FileReader(mpt::byte_cast(mpt::as_span(unpackedData))); } return result; } #endif // !MPT_WITH_ANCIENT OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MixFuncTable.h0000644000175000017500000000202714052666041020574 00000000000000/* * MixFuncTable.h * -------------- * Purpose: Table containing all mixer functions. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "MixerInterface.h" OPENMPT_NAMESPACE_BEGIN namespace MixFuncTable { // Table index bits: // [b1-b0] format (8-bit-mono, 16-bit-mono, 8-bit-stereo, 16-bit-stereo) // [b2] ramp // [b3] filter // [b6-b4] src type // Sample type / processing type index enum FunctionIndex { ndx16Bit = 0x01, ndxStereo = 0x02, ndxRamp = 0x04, ndxFilter = 0x08, }; // SRC index enum ResamplingIndex { ndxNoInterpolation = 0x00, ndxLinear = 0x10, ndxFastSinc = 0x20, ndxKaiser = 0x30, ndxFIRFilter = 0x40, ndxAmigaBlep = 0x50, }; extern const MixFuncInterface Functions[6 * 16]; ResamplingIndex ResamplingModeToMixFlags(ResamplingMode resamplingMode); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleFormatMP3.cpp0000644000175000017500000005176515021077243021532 00000000000000/* * SampleFormatMP3.cpp * ------------------- * Purpose: MP3 sample import. * Notes : * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Sndfile.h" #ifndef MODPLUG_NO_FILESAVE #include "../common/mptFileIO.h" #endif #include "../common/misc_util.h" #include "Tagging.h" #include "Loaders.h" #include "../common/FileReader.h" #include "modsmp_ctrl.h" #include "openmpt/soundbase/Copy.hpp" #include "../soundlib/ModSampleCopy.h" #include "../common/ComponentManager.h" #ifdef MPT_ENABLE_MP3_SAMPLES #include "MPEGFrame.h" #endif // MPT_ENABLE_MP3_SAMPLES #if defined(MPT_WITH_MINIMP3) #include "mpt/base/alloc.hpp" #endif // MPT_WITH_MINIMP3 #if defined(MPT_WITH_MINIMP3) #include #endif // MPT_WITH_MINIMP3 // mpg123 must be last because of mpg123 large file support insanity #if defined(MPT_WITH_MPG123) #include #include #include #if MPT_OS_OPENBSD // This is kind-of a hack. // See . #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif #ifdef _FILE_OFFSET_BITS #undef _FILE_OFFSET_BITS #endif #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif #endif #include #define MPT_USE_MPG123_PORTABLE_API 1 #endif OPENMPT_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////////////////////////// // MP3 Samples #if defined(MPT_WITH_MPG123) #if (MPG123_API_VERSION < 48) || !MPT_USE_MPG123_PORTABLE_API using mpg123_off_t = off_t; using mpg123_size_t = size_t; // Check for exactly _MSC_VER as libmpg123 does, in order to also catch clang-cl. #ifdef _MSC_VER // ssize_t definition in libmpg123.h.in should never have existed at all. // It got removed from libmpg23.h.in after 1.28.0 and before 1.28.1. using mpg123_ssize_t = ptrdiff_t; #else using mpg123_ssize_t = ssize_t; #endif #endif class ComponentMPG123 : public ComponentBuiltin { MPT_DECLARE_COMPONENT_MEMBERS(ComponentMPG123, "") public: #if (MPG123_API_VERSION >= 48) && MPT_USE_MPG123_PORTABLE_API static int FileReaderRead(void *fp, void *buf, size_t count, size_t *returned) { FileReader &file = *static_cast(fp); std::size_t readBytes = std::min(count, mpt::saturate_cast(file.BytesLeft())); file.ReadRaw(mpt::span(mpt::void_cast(buf), readBytes)); if(!returned) { return -1; } *returned = readBytes; return 0; } static int64_t FileReaderSeek(void *fp, int64_t offset, int whence) { FileReader &file = *static_cast(fp); if(whence == SEEK_CUR) { if(!mpt::in_range(file.GetPosition() + offset)) { return -1; } file.Seek(static_cast(file.GetPosition() + offset)); } else if(whence == SEEK_END) { if(!mpt::in_range(file.GetLength() + offset)) { return -1; } file.Seek(static_cast(file.GetLength() + offset)); } else { if(!mpt::in_range(offset)) { return -1; } file.Seek(static_cast(offset)); } return static_cast(file.GetPosition()); } #else static mpg123_ssize_t FileReaderRead(void *fp, void *buf, mpg123_size_t count) { FileReader &file = *static_cast(fp); std::size_t readBytes = std::min(count, static_cast(file.BytesLeft())); file.ReadRaw(mpt::span(mpt::void_cast(buf), readBytes)); return readBytes; } static mpg123_off_t FileReaderLSeek(void *fp, mpg123_off_t offset, int whence) { FileReader &file = *static_cast(fp); FileReader::pos_type oldpos = file.GetPosition(); if(whence == SEEK_CUR) file.Seek(file.GetPosition() + offset); else if(whence == SEEK_END) file.Seek(file.GetLength() + offset); else file.Seek(offset); MPT_MAYBE_CONSTANT_IF(!mpt::in_range(file.GetPosition())) { file.Seek(oldpos); return static_cast(-1); } return static_cast(file.GetPosition()); } #endif public: ComponentMPG123() : ComponentBuiltin() { return; } bool DoInitialize() override { if(mpg123_init() != 0) { return false; } return true; } virtual ~ComponentMPG123() { if(IsAvailable()) { mpg123_exit(); } } }; static mpt::ustring ReadMPG123String(const mpg123_string &str) { mpt::ustring result; if(!str.p) { return result; } if(str.fill < 1) { return result; } result = mpt::ToUnicode(mpt::Charset::UTF8, std::string(str.p, str.p + str.fill - 1)); return result; } static mpt::ustring ReadMPG123String(const mpg123_string *str) { mpt::ustring result; if(!str) { return result; } result = ReadMPG123String(*str); return result; } template static mpt::ustring ReadMPG123String(const char (&str)[N]) { return mpt::ToUnicode(mpt::Charset::ISO8859_1, mpt::String::ReadBuf(mpt::String::spacePadded, str)); } #endif // MPT_WITH_MPG123 #if defined(MPT_WITH_MINIMP3) #if MPT_COMPILER_GCC #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wframe-larger-than=16000" #endif // MPT_COMPILER_GCC #if (MPT_CLANG_AT_LEAST(13,0,0) && !defined(MPT_COMPILER_QUIRK_APPLE_CLANG)) || MPT_CLANG_AT_LEAST(13,1,0) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wframe-larger-than" #endif // MPT_COMPILER_CLANG static MPT_NOINLINE int mp3dec_decode_frame_no_inline(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info) { return mp3dec_decode_frame(dec, mp3, mp3_bytes, pcm, info); } #if (MPT_CLANG_AT_LEAST(13,0,0) && !defined(MPT_COMPILER_QUIRK_APPLE_CLANG)) || MPT_CLANG_AT_LEAST(13,1,0) #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #if MPT_COMPILER_GCC #pragma GCC diagnostic pop #endif // MPT_COMPILER_GCC #endif // MPT_WITH_MINIMP3 bool CSoundFile::ReadMP3Sample(SAMPLEINDEX sample, FileReader &file, bool raw, bool mo3Decode) { #if defined(MPT_WITH_MPG123) || defined(MPT_WITH_MINIMP3) // Check file for validity, or else mpg123 will happily munch many files that start looking vaguely resemble an MPEG stream mid-file. file.Rewind(); while(file.CanRead(4)) { uint8 magic[3]; file.ReadArray(magic); if(!memcmp(magic, "ID3", 3)) { // Skip ID3 tags uint8 header[7]; file.ReadArray(header); uint32 size = 0; for(int i = 3; i < 7; i++) { if(header[i] & 0x80) return false; size = (size << 7) | header[i]; } file.Skip(size); } else if(!memcmp(magic, "APE", 3) && file.ReadMagic("TAGEX")) { // Skip APE tags uint32 size = file.ReadUint32LE(); file.Skip(16 + size); } else if(!memcmp(magic, "\x00\x00\x00", 3) || !memcmp(magic, "\xFF\x00\x00", 3)) { // Some MP3 files are padded with zeroes... } else if(magic[0] == 0) { // This might be some padding, followed by an MPEG header, so try again. file.SkipBack(2); } else if(MPEGFrame::IsMPEGHeader(magic)) { // This is what we want! break; } else { // This, on the other hand, isn't. return false; } } #endif // MPT_WITH_MPG123 || MPT_WITH_MINIMP3 #if defined(MPT_WITH_MPG123) ComponentHandle mpg123; if(!IsComponentAvailable(mpg123)) { return false; } struct MPG123Handle { mpg123_handle *mh; MPG123Handle() : mh(mpg123_new(0, nullptr)) { } ~MPG123Handle() { mpg123_delete(mh); } operator mpg123_handle *() { return mh; } }; bool hasLameXingVbriHeader = false; if(!raw) { #if (MPG123_API_VERSION >= 48) && MPT_USE_MPG123_PORTABLE_API int64_t length_raw = 0; int64_t length_hdr = 0; #else mpg123_off_t length_raw = 0; mpg123_off_t length_hdr = 0; #endif // libmpg123 provides no way to determine whether it parsed ID3V2 or VBR tags. // Thus, we use a pre-scan with those disabled and compare the resulting length. // We ignore ID3V2 stream length here, althrough we parse the ID3V2 header. // libmpg123 only accounts for the VBR info frame if gapless &&!ignore_infoframe, // thus we switch both of those for comparison. { MPG123Handle mh; if(!mh) { return false; } file.Rewind(); if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_QUIET, 0.0)) { return false; } if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_AUTO_RESAMPLE, 0.0)) { return false; } if(mpg123_param(mh, MPG123_REMOVE_FLAGS, MPG123_GAPLESS, 0.0)) { return false; } if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_IGNORE_INFOFRAME, 0.0)) { return false; } if(mpg123_param(mh, MPG123_REMOVE_FLAGS, MPG123_SKIP_ID3V2, 0.0)) { return false; } if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_IGNORE_STREAMLENGTH, 0.0)) { return false; } if(mpg123_param(mh, MPG123_INDEX_SIZE, -1000, 0.0)) // auto-grow { return false; } #if (MPG123_API_VERSION >= 48) && MPT_USE_MPG123_PORTABLE_API if(mpg123_reader64(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderSeek, 0)) { return false; } #else if(mpg123_replace_reader_handle(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderLSeek, 0)) { return false; } #endif #if (MPG123_API_VERSION >= 49) && MPT_USE_MPG123_PORTABLE_API if(mpg123_open_handle64(mh, &file)) { return false; } #else if(mpg123_open_handle(mh, &file)) { return false; } #endif if(mpg123_scan(mh)) { return false; } long rate = 0; int channels = 0; int encoding = 0; if(mpg123_getformat(mh, &rate, &channels, &encoding)) { return false; } if((channels != 1 && channels != 2) || (encoding & (MPG123_ENC_16 | MPG123_ENC_SIGNED)) != (MPG123_ENC_16 | MPG123_ENC_SIGNED)) { return false; } mpg123_frameinfo frameinfo; MemsetZero(frameinfo); if(mpg123_info(mh, &frameinfo)) { return false; } if(frameinfo.layer < 1 || frameinfo.layer > 3) { return false; } if(mpg123_param(mh, MPG123_FORCE_RATE, rate, 0.0)) { return false; } if(mpg123_param(mh, MPG123_ADD_FLAGS, (channels > 1) ? MPG123_FORCE_STEREO : MPG123_FORCE_MONO, 0.0)) { return false; } #if (MPG123_API_VERSION >= 48) && MPT_USE_MPG123_PORTABLE_API length_raw = mpg123_length64(mh); #else length_raw = mpg123_length(mh); #endif } { MPG123Handle mh; if(!mh) { return false; } file.Rewind(); if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_QUIET, 0.0)) { return false; } if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_AUTO_RESAMPLE, 0.0)) { return false; } if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_GAPLESS, 0.0)) { return false; } if(mpg123_param(mh, MPG123_REMOVE_FLAGS, MPG123_IGNORE_INFOFRAME, 0.0)) { return false; } if(mpg123_param(mh, MPG123_REMOVE_FLAGS, MPG123_SKIP_ID3V2, 0.0)) { return false; } if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_IGNORE_STREAMLENGTH, 0.0)) { return false; } if(mpg123_param(mh, MPG123_INDEX_SIZE, -1000, 0.0)) // auto-grow { return false; } #if (MPG123_API_VERSION >= 48) && MPT_USE_MPG123_PORTABLE_API if(mpg123_reader64(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderSeek, 0)) { return false; } #else if(mpg123_replace_reader_handle(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderLSeek, 0)) { return false; } #endif #if (MPG123_API_VERSION >= 49) && MPT_USE_MPG123_PORTABLE_API if(mpg123_open_handle64(mh, &file)) { return false; } #else if(mpg123_open_handle(mh, &file)) { return false; } #endif if(mpg123_scan(mh)) { return false; } long rate = 0; int channels = 0; int encoding = 0; if(mpg123_getformat(mh, &rate, &channels, &encoding)) { return false; } if((channels != 1 && channels != 2) || (encoding & (MPG123_ENC_16 | MPG123_ENC_SIGNED)) != (MPG123_ENC_16 | MPG123_ENC_SIGNED)) { return false; } mpg123_frameinfo frameinfo; MemsetZero(frameinfo); if(mpg123_info(mh, &frameinfo)) { return false; } if(frameinfo.layer < 1 || frameinfo.layer > 3) { return false; } if(mpg123_param(mh, MPG123_FORCE_RATE, rate, 0.0)) { return false; } if(mpg123_param(mh, MPG123_ADD_FLAGS, (channels > 1) ? MPG123_FORCE_STEREO : MPG123_FORCE_MONO, 0.0)) { return false; } #if (MPG123_API_VERSION >= 48) && MPT_USE_MPG123_PORTABLE_API length_hdr = mpg123_length64(mh); #else length_hdr = mpg123_length(mh); #endif } hasLameXingVbriHeader = (length_raw != length_hdr); } // Set up decoder... MPG123Handle mh; if(!mh) { return false; } file.Rewind(); if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_QUIET, 0.0)) { return false; } if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_AUTO_RESAMPLE, 0.0)) { return false; } if(mpg123_param(mh, raw ? MPG123_REMOVE_FLAGS : MPG123_ADD_FLAGS, MPG123_GAPLESS, 0.0)) { return false; } if(mpg123_param(mh, raw ? MPG123_ADD_FLAGS : MPG123_REMOVE_FLAGS, MPG123_IGNORE_INFOFRAME, 0.0)) { return false; } if(mpg123_param(mh, MPG123_REMOVE_FLAGS, MPG123_SKIP_ID3V2, 0.0)) { return false; } if(mpg123_param(mh, raw ? MPG123_ADD_FLAGS : MPG123_REMOVE_FLAGS, MPG123_IGNORE_STREAMLENGTH, 0.0)) { return false; } if(mpg123_param(mh, MPG123_INDEX_SIZE, -1000, 0.0)) // auto-grow { return false; } #if (MPG123_API_VERSION >= 48) && MPT_USE_MPG123_PORTABLE_API if(mpg123_reader64(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderSeek, 0)) { return false; } #else if(mpg123_replace_reader_handle(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderLSeek, 0)) { return false; } #endif #if (MPG123_API_VERSION >= 49) && MPT_USE_MPG123_PORTABLE_API if(mpg123_open_handle64(mh, &file)) { return false; } #else if(mpg123_open_handle(mh, &file)) { return false; } #endif if(mpg123_scan(mh)) { return false; } long rate = 0; int channels = 0; int encoding = 0; if(mpg123_getformat(mh, &rate, &channels, &encoding)) { return false; } if((channels != 1 && channels != 2) || (encoding & (MPG123_ENC_16 | MPG123_ENC_SIGNED)) != (MPG123_ENC_16 | MPG123_ENC_SIGNED)) { return false; } mpg123_frameinfo frameinfo; MemsetZero(frameinfo); if(mpg123_info(mh, &frameinfo)) { return false; } if(frameinfo.layer < 1 || frameinfo.layer > 3) { return false; } // We force samplerate, channels and sampleformat, which in // combination with auto-resample (set above) will cause libmpg123 // to stay with the given format even for completely confused // MPG123_FRANKENSTEIN streams. // Note that we cannot rely on mpg123_length() for the way we // decode the mpeg streams because it depends on the actual frame // sample rate instead of the returned sample rate. if(mpg123_param(mh, MPG123_FORCE_RATE, rate, 0.0)) { return false; } if(mpg123_param(mh, MPG123_ADD_FLAGS, (channels > 1) ? MPG123_FORCE_STEREO : MPG123_FORCE_MONO, 0.0)) { return false; } std::vector data; // decoder delay std::size_t data_skip_frames = 0; if(!raw && !hasLameXingVbriHeader) { if(frameinfo.layer == 1) { data_skip_frames = 240 + 1; } else if(frameinfo.layer == 2) { data_skip_frames = 240 + 1; } else if(frameinfo.layer == 3) { data_skip_frames = 528 + 1; } } std::vector buf_bytes; std::vector buf_samples; bool decode_error = false; bool decode_done = false; while(!decode_error && !decode_done) { buf_bytes.resize(mpg123_outblock(mh)); buf_samples.resize(buf_bytes.size() / sizeof(int16)); #if (MPG123_API_VERSION >= 48) && MPT_USE_MPG123_PORTABLE_API size_t buf_bytes_decoded = 0; #else mpg123_size_t buf_bytes_decoded = 0; #endif int mpg123_read_result = mpg123_read(mh, mpt::byte_cast(buf_bytes.data()), buf_bytes.size(), &buf_bytes_decoded); std::memcpy(buf_samples.data(), buf_bytes.data(), buf_bytes_decoded); mpt::append(data, buf_samples.data(), buf_samples.data() + buf_bytes_decoded / sizeof(int16)); if((data.size() / channels) > MAX_SAMPLE_LENGTH) { break; } if(mpg123_read_result == MPG123_OK) { // continue } else if(mpg123_read_result == MPG123_NEW_FORMAT) { // continue } else if(mpg123_read_result == MPG123_DONE) { decode_done = true; } else { decode_error = true; } } if((data.size() / channels) > MAX_SAMPLE_LENGTH) { return false; } FileTags tags; mpg123_id3v1 *id3v1 = nullptr; mpg123_id3v2 *id3v2 = nullptr; if(mpg123_id3(mh, &id3v1, &id3v2) == MPG123_OK) { if(id3v2) { if(tags.title.empty()) tags.title = ReadMPG123String(id3v2->title); if(tags.artist.empty()) tags.artist = ReadMPG123String(id3v2->artist); if(tags.album.empty()) tags.album = ReadMPG123String(id3v2->album); if(tags.year.empty()) tags.year = ReadMPG123String(id3v2->year); if(tags.genre.empty()) tags.genre = ReadMPG123String(id3v2->genre); if(tags.comments.empty()) tags.comments = ReadMPG123String(id3v2->comment); } if(id3v1) { if(tags.title.empty()) tags.title = ReadMPG123String(id3v1->title); if(tags.artist.empty()) tags.artist = ReadMPG123String(id3v1->artist); if(tags.album.empty()) tags.album = ReadMPG123String(id3v1->album); if(tags.year.empty()) tags.year = ReadMPG123String(id3v1->year); if(tags.comments.empty()) tags.comments = ReadMPG123String(id3v1->comment); } } mpt::ustring sampleName = GetSampleNameFromTags(tags); DestroySampleThreadsafe(sample); if(!mo3Decode) { m_szNames[sample] = mpt::ToCharset(GetCharsetInternal(), sampleName); Samples[sample].Initialize(); Samples[sample].nC5Speed = static_cast(rate); } Samples[sample].nLength = mpt::saturate_cast((data.size() / channels) - data_skip_frames); Samples[sample].uFlags.set(CHN_16BIT); Samples[sample].uFlags.set(CHN_STEREO, channels == 2); Samples[sample].AllocateSample(); if(Samples[sample].HasSampleData()) { std::memcpy(Samples[sample].sampleb(), data.data() + (data_skip_frames * channels), (data.size() - (data_skip_frames * channels)) * sizeof(int16)); } if(!mo3Decode) { Samples[sample].Convert(MOD_TYPE_IT, GetType()); Samples[sample].PrecomputeLoops(*this, false); } return Samples[sample].HasSampleData(); #elif defined(MPT_WITH_MINIMP3) MPT_UNREFERENCED_PARAMETER(raw); file.Rewind(); FileReader::PinnedView rawDataView = file.GetPinnedView(); int64 bytes_left = rawDataView.size(); const uint8 *stream_pos = mpt::byte_cast(rawDataView.data()); std::vector raw_sample_data; mpt::heap_value mp3; std::memset(&*mp3, 0, sizeof(mp3dec_t)); mp3dec_init(&*mp3); int rate = 0; int channels = 0; mp3dec_frame_info_t info; std::memset(&info, 0, sizeof(mp3dec_frame_info_t)); std::vector sample_buf(MINIMP3_MAX_SAMPLES_PER_FRAME); do { int frame_samples = mp3dec_decode_frame_no_inline(&*mp3, stream_pos, mpt::saturate_cast(bytes_left), sample_buf.data(), &info); if(frame_samples < 0 || info.frame_bytes < 0) break; // internal error in minimp3 if(frame_samples > 0 && info.frame_bytes == 0) break; // internal error in minimp3 if(frame_samples == 0 && info.frame_bytes == 0) break; // end of stream, no progress if(frame_samples == 0 && info.frame_bytes > 0) do { } while(0); // decoder skipped non-mp3 data if(frame_samples > 0 && info.frame_bytes > 0) do { } while(0); // normal if(info.frame_bytes > 0) { if(rate != 0 && rate != info.hz) break; // inconsistent stream if(channels != 0 && channels != info.channels) break; // inconsistent stream rate = info.hz; channels = info.channels; if(rate <= 0) break; // broken stream if(channels != 1 && channels != 2) break; // broken stream stream_pos += std::clamp(info.frame_bytes, 0, mpt::saturate_cast(bytes_left)); bytes_left -= std::clamp(info.frame_bytes, 0, mpt::saturate_cast(bytes_left)); if(frame_samples > 0) { try { mpt::append(raw_sample_data, sample_buf.data(), sample_buf.data() + frame_samples * channels); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); break; } } } if((raw_sample_data.size() / channels) > MAX_SAMPLE_LENGTH) { break; } } while(bytes_left > 0); if(rate == 0 || channels == 0 || raw_sample_data.empty()) { return false; } if((raw_sample_data.size() / channels) > MAX_SAMPLE_LENGTH) { return false; } DestroySampleThreadsafe(sample); if(!mo3Decode) { m_szNames[sample] = ""; Samples[sample].Initialize(); Samples[sample].nC5Speed = rate; } Samples[sample].nLength = mpt::saturate_cast(raw_sample_data.size() / channels); Samples[sample].uFlags.set(CHN_16BIT); Samples[sample].uFlags.set(CHN_STEREO, channels == 2); Samples[sample].AllocateSample(); if(Samples[sample].HasSampleData()) { std::copy(raw_sample_data.begin(), raw_sample_data.end(), Samples[sample].sample16()); } if(!mo3Decode) { Samples[sample].Convert(MOD_TYPE_IT, GetType()); Samples[sample].PrecomputeLoops(*this, false); } return Samples[sample].HasSampleData(); #else MPT_UNREFERENCED_PARAMETER(sample); MPT_UNREFERENCED_PARAMETER(file); MPT_UNREFERENCED_PARAMETER(raw); MPT_UNREFERENCED_PARAMETER(mo3Decode); #endif // MPT_WITH_MPG123 || MPT_WITH_MINIMP3 return false; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Loaders.h0000644000175000017500000000415414704715777017666 00000000000000/* * Loaders.h * --------- * Purpose: Common functions for module loaders * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "../common/misc_util.h" #include "../common/FileReader.h" #include "Sndfile.h" #include "SampleIO.h" #include "openmpt/fileformat_base/magic.hpp" OPENMPT_NAMESPACE_BEGIN // Read 'howMany' order items from an array. // 'stopIndex' is treated as '---', 'ignoreIndex' is treated as '+++'. If the format doesn't support such indices, just pass uint16_max. template bool ReadOrderFromArray(ModSequence &order, const T(&orders)[arraySize], size_t howMany = arraySize, uint16 stopIndex = uint16_max, uint16 ignoreIndex = uint16_max) { static_assert(mpt::is_binary_safe::value); LimitMax(howMany, arraySize); LimitMax(howMany, MAX_ORDERS); ORDERINDEX readEntries = static_cast(howMany); order.resize(readEntries); for(int i = 0; i < readEntries; i++) { PATTERNINDEX pat = static_cast(orders[i]); if(pat == stopIndex) pat = PATTERNINDEX_INVALID; else if(pat == ignoreIndex) pat = PATTERNINDEX_SKIP; order.at(i) = pat; } return true; } // Read 'howMany' order items as integers with defined endianness from a file. // 'stopIndex' is treated as '---', 'ignoreIndex' is treated as '+++'. If the format doesn't support such indices, just pass uint16_max. template bool ReadOrderFromFile(ModSequence &order, FileReader &file, size_t howMany, uint16 stopIndex = uint16_max, uint16 ignoreIndex = uint16_max) { static_assert(mpt::is_binary_safe::value); if(!file.CanRead(howMany * sizeof(T))) return false; LimitMax(howMany, MAX_ORDERS); ORDERINDEX readEntries = static_cast(howMany); order.resize(readEntries); T patF; for(auto &pat : order) { file.ReadStruct(patF); pat = static_cast(patF); if(pat == stopIndex) pat = PATTERNINDEX_INVALID; else if(pat == ignoreIndex) pat = PATTERNINDEX_SKIP; } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleIO.h0000644000175000017500000001516714423223712017731 00000000000000/* * SampleIO.h * ---------- * Purpose: Central code for reading and writing samples. Create your SampleIO object and have a go at the ReadSample and WriteSample functions! * Notes : Not all combinations of possible sample format combinations are implemented, especially for WriteSample. * Using the existing generic sample conversion functors in SampleFormatConverters.h, it should be quite easy to extend the code, though. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" #include "../common/FileReaderFwd.h" OPENMPT_NAMESPACE_BEGIN struct ModSample; // Sample import / export formats class SampleIO { public: // Bits per sample enum Bitdepth : uint8 { _8bit = 8, _16bit = 16, _24bit = 24, _32bit = 32, _64bit = 64, }; // Number of channels + channel format enum Channels : uint8 { mono = 1, stereoInterleaved, // LRLRLR... stereoSplit, // LLL...RRR... }; // Sample byte order enum Endianness : uint8 { littleEndian = 0, bigEndian = 1, }; // Sample encoding enum Encoding : uint8 { signedPCM = 0, // Integer PCM, signed unsignedPCM, // Integer PCM, unsigned deltaPCM, // Integer PCM, delta-encoded floatPCM, // Floating point PCM IT214, // Impulse Tracker 2.14 compressed IT215, // Impulse Tracker 2.15 compressed AMS, // AMS / Velvet Studio packed DMF, // DMF Huffman compression MDL, // MDL Huffman compression PTM8Dto16, // PTM 8-Bit delta value -> 16-Bit sample ADPCM, // 4-Bit ADPCM-packed MT2, // MadTracker 2 stereo delta encoding floatPCM15, // Floating point PCM with 2^15 full scale floatPCM23, // Floating point PCM with 2^23 full scale floatPCMnormalize, // Floating point PCM and data will be normalized while reading signedPCMnormalize, // Integer PCM and data will be normalized while reading uLaw, // 8-to-16 bit G.711 u-law compression aLaw, // 8-to-16 bit G.711 a-law compression }; protected: Bitdepth m_bitdepth; Channels m_channels; Endianness m_endianness; Encoding m_encoding; public: constexpr SampleIO(Bitdepth bits = _8bit, Channels channels = mono, Endianness endianness = littleEndian, Encoding encoding = signedPCM) : m_bitdepth(bits), m_channels(channels), m_endianness(endianness), m_encoding(encoding) { } bool operator== (const SampleIO &other) const { return memcmp(this, &other, sizeof(*this)) == 0; } bool operator!= (const SampleIO &other) const { return memcmp(this, &other, sizeof(*this)) != 0; } void operator|= (Bitdepth bits) { m_bitdepth = bits; } void operator|= (Channels channels) { m_channels = channels; } void operator|= (Endianness endianness) { m_endianness = endianness; } void operator|= (Encoding encoding) { m_encoding = encoding; } void MayNormalize() { if(GetBitDepth() >= 24) { if(GetEncoding() == SampleIO::signedPCM) { m_encoding = SampleIO::signedPCMnormalize; } else if(GetEncoding() == SampleIO::floatPCM) { m_encoding = SampleIO::floatPCMnormalize; } } } // Return 0 in case of variable-length encoded samples. MPT_CONSTEXPRINLINE uint8 GetEncodedBitsPerSample() const { switch(GetEncoding()) { case signedPCM: // Integer PCM, signed case unsignedPCM: //Integer PCM, unsigned case deltaPCM: // Integer PCM, delta-encoded case floatPCM: // Floating point PCM case MT2: // MadTracker 2 stereo delta encoding case floatPCM15: // Floating point PCM with 2^15 full scale case floatPCM23: // Floating point PCM with 2^23 full scale case floatPCMnormalize: // Floating point PCM and data will be normalized while reading case signedPCMnormalize: // Integer PCM and data will be normalized while reading return GetBitDepth(); case IT214: // Impulse Tracker 2.14 compressed case IT215: // Impulse Tracker 2.15 compressed case AMS: // AMS / Velvet Studio packed case DMF: // DMF Huffman compression case MDL: // MDL Huffman compression return 0; // variable-length compressed case PTM8Dto16: // PTM 8-Bit delta value -> 16-Bit sample return 16; case ADPCM: // 4-Bit ADPCM-packed return 4; case uLaw: // G.711 u-law return 8; case aLaw: // G.711 a-law return 8; default: return 0; } } // Return the static header size additional to the raw encoded sample data. MPT_CONSTEXPRINLINE std::size_t GetEncodedHeaderSize() const { switch(GetEncoding()) { case ADPCM: return 16; default: return 0; } } // Returns true if the encoded size cannot be calculated apriori from the encoding format and the sample length. MPT_CONSTEXPRINLINE bool IsVariableLengthEncoded() const { return GetEncodedBitsPerSample() == 0; } // Returns true if the decoder for a given format uses FileReader interface and thus do not need to call GetPinnedView() MPT_CONSTEXPRINLINE bool UsesFileReaderForDecoding() const { switch(GetEncoding()) { case IT214: case IT215: case AMS: case DMF: case MDL: return true; default: return false; } } // Get bits per sample constexpr uint8 GetBitDepth() const { return static_cast(m_bitdepth); } // Get channel layout constexpr Channels GetChannelFormat() const { return m_channels; } // Get number of channels constexpr uint8 GetNumChannels() const { return GetChannelFormat() == mono ? 1u : 2u; } // Get sample byte order constexpr Endianness GetEndianness() const { return m_endianness; } // Get sample format / encoding constexpr Encoding GetEncoding() const { return m_encoding; } // Returns the encoded size of the sample. In case of variable-length encoding returns 0. std::size_t CalculateEncodedSize(SmpLength length) const { if(IsVariableLengthEncoded()) { return 0; } uint8 bps = GetEncodedBitsPerSample(); if(bps % 8u != 0) { MPT_ASSERT(GetEncoding() == ADPCM && bps == 4); return GetEncodedHeaderSize() + (((length + 1) / 2) * GetNumChannels()); // round up } return GetEncodedHeaderSize() + (length * (bps / 8) * GetNumChannels()); } // Read a sample from memory size_t ReadSample(ModSample &sample, FileReader &file) const; #ifndef MODPLUG_NO_FILESAVE // Write a sample to file size_t WriteSample(std::ostream &f, const ModSample &sample, SmpLength maxSamples = 0) const; #endif // MODPLUG_NO_FILESAVE }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_mtm.cpp0000644000175000017500000002144714644610543020354 00000000000000/* * Load_mtm.cpp * ------------ * Purpose: MTM (MultiTracker) module loader * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN // File Header struct MTMFileHeader { char id[3]; // MTM file marker uint8le version; // Tracker version char songName[20]; // ASCIIZ songname uint16le numTracks; // Number of tracks saved uint8le lastPattern; // Last pattern number saved uint8le lastOrder; // Last order number to play (songlength-1) uint16le commentSize; // Length of comment field uint8le numSamples; // Number of samples saved uint8le attribute; // Attribute byte (unused) uint8le beatsPerTrack; // Numbers of rows in every pattern (MultiTracker itself does not seem to support values != 64) uint8le numChannels; // Number of channels used uint8le panPos[32]; // Channel pan positions }; MPT_BINARY_STRUCT(MTMFileHeader, 66) // Sample Header struct MTMSampleHeader { char samplename[22]; uint32le length; uint32le loopStart; uint32le loopEnd; int8le finetune; uint8le volume; uint8le attribute; // Convert an MTM sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.nVolume = std::min(uint16(volume * 4), uint16(256)); if(length > 2) { mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = std::max(loopEnd.get(), uint32(1)) - 1; LimitMax(mptSmp.nLoopEnd, mptSmp.nLength); if(mptSmp.nLoopStart + 4 >= mptSmp.nLoopEnd) mptSmp.nLoopStart = mptSmp.nLoopEnd = 0; if(mptSmp.nLoopEnd > 2) mptSmp.uFlags.set(CHN_LOOP); mptSmp.nFineTune = finetune; // Uses MOD units but allows the full int8 range rather than just -8...+7 so we keep the value as-is and convert it during playback mptSmp.nC5Speed = ModSample::TransposeToFrequency(0, finetune * 16); if(attribute & 0x01) { mptSmp.uFlags.set(CHN_16BIT); mptSmp.nLength /= 2; mptSmp.nLoopStart /= 2; mptSmp.nLoopEnd /= 2; } } } }; MPT_BINARY_STRUCT(MTMSampleHeader, 37) static bool ValidateHeader(const MTMFileHeader &fileHeader) { if(std::memcmp(fileHeader.id, "MTM", 3) || fileHeader.version >= 0x20 || fileHeader.lastOrder > 127 || fileHeader.beatsPerTrack > 64 || fileHeader.numChannels > 32 || fileHeader.numChannels == 0 ) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const MTMFileHeader &fileHeader) { return sizeof(MTMSampleHeader) * fileHeader.numSamples + 128 + 192 * fileHeader.numTracks + 64 * (fileHeader.lastPattern + 1) + fileHeader.commentSize; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMTM(MemoryFileReader file, const uint64 *pfilesize) { MTMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); MTMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_MTM, fileHeader.numChannels); m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songName); m_nSamples = fileHeader.numSamples; m_modFormat.formatName = UL_("MultiTracker"); m_modFormat.type = UL_("mtm"); m_modFormat.madeWithTracker = MPT_UFORMAT("MultiTracker {}.{}")(fileHeader.version >> 4, fileHeader.version & 0x0F); m_modFormat.charset = mpt::Charset::CP437; // Reading instruments for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { MTMSampleHeader sampleHeader; file.ReadStruct(sampleHeader); sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.samplename); } // Setting Channel Pan Position for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = ((fileHeader.panPos[chn] & 0x0F) << 4) + 8; } // Reading pattern order uint8 orders[128]; file.ReadArray(orders); ReadOrderFromArray(Order(), orders, fileHeader.lastOrder + 1, 0xFF, 0xFE); // Reading Patterns const ROWINDEX rowsPerPat = fileHeader.beatsPerTrack ? fileHeader.beatsPerTrack : 64; FileReader tracks = file.ReadChunk(192 * fileHeader.numTracks); if(loadFlags & loadPatternData) Patterns.ResizeArray(fileHeader.lastPattern + 1); bool hasSpeed = false, hasTempo = false; for(PATTERNINDEX pat = 0; pat <= fileHeader.lastPattern; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, rowsPerPat)) { file.Skip(64); continue; } for(CHANNELINDEX chn = 0; chn < 32; chn++) { uint16 track = file.ReadUint16LE(); if(track == 0 || track > fileHeader.numTracks || chn >= GetNumChannels()) { continue; } tracks.Seek(192 * (track - 1)); ModCommand *m = Patterns[pat].GetpModCommand(0, chn); for(ROWINDEX row = 0; row < rowsPerPat; row++, m += GetNumChannels()) { const auto [noteInstr, instrCmd, par] = tracks.ReadArray(); if(noteInstr & 0xFC) m->note = (noteInstr >> 2) + 36 + NOTE_MIN; m->instr = ((noteInstr & 0x03) << 4) | (instrCmd >> 4); uint8 cmd = instrCmd & 0x0F; uint8 param = par; if(cmd == 0x0A) { if(param & 0xF0) param &= 0xF0; else param &= 0x0F; } else if(cmd == 0x08) { // No 8xx panning in MultiTracker, only E8x cmd = param = 0; } else if(cmd == 0x0E) { // MultiTracker does not support these commands switch(param & 0xF0) { case 0x00: case 0x30: case 0x40: case 0x60: case 0x70: case 0xF0: cmd = param = 0; break; } } if(cmd != 0 || param != 0) { ConvertModCommand(*m, cmd, param); #ifdef MODPLUG_TRACKER m->Convert(MOD_TYPE_MTM, MOD_TYPE_S3M, *this); #endif if(m->command == CMD_SPEED) hasSpeed = true; else if(m->command == CMD_TEMPO) hasTempo = true; } } } } // Curiously, speed commands reset the tempo to 125 in MultiTracker, and tempo commands reset the speed to 6. // External players of the time (e.g. DMP) did not implement this quirk and assumed a more ProTracker-like interpretation of speed and tempo. // Quite a few musicians created MTMs that make use DMP's speed and tempo interpretation, which in return means that they will play too // fast or too slow in MultiTracker. On the other hand there are also a few MTMs that break when using ProTracker-like speed and tempo. // As a way to support as many modules of both types as possible, we will assume a ProTracker-like interpretation if both speed and tempo // commands are found on the same line, and a MultiTracker-like interpretation when they are never found on the same line. if(hasSpeed && hasTempo) { bool hasSpeedAndTempoOnSameRow = false; for(const auto &pattern : Patterns) { for(ROWINDEX row = 0; row < pattern.GetNumRows(); row++) { bool hasSpeedOnRow = false, hasTempoOnRow = false; for(const ModCommand &m : pattern.GetRow(row)) { if(m.command == CMD_SPEED) hasSpeedOnRow = true; else if(m.command == CMD_TEMPO) hasTempoOnRow = true; } if(hasSpeedOnRow && hasTempoOnRow) { hasSpeedAndTempoOnSameRow = true; break; } } if(hasSpeedAndTempoOnSameRow) break; } if(!hasSpeedAndTempoOnSameRow) { for(auto &pattern : Patterns) { for(ROWINDEX row = 0; row < pattern.GetNumRows(); row++) { for(const ModCommand &m : pattern.GetRow(row)) { if(m.command == CMD_SPEED || m.command == CMD_TEMPO) { const bool writeTempo = m.command == CMD_SPEED; pattern.WriteEffect(EffectWriter(writeTempo ? CMD_TEMPO : CMD_SPEED, writeTempo ? 125 : 6).Row(row)); break; } } } } } } if(fileHeader.commentSize != 0) { // Read message with a fixed line length of 40 characters // (actually the last character is always null, so make that 39 + 1 padding byte) m_songMessage.ReadFixedLineLength(file, fileHeader.commentSize, 39, 1); } // Reading Samples if(loadFlags & loadSampleData) { for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { SampleIO( Samples[smp].uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::unsignedPCM) .ReadSample(Samples[smp], file); } } m_nMinPeriod = 64; m_nMaxPeriod = 32767; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Resampler.h0000644000175000017500000000716114614221151020202 00000000000000/* * Resampler.h * ----------- * Purpose: Holds the tables for all available resamplers. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "WindowedFIR.h" #include "Mixer.h" #include "MixerSettings.h" #include "Paula.h" OPENMPT_NAMESPACE_BEGIN #ifdef LIBOPENMPT_BUILD // All these optimizations are not applicable to the tracker // because cutoff and firtype are configurable there. // Cache resampler tables across resampler object creation. // A C++11-style function-static singleton is holding the cached values. #define MPT_RESAMPLER_TABLES_CACHED // Prime the tables cache when the library is loaded. // Caching gets triggered via a global object that primes the cache during // construction. // This is only really useful with MPT_RESAMPLER_TABLES_CACHED. #ifdef MPT_BUILD_FUZZER #define MPT_RESAMPLER_TABLES_CACHED_ONSTARTUP #endif #endif // LIBOPENMPT_BUILD #define SINC_WIDTH 8 #define SINC_PHASES_BITS 12 #define SINC_PHASES (1<= 2 && note <= 121 && newVersion) { m.note = note - 2 + NOTE_MIN; } else if(note >= 12 && note <= 108 && !newVersion) { m.note = note + 12 + NOTE_MIN; } m.instr = patternChunk.ReadUint8(); } while(moreCommands) { // Read one more effect command ModCommand origCmd = m; const uint8 command = patternChunk.ReadUint8(), effect = (command & commandMask); moreCommands = (command & readNextCmd) != 0; if(command & volCommand) { m.volcmd = VOLCMD_VOLUME; m.vol = effect; } else { m.param = patternChunk.ReadUint8(); if(effect < 0x10) { // PT commands CSoundFile::ConvertModCommand(m, effect, m.param); // Post-fix some commands switch(m.command) { case CMD_PANNING8: // 4-Bit panning m.command = CMD_PANNING8; m.param = (m.param & 0x0F) * 0x11; break; case CMD_VOLUME: m.command = CMD_NONE; m.volcmd = VOLCMD_VOLUME; m.vol = static_cast(std::min((m.param + 1) / 2, 64)); break; case CMD_MODCMDEX: if(m.param == 0x80) { // Break sample loop (cut after loop) m.command = CMD_NONE; } else { m.ExtendedMODtoS3MEffect(); } break; default: break; } } else if(effect < 0x10 + mpt::array_size::size) { // Extended commands m.command = effTrans[effect - 0x10]; // Post-fix some commands switch(effect) { case 0x10: // Play sample forwards / backwards if(m.param <= 0x01) { m.param |= 0x9E; } else { m.command = CMD_NONE; } break; case 0x11: case 0x12: // Extra fine slides m.param = static_cast(std::min(uint8(0x0F), m.param) | 0xE0); break; case 0x15: case 0x16: // Fine slides m.param = static_cast((std::min(0x10, m.param + 1) / 2) | 0xF0); break; case 0x1E: // More fine slides switch(m.param >> 4) { case 0x1: // Fine porta up m.command = CMD_PORTAMENTOUP; m.param |= 0xF0; break; case 0x2: // Fine porta down m.command = CMD_PORTAMENTODOWN; m.param |= 0xF0; break; case 0xA: // Extra fine volume slide up m.command = CMD_VOLUMESLIDE; m.param = static_cast(((((m.param & 0x0F) + 1) / 2) << 4) | 0x0F); break; case 0xB: // Extra fine volume slide down m.command = CMD_VOLUMESLIDE; m.param = static_cast((((m.param & 0x0F) + 1) / 2) | 0xF0); break; default: m.command = CMD_NONE; break; } break; case 0x1C: // Adjust channel volume range m.param = static_cast(std::min((m.param + 1) / 2, 64)); break; } } // Try merging commands first ModCommand::CombineEffects(m.command, m.param, origCmd.command, origCmd.param); if(ModCommand::GetEffectWeight(origCmd.command) > ModCommand::GetEffectWeight(m.command)) { if(m.volcmd == VOLCMD_NONE) { // Volume column to the rescue! m.SetVolumeCommand(ModCommand::ConvertToVolCommand(m.command, m.param, true)); } m.command = origCmd.command; m.param = origCmd.param; } } } if(flags & endOfRowMask) { // End of row break; } } } } ///////////////////////////////////////////////////////////////////// // AMS (Extreme's Tracker) 1.x loader // AMS File Header struct AMSFileHeader { uint8le versionLow; uint8le versionHigh; uint8le channelConfig; uint8le numSamps; uint16le numPats; uint16le numOrds; uint8le midiChannels; uint16le extraSize; }; MPT_BINARY_STRUCT(AMSFileHeader, 11) // AMS Sample Header struct AMSSampleHeader { enum SampleFlags { smp16BitOld = 0x04, // AMS 1.0 (at least according to docs, I yet have to find such a file) smp16Bit = 0x80, // AMS 1.1+ smpPacked = 0x03, }; uint32le length; uint32le loopStart; uint32le loopEnd; uint8le panFinetune; // High nibble = pan position, low nibble = finetune value uint16le sampleRate; uint8le volume; // 0...127 uint8le flags; // See SampleFlags // Convert sample header to OpenMPT's internal format. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.nLength = length; mptSmp.nLoopStart = std::min(loopStart, length); mptSmp.nLoopEnd = std::min(loopEnd, length); mptSmp.nVolume = static_cast((std::min(uint8(127), volume.get()) * 256 + 64) / 127); if(panFinetune & 0xF0) { mptSmp.nPan = (panFinetune & 0xF0); mptSmp.uFlags = CHN_PANNING; } mptSmp.nC5Speed = 2 * sampleRate; if(sampleRate == 0) { mptSmp.nC5Speed = 2 * 8363; } uint32 newC4speed = ModSample::TransposeToFrequency(0, MOD2XMFineTune(panFinetune & 0x0F)); mptSmp.nC5Speed = (mptSmp.nC5Speed * newC4speed) / 8363; if(mptSmp.nLoopStart < mptSmp.nLoopEnd) { mptSmp.uFlags.set(CHN_LOOP); } if(flags & (smp16Bit | smp16BitOld)) { mptSmp.uFlags.set(CHN_16BIT); } } }; MPT_BINARY_STRUCT(AMSSampleHeader, 17) static bool ValidateHeader(const AMSFileHeader &fileHeader) { if(fileHeader.versionHigh != 0x01) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const AMSFileHeader &fileHeader) { return fileHeader.extraSize + 3u + fileHeader.numSamps * (1u + sizeof(AMSSampleHeader)) + fileHeader.numOrds * 2u + fileHeader.numPats * 4u; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMS(MemoryFileReader file, const uint64 *pfilesize) { if(!file.CanRead(7)) { return ProbeWantMoreData; } if(!file.ReadMagic("Extreme")) { return ProbeFailure; } AMSFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadAMS(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); if(!file.ReadMagic("Extreme")) { return false; } AMSFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } if(!file.Skip(fileHeader.extraSize)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_AMS, (fileHeader.channelConfig & 0x1F) + 1); m_SongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS; m_nSamples = fileHeader.numSamps; SetupMODPanning(true); m_modFormat.formatName = UL_("Extreme's Tracker"); m_modFormat.type = UL_("ams"); m_modFormat.madeWithTracker = MPT_UFORMAT("Extreme's Tracker {}.{}")(fileHeader.versionHigh, fileHeader.versionLow); m_modFormat.charset = mpt::Charset::CP437; std::vector packSample(fileHeader.numSamps); static_assert(MAX_SAMPLES > 255); for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { AMSSampleHeader sampleHeader; file.ReadStruct(sampleHeader); sampleHeader.ConvertToMPT(Samples[smp]); packSample[smp - 1] = (sampleHeader.flags & AMSSampleHeader::smpPacked) != 0; } // Texts file.ReadSizedString(m_songName); // Read sample names for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { file.ReadSizedString(m_szNames[smp]); } // Read channel names for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { file.ReadSizedString(ChnSettings[chn].szName); } // Read pattern names and create patterns Patterns.ResizeArray(fileHeader.numPats); for(PATTERNINDEX pat = 0; pat < fileHeader.numPats; pat++) { char name[11]; const bool ok = file.ReadSizedString(name); // Create pattern now, so name won't be reset later. if(Patterns.Insert(pat, 64) && ok) { Patterns[pat].SetName(name); } } // Read packed song message const uint16 packedLength = file.ReadUint16LE(); if(packedLength && file.CanRead(packedLength)) { std::vector textIn; file.ReadVector(textIn, packedLength); std::string textOut; textOut.reserve(packedLength); for(auto c : textIn) { if(c & 0x80) { textOut.insert(textOut.end(), (c & 0x7F), ' '); } else { textOut.push_back(c); } } textOut = mpt::ToCharset(mpt::Charset::CP437, mpt::Charset::CP437AMS, textOut); // Packed text doesn't include any line breaks! m_songMessage.ReadFixedLineLength(mpt::byte_cast(textOut.c_str()), textOut.length(), 76, 0); } // Read Order List ReadOrderFromFile(Order(), file, fileHeader.numOrds); // Read patterns for(PATTERNINDEX pat = 0; pat < fileHeader.numPats && file.CanRead(4); pat++) { uint32 patLength = file.ReadUint32LE(); FileReader patternChunk = file.ReadChunk(patLength); if((loadFlags & loadPatternData) && Patterns.IsValidPat(pat)) { ReadAMSPattern(Patterns[pat], false, patternChunk); } } if(loadFlags & loadSampleData) { // Read Samples for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { SampleIO( Samples[smp].uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, packSample[smp - 1] ? SampleIO::AMS : SampleIO::signedPCM) .ReadSample(Samples[smp], file); } } return true; } ///////////////////////////////////////////////////////////////////// // AMS (Velvet Studio) 2.0 - 2.02 loader // AMS2 File Header struct AMS2FileHeader { enum FileFlags { linearSlides = 0x40, }; uint8le versionLow; // Version of format (Hi = MainVer, Low = SubVer e.g. 0202 = 2.02) uint8le versionHigh; // ditto uint8le numIns; // Nr of Instruments (0-255) uint16le numPats; // Nr of Patterns (1-1024) uint16le numOrds; // Nr of Positions (1-65535) // Rest of header differs between format revision 2.01 and 2.02 }; MPT_BINARY_STRUCT(AMS2FileHeader, 7) // AMS2 Instument Envelope struct AMS2Envelope { uint8 speed; // Envelope speed (currently not supported, always the same as current BPM) uint8 sustainPoint; // Envelope sustain point uint8 loopStart; // Envelope loop Start uint8 loopEnd; // Envelope loop End uint8 numPoints; // Envelope length // Read envelope and do partial conversion. void ConvertToMPT(InstrumentEnvelope &mptEnv, FileReader &file) { file.ReadStruct(*this); // Read envelope points uint8 data[64][3]; file.ReadStructPartial(data, numPoints * 3); if(numPoints <= 1) { // This is not an envelope. return; } static_assert(MAX_ENVPOINTS >= std::size(data)); mptEnv.resize(std::min(numPoints, mpt::saturate_cast(std::size(data)))); mptEnv.nLoopStart = loopStart; mptEnv.nLoopEnd = loopEnd; mptEnv.nSustainStart = mptEnv.nSustainEnd = sustainPoint; for(uint32 i = 0; i < mptEnv.size(); i++) { if(i != 0) { mptEnv[i].tick = mptEnv[i - 1].tick + static_cast(std::max(1, data[i][0] | ((data[i][1] & 0x01) << 8))); } mptEnv[i].value = data[i][2]; } } }; MPT_BINARY_STRUCT(AMS2Envelope, 5) // AMS2 Instrument Data struct AMS2Instrument { enum EnvelopeFlags { envLoop = 0x01, envSustain = 0x02, envEnabled = 0x04, // Flag shift amounts volEnvShift = 0, panEnvShift = 1, vibEnvShift = 2, vibAmpMask = 0x3000, vibAmpShift = 12, fadeOutMask = 0xFFF, }; uint8le shadowInstr; // Shadow Instrument. If non-zero, the value=the shadowed inst. uint16le vibampFadeout; // Vib.Amplify + Volume fadeout in one variable! uint16le envFlags; // See EnvelopeFlags void ApplyFlags(InstrumentEnvelope &mptEnv, EnvelopeFlags shift) const { const int flags = envFlags >> (shift * 3); mptEnv.dwFlags.set(ENV_ENABLED, (flags & envEnabled) != 0); mptEnv.dwFlags.set(ENV_LOOP, (flags & envLoop) != 0); mptEnv.dwFlags.set(ENV_SUSTAIN, (flags & envSustain) != 0); // "Break envelope" should stop the envelope loop when encountering a note-off... We can only use the sustain loop to emulate this behaviour. if(!(flags & envSustain) && (flags & envLoop) != 0 && (flags & (1 << (9 - shift * 2))) != 0) { mptEnv.nSustainStart = mptEnv.nLoopStart; mptEnv.nSustainEnd = mptEnv.nLoopEnd; mptEnv.dwFlags.set(ENV_SUSTAIN); mptEnv.dwFlags.reset(ENV_LOOP); } } }; MPT_BINARY_STRUCT(AMS2Instrument, 5) // AMS2 Sample Header struct AMS2SampleHeader { enum SampleFlags { smpPacked = 0x03, smp16Bit = 0x04, smpLoop = 0x08, smpBidiLoop = 0x10, smpReverse = 0x40, }; uint32le length; uint32le loopStart; uint32le loopEnd; uint16le sampledRate; // Whyyyy? uint8le panFinetune; // High nibble = pan position, low nibble = finetune value uint16le c4speed; // Why is all of this so redundant? int8le relativeTone; // q.e.d. uint8le volume; // 0...127 uint8le flags; // See SampleFlags // Convert sample header to OpenMPT's internal format. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.nLength = length; mptSmp.nLoopStart = std::min(loopStart, length); mptSmp.nLoopEnd = std::min(loopEnd, length); mptSmp.nC5Speed = c4speed * 2; if(c4speed == 0) { mptSmp.nC5Speed = 8363 * 2; } // Why, oh why, does this format need a c5speed and transpose/finetune at the same time... uint32 newC4speed = ModSample::TransposeToFrequency(relativeTone, MOD2XMFineTune(panFinetune & 0x0F)); mptSmp.nC5Speed = (mptSmp.nC5Speed * newC4speed) / 8363; mptSmp.nVolume = static_cast((std::min(volume.get(), uint8(127)) * 256 + 64) / 127); if(panFinetune & 0xF0) { mptSmp.nPan = (panFinetune & 0xF0); mptSmp.uFlags = CHN_PANNING; } if(flags & smp16Bit) mptSmp.uFlags.set(CHN_16BIT); if((flags & smpLoop) && mptSmp.nLoopStart < mptSmp.nLoopEnd) { mptSmp.uFlags.set(CHN_LOOP); if(flags & smpBidiLoop) mptSmp.uFlags.set(CHN_PINGPONGLOOP); if(flags & smpReverse) mptSmp.uFlags.set(CHN_REVERSE); } } }; MPT_BINARY_STRUCT(AMS2SampleHeader, 20) // AMS2 Song Description Header struct AMS2Description { uint32le packedLen; // Including header uint32le unpackedLen; uint8le packRoutine; // 01 uint8le preProcessing; // None! uint8le packingMethod; // RLE }; MPT_BINARY_STRUCT(AMS2Description, 11) static bool ValidateHeader(const AMS2FileHeader &fileHeader) { if(fileHeader.versionHigh != 2 || fileHeader.versionLow > 2) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const AMS2FileHeader &fileHeader) { return 36u + sizeof(AMS2Description) + fileHeader.numIns * 2u + fileHeader.numOrds * 2u + fileHeader.numPats * 4u; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMS2(MemoryFileReader file, const uint64 *pfilesize) { if(!file.CanRead(7)) { return ProbeWantMoreData; } if(!file.ReadMagic("AMShdr\x1A")) { return ProbeFailure; } if(!file.CanRead(1)) { return ProbeWantMoreData; } const uint8 songNameLength = file.ReadUint8(); if(!file.Skip(songNameLength)) { return ProbeWantMoreData; } AMS2FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); if(!file.ReadMagic("AMShdr\x1A")) { return false; } std::string songName; if(!file.ReadSizedString(songName)) { return false; } AMS2FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_AMS, 32); m_songName = std::move(songName); m_nInstruments = fileHeader.numIns; SetupMODPanning(true); m_modFormat.formatName = UL_("Velvet Studio"); m_modFormat.type = UL_("ams"); m_modFormat.madeWithTracker = MPT_UFORMAT("Velvet Studio {}.{}")(fileHeader.versionHigh.get(), mpt::ufmt::dec0<2>(fileHeader.versionLow.get())); m_modFormat.charset = mpt::Charset::CP437; uint16 headerFlags; if(fileHeader.versionLow >= 2) { uint16 tempo = std::max(uint16(32 << 8), file.ReadUint16LE()); // 8.8 tempo Order().SetDefaultTempo(TEMPO{}.SetRaw((tempo * TEMPO::fractFact) >> 8)); Order().SetDefaultSpeed(std::max(uint8(1), file.ReadUint8())); file.Skip(3); // Default values for pattern editor headerFlags = file.ReadUint16LE(); } else { Order().SetDefaultTempoInt(std::max(uint8(32), file.ReadUint8())); Order().SetDefaultSpeed(std::max(uint8(1), file.ReadUint8())); headerFlags = file.ReadUint8(); } m_SongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS | ((headerFlags & AMS2FileHeader::linearSlides) ? SONG_LINEARSLIDES : SongFlags(0)); // Instruments std::vector firstSample; // First sample of instrument std::vector sampleSettings; // Shadow sample map... Lo byte = Instrument, Hi byte, lo nibble = Sample index in instrument, Hi byte, hi nibble = Sample pack status enum { instrIndexMask = 0xFF, // Shadow instrument sampleIndexMask = 0x7F00, // Sample index in instrument sampleIndexShift = 8, packStatusMask = 0x8000, // If bit is set, sample is packed }; static_assert(MAX_INSTRUMENTS > 255); for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++) { ModInstrument *instrument = AllocateInstrument(ins); if(instrument == nullptr || !file.ReadSizedString(instrument->name)) { break; } uint8 numSamples = file.ReadUint8(); std::array sampleAssignment; sampleAssignment.fill(0); // Only really needed for v2.0, where the lowest and highest octave aren't cleared. if(numSamples == 0 || (fileHeader.versionLow > 0 && !file.ReadArray(sampleAssignment)) // v2.01+: 120 Notes || (fileHeader.versionLow == 0 && !file.ReadRaw(mpt::as_span(sampleAssignment).subspan(12, 96)).size())) // v2.0: 96 Notes { continue; } static_assert(mpt::array_sizeKeyboard)>::size >= std::size(sampleAssignment)); for(size_t i = 0; i < 120; i++) { instrument->Keyboard[i] = static_cast(sampleAssignment[i] + GetNumSamples() + 1); } AMS2Envelope volEnv, panEnv, vibratoEnv; volEnv.ConvertToMPT(instrument->VolEnv, file); panEnv.ConvertToMPT(instrument->PanEnv, file); vibratoEnv.ConvertToMPT(instrument->PitchEnv, file); AMS2Instrument instrHeader; file.ReadStruct(instrHeader); instrument->nFadeOut = (instrHeader.vibampFadeout & AMS2Instrument::fadeOutMask); const int16 vibAmp = 1 << ((instrHeader.vibampFadeout & AMS2Instrument::vibAmpMask) >> AMS2Instrument::vibAmpShift); instrHeader.ApplyFlags(instrument->VolEnv, AMS2Instrument::volEnvShift); instrHeader.ApplyFlags(instrument->PanEnv, AMS2Instrument::panEnvShift); instrHeader.ApplyFlags(instrument->PitchEnv, AMS2Instrument::vibEnvShift); // Scale envelopes to correct range for(auto &p : instrument->VolEnv) { p.value = std::min(uint8(ENVELOPE_MAX), static_cast((p.value * ENVELOPE_MAX + 64u) / 127u)); } for(auto &p : instrument->PanEnv) { p.value = std::min(uint8(ENVELOPE_MAX), static_cast((p.value * ENVELOPE_MAX + 128u) / 255u)); } for(auto &p : instrument->PitchEnv) { #ifdef MODPLUG_TRACKER p.value = std::min(uint8(ENVELOPE_MAX), static_cast(32 + Util::muldivrfloor(static_cast(p.value - 128), vibAmp, 255))); #else // Try to keep as much precision as possible... divide by 8 since that's the highest possible vibAmp factor. p.value = static_cast(128 + Util::muldivrfloor(static_cast(p.value - 128), vibAmp, 8)); #endif } // Sample headers - we will have to read them even for shadow samples, and we will have to load them several times, // as it is possible that shadow samples use different sample settings like base frequency or panning. const SAMPLEINDEX firstSmp = GetNumSamples() + 1; std::string sampleName; for(SAMPLEINDEX smp = 0; smp < numSamples; smp++) { file.ReadSizedString(sampleName); AMS2SampleHeader sampleHeader; file.ReadStruct(sampleHeader); if(firstSmp + smp >= MAX_SAMPLES) continue; sampleHeader.ConvertToMPT(Samples[firstSmp + smp]); m_szNames[firstSmp + smp] = sampleName; uint16 settings = (instrHeader.shadowInstr & instrIndexMask) | ((smp << sampleIndexShift) & sampleIndexMask) | ((sampleHeader.flags & AMS2SampleHeader::smpPacked) ? packStatusMask : 0); sampleSettings.push_back(settings); } firstSample.push_back(firstSmp); m_nSamples = static_cast(std::min(MAX_SAMPLES - 1, GetNumSamples() + numSamples)); } // Text // Read composer name if(std::string composer; file.ReadSizedString(composer)) { m_songArtist = mpt::ToUnicode(mpt::Charset::CP437AMS2, composer); } // Channel names for(CHANNELINDEX chn = 0; chn < 32; chn++) { file.ReadSizedString(ChnSettings[chn].szName); } // RLE-Packed description text AMS2Description descriptionHeader; if(!file.ReadStruct(descriptionHeader)) { return true; } if(descriptionHeader.packedLen > sizeof(descriptionHeader) && file.CanRead(descriptionHeader.packedLen - sizeof(descriptionHeader))) { const uint32 textLength = descriptionHeader.packedLen - static_cast(sizeof(descriptionHeader)); std::vector textIn; file.ReadVector(textIn, textLength); // In the best case, every byte triplet can decode to 255 bytes, which is a ratio of exactly 1:85 const uint32 maxLength = std::min(textLength, Util::MaxValueOfType(textLength) / 85u) * 85u; std::string textOut; textOut.reserve(std::min(maxLength, descriptionHeader.unpackedLen.get())); size_t readLen = 0; while(readLen < textLength) { uint8 c = textIn[readLen++]; if(c == 0xFF && textLength - readLen >= 2) { c = textIn[readLen++]; uint32 count = textIn[readLen++]; textOut.insert(textOut.end(), count, c); } else { textOut.push_back(c); } } textOut = mpt::ToCharset(mpt::Charset::CP437, mpt::Charset::CP437AMS2, textOut); // Packed text doesn't include any line breaks! m_songMessage.ReadFixedLineLength(mpt::byte_cast(textOut.c_str()), textOut.length(), 74, 0); } // Read Order List ReadOrderFromFile(Order(), file, fileHeader.numOrds); // Read Patterns if(loadFlags & loadPatternData) Patterns.ResizeArray(fileHeader.numPats); for(PATTERNINDEX pat = 0; pat < fileHeader.numPats && file.CanRead(4); pat++) { uint32 patLength = file.ReadUint32LE(); FileReader patternChunk = file.ReadChunk(patLength); if(loadFlags & loadPatternData) { const ROWINDEX numRows = patternChunk.ReadUint8() + 1; // We don't need to know the number of channels or commands. patternChunk.Skip(1); if(!Patterns.Insert(pat, numRows)) { continue; } char patternName[11]; if(patternChunk.ReadSizedString(patternName)) Patterns[pat].SetName(patternName); ReadAMSPattern(Patterns[pat], true, patternChunk); } } if(!(loadFlags & loadSampleData)) { return true; } // Read Samples for(SAMPLEINDEX smp = 0; smp < GetNumSamples(); smp++) { if((sampleSettings[smp] & instrIndexMask) == 0) { // Only load samples that aren't part of a shadow instrument SampleIO( (Samples[smp + 1].uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, (sampleSettings[smp] & packStatusMask) ? SampleIO::AMS : SampleIO::signedPCM) .ReadSample(Samples[smp + 1], file); } } // Copy shadow samples for(SAMPLEINDEX smp = 0; smp < GetNumSamples(); smp++) { INSTRUMENTINDEX sourceInstr = (sampleSettings[smp] & instrIndexMask); if(sourceInstr == 0 || --sourceInstr >= firstSample.size()) { continue; } SAMPLEINDEX sourceSample = ((sampleSettings[smp] & sampleIndexMask) >> sampleIndexShift) + firstSample[sourceInstr]; if(sourceSample > GetNumSamples() || !Samples[sourceSample].HasSampleData()) { continue; } // Copy over original sample ModSample &sample = Samples[smp + 1]; ModSample &source = Samples[sourceSample]; sample.uFlags.set(CHN_16BIT, source.uFlags[CHN_16BIT]); sample.nLength = source.nLength; if(sample.AllocateSample()) { memcpy(sample.sampleb(), source.sampleb(), source.GetSampleSizeInBytes()); } } return true; } ///////////////////////////////////////////////////////////////////// // AMS Sample unpacking void AMSUnpack(mpt::const_byte_span source, mpt::byte_span dest, int8 packCharacter) { std::vector tempBuf(dest.size(), 0); std::size_t depackSize = dest.size(); // Unpack Loop { const std::byte *in = source.data(); int8 *out = tempBuf.data(); size_t i = source.size(), j = dest.size(); while(i != 0 && j != 0) { int8 ch = mpt::byte_cast(*(in++)); if(--i != 0 && ch == packCharacter) { uint8 repCount = mpt::byte_cast(*(in++)); repCount = static_cast(std::min(static_cast(repCount), j)); if(--i != 0 && repCount) { ch = mpt::byte_cast(*(in++)); i--; while(repCount-- != 0) { *(out++) = ch; j--; } } else { *(out++) = packCharacter; j--; } } else { *(out++) = ch; j--; } } // j should only be non-zero for truncated samples depackSize -= j; } // Bit Unpack Loop { int8 *out = tempBuf.data(); uint16 bitcount = 0x80; size_t k = 0; uint8 *dst = mpt::byte_cast(dest.data()); for(size_t i = 0; i < depackSize; i++) { uint8 al = *out++; uint16 dh = 0; for(uint16 count = 0; count < 8; count++) { uint16 bl = al & bitcount; bl = static_cast((bl | (bl << 8)) >> ((dh + 8 - count) & 7)); bitcount = ((bitcount | (bitcount << 8)) >> 1) & 0xFF; dst[k++] |= (bl & 0xFFu); if(k >= dest.size()) { k = 0; dh++; } } bitcount = ((bitcount | (bitcount << 8)) >> dh) & 0xFF; } } // Delta Unpack { int8 old = 0; uint8 *out = mpt::byte_cast(dest.data()); for(size_t i = depackSize; i != 0; i--) { int pos = static_cast(*out); if(pos != 128 && (pos & 0x80) != 0) { pos = -(pos & 0x7F); } old -= static_cast(pos); *(out++) = static_cast(old); } } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/S3MTools.cpp0000644000175000017500000001012514500065511020220 00000000000000/* * S3MTools.cpp * ------------ * Purpose: Definition of S3M file structures and helper functions * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "S3MTools.h" #include "Loaders.h" #include "../common/mptStringBuffer.h" OPENMPT_NAMESPACE_BEGIN // Convert an S3M sample header to OpenMPT's internal sample header. void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp, bool isST3) const { mptSmp.Initialize(MOD_TYPE_S3M); mptSmp.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, filename); if(sampleType == typePCM || sampleType == typeNone) { // Sample Length and Loops if(sampleType == typePCM) { mptSmp.nLength = length; mptSmp.nLoopStart = std::min(static_cast(loopStart), mptSmp.nLength - 1); mptSmp.nLoopEnd = std::min(static_cast(loopEnd), mptSmp.nLength); mptSmp.uFlags.set(CHN_LOOP, (flags & smpLoop) != 0); } if(mptSmp.nLoopEnd < 2 || mptSmp.nLoopStart >= mptSmp.nLoopEnd || mptSmp.nLoopEnd - mptSmp.nLoopStart < 1) { mptSmp.nLoopStart = mptSmp.nLoopEnd = 0; mptSmp.uFlags.reset(); } } else if(sampleType == typeAdMel) { OPLPatch patch; std::memcpy(patch.data() + 0, mpt::as_raw_memory(length).data(), 4); std::memcpy(patch.data() + 4, mpt::as_raw_memory(loopStart).data(), 4); std::memcpy(patch.data() + 8, mpt::as_raw_memory(loopEnd).data(), 4); mptSmp.SetAdlib(true, patch); } // Volume / Panning mptSmp.nVolume = std::min(defaultVolume.get(), uint8(64)) * 4; // C-5 frequency mptSmp.nC5Speed = c5speed; if(isST3) { // ST3 ignores or clamps the high 16 bits depending on the instrument type if(sampleType == typeAdMel) mptSmp.nC5Speed &= 0xFFFF; else LimitMax(mptSmp.nC5Speed, uint16_max); } if(mptSmp.nC5Speed == 0) mptSmp.nC5Speed = 8363; else if(mptSmp.nC5Speed < 1024) mptSmp.nC5Speed = 1024; } // Convert OpenMPT's internal sample header to an S3M sample header. SmpLength S3MSampleHeader::ConvertToS3M(const ModSample &mptSmp) { SmpLength smpLength = 0; mpt::String::WriteBuf(mpt::String::maybeNullTerminated, filename) = mptSmp.filename; memcpy(magic, "SCRS", 4); if(mptSmp.uFlags[CHN_ADLIB]) { memcpy(magic, "SCRI", 4); sampleType = typeAdMel; std::memcpy(mpt::as_raw_memory(length ).data(), mptSmp.adlib.data() + 0, 4); std::memcpy(mpt::as_raw_memory(loopStart).data(), mptSmp.adlib.data() + 4, 4); std::memcpy(mpt::as_raw_memory(loopEnd ).data(), mptSmp.adlib.data() + 8, 4); } else if(mptSmp.HasSampleData()) { sampleType = typePCM; length = mpt::saturate_cast(mptSmp.nLength); loopStart = mpt::saturate_cast(mptSmp.nLoopStart); loopEnd = mpt::saturate_cast(mptSmp.nLoopEnd); smpLength = length; flags = (mptSmp.uFlags[CHN_LOOP] ? smpLoop : 0); if(mptSmp.uFlags[CHN_16BIT]) { flags |= smp16Bit; } if(mptSmp.uFlags[CHN_STEREO]) { flags |= smpStereo; } } else { sampleType = typeNone; } defaultVolume = static_cast(std::min(static_cast(mptSmp.nVolume / 4), uint16(64))); if(mptSmp.nC5Speed != 0) { c5speed = mptSmp.nC5Speed; } else { c5speed = ModSample::TransposeToFrequency(mptSmp.RelativeTone, mptSmp.nFineTune); } return smpLength; } // Retrieve the internal sample format flags for this sample. SampleIO S3MSampleHeader::GetSampleFormat(bool signedSamples) const { if(pack == S3MSampleHeader::pADPCM && !(flags & S3MSampleHeader::smp16Bit) && !(flags & S3MSampleHeader::smpStereo)) { // MODPlugin :( return SampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::ADPCM); } else { return SampleIO( (flags & S3MSampleHeader::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit, (flags & S3MSampleHeader::smpStereo) ? SampleIO::stereoSplit : SampleIO::mono, SampleIO::littleEndian, signedSamples ? SampleIO::signedPCM : SampleIO::unsignedPCM); } } // Calculate the sample position in file uint32 S3MSampleHeader::GetSampleOffset() const { return (dataPointer[1] << 4) | (dataPointer[2] << 12) | (dataPointer[0] << 20); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_kris.cpp0000644000175000017500000001123414725361701020517 00000000000000/* * Load_kris.cpp * ------------- * Purpose: ChipTracker loader * Notes : Another NoiseTracker variant, storing tracks instead of patterns (like ICE / ST26) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "MODTools.h" OPENMPT_NAMESPACE_BEGIN CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderKRIS(MemoryFileReader file, const uint64 *pfilesize) { if(!file.CanRead(952 + 4)) return ProbeWantMoreData; file.Seek(952); if(!file.ReadMagic("KRIS")) return ProbeFailure; const auto [numOrders, restartPos] = file.ReadArray(); if(numOrders > 128 || restartPos > 127) return ProbeFailure; file.Seek(22); uint32 invalidBytes = 0; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { MODSampleHeader sampleHeader; file.ReadStruct(sampleHeader); if(sampleHeader.name[0] != 0) invalidBytes += sampleHeader.GetInvalidByteScore(); if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadKRIS(FileReader &file, ModLoadingFlags loadFlags) { if(!file.Seek(952) || !file.ReadMagic("KRIS")) return false; const auto [numOrders, restartPos] = file.ReadArray(); if(numOrders > 128 || restartPos > 127) return false; std::array, 128 * 4> tracks; if(!file.ReadArray(tracks)) return false; uint32 tracksOffset = 1984; InitializeGlobals(MOD_TYPE_MOD, 4); file.Seek(0); file.ReadString(m_songName, 22); m_nSamples = 31; uint32 invalidBytes = 0; uint8 numSynthWaveforms = 0; for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { MODSampleHeader sampleHeader; file.ReadStruct(sampleHeader); if(sampleHeader.name[0] != 0) { invalidBytes += ReadMODSample(sampleHeader, Samples[smp], m_szNames[smp], true); } else { // Unfinished feature. Synth parameters are stored in the module, but loading and saving of synth waveforms // (which I'd assume the extra space before the track data is reserved for) is completely absent, making the feature useless. Samples[smp].Initialize(MOD_TYPE_MOD); m_szNames[smp] = "Synthetic"; const uint8 maxWaveform = std::max({ sampleHeader.name[1], sampleHeader.name[5], sampleHeader.name[10], sampleHeader.name[19] }); if(maxWaveform) numSynthWaveforms = std::max(numSynthWaveforms, static_cast(maxWaveform + 1)); } if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) return false; } tracksOffset += numSynthWaveforms * 64u; if(loadFlags == onlyVerifyHeader) return true; SetupMODPanning(true); Order().SetDefaultSpeed(6); Order().SetDefaultTempoInt(125); Order().SetRestartPos(restartPos); m_nMinPeriod = 113 * 4; m_nMaxPeriod = 856 * 4; m_nSamplePreAmp = 64; m_SongFlags.set(SONG_PT_MODE | SONG_IMPORTED | SONG_FORMAT_NO_VOLCOL); m_playBehaviour.set(kMODIgnorePanning); m_playBehaviour.set(kMODSampleSwap); Order().resize(numOrders); if(loadFlags & loadPatternData) Patterns.ResizeArray(numOrders); for(PATTERNINDEX pat = 0; pat < numOrders; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) break; Order()[pat] = pat; for(CHANNELINDEX chn = 0; chn < 4; chn++) { const uint8 track = tracks[pat * 4u + chn][0]; const int8 transpose = tracks[pat * 4u + chn][1]; if(!file.Seek(tracksOffset + track * 256u)) return false; ModCommand *m = Patterns[pat].GetpModCommand(0, chn); for(ROWINDEX row = 0; row < 64; row++, m += 4) { const auto data = file.ReadArray(); if(data[0] & 1) return false; if(data[0] >= 0x18 && data[0] <= 0x9E) m->note = static_cast(Clamp(NOTE_MIDDLEC - 36 + (data[0] - 0x18) / 2 + transpose, NOTE_MIDDLEC - 12, NOTE_MIDDLEC + 23)); else if(data[0] != 0xA8) return false; if(data[2] >> 4) return false; m->instr = data[1]; ConvertModCommand(*m, data[2] & 0x0F, data[3]); } } } m_modFormat.formatName = UL_("ChipTracker"); m_modFormat.type = UL_("mod"); m_modFormat.madeWithTracker = UL_("ChipTracker"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; if(loadFlags & loadSampleData) { uint8 maxTrack = 0; for(uint32 ord = 0; ord < numOrders * 4u; ord++) { maxTrack = std::max(tracks[ord][0], maxTrack); } file.Seek(tracksOffset + (maxTrack + 1u) * 256u); for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) if(Samples[smp].nLength) { SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(Samples[smp], file); } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_stk.cpp0000644000175000017500000003760214721715306020357 00000000000000/* * Load_stk.cpp * ------------ * Purpose: M15 / STK (Ultimate Soundtracker / Soundtracker) loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "MODTools.h" OPENMPT_NAMESPACE_BEGIN // We'll have to do some heuristic checks to find out whether this is an old Ultimate Soundtracker module // or if it was made with the newer Soundtracker versions. // Thanks for Fraggie for this information! (https://www.un4seen.com/forum/?topic=14471.msg100829#msg100829) enum STVersions { UST1_00, // Ultimate Soundtracker 1.0-1.21 (K. Obarski) UST1_80, // Ultimate Soundtracker 1.8-2.0 (K. Obarski) ST2_00_Exterminator, // SoundTracker 2.0 (The Exterminator), D.O.C. Sountracker II (Unknown/D.O.C.) ST_III, // Defjam Soundtracker III (Il Scuro/Defjam), Alpha Flight SoundTracker IV (Alpha Flight), D.O.C. SoundTracker IV (Unknown/D.O.C.), D.O.C. SoundTracker VI (Unknown/D.O.C.) ST_IX, // D.O.C. SoundTracker IX (Unknown/D.O.C.) MST1_00, // Master Soundtracker 1.0 (Tip/The New Masters) ST2_00, // SoundTracker 2.0, 2.1, 2.2 (Unknown/D.O.C.) }; struct STKFileHeaders { char songname[20]; MODSampleHeader sampleHeaders[15]; MODFileHeader fileHeader; }; MPT_BINARY_STRUCT(STKFileHeaders, 20 + 15 * 30 + 130) static bool ValidateHeader(const STKFileHeaders &fileHeaders) { // In theory, sample and song names should only ever contain printable ASCII chars and null. // However, there are quite a few SoundTracker modules in the wild with random // characters. To still be able to distguish them from other formats, we just reject // files with *too* many bogus characters. Arbitrary threshold: 48 bogus characters in total // or more than 5 invalid characters just in the title alone uint32 invalidCharsInTitle = CountInvalidChars(fileHeaders.songname); uint32 invalidChars = invalidCharsInTitle; SmpLength totalSampleLen = 0; uint8 allVolumes = 0; uint8 validNameCount = 0; bool invalidNames = false; for(SAMPLEINDEX smp = 0; smp < 15; smp++) { const MODSampleHeader &sampleHeader = fileHeaders.sampleHeaders[smp]; invalidChars += CountInvalidChars(sampleHeader.name); // schmokk.mod has a non-zero value here but it should not be treated as finetune if(sampleHeader.finetune != 0) invalidChars += 16; if(const auto nameType = ClassifyName(sampleHeader.name); nameType == NameClassification::ValidASCII) validNameCount++; else if(nameType == NameClassification::Invalid) invalidNames = true; // Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874) // Sample length adjusted for romantic.stk which has a (valid) sample of length 72222 if(invalidChars > 48 || sampleHeader.volume > 64 || sampleHeader.length > 37000) { return false; } totalSampleLen += sampleHeader.length; allVolumes |= sampleHeader.volume; } // scramble_2.mod has a lot of garbage in the song title, but it has lots of properly-formatted sample names, so we consider those to be more important than the garbage bytes. if(invalidCharsInTitle > 5 && (validNameCount < 4 || invalidNames)) return false; // Reject any files with no (or only silent) samples at all, as this might just be a random binary file (e.g. ID3 tags with tons of padding) if(totalSampleLen == 0 || allVolumes == 0) return false; // Sanity check: No more than 128 positions. ST's GUI limits tempo to [1, 220]. // There are some mods with a tempo of 0 (explora3-death.mod) though, so ignore the lower limit. if(fileHeaders.fileHeader.numOrders > 128 || fileHeaders.fileHeader.restartPos > 220) return false; uint8 maxPattern = *std::max_element(std::begin(fileHeaders.fileHeader.orderList), std::end(fileHeaders.fileHeader.orderList)); // Sanity check: 64 patterns max. if(maxPattern > 63) return false; // No playable song, and lots of null values => most likely a sparse binary file but not a module if(fileHeaders.fileHeader.restartPos == 0 && fileHeaders.fileHeader.numOrders == 0 && maxPattern == 0) return false; return true; } template static bool ValidateFirstSTKPattern(TFileReader &file) { // threshold is chosen as: [threshold for all patterns combined] / [max patterns] * [margin, do not reject too much] return ValidateMODPatternData(file, 512 / 64 * 2, false); } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTK(MemoryFileReader file, const uint64 *pfilesize) { STKFileHeaders fileHeaders; if(!file.ReadStruct(fileHeaders)) return ProbeWantMoreData; if(!ValidateHeader(fileHeaders)) return ProbeFailure; if(!file.CanRead(sizeof(MODPatternData))) return ProbeWantMoreData; if(!ValidateFirstSTKPattern(file)) return ProbeFailure; MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadSTK(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); STKFileHeaders fileHeaders; if(!file.ReadStruct(fileHeaders)) return false; if(!ValidateHeader(fileHeaders)) return false; if(!ValidateFirstSTKPattern(file)) return false; file.Seek(sizeof(STKFileHeaders)); InitializeGlobals(MOD_TYPE_MOD, 4); m_playBehaviour.reset(kMODOneShotLoops); m_playBehaviour.set(kMODIgnorePanning); m_playBehaviour.set(kMODSampleSwap); // untested STVersions minVersion = UST1_00; bool hasDiskNames = true; SmpLength totalSampleLen = 0; m_nSamples = 15; for(SAMPLEINDEX smp = 1; smp <= 15; smp++) { ModSample &mptSmp = Samples[smp]; const MODSampleHeader &sampleHeader = fileHeaders.sampleHeaders[smp - 1]; ReadMODSample(sampleHeader, Samples[smp], m_szNames[smp], true); mptSmp.nFineTune = 0; totalSampleLen += mptSmp.nLength; if(sampleHeader.HasDiskName()) { // Ultimate Soundtracker 1.8 and D.O.C. SoundTracker IX always have sample names containing disk names. hasDiskNames = false; } // Loop start is always in bytes, not words, so don't trust the auto-fix magic in the sample header conversion (fixes loop of "st-01:asia" in mod.drag 10) if(sampleHeader.loopLength > 1) { mptSmp.nLoopStart = sampleHeader.loopStart; mptSmp.nLoopEnd = sampleHeader.loopStart + sampleHeader.loopLength * 2; mptSmp.SanitizeLoops(); } // UST only handles samples up to 9999 bytes. Master Soundtracker 1.0 and SoundTracker 2.0 introduce 32KB samples. if(sampleHeader.length > 4999 || sampleHeader.loopStart > 9999) minVersion = std::max(minVersion, MST1_00); } MODFileHeader &fileHeader = fileHeaders.fileHeader; ReadOrderFromArray(Order(), fileHeader.orderList); PATTERNINDEX numPatterns = GetNumPatterns(file, *this, fileHeader.numOrders, totalSampleLen, 0, true); // Most likely just a file with lots of NULs at the start if(fileHeader.restartPos == 0 && fileHeader.numOrders == 0 && numPatterns <= 1) { return false; } // Let's see if the file is too small (including some overhead for broken files like sll7.mod or ghostbus.mod) std::size_t requiredRemainingDataSize = numPatterns * 64u * 4u * 4u + totalSampleLen; if(!file.CanRead(requiredRemainingDataSize - std::min(requiredRemainingDataSize, 65536u))) return false; if(loadFlags == onlyVerifyHeader) return true; // Now we can be pretty sure that this is a valid Soundtracker file. Set up default song settings. // explora3-death.mod has a tempo of 0 if(!fileHeader.restartPos) fileHeader.restartPos = 0x78; // jjk55 by Jesper Kyd has a weird tempo set, but it needs to be ignored. if(!memcmp(fileHeaders.songname, "jjk55", 6)) fileHeader.restartPos = 0x78; // Sample 7 in echoing.mod won't "loop" correctly if we don't convert the VBlank tempo. Order().SetDefaultTempoInt(125); if(fileHeader.restartPos != 0x78) { // Convert to CIA timing Order().SetDefaultTempo(TEMPO((709379.0 * 125.0 / 50.0) / ((240 - fileHeader.restartPos) * 122.0))); if(minVersion > UST1_80) { // D.O.C. SoundTracker IX re-introduced the variable tempo after some other versions dropped it. minVersion = std::max(minVersion, hasDiskNames ? ST_IX : MST1_00); } else { // Ultimate Soundtracker 1.8 adds variable tempo minVersion = std::max(minVersion, hasDiskNames ? UST1_80 : ST2_00_Exterminator); } } m_nMinPeriod = 113 * 4; m_nMaxPeriod = 856 * 4; m_nSamplePreAmp = 64; m_SongFlags.set(SONG_PT_MODE | SONG_FORMAT_NO_VOLCOL | SONG_AUTO_VOLSLIDE_STK); m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeaders.songname); // Setup channel pan positions and volume SetupMODPanning(); FileReader::pos_type patOffset = file.GetPosition(); // Scan patterns to identify Soundtracker versions and reject garbage. uint32 illegalBytes = 0, totalNumDxx = 0; bool useAutoSlides = false; for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { const bool patternInUse = mpt::contains(Order(), pat); uint8 numDxx = 0, autoSlides = 0; uint8 emptyCmds = 0; MODPatternData patternData; file.ReadArray(patternData); if(patternInUse) { illegalBytes += CountMalformedMODPatternData(patternData, false); // Reject files that contain a lot of illegal pattern data. // STK.the final remix (MD5 5ff13cdbd77211d1103be7051a7d89c9, SHA1 e94dba82a5da00a4758ba0c207eb17e3a89c3aa3) // has one illegal byte, so we only reject after an arbitrary threshold has been passed. // This also allows to play some rather damaged files like // crockets.mod (MD5 995ed9f44cab995a0eeb19deb52e2a8b, SHA1 6c79983c3b7d55c9bc110b625eaa07ce9d75f369) // but naturally we cannot recover the broken data. // We only check patterns that are actually being used in the order list, because some bad rips of the // "operation wolf" soundtrack have 15 patterns for several songs, but the last few patterns are just garbage. // Apart from those hidden patterns, the files play fine. // Example: operation wolf - wolf1.mod (MD5 739acdbdacd247fbefcac7bc2d8abe6b, SHA1 e6b4813daacbf95f41ce9ec3b22520a2ae07eed8) if(illegalBytes > std::max(512u, numPatterns * 128u)) return false; } for(ROWINDEX row = 0; row < 64; row++) { for(CHANNELINDEX chn = 0; chn < 4; chn++) { const auto &data = patternData[row][chn]; const uint8 eff = data[2] & 0x0F, param = data[3]; // Check for empty space between the last Dxx command and the beginning of another pattern if(emptyCmds != 0 && !memcmp(data.data(), "\0\0\0\0", 4)) { emptyCmds++; if(emptyCmds > 32) { // Since there is a lot of empty space after the last Dxx command, // we assume it's supposed to be a pattern break effect. minVersion = ST2_00; } } else { emptyCmds = 0; } switch(eff) { case 1: case 2: if(param > 0x1F && minVersion == UST1_80) { // If a 1xx / 2xx effect has a parameter greater than 0x20, it is assumed to be UST. minVersion = hasDiskNames ? UST1_80 : UST1_00; } else if(eff == 1 && param > 0 && param < 0x03) { // This doesn't look like an arpeggio. minVersion = std::max(minVersion, ST2_00_Exterminator); } else if(eff == 1 && (param == 0x37 || param == 0x47) && minVersion <= ST2_00_Exterminator) { // This suspiciously looks like an arpeggio. // Catch sleepwalk.mod by Karsten Obarski, which has a default tempo of 125 rather than 120 in the header, so gets mis-identified as a later tracker version. minVersion = hasDiskNames ? UST1_80 : UST1_00; } break; case 0x0B: minVersion = ST2_00; break; case 0x0C: case 0x0D: case 0x0E: minVersion = std::max(minVersion, ST2_00_Exterminator); if(eff == 0x0D) { emptyCmds = 1; if(param == 0 && row == 0) { // Fix a possible tracking mistake in Blood Money title - who wants to do a pattern break on the first row anyway? break; } numDxx++; } else if(eff == 0x0E) { if(param > 1 || ++autoSlides > 1) useAutoSlides = true; } break; case 0x0F: minVersion = std::max(minVersion, ST_III); break; } } } if(numDxx > 0 && numDxx < 3) { // Not many Dxx commands in one pattern means they were probably pattern breaks minVersion = ST2_00; } totalNumDxx += numDxx; } // If there is a huge number of Dxx commands, this is extremely unlikely to be a SoundTracker 2.0 module if(totalNumDxx > numPatterns + 32u && minVersion == ST2_00) minVersion = MST1_00; file.Seek(patOffset); // Reading patterns if(loadFlags & loadPatternData) Patterns.ResizeArray(numPatterns); for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { MODPatternData patternData; file.ReadArray(patternData); if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { continue; } for(ROWINDEX row = 0; row < 64; row++) { auto rowBase = Patterns[pat].GetRow(row); for(CHANNELINDEX chn = 0; chn < 4; chn++) { ModCommand &m = rowBase[chn]; auto [command, param] = ReadMODPatternEntry(patternData[row][chn], m); if(command || param) { if(command == 0x0D) { if(minVersion != ST2_00) { // Dxy is volume slide in some Soundtracker versions, D00 is a pattern break in the latest versions. command = 0x0A; } else { param = 0; } } else if(command == 0x0C) { // Volume is sent as-is to the chip, which ignores the highest bit. param &= 0x7F; } else if(command == 0x0E && (param > 0x01 || minVersion < ST_IX) && useAutoSlides) { m.command = CMD_AUTO_VOLUMESLIDE; m.param = param; continue; } else if(command == 0x0F) { // Only the low nibble is evaluated in Soundtracker. param &= 0x0F; } if(minVersion <= UST1_80) { // UST effects m.param = param; switch(command) { case 0: // jackdance.mod by Karsten Obarski has 0xy arpeggios... if(param < 0x03) { m.command = CMD_NONE; } else { m.command = CMD_ARPEGGIO; } break; case 1: m.command = CMD_ARPEGGIO; break; case 2: if(m.param & 0x0F) { m.command = CMD_PORTAMENTOUP; m.param &= 0x0F; } else if(m.param >> 4) { m.command = CMD_PORTAMENTODOWN; m.param >>= 4; } break; default: m.command = CMD_NONE; break; } } else { ConvertModCommand(m, command, param); } } } } } [[maybe_unused]] /* silence clang-tidy deadcode.DeadStores */ const mpt::uchar *madeWithTracker = UL_(""); switch(minVersion) { case UST1_00: madeWithTracker = UL_("Ultimate Soundtracker 1.0-1.21"); break; case UST1_80: madeWithTracker = UL_("Ultimate Soundtracker 1.8-2.0"); break; case ST2_00_Exterminator: madeWithTracker = UL_("SoundTracker 2.0 / D.O.C. SoundTracker II"); break; case ST_III: madeWithTracker = UL_("Defjam Soundtracker III / Alpha Flight SoundTracker IV / D.O.C. SoundTracker IV / VI"); break; case ST_IX: madeWithTracker = UL_("D.O.C. SoundTracker IX"); break; case MST1_00: madeWithTracker = UL_("Master Soundtracker 1.0"); break; case ST2_00: madeWithTracker = UL_("SoundTracker 2.0 / 2.1 / 2.2"); break; } m_modFormat.formatName = UL_("Soundtracker"); m_modFormat.type = UL_("stk"); m_modFormat.madeWithTracker = madeWithTracker; m_modFormat.charset = mpt::Charset::Amiga_no_C1; // Reading samples if(loadFlags & loadSampleData) { for(SAMPLEINDEX smp = 1; smp <= 15; smp++) { // Looped samples in (Ultimate) Soundtracker seem to ignore all sample data before the actual loop start. // This avoids the clicks in the first sample of pretend.mod by Karsten Obarski. file.Skip(Samples[smp].nLoopStart); Samples[smp].nLength -= Samples[smp].nLoopStart; Samples[smp].nLoopEnd -= Samples[smp].nLoopStart; Samples[smp].nLoopStart = 0; MODSampleHeader::GetSampleFormat().ReadSample(Samples[smp], file); } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MODTools.cpp0000644000175000017500000004332614721611577020264 00000000000000/* * MODTools.cpp * ------------ * Purpose: Definition of MOD file structures (shared between several SoundTracker-/ProTracker-like formats) and helper functions * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "MODTools.h" #include "Tables.h" OPENMPT_NAMESPACE_BEGIN void CSoundFile::ConvertModCommand(ModCommand &m, const uint8 command, const uint8 param) { static constexpr EffectCommand effTrans[] = { // MOD effects CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, // 0123 CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, // 4567 CMD_PANNING8, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_POSITIONJUMP, // 89AB CMD_VOLUME, CMD_PATTERNBREAK, CMD_MODCMDEX, CMD_TEMPO, // CDEF // XM extended effects CMD_GLOBALVOLUME, CMD_GLOBALVOLSLIDE, CMD_NONE, CMD_NONE, // GHIJ CMD_KEYOFF, CMD_SETENVPOSITION, CMD_NONE, CMD_NONE, // KLMN CMD_NONE, CMD_PANNINGSLIDE, CMD_NONE, CMD_RETRIG, // OPQR CMD_NONE, CMD_TREMOR, CMD_NONE, CMD_NONE, // STUV CMD_DUMMY, CMD_XFINEPORTAUPDOWN, CMD_PANBRELLO, CMD_MIDI, // WXYZ CMD_SMOOTHMIDI, CMD_SMOOTHMIDI, CMD_XPARAM, // \\# (BeRoTracker uses command 37 instead of 36 for smooth MIDI macros; in old OpenMPT versions this was reserved for the unimplemented "velocity" command) }; m.command = CMD_NONE; m.param = param; if(command == 0x00 && param == 0x00) { m.command = CMD_NONE; } else if(command == 0x0F && param < 0x20) { // For a very long time (until OpenMPT 1.25.02.02), this code also imported 0x20 as CMD_SPEED for MOD files, // but this seems to contradict pretty much the majority of other MOD player out there. // 0x20 is Speed: Impulse Tracker, Scream Tracker, old ModPlug // 0x20 is Tempo: ProTracker, XMPlay, Imago Orpheus, Cubic Player, ChibiTracker, BeRoTracker, DigiTrakker, DigiTrekker, Disorder Tracker 2, DMP, Extreme's Tracker, ... m.command = CMD_SPEED; } else if(command < std::size(effTrans)) { m.command = effTrans[command]; if(m.command == CMD_PATTERNBREAK) m.param = static_cast(((m.param >> 4) * 10) + (m.param & 0x0F)); } } #ifndef MODPLUG_NO_FILESAVE void CSoundFile::ModSaveCommand(const ModCommand &source, uint8 &command, uint8 ¶m, const bool toXM, const bool compatibilityExport) const { command = 0; param = source.param; switch(source.command) { case CMD_NONE: command = param = 0; break; case CMD_ARPEGGIO: command = 0; break; case CMD_PORTAMENTOUP: command = 0x01; if(UseCombinedPortamentoCommands() && param >= 0xE0) { command = 0x0E; if(param < 0xF0) param = ((param & 0x0F) >> 2) | 0x10; else param = (param & 0x0F) | 0x10; } break; case CMD_PORTAMENTODOWN: command = 0x02; if(UseCombinedPortamentoCommands() && param >= 0xE0) { command = 0x0E; if(param < 0xF0) param = ((param & 0x0F) >> 2) | 0x20; else param = (param & 0x0F) | 0x20; } break; case CMD_TONEPORTAMENTO: command = 0x03; break; case CMD_VIBRATO: command = 0x04; break; case CMD_TONEPORTAVOL: command = 0x05; break; case CMD_VIBRATOVOL: command = 0x06; break; case CMD_TREMOLO: command = 0x07; break; case CMD_PANNING8: command = 0x08; if(GetType() & MOD_TYPE_S3M) { if(param <= 0x80) { param = mpt::saturate_cast(param * 2); } else if(param == 0xA4) // Surround { if(compatibilityExport || !toXM) { command = param = 0; } else { command = 'X' - 55; param = 91; } } } break; case CMD_OFFSETPERCENTAGE: case CMD_OFFSET: command = 0x09; break; case CMD_VOLUMESLIDE: command = 0x0A; break; case CMD_POSITIONJUMP: command = 0x0B; break; case CMD_VOLUME: command = 0x0C; break; case CMD_PATTERNBREAK: command = 0x0D; param = ((param / 10) << 4) | (param % 10); break; case CMD_MODCMDEX: command = 0x0E; break; case CMD_SPEED: command = 0x0F; param = std::min(param, uint8(0x1F)); break; case CMD_TEMPO: command = 0x0F; param = std::max(param, uint8(0x20)); break; case CMD_GLOBALVOLUME: command = 'G' - 55; break; case CMD_GLOBALVOLSLIDE: command = 'H' - 55; break; case CMD_KEYOFF: command = 'K' - 55; break; case CMD_SETENVPOSITION: command = 'L' - 55; break; case CMD_PANNINGSLIDE: command = 'P' - 55; break; case CMD_RETRIG: command = 'R' - 55; break; case CMD_TREMOR: command = 'T' - 55; break; case CMD_DUMMY: command = 'W' - 55; break; case CMD_XFINEPORTAUPDOWN: command = 'X' - 55; if(compatibilityExport && param >= 0x30) // X1x and X2x are legit, everything above are MPT extensions, which don't belong here. param = 0; // Don't set command to 0 to indicate that there *was* some X command here... break; case CMD_PANBRELLO: if(compatibilityExport) command = param = 0; else command = 'Y' - 55; break; case CMD_MIDI: if(compatibilityExport) command = param = 0; else command = 'Z' - 55; break; case CMD_SMOOTHMIDI: if(compatibilityExport) command = param = 0; else command = '\\' - 56; break; case CMD_XPARAM: if(compatibilityExport) command = param = 0; else command = '#' + 3; break; case CMD_S3MCMDEX: { ModCommand mConv; mConv.command = CMD_S3MCMDEX; mConv.param = param; mConv.ExtendedS3MtoMODEffect(); ModSaveCommand(mConv, command, param, toXM, compatibilityExport); } return; case CMD_VOLUME8: command = 0x0C; param = static_cast((param + 3u) / 4u); break; default: command = param = 0; } // Don't even think about saving XM effects in MODs... if(command > 0x0F && !toXM) { command = param = 0; } } #endif // MODPLUG_NO_FILESAVE // Convert an MOD sample header to OpenMPT's internal sample header. void MODSampleHeader::ConvertToMPT(ModSample &mptSmp, bool is4Chn) const { mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.nLength = length * 2; mptSmp.nFineTune = MOD2XMFineTune(finetune & 0x0F); mptSmp.nVolume = 4u * std::min(volume.get(), uint8(64)); SmpLength lStart = loopStart * 2; SmpLength lLength = loopLength * 2; // See if loop start is incorrect as words, but correct as bytes (like in Soundtracker modules) if(lLength > 2 && (lStart + lLength > mptSmp.nLength) && (lStart / 2 + lLength <= mptSmp.nLength)) { lStart /= 2; } if(mptSmp.nLength == 2) { mptSmp.nLength = 0; } if(mptSmp.nLength) { mptSmp.nLoopStart = lStart; mptSmp.nLoopEnd = lStart + lLength; if(mptSmp.nLoopStart >= mptSmp.nLength) { mptSmp.nLoopStart = mptSmp.nLength - 1; } if(mptSmp.nLoopStart > mptSmp.nLoopEnd || mptSmp.nLoopEnd < 4 || mptSmp.nLoopEnd - mptSmp.nLoopStart < 4) { mptSmp.nLoopStart = 0; mptSmp.nLoopEnd = 0; } // Fix for most likely broken sample loops. This fixes super_sufm_-_new_life.mod (M.K.) which has a long sample which is looped from 0 to 4. // This module also has notes outside of the Amiga frequency range, so we cannot say that it should be played using ProTracker one-shot loops. // On the other hand, "Crew Generation" by Necros (6CHN) has a sample with a similar loop, which is supposed to be played. // To be able to correctly play both modules, we will draw a somewhat arbitrary line here and trust the loop points in MODs with more than // 4 channels, even if they are tiny and at the very beginning of the sample. if(mptSmp.nLoopEnd <= 8 && mptSmp.nLoopStart == 0 && mptSmp.nLength > mptSmp.nLoopEnd && is4Chn) { mptSmp.nLoopEnd = 0; } if(mptSmp.nLoopEnd > mptSmp.nLoopStart) { mptSmp.uFlags.set(CHN_LOOP); } } } // Convert OpenMPT's internal sample header to a MOD sample header. SmpLength MODSampleHeader::ConvertToMOD(const ModSample &mptSmp) { SmpLength writeLength = mptSmp.HasSampleData() ? mptSmp.nLength : 0; // If the sample size is odd, we have to add a padding byte, as all sample sizes in MODs are even. if((writeLength % 2u) != 0) { writeLength++; } LimitMax(writeLength, SmpLength(0x1FFFE)); length = static_cast(writeLength / 2u); if(mptSmp.RelativeTone < 0) { finetune = 0x08; } else if(mptSmp.RelativeTone > 0) { finetune = 0x07; } else { finetune = XM2MODFineTune(mptSmp.nFineTune); } volume = static_cast(mptSmp.nVolume / 4u); loopStart = 0; loopLength = 1; if(mptSmp.uFlags[CHN_LOOP] && (mptSmp.nLoopStart + 2u) < writeLength) { const SmpLength loopEnd = Clamp(mptSmp.nLoopEnd, (mptSmp.nLoopStart & ~1) + 2u, writeLength) & ~1; loopStart = static_cast(mptSmp.nLoopStart / 2u); loopLength = static_cast((loopEnd - (mptSmp.nLoopStart & ~1)) / 2u); } return writeLength; } // Compute a "rating" of this sample header by counting invalid header data to ultimately reject garbage files. uint32 MODSampleHeader::GetInvalidByteScore() const { return ((volume > 64) ? 1 : 0) + ((finetune > 15) ? 1 : 0) + ((loopStart > length * 2) ? 1 : 0); } bool MODSampleHeader::HasDiskName() const { return (!memcmp(name, "st-", 3) || !memcmp(name, "ST-", 3)) && name[5] == ':'; } uint32 ReadMODSample(const MODSampleHeader &sampleHeader, ModSample &sample, mpt::charbuf &sampleName, bool is4Chn) { sampleHeader.ConvertToMPT(sample, is4Chn); sampleName = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); // Get rid of weird characters in sample names. for(auto &c : sampleName.buf) { if(c > 0 && c < ' ') { c = ' '; } } // Check for invalid values return sampleHeader.GetInvalidByteScore(); } // Check if a name string is valid (i.e. doesn't contain binary garbage data) uint32 CountInvalidChars(const mpt::span name) noexcept { uint32 invalidChars = 0; for(int8 c : name) // char can be signed or unsigned { // Check for any Extended ASCII and control characters if(c != 0 && c < ' ') invalidChars++; } return invalidChars; } // Check if a name is a valid null-terminated ASCII string with no garbage after the null terminator, or if it's empty NameClassification ClassifyName(const mpt::span name) noexcept { bool foundNull = false, foundNormal = false; for(int8 c : name) { if(c != 0 && c < ' ') return NameClassification::Invalid; if(c == 0) foundNull = true; else if(foundNull) return NameClassification::Invalid; else foundNormal = true; } if(!foundNull) return NameClassification::Invalid; return foundNormal ? NameClassification::ValidASCII : NameClassification::Empty; } // Count malformed bytes in MOD pattern data uint32 CountMalformedMODPatternData(const MODPatternData &patternData, const bool extendedFormat) { const uint8 mask = extendedFormat ? 0xE0 : 0xF0; uint32 malformedBytes = 0; for(const auto &row : patternData) { for(const auto &data : row) { if(data[0] & mask) malformedBytes++; if(!extendedFormat) { const uint16 period = (((static_cast(data[0]) & 0x0F) << 8) | data[1]); if(period && period != 0xFFF) { // Allow periods to deviate by +/-1 as found in some files const auto CompareFunc = [](uint16 l, uint16 r) { return l > (r + 1); }; const auto PeriodTable = mpt::as_span(ProTrackerPeriodTable).subspan(24, 36); if(!std::binary_search(PeriodTable.begin(), PeriodTable.end(), period, CompareFunc)) malformedBytes += 2; } } } } return malformedBytes; } // Parse the order list to determine how many patterns are used in the file. PATTERNINDEX GetNumPatterns(FileReader &file, CSoundFile &sndFile, ORDERINDEX numOrders, SmpLength totalSampleLen, SmpLength wowSampleLen, bool validateHiddenPatterns) { ModSequence &Order = sndFile.Order(); PATTERNINDEX numPatterns = 0; // Total number of patterns in file (determined by going through the whole order list) with pattern number < 128 PATTERNINDEX officialPatterns = 0; // Number of patterns only found in the "official" part of the order list (i.e. order positions < claimed order length) PATTERNINDEX numPatternsIllegal = 0; // Total number of patterns in file, also counting in "invalid" pattern indexes >= 128 for(ORDERINDEX ord = 0; ord < 128; ord++) { PATTERNINDEX pat = Order[ord]; if(pat < 128 && numPatterns <= pat) { numPatterns = pat + 1; if(ord < numOrders) { officialPatterns = numPatterns; } } if(pat >= numPatternsIllegal) { numPatternsIllegal = pat + 1; } } // Remove the garbage patterns past the official order end now that we don't need them anymore. Order.resize(numOrders); const size_t patternStartOffset = file.GetPosition(); const size_t sizeWithoutPatterns = totalSampleLen + patternStartOffset; const size_t sizeWithOfficialPatterns = sizeWithoutPatterns + officialPatterns * sndFile.GetNumChannels() * 256; // There are some WOW files with an extra byte at the end, and also a MOD file (idntmind.mod, MD5 a3af5c3e1af269e32dfb6677c41c8453, SHA1 4884717c298575f9884b2211c762bb1725f73743) // where only the "official" patterns should be counted but the file also has an extra byte at the end. // Since MOD files can technically not have an odd file size, we just always round the actual file size down. const auto fileSize = mpt::align_down(file.GetLength(), FileReader::pos_type{2}); if(wowSampleLen && (wowSampleLen + patternStartOffset) + numPatterns * 8 * 256 == fileSize) { // Check if this is a Mod's Grave WOW file... WOW files use the M.K. magic but are actually 8CHN files. // We do a simple pattern validation as well for regular MOD files that have non-module data attached at the end // (e.g. ponylips.mod, MD5 c039af363b1d99a492dafc5b5f9dd949, SHA1 1bee1941c47bc6f913735ce0cf1880b248b8fc93) file.Seek(patternStartOffset + numPatterns * 4 * 256); if(ValidateMODPatternData(file, 16, true)) sndFile.ChnSettings.resize(8); file.Seek(patternStartOffset); } else if(numPatterns != officialPatterns && (validateHiddenPatterns || sizeWithOfficialPatterns == fileSize)) { // 15-sample SoundTracker specifics: // Fix SoundTracker modules where "hidden" patterns should be ignored. // razor-1911.mod (MD5 b75f0f471b0ae400185585ca05bf7fe8, SHA1 4de31af234229faec00f1e85e1e8f78f405d454b) // and captain_fizz.mod (MD5 55bd89fe5a8e345df65438dbfc2df94e, SHA1 9e0e8b7dc67939885435ea8d3ff4be7704207a43) // seem to have the "correct" file size when only taking the "official" patterns into account, // but they only play correctly when also loading the inofficial patterns. // On the other hand, the SoundTracker module // wolf1.mod (MD5 a4983d7a432d324ce8261b019257f4ed, SHA1 aa6b399d02546bcb6baf9ec56a8081730dea3f44), // wolf3.mod (MD5 af60840815aa9eef43820a7a04417fa6, SHA1 24d6c2e38894f78f6c5c6a4b693a016af8fa037b) // and jean_baudlot_-_bad_dudes_vs_dragonninja-dragonf.mod (MD5 fa48e0f805b36bdc1833f6b82d22d936, SHA1 39f2f8319f4847fe928b9d88eee19d79310b9f91) // only play correctly if we ignore the hidden patterns. // Hence, we have a peek at the first hidden pattern and check if it contains a lot of illegal data. // If that is the case, we assume it's part of the sample data and only consider the "official" patterns. // 31-sample NoiseTracker / ProTracker specifics: // Interestingly, (broken) variants of the ProTracker modules // "killing butterfly" (MD5 bd676358b1dbb40d40f25435e845cf6b, SHA1 9df4ae21214ff753802756b616a0cafaeced8021), // "quartex" by Reflex (MD5 35526bef0fb21cb96394838d94c14bab, SHA1 116756c68c7b6598dcfbad75a043477fcc54c96c), // seem to have the "correct" file size when only taking the "official" patterns into account, but they only play // correctly when also loading the inofficial patterns. // On the other hand, "Shofixti Ditty.mod" from Star Control 2 (MD5 62b7b0819123400e4d5a7813eef7fc7d, SHA1 8330cd595c61f51c37a3b6f2a8559cf3fcaaa6e8) // doesn't sound correct when taking the second "inofficial" pattern into account. file.Seek(patternStartOffset + officialPatterns * sndFile.GetNumChannels() * 256); if(!ValidateMODPatternData(file, 64, true)) numPatterns = officialPatterns; file.Seek(patternStartOffset); } if(numPatternsIllegal > numPatterns && sizeWithoutPatterns + numPatternsIllegal * sndFile.GetNumChannels() * 256 == fileSize) { // Even those illegal pattern indexes (> 128) appear to be valid... What a weird file! // e.g. NIETNU.MOD, where the end of the order list is filled with FF rather than 00, and the file actually contains 256 patterns. numPatterns = numPatternsIllegal; } else if(numPatternsIllegal >= 0xFF) { // Patterns FE and FF are used with S3M semantics (e.g. some MODs written with old OpenMPT versions) Order.Replace(0xFE, PATTERNINDEX_SKIP); Order.Replace(0xFF, PATTERNINDEX_INVALID); } return numPatterns; } std::pair CSoundFile::ReadMODPatternEntry(FileReader &file, ModCommand &m) { return ReadMODPatternEntry(file.ReadArray(), m); } std::pair CSoundFile::ReadMODPatternEntry(const std::array data, ModCommand &m) { // Read Period uint16 period = (((static_cast(data[0]) & 0x0F) << 8) | data[1]); size_t note = NOTE_NONE; if(period > 0 && period != 0xFFF) { note = std::size(ProTrackerPeriodTable) + 23 + NOTE_MIN; for(size_t i = 0; i < std::size(ProTrackerPeriodTable); i++) { if(period >= ProTrackerPeriodTable[i]) { if(period != ProTrackerPeriodTable[i] && i != 0) { uint16 p1 = ProTrackerPeriodTable[i - 1]; uint16 p2 = ProTrackerPeriodTable[i]; if(p1 - period < (period - p2)) { note = i + 23 + NOTE_MIN; break; } } note = i + 24 + NOTE_MIN; break; } } } m.note = static_cast(note); // Read Instrument m.instr = (data[2] >> 4) | (data[0] & 0x10); // Read Effect m.command = CMD_NONE; uint8 command = data[2] & 0x0F, param = data[3]; return {command, param}; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_cba.cpp0000644000175000017500000001122014726651243020273 00000000000000/* * Load_cba.cpp * ------------ * Purpose: Chuck Biscuits / Black Artist (CBA) module loader * Notes : This format appears to have been used only for the Expoze musicdisk by Heretics. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct CBAFileHeader { char magic[4]; // 'CBA\xF9' char title[32]; uint8 eof; uint16le messageLength; uint8 numChannels; uint8 lastPattern; uint8 numOrders; uint8 numSamples; uint8 speed; uint8 tempo; uint8 panPos[32]; uint8 orders[255]; bool IsValid() const { return !memcmp(magic, "CBA\xF9", 4) && eof == 0x1A && numChannels > 0 && numChannels <= 32 && speed > 0 && tempo >= 32; } uint32 GetHeaderMinimumAdditionalSize() const { return numSamples * 48 + messageLength; } }; MPT_BINARY_STRUCT(CBAFileHeader, 332) struct CBASampleHeader { char name[32]; uint8 flags; uint8 volume; uint16le sampleRate; uint32le length; uint32le loopStart; uint32le loopEnd; void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.nVolume = volume * 4; mptSmp.nC5Speed = sampleRate; mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; mptSmp.uFlags.set(CHN_LOOP, flags & 0x08); } }; MPT_BINARY_STRUCT(CBASampleHeader, 48) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderCBA(MemoryFileReader file, const uint64 *pfilesize) { CBAFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadCBA(FileReader &file, ModLoadingFlags loadFlags) { CBAFileHeader fileHeader; file.Rewind(); if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) return false; if(!file.CanRead(fileHeader.GetHeaderMinimumAdditionalSize())) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_S3M, fileHeader.numChannels); m_SongFlags.set(SONG_IMPORTED); m_playBehaviour.set(kST3SampleSwap); // AFTERMIX.CBA, pattern 53 m_nMixLevels = MixLevels::CompatibleFT2; m_nSamples = fileHeader.numSamples; m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.title); Order().SetDefaultTempoInt(fileHeader.tempo); Order().SetDefaultSpeed(fileHeader.speed); ReadOrderFromArray(Order(), fileHeader.orders, fileHeader.numOrders, 0xFF, 0xFE); for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = fileHeader.panPos[chn] * 2; } for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { CBASampleHeader sampleHeader; file.ReadStruct(sampleHeader); sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name); } Patterns.ResizeArray(fileHeader.lastPattern + 1); for(PATTERNINDEX pat = 0; pat < Patterns.Size(); pat++) { if(!(loadFlags & loadPatternData) || !file.CanRead(64 * 5 * fileHeader.numChannels) || !Patterns.Insert(pat, 64)) { file.Skip(64 * 5 * fileHeader.numChannels); continue; } for(ModCommand &m : Patterns[pat]) { const auto [instr, note, vol, command, param] = file.ReadArray(); m.instr = instr; if(note == 255) m.note = NOTE_NOTECUT; else if(note > 0 && note <= 96) m.note = NOTE_MIDDLEC - 49 + note; if(vol) m.SetVolumeCommand(VOLCMD_VOLUME, std::min(vol, uint8(65)) - 1); if(command > 0 && command < 0x0F) ConvertModCommand(m, command - 1, param); else if(command == 0x0F) // "Funky sync" m.SetEffectCommand(CMD_DUMMY, param); else if(command == 0x18) m.SetEffectCommand(CMD_RETRIG, param); else if(command >= 0x10 && command <= 0x1E) m.SetEffectCommand(CMD_MODCMDEX, static_cast(((command << 4) + 0x10) | std::min(param, uint8(0x0F)))); else if(command == 0x1F) m.SetEffectCommand(CMD_SPEED, param); else if(command == 0x20) m.SetEffectCommand(CMD_TEMPO, param); m.ExtendedMODtoS3MEffect(); } } for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { if(loadFlags & loadSampleData) { SampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::deltaPCM) .ReadSample(Samples[smp], file); } else { file.Skip(Samples[smp].nLength); } } m_songMessage.Read(file, fileHeader.messageLength, SongMessage::leCRLF); m_modFormat.formatName = UL_("Chuck Biscuits / Black Artist"); m_modFormat.type = UL_("cba"); m_modFormat.charset = mpt::Charset::CP437; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Paula.h0000644000175000017500000000433614405407751017325 00000000000000/* * Paula.h * ------- * Purpose: Emulating the Amiga's sound chip, Paula, by implementing resampling using band-limited steps (BLEPs) * Notes : (currently none) * Authors: OpenMPT Devs * Antti S. Lankila * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" #include "Mixer.h" OPENMPT_NAMESPACE_BEGIN namespace Paula { inline constexpr int PAULA_HZ = 3546895; inline constexpr int MINIMUM_INTERVAL = 4; // Tradeoff between quality and speed (lower = less aliasing) inline constexpr int BLEP_SCALE = 17; // TODO: Should be 0 for float mixer inline constexpr int BLEP_SIZE = 2048; using BlepArray = std::array; class BlepTables { enum AmigaFilter { A500Off = 0, A500On, A1200Off, A1200On, Unfiltered, NumFilterTypes }; std::array WinSincIntegral; public: void InitTables(); const Paula::BlepArray &GetAmigaTable(Resampling::AmigaFilter amigaType, bool enableFilter) const; }; class State { // MAX_BLEPS configures how many BLEPs (volume steps) are being kept track of per channel, // and thus directly influences how much memory this feature wastes per virtual channel. // Paula::BLEP_SIZE / Paula::MINIMUM_INTERVAL would be a safe maximum, // but even a sample (alternating at +1/-1, thus causing a step on every frame) played at 200 kHz, // which is way out of spec for the Amiga, will only get close to 128 active BLEPs with Paula::MINIMUM_INTERVAL == 4. // Hence 128 is chosen as a tradeoff between quality and memory consumption. static constexpr uint16 MAX_BLEPS = 128; struct Blep { int16 level; uint16 age; }; public: SamplePosition remainder, stepRemainder; int numSteps; // Number of full-length steps private: uint16 activeBleps = 0, firstBlep = 0; // Count of simultaneous bleps to keep track of int16 globalOutputLevel = 0; // The instantenous value of Paula output Blep blepState[MAX_BLEPS]; public: State(uint32 sampleRate = 48000); void Reset(); void InputSample(int16 sample); int OutputSample(const BlepArray &WinSincIntegral); void Clock(int cycles); }; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Fastmix.cpp0000644000175000017500000006152714735071054020235 00000000000000/* * Fastmix.cpp * ----------- * Purpose: Mixer core for rendering samples, mixing plugins, etc... * Notes : If this is Fastmix.cpp, where is Slowmix.cpp? :) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ // FIXME: // - Playing samples backwards should reverse interpolation LUTs for interpolation modes // with more than two taps since they're not symmetric. We might need separate LUTs // because otherwise we will add tons of branches. // - Loop wraparound works pretty well in general, but not at the start of bidi samples. // - The loop lookahead stuff might still fail for samples with backward loops. #include "stdafx.h" #include "Sndfile.h" #include "MixerLoops.h" #include "MixFuncTable.h" #include "plugins/PlugInterface.h" #include // For FLT_EPSILON #include OPENMPT_NAMESPACE_BEGIN ///////////////////////////////////////////////////////////////////////// struct MixLoopState { const int8 * samplePointer = nullptr; const int8 * lookaheadPointer = nullptr; SmpLength lookaheadStart = 0; uint32 maxSamples = 0; const uint8 ITPingPongDiff; const bool precisePingPongLoops; MixLoopState(const CSoundFile &sndFile, const ModChannel &chn) : ITPingPongDiff{sndFile.m_playBehaviour[kITPingPongMode] ? uint8(1) : uint8(0)} , precisePingPongLoops{!sndFile.m_playBehaviour[kImprecisePingPongLoops]} { if(chn.pCurrentSample == nullptr) return; UpdateLookaheadPointers(chn); // For platforms that have no fast 64-bit division, precompute this constant // as it won't change during the invocation of CreateStereoMix. SamplePosition increment = chn.increment; if(increment.IsNegative()) increment.Negate(); maxSamples = 16384u / (increment.GetUInt() + 1u); if(maxSamples < 2) maxSamples = 2; } // Calculate offset of loop wrap-around buffer for this sample. void UpdateLookaheadPointers(const ModChannel &chn) { samplePointer = static_cast(chn.pCurrentSample); lookaheadPointer = nullptr; if(!samplePointer) return; if(chn.nLoopEnd < InterpolationLookaheadBufferSize) lookaheadStart = chn.nLoopStart; else lookaheadStart = std::max(chn.nLoopStart, chn.nLoopEnd - InterpolationLookaheadBufferSize); // We only need to apply the loop wrap-around logic if the sample is actually looping. // As we round rather than truncate with No Interpolation, we also need the wrap-around logic for samples that are not interpolated. if(chn.dwFlags[CHN_LOOP]) { const bool inSustainLoop = chn.InSustainLoop() && chn.nLoopStart == chn.pModSample->nSustainStart && chn.nLoopEnd == chn.pModSample->nSustainEnd; // Do not enable wraparound magic if we're previewing a custom loop! if(inSustainLoop || (chn.nLoopStart == chn.pModSample->nLoopStart && chn.nLoopEnd == chn.pModSample->nLoopEnd)) { SmpLength lookaheadOffset = 3 * InterpolationLookaheadBufferSize + chn.pModSample->nLength - chn.nLoopEnd; if(inSustainLoop) { lookaheadOffset += 4 * InterpolationLookaheadBufferSize; } lookaheadPointer = samplePointer + lookaheadOffset * chn.pModSample->GetBytesPerSample(); } } } // Returns the buffer length required to render a certain amount of samples, based on the channel's playback speed. static MPT_FORCEINLINE uint32 DistanceToBufferLength(SamplePosition from, SamplePosition to, SamplePosition inc) { return static_cast((to - from - SamplePosition(1)) / inc) + 1; } // Check how many samples can be rendered without encountering loop or sample end, and also update loop position / direction MPT_FORCEINLINE uint32 GetSampleCount(ModChannel &chn, uint32 nSamples) const { int32 nLoopStart = chn.dwFlags[CHN_LOOP] ? chn.nLoopStart : 0; SamplePosition nInc = chn.increment; if(nSamples <= 0 || nInc.IsZero() || !chn.nLength || !samplePointer) return 0; // Part 1: Making sure the play position is valid, and if necessary, invert the play direction in case we reached a loop boundary of a ping-pong loop. chn.pCurrentSample = samplePointer; // Under zero ? if (chn.position.GetInt() < nLoopStart) { if (nInc.IsNegative()) { // Invert loop direction for bidi loops chn.position = SamplePosition(nLoopStart + nLoopStart, 0) - chn.position; if ((chn.position.GetInt() < nLoopStart) || (chn.position.GetUInt() >= (nLoopStart + chn.nLength) / 2)) { chn.position.Set(nLoopStart, 0); } if(chn.dwFlags[CHN_PINGPONGLOOP]) { chn.dwFlags.reset(CHN_PINGPONGFLAG); // go forward nInc.Negate(); chn.increment = nInc; } else { chn.position.SetInt(chn.nLength - 1); } if(!chn.dwFlags[CHN_LOOP] || chn.position.GetUInt() >= chn.nLength) { chn.position.Set(chn.nLength); return 0; } } else { // We probably didn't hit the loop end yet (first loop), so we do nothing if (chn.position.GetInt() < 0) chn.position.SetInt(0); } } else if (chn.position.GetUInt() >= chn.nLength) { // Past the end if(!chn.dwFlags[CHN_LOOP]) return 0; // not looping -> stop this channel if(chn.dwFlags[CHN_PINGPONGLOOP]) { // Invert loop if (nInc.IsPositive()) { nInc.Negate(); chn.increment = nInc; } chn.dwFlags.set(CHN_PINGPONGFLAG); // Adjust loop position if(precisePingPongLoops) { // More accurate loop end overshoot calculation. // Test cases: BidiPrecision.it, BidiPrecision.xm const auto overshoot = chn.position - SamplePosition(chn.nLength, 0); const auto loopLength = chn.nLoopEnd - chn.nLoopStart - ITPingPongDiff; if(overshoot.GetUInt() < loopLength) chn.position = SamplePosition(chn.nLength - ITPingPongDiff, 0) - overshoot; else chn.position = SamplePosition(chn.nLoopStart, 0); } else { SamplePosition invFract = chn.position.GetInvertedFract(); chn.position = SamplePosition(chn.nLength - (chn.position.GetInt() - chn.nLength) - invFract.GetInt(), invFract.GetFract()); if(chn.position.GetUInt() <= chn.nLoopStart || chn.position.GetUInt() >= chn.nLength) { // Impulse Tracker's software mixer would put a -2 (instead of -1) in the following line (doesn't happen on a GUS) chn.position.SetInt(chn.nLength - std::min(chn.nLength, static_cast(ITPingPongDiff + 1))); } } } else { if (nInc.IsNegative()) // This is a bug { nInc.Negate(); chn.increment = nInc; } // Restart at loop start chn.position += SamplePosition(nLoopStart - chn.nLength, 0); MPT_ASSERT(chn.position.GetInt() >= nLoopStart); // Interpolate correctly after wrapping around chn.dwFlags.set(CHN_WRAPPED_LOOP); } } // Part 2: Compute how many samples we can render until we reach the end of sample / loop boundary / etc. SamplePosition nPos = chn.position; const SmpLength nPosInt = nPos.GetUInt(); if(nPos.GetInt() < nLoopStart) { // too big increment, and/or too small loop length if(nPos.IsNegative() || nInc.IsNegative()) return 0; } else { // Not testing for equality since we might be going backwards from the very end of the sample if(nPosInt > chn.nLength) return 0; // If going forwards and we're preceisely at the end, there's no point in going further if(nPosInt == chn.nLength && nInc.IsPositive()) return 0; } uint32 nSmpCount = nSamples; SamplePosition nInv = nInc; if (nInc.IsNegative()) { nInv.Negate(); } LimitMax(nSamples, maxSamples); SamplePosition incSamples = nInc * (nSamples - 1); int32 nPosDest = (nPos + incSamples).GetInt(); const bool isAtLoopStart = (nPosInt >= chn.nLoopStart && nPosInt < chn.nLoopStart + InterpolationLookaheadBufferSize); if(!isAtLoopStart) { chn.dwFlags.reset(CHN_WRAPPED_LOOP); } // Loop wrap-around magic. bool checkDest = true; if(lookaheadPointer != nullptr) { if(nPosInt >= lookaheadStart) { #if 0 const uint32 oldCount = nSmpCount; // When going backwards - we can only go back up to lookaheadStart. // When going forwards - read through the whole pre-computed wrap-around buffer if possible. // TODO: ProTracker sample swapping needs hard cut at sample end. int32 samplesToRead = nInc.IsNegative() ? (nPosInt - lookaheadStart) //: 2 * InterpolationMaxLookahead - (nPosInt - mixLoopState.lookaheadStart); : (chn.nLoopEnd - nPosInt); //LimitMax(samplesToRead, chn.nLoopEnd - chn.nLoopStart); nSmpCount = SamplesToBufferLength(samplesToRead, chn); Limit(nSmpCount, 1u, oldCount); #else if (nInc.IsNegative()) { nSmpCount = DistanceToBufferLength(SamplePosition(lookaheadStart, 0), nPos, nInv); } else { nSmpCount = DistanceToBufferLength(nPos, SamplePosition(chn.nLoopEnd, 0), nInv); } #endif chn.pCurrentSample = lookaheadPointer; checkDest = false; } else if(chn.dwFlags[CHN_WRAPPED_LOOP] && isAtLoopStart) { // We just restarted the loop, so interpolate correctly after wrapping around nSmpCount = DistanceToBufferLength(nPos, SamplePosition(nLoopStart + InterpolationLookaheadBufferSize, 0), nInv); chn.pCurrentSample = lookaheadPointer + (chn.nLoopEnd - nLoopStart) * chn.pModSample->GetBytesPerSample(); checkDest = false; } else if(nInc.IsPositive() && static_cast(nPosDest) >= lookaheadStart && nSmpCount > 1) { // We shouldn't read that far if we're not using the pre-computed wrap-around buffer. nSmpCount = DistanceToBufferLength(nPos, SamplePosition(lookaheadStart, 0), nInv); checkDest = false; } } if(checkDest) { // Fix up sample count if target position is invalid if (nInc.IsNegative()) { if (nPosDest < nLoopStart) { nSmpCount = DistanceToBufferLength(SamplePosition(nLoopStart, 0), nPos, nInv); } } else { if (nPosDest >= (int32)chn.nLength) { nSmpCount = DistanceToBufferLength(nPos, SamplePosition(chn.nLength, 0), nInv); } } } Limit(nSmpCount, uint32(1u), nSamples); #ifdef MPT_BUILD_DEBUG { SmpLength posDest = (nPos + nInc * (nSmpCount - 1)).GetUInt(); MPT_MAYBE_CONSTANT_IF(posDest < 0 || posDest > chn.nLength) { // We computed an invalid delta! MPT_ASSERT_NOTREACHED(); return 0; } } #endif return nSmpCount; } }; // Render count * number of channels samples void CSoundFile::CreateStereoMix(int count) { if(!count) return; // Resetting sound buffer StereoFill(MixSoundBuffer, count, m_dryROfsVol, m_dryLOfsVol); if(m_MixerSettings.gnChannels > 2) StereoFill(MixRearBuffer, count, m_surroundROfsVol, m_surroundLOfsVol); // Channels that are actually mixed and not skipped (because they are paused or muted) CHANNELINDEX numChannelsMixed = 0; for(uint32 nChn = 0; nChn < m_nMixChannels; nChn++) { if(MixChannel(count, m_PlayState.Chn[m_PlayState.ChnMix[nChn]], m_PlayState.ChnMix[nChn], numChannelsMixed < m_MixerSettings.m_nMaxMixChannels)) numChannelsMixed++; } m_nMixStat = std::max(m_nMixStat, numChannelsMixed); } bool CSoundFile::MixChannel(int count, ModChannel &chn, CHANNELINDEX channel, bool doMix) { if(chn.pCurrentSample || chn.nLOfs || chn.nROfs) { mixsample_t *pOfsR = &m_dryROfsVol; mixsample_t *pOfsL = &m_dryLOfsVol; uint32 functionNdx = MixFuncTable::ResamplingModeToMixFlags(static_cast(chn.resamplingMode)); if(chn.dwFlags[CHN_16BIT]) functionNdx |= MixFuncTable::ndx16Bit; if(chn.dwFlags[CHN_STEREO]) functionNdx |= MixFuncTable::ndxStereo; #ifndef NO_FILTER if(chn.dwFlags[CHN_FILTER]) functionNdx |= MixFuncTable::ndxFilter; #endif mixsample_t *pbuffer = MixSoundBuffer; #ifndef NO_REVERB if(((m_MixerSettings.DSPMask & SNDDSP_REVERB) && !chn.dwFlags[CHN_NOREVERB]) || chn.dwFlags[CHN_REVERB]) { m_Reverb.TouchReverbSendBuffer(ReverbSendBuffer, m_RvbROfsVol, m_RvbLOfsVol, count); pbuffer = ReverbSendBuffer; pOfsR = &m_RvbROfsVol; pOfsL = &m_RvbLOfsVol; } #endif if(chn.dwFlags[CHN_SURROUND] && m_MixerSettings.gnChannels > 2) { pbuffer = MixRearBuffer; pOfsR = &m_surroundROfsVol; pOfsL = &m_surroundLOfsVol; } // Look for plugins associated with this implicit tracker channel. #ifndef NO_PLUGINS const PLUGINDEX mixPlugin = GetBestPlugin(chn, channel, PrioritiseInstrument, RespectMutes); if((mixPlugin > 0) && (mixPlugin <= MAX_MIXPLUGINS) && m_MixPlugins[mixPlugin - 1].pMixPlugin != nullptr) { // Render into plugin buffer instead of global buffer SNDMIXPLUGINSTATE &mixState = m_MixPlugins[mixPlugin - 1].pMixPlugin->m_MixState; if (mixState.pMixBuffer) { pbuffer = mixState.pMixBuffer; pOfsR = &mixState.nVolDecayR; pOfsL = &mixState.nVolDecayL; if (!(mixState.dwFlags & SNDMIXPLUGINSTATE::psfMixReady)) { StereoFill(pbuffer, count, *pOfsR, *pOfsL); mixState.dwFlags |= SNDMIXPLUGINSTATE::psfMixReady; } } } #endif // NO_PLUGINS if(chn.isPaused) { EndChannelOfs(chn, pbuffer, count); *pOfsR += chn.nROfs; *pOfsL += chn.nLOfs; chn.nROfs = chn.nLOfs = 0; return false; } MixLoopState mixLoopState(*this, chn); //////////////////////////////////////////////////// bool addToMix = false; int nsamples = count; // Keep mixing this sample until the buffer is filled. do { uint32 nrampsamples = nsamples; int32 nSmpCount; if(chn.nRampLength > 0) { if (nrampsamples > chn.nRampLength) nrampsamples = chn.nRampLength; } if((nSmpCount = mixLoopState.GetSampleCount(chn, nrampsamples)) <= 0) { // Stopping the channel chn.pCurrentSample = nullptr; chn.nLength = 0; chn.position.Set(0); chn.nRampLength = 0; EndChannelOfs(chn, pbuffer, nsamples); *pOfsR += chn.nROfs; *pOfsL += chn.nLOfs; chn.nROfs = chn.nLOfs = 0; chn.dwFlags.reset(CHN_PINGPONGFLAG); break; } // Should we mix this channel? if(!doMix // Too many channels || (!chn.nRampLength && !(chn.leftVol | chn.rightVol))) // Channel is completely silent { chn.position += chn.increment * nSmpCount; chn.nROfs = chn.nLOfs = 0; pbuffer += nSmpCount * 2; addToMix = false; } #ifdef MODPLUG_TRACKER else if(m_SamplePlayLengths != nullptr) { // Detecting the longest play time for each sample for optimization SmpLength pos = chn.position.GetUInt(); chn.position += chn.increment * nSmpCount; if(!chn.increment.IsNegative()) { pos = chn.position.GetUInt(); } size_t smp = std::distance(static_cast(static_cast::type>(Samples)), chn.pModSample); if(smp < m_SamplePlayLengths->size()) { (*m_SamplePlayLengths)[smp] = std::max((*m_SamplePlayLengths)[smp], pos); } } #endif else { // Do mixing mixsample_t *pbufmax = pbuffer + (nSmpCount * 2); chn.nROfs = -*(pbufmax - 2); chn.nLOfs = -*(pbufmax - 1); #ifdef MPT_BUILD_DEBUG SamplePosition targetpos = chn.position + chn.increment * nSmpCount; #endif MixFuncTable::Functions[functionNdx | (chn.nRampLength ? MixFuncTable::ndxRamp : 0)](chn, m_Resampler, pbuffer, nSmpCount); #ifdef MPT_BUILD_DEBUG MPT_ASSERT(chn.position.GetUInt() == targetpos.GetUInt()); #endif chn.nROfs += *(pbufmax - 2); chn.nLOfs += *(pbufmax - 1); pbuffer = pbufmax; addToMix = true; } nsamples -= nSmpCount; if (chn.nRampLength) { if (chn.nRampLength <= static_cast(nSmpCount)) { // Ramping is done chn.nRampLength = 0; chn.leftVol = chn.newLeftVol; chn.rightVol = chn.newRightVol; chn.rightRamp = chn.leftRamp = 0; if(chn.dwFlags[CHN_NOTEFADE] && !chn.nFadeOutVol) { chn.nLength = 0; chn.pCurrentSample = nullptr; } } else { chn.nRampLength -= nSmpCount; } } const bool pastLoopEnd = chn.position.GetUInt() >= chn.nLoopEnd && chn.dwFlags[CHN_LOOP]; const bool pastSampleEnd = chn.position.GetUInt() >= chn.nLength && !chn.dwFlags[CHN_LOOP] && chn.nLength && !chn.nMasterChn; const bool doSampleSwap = m_playBehaviour[kMODSampleSwap] && chn.swapSampleIndex && chn.swapSampleIndex <= GetNumSamples() && chn.pModSample != &Samples[chn.swapSampleIndex]; if((pastLoopEnd || pastSampleEnd) && doSampleSwap) { // ProTracker compatibility: Instrument changes without a note do not happen instantly, but rather when the sample loop has finished playing. // Test case: PTInstrSwap.mod, PTSwapNoLoop.mod #ifdef MODPLUG_TRACKER if(m_SamplePlayLengths != nullptr) { // Even if the sample was playing at zero volume, we need to retain its full length for correct sample swap timing size_t smp = std::distance(static_cast(static_cast::type>(Samples)), chn.pModSample); if(smp < m_SamplePlayLengths->size()) { (*m_SamplePlayLengths)[smp] = std::max((*m_SamplePlayLengths)[smp], std::min(chn.nLength, chn.position.GetUInt())); } } #endif const ModSample &smp = Samples[chn.swapSampleIndex]; chn.pModSample = &smp; chn.pCurrentSample = smp.samplev(); chn.dwFlags = (chn.dwFlags & CHN_CHANNELFLAGS) | smp.uFlags; if(smp.uFlags[CHN_LOOP]) chn.nLength = smp.nLoopEnd; else if(!m_playBehaviour[kMODOneShotLoops]) chn.nLength = smp.nLength; else chn.nLength = 0; // non-looping sample continue in oneshot mode (i.e. they will most probably just play silence) chn.nLoopStart = smp.nLoopStart; chn.nLoopEnd = smp.nLoopEnd; chn.position.SetInt(chn.nLoopStart); chn.swapSampleIndex = 0; mixLoopState.UpdateLookaheadPointers(chn); if(!chn.pCurrentSample) break; } else if(pastLoopEnd && !doSampleSwap && m_playBehaviour[kMODOneShotLoops] && chn.nLoopStart == 0) { // ProTracker "oneshot" loops (if loop start is 0, play the whole sample once and then repeat until loop end) chn.position.SetInt(0); chn.nLoopEnd = chn.nLength = chn.pModSample->nLoopEnd; } } while(nsamples > 0); // Restore sample pointer in case it got changed through loop wrap-around chn.pCurrentSample = mixLoopState.samplePointer; #ifndef NO_PLUGINS if(addToMix && mixPlugin > 0 && mixPlugin <= MAX_MIXPLUGINS && m_MixPlugins[mixPlugin - 1].pMixPlugin) { m_MixPlugins[mixPlugin - 1].pMixPlugin->ResetSilence(); } #endif // NO_PLUGINS return addToMix; } return false; } void CSoundFile::ProcessPlugins(uint32 nCount) { #ifndef NO_PLUGINS // If any sample channels are active or any plugin has some input, possibly suspended master plugins need to be woken up. bool masterHasInput = (m_nMixStat > 0); #ifdef MPT_INTMIXER const float IntToFloat = m_PlayConfig.getIntToFloat(); const float FloatToInt = m_PlayConfig.getFloatToInt(); #endif // MPT_INTMIXER // Setup float inputs from samples for(PLUGINDEX plug = 0; plug < MAX_MIXPLUGINS; plug++) { SNDMIXPLUGIN &plugin = m_MixPlugins[plug]; if(plugin.pMixPlugin != nullptr && plugin.pMixPlugin->m_MixState.pMixBuffer != nullptr && plugin.pMixPlugin->m_mixBuffer.Ok()) { IMixPlugin *mixPlug = plugin.pMixPlugin; SNDMIXPLUGINSTATE &state = mixPlug->m_MixState; //We should only ever reach this point if the song is playing. if (!mixPlug->IsSongPlaying()) { //Plugin doesn't know it is in a song that is playing; //we must have added it during playback. Initialise it! mixPlug->NotifySongPlaying(true); mixPlug->Resume(); } // Setup float input float *plugInputL = mixPlug->m_mixBuffer.GetInputBuffer(0); float *plugInputR = mixPlug->m_mixBuffer.GetInputBuffer(1); if (state.dwFlags & SNDMIXPLUGINSTATE::psfMixReady) { #ifdef MPT_INTMIXER StereoMixToFloat(state.pMixBuffer, plugInputL, plugInputR, nCount, IntToFloat); #else DeinterleaveStereo(state.pMixBuffer, plugInputL, plugInputR, nCount); #endif // MPT_INTMIXER } else if (state.nVolDecayR || state.nVolDecayL) { StereoFill(state.pMixBuffer, nCount, state.nVolDecayR, state.nVolDecayL); #ifdef MPT_INTMIXER StereoMixToFloat(state.pMixBuffer, plugInputL, plugInputR, nCount, IntToFloat); #else DeinterleaveStereo(state.pMixBuffer, plugInputL, plugInputR, nCount); #endif // MPT_INTMIXER } else { memset(plugInputL, 0, nCount * sizeof(plugInputL[0])); memset(plugInputR, 0, nCount * sizeof(plugInputR[0])); } state.dwFlags &= ~SNDMIXPLUGINSTATE::psfMixReady; if(!plugin.IsMasterEffect() && !(state.dwFlags & SNDMIXPLUGINSTATE::psfSilenceBypass)) { masterHasInput = true; } } } // Convert mix buffer #ifdef MPT_INTMIXER StereoMixToFloat(MixSoundBuffer, MixFloatBuffer[0], MixFloatBuffer[1], nCount, IntToFloat); #else DeinterleaveStereo(MixSoundBuffer, MixFloatBuffer[0], MixFloatBuffer[1], nCount); #endif // MPT_INTMIXER float *pMixL = MixFloatBuffer[0]; float *pMixR = MixFloatBuffer[1]; const bool positionChanged = HasPositionChanged(); // Process Plugins for(PLUGINDEX plug = 0; plug < MAX_MIXPLUGINS; plug++) { SNDMIXPLUGIN &plugin = m_MixPlugins[plug]; if (plugin.pMixPlugin != nullptr && plugin.pMixPlugin->m_MixState.pMixBuffer != nullptr && plugin.pMixPlugin->m_mixBuffer.Ok()) { IMixPlugin *pObject = plugin.pMixPlugin; if(!plugin.IsMasterEffect() && !plugin.pMixPlugin->ShouldProcessSilence() && !(plugin.pMixPlugin->m_MixState.dwFlags & SNDMIXPLUGINSTATE::psfHasInput)) { // If plugin has no inputs and isn't a master plugin, we shouldn't let it process silence if possible. // I have yet to encounter a VST plugin which actually sets this flag. bool hasInput = false; for(PLUGINDEX inPlug = 0; inPlug < plug; inPlug++) { if(m_MixPlugins[inPlug].GetOutputPlugin() == plug) { hasInput = true; break; } } if(!hasInput) { continue; } } bool isMasterMix = false; float *plugInputL = pObject->m_mixBuffer.GetInputBuffer(0); float *plugInputR = pObject->m_mixBuffer.GetInputBuffer(1); if (pMixL == plugInputL) { isMasterMix = true; pMixL = MixFloatBuffer[0]; pMixR = MixFloatBuffer[1]; } SNDMIXPLUGINSTATE &state = plugin.pMixPlugin->m_MixState; float *pOutL = pMixL; float *pOutR = pMixR; if (!plugin.IsOutputToMaster()) { PLUGINDEX nOutput = plugin.GetOutputPlugin(); if(nOutput > plug && nOutput < MAX_MIXPLUGINS && m_MixPlugins[nOutput].pMixPlugin != nullptr) { IMixPlugin *outPlugin = m_MixPlugins[nOutput].pMixPlugin; if(!(state.dwFlags & SNDMIXPLUGINSTATE::psfSilenceBypass)) outPlugin->ResetSilence(); if(outPlugin->m_mixBuffer.Ok()) { pOutL = outPlugin->m_mixBuffer.GetInputBuffer(0); pOutR = outPlugin->m_mixBuffer.GetInputBuffer(1); } } } /* if (plugin.multiRouting) { int nOutput=0; for (int nOutput=0; nOutput < plugin.nOutputs / 2; nOutput++) { destinationPlug = plugin.multiRoutingDestinations[nOutput]; pOutState = m_MixPlugins[destinationPlug].pMixState; pOutputs[2 * nOutput] = plugInputL; pOutputs[2 * (nOutput + 1)] = plugInputR; } }*/ if (plugin.IsMasterEffect()) { if (!isMasterMix) { float *pInL = plugInputL; float *pInR = plugInputR; for (uint32 i=0; iResetSilence(); SNDMIXPLUGIN *chain = &plugin; PLUGINDEX out = chain->GetOutputPlugin(), prevOut = plug; while(out > prevOut && out < MAX_MIXPLUGINS) { chain = &m_MixPlugins[out]; prevOut = out; out = chain->GetOutputPlugin(); if(chain->pMixPlugin) { chain->pMixPlugin->ResetSilence(); } } } } if(plugin.IsBypassed() || (plugin.IsAutoSuspendable() && (state.dwFlags & SNDMIXPLUGINSTATE::psfSilenceBypass))) { const float * const pInL = plugInputL; const float * const pInR = plugInputR; for (uint32 i=0; iPositionChanged(); pObject->Process(pOutL, pOutR, nCount); state.inputSilenceCount += nCount; if(plugin.IsAutoSuspendable() && pObject->GetNumOutputChannels() > 0 && state.inputSilenceCount >= m_MixerSettings.gdwMixingFreq * 4) { bool isSilent = true; for(uint32 i = 0; i < nCount; i++) { if(pOutL[i] >= FLT_EPSILON || pOutL[i] <= -FLT_EPSILON || pOutR[i] >= FLT_EPSILON || pOutR[i] <= -FLT_EPSILON) { isSilent = false; break; } } if(isSilent) { state.dwFlags |= SNDMIXPLUGINSTATE::psfSilenceBypass; } else { state.inputSilenceCount = 0; } } } state.dwFlags &= ~SNDMIXPLUGINSTATE::psfHasInput; } } #ifdef MPT_INTMIXER FloatToStereoMix(pMixL, pMixR, MixSoundBuffer, nCount, FloatToInt); #else InterleaveStereo(pMixL, pMixR, MixSoundBuffer, nCount); #endif // MPT_INTMIXER #else MPT_UNREFERENCED_PARAMETER(nCount); #endif // NO_PLUGINS } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_ult.cpp0000644000175000017500000002576014674124105020362 00000000000000/* * Load_ult.cpp * ------------ * Purpose: ULT (UltraTracker) module loader * Notes : (currently none) * Authors: Storlek (Original author - http://schismtracker.org/ - code ported with permission) * Johannes Schultz (OpenMPT Port, tweaks) * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct UltFileHeader { char signature[14]; // "MAS_UTrack_V00" uint8 version; // '1'...'4' char songName[32]; // Song Name, space-padded uint8 messageLength; // Number of Lines }; MPT_BINARY_STRUCT(UltFileHeader, 48) struct UltSample { enum UltSampleFlags { ULT_16BIT = 4, ULT_LOOP = 8, ULT_PINGPONGLOOP = 16, }; char name[32]; char filename[12]; uint32le loopStart; uint32le loopEnd; uint32le sizeStart; uint32le sizeEnd; uint8le volume; // 0-255, apparently prior to 1.4 this was logarithmic? uint8le flags; // above uint16le speed; // only exists for 1.4+ int16le finetune; // Convert an ULT sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.Set16BitCuePoints(); mptSmp.filename = mpt::String::ReadBuf(mpt::String::spacePadded, filename); if(sizeEnd <= sizeStart) { return; } mptSmp.nLength = sizeEnd - sizeStart; mptSmp.nSustainStart = loopStart; mptSmp.nSustainEnd = std::min(static_cast(loopEnd), mptSmp.nLength); mptSmp.nVolume = volume; mptSmp.nC5Speed = speed * 2; // Doubled to fit the note range if(finetune) { mptSmp.Transpose(finetune / (12.0 * 32768.0)); } if(flags & ULT_LOOP) mptSmp.uFlags.set(CHN_SUSTAINLOOP); if(flags & ULT_PINGPONGLOOP) mptSmp.uFlags.set(CHN_PINGPONGSUSTAIN); if(flags & ULT_16BIT) { mptSmp.uFlags.set(CHN_16BIT); mptSmp.nSustainStart /= 2; mptSmp.nSustainEnd /= 2; } } }; MPT_BINARY_STRUCT(UltSample, 66) /* Unhandled effects: 5x1 - do not loop sample (x is unused) E0x - set vibrato strength (2 is normal) The logarithmic volume scale used in older format versions here, or pretty much anywhere for that matter. I don't even think Ultra Tracker tries to convert them. */ static std::pair TranslateULTCommands(const uint8 e, uint8 param, uint8 version) { static constexpr EffectCommand ultEffTrans[] = { CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VIBRATO, CMD_NONE, CMD_NONE, CMD_TREMOLO, CMD_NONE, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_PANNING8, CMD_VOLUME8, CMD_PATTERNBREAK, CMD_NONE, // extended effects, processed separately CMD_SPEED, }; EffectCommand effect = ultEffTrans[e & 0x0F]; switch(e & 0x0F) { case 0x00: if(!param || version < '3') effect = CMD_NONE; break; case 0x05: // play backwards if((param & 0x0F) == 0x02 || (param & 0xF0) == 0x20) { effect = CMD_S3MCMDEX; param = 0x9F; } if(((param & 0x0F) == 0x0C || (param & 0xF0) == 0xC0) && version >= '3') { effect = CMD_KEYOFF; param = 0; } break; case 0x07: if(version < '4') effect = CMD_NONE; break; case 0x0A: if(param & 0xF0) param &= 0xF0; break; case 0x0B: param = (param & 0x0F) * 0x11; break; case 0x0D: // pattern break param = static_cast(10 * (param >> 4) + (param & 0x0F)); break; case 0x0E: // special switch(param >> 4) { case 0x01: effect = CMD_PORTAMENTOUP; param = 0xF0 | (param & 0x0F); break; case 0x02: effect = CMD_PORTAMENTODOWN; param = 0xF0 | (param & 0x0F); break; case 0x08: if(version >= '4') { effect = CMD_S3MCMDEX; param = 0x60 | (param & 0x0F); } break; case 0x09: effect = CMD_RETRIG; param &= 0x0F; break; case 0x0A: effect = CMD_VOLUMESLIDE; param = ((param & 0x0F) << 4) | 0x0F; break; case 0x0B: effect = CMD_VOLUMESLIDE; param = 0xF0 | (param & 0x0F); break; case 0x0C: case 0x0D: effect = CMD_S3MCMDEX; break; } break; case 0x0F: if(param > 0x2F) effect = CMD_TEMPO; break; } return {effect, param}; } struct ULTEventResult { uint8 repeat = 0; ModCommand::COMMAND lostCommand = CMD_NONE; ModCommand::PARAM lostParam = 0; }; static ULTEventResult ReadULTEvent(ModCommand &m, FileReader &file, uint8 version) { uint8 repeat = 1; uint8 b = file.ReadUint8(); if(b == 0xFC) // repeat event { repeat = file.ReadUint8(); b = file.ReadUint8(); } m.note = (b > 0 && b < 97) ? (b + 23 + NOTE_MIN) : NOTE_NONE; const auto [instr, cmd, para1, para2] = file.ReadArray(); m.instr = instr; auto [cmd1, param1] = TranslateULTCommands(cmd & 0x0F, para1, version); auto [cmd2, param2]= TranslateULTCommands(cmd >> 4, para2, version); // sample offset -- this is even more special than digitrakker's if(cmd1 == CMD_OFFSET && cmd2 == CMD_OFFSET) { uint32 offset = ((param2 << 8) | param1) >> 6; m.SetEffectCommand(CMD_OFFSET, static_cast(offset)); if(offset > 0xFF) m.SetVolumeCommand(VOLCMD_OFFSET, static_cast(offset >> 8)); return {repeat}; } else if(cmd1 == CMD_OFFSET) { uint32 offset = param1 * 4; param1 = mpt::saturate_cast(offset); if(offset > 0xFF && ModCommand::GetEffectWeight(cmd2) < ModCommand::GetEffectWeight(CMD_OFFSET)) { m.SetEffectCommand(CMD_OFFSET, static_cast(offset)); m.SetVolumeCommand(VOLCMD_OFFSET, static_cast(offset >> 8)); return {repeat}; } } else if(cmd2 == CMD_OFFSET) { uint32 offset = param2 * 4; param2 = mpt::saturate_cast(offset); if(offset > 0xFF && ModCommand::GetEffectWeight(cmd1) < ModCommand::GetEffectWeight(CMD_OFFSET)) { m.SetEffectCommand(CMD_OFFSET, static_cast(offset)); m.SetVolumeCommand(VOLCMD_OFFSET, static_cast(offset >> 8)); return {repeat}; } } else if(cmd1 == cmd2) { // don't try to figure out how ultratracker does this, it's quite random cmd2 = CMD_NONE; } if(cmd2 == CMD_VOLUME || (cmd2 == CMD_NONE && cmd1 != CMD_VOLUME)) { // swap commands std::swap(cmd1, cmd2); std::swap(param1, param2); } // Combine slide commands, if possible ModCommand::CombineEffects(cmd2, param2, cmd1, param1); const auto lostCommand = m.FillInTwoCommands(cmd1, param1, cmd2, param2); return {repeat, lostCommand.first, lostCommand.second}; } static bool ValidateHeader(const UltFileHeader &fileHeader) { if(fileHeader.version < '1' || fileHeader.version > '4' || std::memcmp(fileHeader.signature, "MAS_UTrack_V00", sizeof(fileHeader.signature))) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const UltFileHeader &fileHeader) { return fileHeader.messageLength * 32u + 3u + 256u; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize) { UltFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!ValidateHeader(fileHeader)) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadULT(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); UltFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return false; if(!ValidateHeader(fileHeader)) return false; if(loadFlags == onlyVerifyHeader) return true; if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) return false; InitializeGlobals(MOD_TYPE_ULT, 0); m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songName); const mpt::uchar *versions[] = {UL_("<1.4"), UL_("1.4"), UL_("1.5"), UL_("1.6")}; m_modFormat.formatName = UL_("UltraTracker"); m_modFormat.type = UL_("ult"); m_modFormat.madeWithTracker = U_("UltraTracker ") + versions[fileHeader.version - '1']; m_modFormat.charset = mpt::Charset::CP437; m_SongFlags = SONG_AUTO_TONEPORTA | SONG_AUTO_TONEPORTA_CONT | SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS; // this will be converted to IT format by MPT. m_playBehaviour.reset(kITClearPortaTarget); m_playBehaviour.reset(kITPortaTargetReached); m_playBehaviour.set(kFT2PortaTargetNoReset); // Read "messageLength" lines, each containing 32 characters. m_songMessage.ReadFixedLineLength(file, fileHeader.messageLength * 32, 32, 0); if(SAMPLEINDEX numSamples = file.ReadUint8(); numSamples < MAX_SAMPLES) m_nSamples = numSamples; else return false; for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { UltSample sampleHeader; // Annoying: v4 added a field before the end of the struct if(fileHeader.version >= '4') { file.ReadStruct(sampleHeader); } else { file.ReadStructPartial(sampleHeader, 64); sampleHeader.finetune = sampleHeader.speed; sampleHeader.speed = 8363; } sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); } ReadOrderFromFile(Order(), file, 256, 0xFF, 0xFE); if(CHANNELINDEX numChannels = file.ReadUint8() + 1u; numChannels <= MAX_BASECHANNELS) ChnSettings.resize(numChannels); else return false; PATTERNINDEX numPats = file.ReadUint8() + 1; for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { if(fileHeader.version >= '3') ChnSettings[chn].nPan = ((file.ReadUint8() & 0x0F) << 4) + 8; else ChnSettings[chn].nPan = (chn & 1) ? 192 : 64; } Patterns.ResizeArray(numPats); for(PATTERNINDEX pat = 0; pat < numPats; pat++) { if(!Patterns.Insert(pat, 64)) return false; } bool postFixSpeedCommands = false; for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ModCommand evnote; for(PATTERNINDEX pat = 0; pat < numPats && file.CanRead(5); pat++) { ModCommand *note = Patterns[pat].GetpModCommand(0, chn); ROWINDEX row = 0; while(row < 64) { const ULTEventResult eventResult = ReadULTEvent(evnote, file, fileHeader.version); if(eventResult.lostCommand != CMD_NONE && ModCommand::IsGlobalCommand(eventResult.lostCommand, eventResult.lostParam)) Patterns[pat].WriteEffect(EffectWriter(eventResult.lostCommand, eventResult.lostParam).Row(row).RetryNextRow()); int repeat = eventResult.repeat; if(repeat + row > 64) repeat = 64 - row; if(repeat == 0) break; if(evnote.command == CMD_SPEED && evnote.param == 0) postFixSpeedCommands = true; while(repeat--) { *note = evnote; note += GetNumChannels(); row++; } } } } if(postFixSpeedCommands) { for(CPattern &pat : Patterns) { for(ROWINDEX row = 0; row < pat.GetNumRows(); row++) { for(auto &m : pat.GetRow(row)) { if(m.command == CMD_SPEED && m.param == 0) { m.param = 6; pat.WriteEffect(EffectWriter(CMD_TEMPO, 125).Row(row).RetryNextRow()); } } } } } if(loadFlags & loadSampleData) { for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { SampleIO( Samples[smp].uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(Samples[smp], file); } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_gt2.cpp0000644000175000017500000014042314711231551020240 00000000000000/* * Load_gt2.cpp * ------------ * Purpose: Graoumf Tracker 1/2 module loader (GTK and GT2) * Notes : DSPs (delay, filter) are currently not supported. * They are kinda tricky because DSP to track assignments are established using pattern commands and can change at any time. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "mpt/parse/parse.hpp" OPENMPT_NAMESPACE_BEGIN // GTK File Header struct GTKFileHeader { char signature[3]; uint8be fileVersion; char songName[32]; char smallComment[160]; uint16be numSamples; uint16be numRows; uint16be numChannels; uint16be numOrders; uint16be restartPos; bool Validate() const { return !std::memcmp(signature, "GTK", 3) && fileVersion >= 1 && fileVersion <= 4 && numSamples <= 255 && numRows > 0 && numRows <= 256 && numChannels > 0 && numChannels <= 32 && numOrders <= 256 && restartPos < numOrders; } uint64 GetHeaderMinimumAdditionalSize() const { return ((fileVersion < 3) ? 48 : 64) * numSamples + 512 // Order list + ((fileVersion < 4) ? 4 : 5) * numRows * numChannels; // One pattern minimum } }; MPT_BINARY_STRUCT(GTKFileHeader, 206) static uint16 GT2LogToLinearVolume(uint16 logVolume) { LimitMax(logVolume, uint16(0xFFF)); return mpt::saturate_round(std::pow(2.0, (logVolume & 0xFF) / 256.0) * 32768.0) >> (15 - (logVolume >> 8)); } static void TranslateGraoumfEffect(CSoundFile &sndFile, ModCommand &m, const uint8 effect, const uint8 param, const int16 fileVersion, const ModCommand::NOTE lastNote, const ModCommand::INSTR lastInstr, TEMPO ¤tTempo, uint32 ¤tSpeed) { if(!effect) return; if(effect >= 0xB0 && fileVersion < 0) return; m.param = param; const bool isFalcon = fileVersion <= 5; const uint16 param12bit = ((effect & 0x0F) << 8) | param; const uint8 param4bit = std::min(param, uint8(0x0F)); const uint8 param4bitSlide = std::min(param, uint8(0x0E)); const uint8 param4bitDiv32 = static_cast(std::min((param + 31) / 32, 0x0E)); const uint8 param4bitDiv128 = static_cast(std::min((param + 127) / 128, 0x0E)); switch(effect >> 4) { case 0x02: // 2xxx: Set Volume m.volcmd = VOLCMD_VOLUME; m.vol = static_cast(std::min(param12bit / 4, 64)); return; case 0x03: // 3xxx: Set Logarithmic Volume m.volcmd = VOLCMD_VOLUME; if(param12bit == 0) m.vol = 0; else m.vol = static_cast(std::min(GT2LogToLinearVolume(param12bit) / 4, 64)); return; case 0x04: // 4xxx: Panning m.command = CMD_PANNING8; m.param = static_cast(param12bit / 16); return; case 0x05: // 5xxx: Linear global volume m.command = CMD_GLOBALVOLUME; m.param = static_cast((param12bit + 1) / 32); return; case 0x06: // 6xxx: Logarithmic global volume m.command = CMD_GLOBALVOLUME; if(param12bit == 0) m.param = 0; else m.param = mpt::saturate_cast(GT2LogToLinearVolume(param12bit) / 32); return; case 0x07: // 7xyy: Roll (x = speed, yy = maximum number of repetitions, 0 = unlimited) m.command = CMD_RETRIG; m.param = effect & 0x0F; return; case 0x08: m.command = CMD_RETRIG; if(fileVersion >= 0) { // GT2: 8xyz: Roll + Volume slide + Set balance if(m.volcmd == VOLCMD_NONE) { m.volcmd = VOLCMD_PANNING; m.vol = static_cast(Util::muldivr(effect & 0x0F, 64, 15)); } } else { // GTK: 8xyy: Roll + Set Linear Volume m.param = effect & 0x0F; m.volcmd = VOLCMD_VOLUME; m.vol = static_cast((param + 3u) / 4u); } return; case 0x09: // 9xxx: Offset m.command = CMD_OFFSET; { SmpLength fullOffset = param12bit; if(isFalcon) { if(!fullOffset) { // 9000 didn't recall last offset param fullOffset = 1; } else { SAMPLEINDEX sample = sndFile.GetSampleIndex(lastNote, lastInstr); if(sample != 0) { const ModSample &smp = sndFile.GetSample(sample); if(smp.uFlags[CHN_16BIT]) fullOffset /= 2; // Offset beyond sample loop restarted from sample loop rather than cutting sample // We could probably also use a compatibility flag for this, but this is what newer GT2 versions do // And it avoids writing VOLCMD_OFFSET in case the parameter is very large if(smp.uFlags[CHN_LOOP] && fullOffset * 256u > smp.nLength) { fullOffset = (smp.nLoopStart + 8u) / 256u; LimitMax(fullOffset, (smp.nLength - 1u) / 256u); } } } } m.param = static_cast(fullOffset); if(fullOffset > 0xFF && m.volcmd == VOLCMD_NONE) { m.volcmd = VOLCMD_OFFSET; m.vol = static_cast(std::min(fullOffset >> 8, static_cast(std::size(ModSample().cues)))); } } return; } switch(effect) { case 0x01: case 0x02: case 0x03: case 0x04: case 0x07: case 0x0B: case 0x0F: CSoundFile::ConvertModCommand(m, effect, param); if(m.command == CMD_TEMPO) currentTempo.Set(m.param, 0); else if(m.command == CMD_SPEED && m.param > 0) currentSpeed = m.param; break; case 0x05: // 05xx: Tone portamento + vibrato m.command = CMD_TONEPORTAMENTO; if(m.volcmd == VOLCMD_NONE) { m.volcmd = VOLCMD_VIBRATODEPTH; m.vol = 0; } break; case 0x06: // 06xx: Vibrato + tone portamento m.command = CMD_VIBRATO; if(m.volcmd == VOLCMD_NONE) { m.volcmd = VOLCMD_TONEPORTAMENTO; m.vol = 0; } break; case 0x08: // 08xy: Detune if(!m.IsNote() || !param) break; m.command = CMD_FINETUNE; m.param = static_cast(0x80 + ((param & 0xF0) >> 1) - ((param & 0x0F) << 3)); if(!sndFile.GetNumInstruments()) { // Need instruments for correct pitch wheel depth sndFile.m_nInstruments = std::min(sndFile.m_nSamples, static_cast(MAX_INSTRUMENTS - 1u)); for(SAMPLEINDEX smp = 1; smp <= sndFile.m_nInstruments; smp++) { if(auto ins = sndFile.AllocateInstrument(smp, smp); ins != nullptr) { ins->midiPWD = 2; ins->name = sndFile.m_szNames[smp]; ins->SetCutoff(0x7F, true); ins->SetResonance(0, true); } } } break; case 0x09: // 09xx: Note Delay m.command = CMD_MODCMDEX; m.param = 0xD0 | param4bit; break; case 0x0A: // 0Axx: Cut Note / Key Off m.command = CMD_KEYOFF; break; case 0x0C: // 0C0x: Vibrato waveform if(param <= 2) { m.command = CMD_MODCMDEX; m.param = 0x40 | param; } break; case 0x0D: // 0Dxx: Pattern break m.command = CMD_PATTERNBREAK; break; case 0x0E: // 0E0x: Tremolo waveform if(param <= 2) { m.command = CMD_MODCMDEX; m.param = 0x70 | param; } break; case 0x10: // 10xy: Arpeggio m.command = CMD_ARPEGGIO; break; case 0x11: // 11xx: Fine portamento up case 0x12: // 12xx: Fine portamento down m.command = CMD_MODCMDEX; m.param = (effect << 4) | param4bitSlide; break; case 0x13: // 13xy: Roll + Volume Slide m.command = CMD_RETRIG; break; case 0x14: // 14xx: Linear volume slide up m.command = CMD_VOLUMESLIDE; m.param = param4bitSlide << 4; break; case 0x15: // 15xx Linear volume slide down m.command = CMD_VOLUMESLIDE; m.param = param4bitSlide; break; case 0x16: // 16xx: Logarithmic volume slide up case 0x17: // 17xx: Logarithmic volume slide down break; case 0x18: // 18xx: Linear volume slide up + Tone portamento m.command = CMD_TONEPORTAVOL; m.param = param4bitSlide << 4; break; case 0x19: // 19xx: Linear volume slide down + Tone portamento m.command = CMD_TONEPORTAVOL; m.param = param4bitSlide; break; case 0x1A: // 1Axx: Logarithmic volume slide up + Tone portamento case 0x1B: // 1Bxx: Logarithmic volume slide down + Tone portamento break; case 0x1C: // 1Cxx: Linear volume slide up + Vibrato m.command = CMD_VIBRATOVOL; m.param = param4bitSlide << 4; break; case 0x1D: // 1Dxx: Linear volume slide down + Vibrato m.command = CMD_VIBRATOVOL; m.param = param4bitSlide; break; case 0x1E: // 1Exx: Logarithmic volume slide up + Vibrato case 0x1F: // 1Fxx: Logarithmic volume slide down + Vibrato break; case 0xA0: // A0xx: Linear master volume slide up if(param) { m.command = CMD_GLOBALVOLSLIDE; m.param = param4bitDiv32 << 4; } break; case 0xA1: // A1xx: Linear master volume slide down if(param) { m.command = CMD_GLOBALVOLSLIDE; m.param = param4bitDiv32; } break; case 0xA4: // A4xx: Fine linear volume slide up m.command = CMD_VOLUMESLIDE; m.param = (param4bitSlide << 4) | 0x0F; break; case 0xA5: // A5xx: Fine linear volume slide down m.command = CMD_VOLUMESLIDE; m.param = param4bitSlide | 0xF0; break; case 0xA6: // A6xx: Fine linear master volume slide up if(param) { m.command = CMD_GLOBALVOLSLIDE; m.param = (param4bitDiv32 << 4) | 0x0F; } break; case 0xA7: // A7xx: Fine linear master volume slide down if(param) { m.command = CMD_GLOBALVOLSLIDE; m.param = param4bitDiv32 | 0xF0; } break; case 0xA8: // A8xx: Set number of ticks if(param) { m.command = CMD_SPEED; currentSpeed = m.param; } break; case 0xA9: // A9xx: Set fine tempo (fractional) if(isFalcon && currentTempo.GetInt() > 0) { // GTK / GT2 Falcon version (assuming 49170 Hz sample rate, the best possible. bigbigbt.gtk and twenty five-twenty.gtk require this sample rate) double samplesPerTick = (49170 * 2.5) / currentTempo.ToDouble(); samplesPerTick += param * 2 - 256; m.command = CMD_TEMPO; m.param = mpt::saturate_round((49170 * 5) / (samplesPerTick * 2)); } else { // GT2 Windows version - Add xx/256 to tempo } break; case 0xAA: // AAxx: Pattern delay m.command = CMD_MODCMDEX; m.param = 0xE0 | param4bit; break; case 0xAC: // ACxx: Extra fine portamento up m.command = CMD_XFINEPORTAUPDOWN; m.param = 0x10 | param4bit; break; case 0xAD: // ADxx: Extra fine portamento down m.command = CMD_XFINEPORTAUPDOWN; m.param = 0x20 | param4bit; break; case 0xAE: // AExx: Pan slide left m.command = CMD_PANNINGSLIDE; m.param = (param4bitSlide / 2u) << 4; // approximation break; case 0xAF: // AFxx: Pan slide right m.command = CMD_PANNINGSLIDE; m.param = param4bitSlide / 2u; // approximation break; case 0xB0: // B0xy: Tremor m.command = CMD_TREMOR; break; case 0xB1: // B1xx: Pattern Loop m.command = CMD_MODCMDEX; m.param = 0xB0 | param4bit; break; case 0xB2: // B2xx: Per-channel interpolation flags case 0xB3: // B3xx: Set Volume Envelope (we have no way to use another envelope) m.command = CMD_S3MCMDEX; m.param = 0x77 + (param ? 1 : 0); break; case 0xB4: // B4xx: Set Tone Envelope (ditto) m.command = CMD_S3MCMDEX; m.param = 0x7B + (param ? 2 : 0); break; case 0xB5: // B5xx: Set Panning Envelope (ditto) m.command = CMD_S3MCMDEX; m.param = 0x79 + (param ? 1 : 0); break; case 0xB6: // B6xx: Set Cutoff Envelope (ditto) m.command = CMD_S3MCMDEX; m.param = 0x7B + (param ? 3 : 0); break; case 0xB7: // B7xx: Set Resonance Envelope (ditto) break; case 0xBA: // BAxx: Fine Offset m.command = CMD_OFFSET; m.param = static_cast((m.param + 15u) / 16u); break; case 0xBB: // BBxx: Very Fine Offset m.command = CMD_OFFSET; m.param = 1; break; case 0xBE: // BExx: Auto Tempo (adjusts tempo so that a C-2 played by the current sample will last exactly xx rows) case 0xBF: // BFxx: Auto Period (adjusts note frequency so that the note will last exactly xx rows) // Auto Tempo crashes GT2 for Windows. Differences from GT2 for Falcon are based on the source code (assuming no crash) if(param != 0 && lastNote != NOTE_NONE && lastInstr != 0 && currentTempo.GetInt() > 0 && currentSpeed > 0) { SAMPLEINDEX sample = sndFile.GetSampleIndex(lastNote, lastInstr); if(!sample) break; const ModSample &smp = sndFile.GetSample(sample); SmpLength length = smp.nLength; if(smp.uFlags[CHN_LOOP]) { length = smp.nLoopEnd; if(isFalcon) length -= smp.nLoopStart; if(smp.uFlags[CHN_PINGPONGLOOP] && !isFalcon) length *= 2; } if(isFalcon && length < 1024) break; if(!length || !smp.nC5Speed) break; int32 transpose = 0, finetune = 0; if(lastInstr <= sndFile.GetNumInstruments() && sndFile.Instruments[lastInstr] != nullptr) transpose = static_cast(sndFile.Instruments[lastInstr]->NoteMap[lastNote - NOTE_MIN]) - lastNote; if(isFalcon && effect == 0xBE) finetune = smp.nFineTune; const double sampleRate = smp.nC5Speed * std::pow(2.0, finetune / (-128.0 * 12.0) + transpose / 12.0); if(effect == 0xBE) { // Note: This assumes that the middle-C frequency was doubled when converting the samples const double tempo = 2.5 * (currentSpeed * param) * (sampleRate * 0.5) / length; // GT2 would divide the tempo by 2 while it's greater than 999 but we cannot store tempos above 255 here anyway m.command = CMD_TEMPO; m.param = mpt::saturate_round(tempo); currentTempo = TEMPO(m.param, 0); } else { const double sampleDurationMiddleC = length / sampleRate; const double wantedDuration = (param * currentSpeed * 2.5) / currentTempo.ToDouble(); const double ratio = sampleDurationMiddleC / wantedDuration; const double note = Clamp(double(NOTE_MIDDLEC) + mpt::log2(ratio) * 12.0, double(NOTE_MIN), double(NOTE_MAX)), frac = note - std::floor(note); const bool hadNote = m.IsNote(); m.note = static_cast(note); m.param = static_cast(0x80 + (frac * 64.0)); if(m.param != 0x80) m.command = CMD_FINETUNE; if(!hadNote) { if(m.volcmd == VOLCMD_NONE) { m.volcmd = VOLCMD_TONEPORTAMENTO; m.vol = 9; } else { m.command = CMD_TONEPORTA_DURATION; m.param = 0; } } } } break; case 0xC0: // C0xy: Change sample direction after y ticks (x: 0 = invert current direction, 1 = forward, 2 = backward) if(const uint8 direction = (param >> 4); direction == 1 || direction == 2) { m.command = CMD_S3MCMDEX; m.param = static_cast(0x9D + direction); } break; case 0xC2: // C2xx: Set linear track volume (0x10 = 0dB) m.command = CMD_CHANNELVOLUME; m.param *= 4; break; case 0xC3: // C2xx: Set logarithmic track volume (0xC0 = 0dB) m.command = CMD_CHANNELVOLUME; m.param = mpt::saturate_cast(GT2LogToLinearVolume(param << 4) / 64); break; case 0xC4: // C4xx: Linear track volume slide up case 0xC6: // C6xx: Logarithmic track volume slide up m.command = CMD_CHANNELVOLSLIDE; m.param = param4bitDiv128 << 4; break; case 0xC5: // C5xx: Linear track volume slide down case 0xC7: // C7xx: Logarithmic track volume slide down m.command = CMD_CHANNELVOLSLIDE; m.param = param4bitDiv128; break; case 0xC8: // C8xx: Fine logarithmic track volume slide up m.command = CMD_CHANNELVOLSLIDE; m.param = (param4bitSlide << 4) | 0x0F; break; case 0xC9: // C9xx: Fine logarithmic track volume slide down m.command = CMD_CHANNELVOLSLIDE; m.param = param4bitSlide | 0xF0; break; default: break; } } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderGTK(MemoryFileReader file, const uint64 *pfilesize) { GTKFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.Validate()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadGTK(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); GTKFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return false; if(!fileHeader.Validate()) return false; if(!file.CanRead(mpt::saturate_cast(fileHeader.GetHeaderMinimumAdditionalSize()))) return false; if(loadFlags == onlyVerifyHeader) return true; // Globals InitializeGlobals(MOD_TYPE_MPT, fileHeader.numChannels); m_SongFlags.set(SONG_IMPORTED); m_playBehaviour = GetDefaultPlaybackBehaviour(MOD_TYPE_IT); m_playBehaviour.set(kApplyOffsetWithoutNote); SetupMODPanning(true); m_modFormat.madeWithTracker = UL_("Graoumf Tracker"); m_modFormat.formatName = MPT_UFORMAT("Graoumf Tracker v{}")(fileHeader.fileVersion); m_modFormat.type = UL_("gtk"); m_modFormat.charset = mpt::Charset::ISO8859_1_no_C1; m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songName); size_t msgLength = sizeof(fileHeader.smallComment); while(msgLength > 0 && fileHeader.smallComment[msgLength - 1] == ' ') msgLength--; m_songMessage.Read(mpt::byte_cast(fileHeader.smallComment), msgLength, SongMessage::leAutodetect); m_nSamples = fileHeader.numSamples; for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { ModSample &mptSmp = Samples[smp]; mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.Set16BitCuePoints(); file.ReadString(m_szNames[smp], (fileHeader.fileVersion == 1) ? 32 : 28); if(fileHeader.fileVersion >= 3) { file.Skip(14); // reserved int16 defaultPan = file.ReadInt16BE(); // -1 = use track panning, 0...4095 otherwise if(defaultPan >= 0) { mptSmp.uFlags.set(CHN_PANNING); mptSmp.nPan = static_cast(Util::muldivr_unsigned(defaultPan, 256, 4095)); } } uint16 bytesPerSample = 1; if(fileHeader.fileVersion >= 2) { bytesPerSample = file.ReadUint16BE(); mptSmp.nC5Speed = file.ReadUint16BE(); } const auto [length, loopStart, loopLength] = file.ReadArray(); mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = mptSmp.nLoopStart + loopLength; mptSmp.uFlags.set(CHN_LOOP, mptSmp.nLoopStart > 0 || loopLength > 2); if(bytesPerSample == 2) { mptSmp.uFlags.set(CHN_16BIT); mptSmp.nLength /= 2u; mptSmp.nLoopStart /= 2u; mptSmp.nLoopEnd /= 2u; } mptSmp.nVolume = file.ReadUint16BE(); int16 finetune = file.ReadInt16BE(); // -8...7 if(finetune != 0) mptSmp.Transpose(finetune / (12.0 * 8.0)); mptSmp.nFineTune = MOD2XMFineTune(finetune); // We store this because we need to undo the finetune for the auto-tempo command } Order().SetRestartPos(fileHeader.restartPos); FileReader orderChunk = file.ReadChunk(512); ReadOrderFromFile(Order(), orderChunk, fileHeader.numOrders); PATTERNINDEX numPatterns = *std::max_element(Order().begin(), Order().end()) + 1u; Patterns.ResizeArray(numPatterns); const uint8 eventSize = fileHeader.fileVersion < 4 ? 4 : 5; TEMPO currentTempo = Order().GetDefaultTempo(); uint32 currentSpeed = Order().GetDefaultSpeed(); for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !file.CanRead(fileHeader.numRows * GetNumChannels() * eventSize) || !Patterns.Insert(pat, fileHeader.numRows)) continue; std::vector> lastNoteInstr(GetNumChannels(), {NOTE_NONE, {}}); for(ROWINDEX row = 0; row < fileHeader.numRows; row++) { auto rowData = Patterns[pat].GetRow(row); for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ModCommand &m = rowData[chn]; uint8 data[5]{}; file.ReadStructPartial(data, eventSize); if(data[0] >= 24 && data[0] < 84) { m.note = data[0] + NOTE_MIN + 12; lastNoteInstr[chn].first = m.note; } if(data[1]) { m.instr = data[1]; lastNoteInstr[chn].second = m.instr; } TranslateGraoumfEffect(*this, m, data[2], data[3], -static_cast(fileHeader.fileVersion), lastNoteInstr[chn].first, lastNoteInstr[chn].second, currentTempo, currentSpeed); if(data[4]) { m.volcmd = VOLCMD_VOLUME; m.vol = static_cast((data[4] + uint32(1)) / 4u); } } } } if(!(loadFlags & loadSampleData)) return true; for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { SampleIO( Samples[smp].uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM).ReadSample(Samples[smp], file); } return true; } // GT2 File Header struct GT2FileHeader { char signature[3]; uint8be fileVersion; uint32be headerSize; char songName[32]; char smallComment[160]; uint8be day; uint8be month; uint16be year; char trackerName[24]; // The following fields are only present in version 0-5. uint16be speed; uint16be tempo; uint16be masterVol; uint16be numPannedTracks; bool Validate() const { if(std::memcmp(signature, "GT2", 3) || fileVersion > 9 || year < 1980 || year > 9999) return false; if(fileVersion > 5) return true; return speed > 0 && tempo > 0 && masterVol <= 0xFFF && numPannedTracks <= 99; } uint64 GetHeaderMinimumAdditionalSize() const { return std::max(static_cast(headerSize), sizeof(GT2FileHeader)) - sizeof(GT2FileHeader) + 20u; // 10 bytes each for required PATS and SONG chunks } }; MPT_BINARY_STRUCT(GT2FileHeader, 236) // GT2 File Header struct GT2Chunk { // 32-Bit chunk identifiers enum ChunkIdentifiers : uint32 { idXCOM = MagicBE("XCOM"), idTCN1 = MagicBE("TCN1"), idTCN2 = MagicBE("TCN2"), idTVOL = MagicBE("TVOL"), idMIXP = MagicBE("MIXP"), idSONG = MagicBE("SONG"), idPATS = MagicBE("PATS"), idPATD = MagicBE("PATD"), idTNAM = MagicBE("TNAM"), idINST = MagicBE("INST"), idVENV = MagicBE("VENV"), idTENV = MagicBE("TENV"), idPENV = MagicBE("PENV"), idSAMP = MagicBE("SAMP"), idSAM2 = MagicBE("SAM2"), idENDC = MagicBE("ENDC"), }; uint32be id; uint32be length; size_t GetLength() const { return std::max(length.get(), uint32(8)) - 8u; } ChunkIdentifiers GetID() const { return static_cast(id.get()); } }; MPT_BINARY_STRUCT(GT2Chunk, 8) // GT2 Pattern Data struct GT2PatternCell { uint8 note; uint8 instr; uint8 effect; uint8 param; uint8 volume; }; MPT_BINARY_STRUCT(GT2PatternCell, 5) // GT2 Track Name struct GT2TrackName { uint16be type; uint16be trackNumber; char name[32]; }; MPT_BINARY_STRUCT(GT2TrackName, 36) // GT2 Instrument struct GT2Instrument { struct SampleInfo { uint8 num; int8 transpose; }; uint16be insNum; char name[28]; uint16be type; // 0 = sample-based uint16be defaultVelocity; // 0...256 int16be defaultPan; // -1 = use track panning, 0...4095 otherwise uint16be volEnv; // 0 = no envelope uint16be toneEnv; // 0 = no envelope uint16be panEnv; // 0 = no envelope uint16be cutoffEnv; // 0 = no envelope uint16be resoEnv; // 0 = no envelope char reserved[4]; uint16be version; // 0...2 SampleInfo samples[128]; }; MPT_BINARY_STRUCT(GT2Instrument, 308) struct GT2InstrumentExt { enum FilterFlags : uint16 { fltEnabled = 0x01, fltVelToCutoff = 0x02, fltVelToReso = 0x04, fltTypeMask = 0x18, fltTypeLowpass = 0x00, fltTypeHighpass = 0x08, fltTypeBandpass = 0x10, fltTypeNotch = 0x18, }; uint16be filterFlags; // See FilterFlags char maxVelFreq[24]; // Cutoff frequency for the minimum velocity (256); <= 20: Multiple of the note frequency, > 20: Fixed frequency in Hz char minVelFreq[24]; // Cutoff frequency for the maximum velocity (0); ditto char maxVelReso[24]; // Q (resonance) value for the minimum velocity (256) char minVelReso[24]; // Q (resonance) value for the maximum velocity (0) uint8 pitchPanCenter; // Unused uint8 pitchPanSep; // Unused uint8 accent; // Unused uint8 numEnvelopes; }; MPT_BINARY_STRUCT(GT2InstrumentExt, 102) struct GT2Envelope { enum EnvelopeFlags : uint16 { envFadeOut = 0x01, envLFO = 0x02, envLoop = 0x10, envSustain = 0x20, }; struct EnvPoint { uint16be duration; int16be value; }; uint16be numPoints; uint16be lfoDepth; uint16be lfoSpeed; uint16be lfoSweep; uint16be lfoWaveform; uint16be fadeOut; uint16be flags; // See EnvelopeFlags uint16be loopStart; uint16be loopEnd; uint16be loopRepCount; uint16be sustainStart; uint16be sustainEnd; uint16be sustainRepCount; EnvPoint data[64]; void ConvertToMPT(ModInstrument &mptIns, EnvelopeType type) const { InstrumentEnvelope &mptEnv = mptIns.GetEnvelope(type); mptEnv.resize(std::min(numPoints.get(), static_cast(std::size(data)))); mptEnv.nLoopStart = static_cast(loopStart); mptEnv.nLoopEnd = static_cast(loopEnd); mptEnv.nSustainStart = static_cast(sustainStart); mptEnv.nSustainEnd = static_cast(sustainEnd); mptEnv.dwFlags.set(ENV_ENABLED, !mptEnv.empty()); mptEnv.dwFlags.set(ENV_LOOP, (flags & envLoop) != 0); mptEnv.dwFlags.set(ENV_SUSTAIN, (flags & envSustain) != 0); int16 minValue, maxValue; switch(type) { case ENV_VOLUME: default: minValue = 0; maxValue = 4096; break; case ENV_PANNING: minValue = -128; maxValue = 127; break; case ENV_PITCH: minValue = -9999 * 16 / 99; maxValue = 9999 * 16 / 99; break; } uint16 tick = 0; for(uint32 i = 0; i < mptEnv.size(); i++) { mptEnv[i].tick = tick; int32 value = data[i].value + minValue; value = Util::muldivr(value, ENVELOPE_MAX, maxValue - minValue); mptEnv[i].value = mpt::saturate_cast(value); tick += std::max(data[i].duration.get(), uint16(1)); } } }; MPT_BINARY_STRUCT(GT2Envelope, 282) struct GT2SampleV2 { uint16be smpNum; char name[28]; uint16be type; // 0 = memory-based, 1 = disk-based uint16be bits; uint16be endian; // 0 = big, 1 = little uint16be numChannels; int16be defaultPan; // -1 = use track panning, 0...4095 otherwise uint16be volume; // 0...4095, 256 = 0dB int16be finetune; // -8...7 uint16be loopType; // 0 = no, 1 = forward, 2 = ping-pong int16be midiNote; // 48 = default (no transpose) uint16be sampleCoding; // 0 = PCM in module, 1 = PCM in separate file uint16be filenameLen; int16be yPanning; // Unused uint32be sampleFreq; // Sample frequency of reference note uint32be length; uint32be loopStart; uint32be loopLength; uint32be loopBufLength; uint32be dataOffset; void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(MOD_TYPE_IT); mptSmp.Set16BitCuePoints(); mptSmp.nGlobalVol = volume / 4u; if(defaultPan > 0) { mptSmp.uFlags.set(CHN_PANNING); mptSmp.nPan = static_cast(Util::muldivr_unsigned(defaultPan, 256, 4095)); } mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopStart + loopLength; mptSmp.uFlags.set(CHN_LOOP, loopType != 0); mptSmp.uFlags.set(CHN_PINGPONGLOOP, loopType & 2); mptSmp.nC5Speed = sampleFreq * 2u; if(finetune != 0) mptSmp.Transpose(finetune / (12.0 * 8.0)); mptSmp.nFineTune = MOD2XMFineTune(finetune); // We store this because we need to undo the finetune for the auto-tempo command } SampleIO GetSampleFormat() const { return SampleIO( bits == 8 ? SampleIO::_8bit : SampleIO::_16bit, numChannels == 1 ? SampleIO::mono : SampleIO::stereoInterleaved, endian == 0 ? SampleIO::bigEndian : SampleIO::littleEndian, SampleIO::signedPCM); } }; MPT_BINARY_STRUCT(GT2SampleV2, 78) struct GT2SampleV1 { enum SampleFlags : uint16 { smpStereo = 0x01, smpPingPong = 0x02, }; uint16be smpNum; char name[28]; uint16be flags; // See SampleFlags int16be defaultPan; // -1 = use track panning, 0...4095 otherwise uint16be bits; uint16be sampleFreq; uint32be length; uint32be loopStart; uint32be loopLength; // Loop is deactivated if loopStart = 0 and loopLength = 2 int16be volume; // 0...255 int16be finetune; // -8...7 uint16be sampleCoding; // 0 void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(MOD_TYPE_IT); mptSmp.Set16BitCuePoints(); mptSmp.nGlobalVol = static_cast(volume / 4u); if(defaultPan > 0) { mptSmp.uFlags.set(CHN_PANNING); mptSmp.nPan = static_cast(Util::muldivr_unsigned(defaultPan, 256, 4095)); } mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopStart + loopLength; if(bits == 16) { mptSmp.nLength /= 2u; mptSmp.nLoopStart /= 2u; mptSmp.nLoopEnd /= 2u; } mptSmp.uFlags.set(CHN_LOOP, loopStart > 0 || loopLength > 2); mptSmp.uFlags.set(CHN_PINGPONGLOOP, (flags & GT2SampleV1::smpPingPong) != 0); mptSmp.nC5Speed = sampleFreq * 2u; if(finetune != 0) mptSmp.Transpose(finetune / (12.0 * 8.0)); mptSmp.nFineTune = MOD2XMFineTune(finetune); // We store this because we need to undo the finetune for the auto-tempo command } SampleIO GetSampleFormat() const { return SampleIO( bits == 8 ? SampleIO::_8bit : SampleIO::_16bit, (flags & GT2SampleV1::smpStereo) ? SampleIO::stereoInterleaved : SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM); } }; MPT_BINARY_STRUCT(GT2SampleV1, 56) struct GT2MixPreset { uint16be number; char name[32]; uint16be trackType; uint16be trackIndex; uint16be numTracks; uint16be volWet; // 0..1000..FFFF uint16be panWet; // 0...FFF uint16be volDry; uint16be panDry; uint16be version; // 0x101 uint16be stereo; uint32be reserved; }; MPT_BINARY_STRUCT(GT2MixPreset, 56) struct GT2MixPresetTrack { uint8 trackType; uint8 dryFlag; // Effects tracks: 0 = wet, 1 = dry uint16be trackIndex; uint16be volume; // 0..1000..FFFF uint16be balance; // 0..800..FFF }; MPT_BINARY_STRUCT(GT2MixPresetTrack, 8) static void ConvertGT2Envelope(InstrumentSynth &synth, const uint16 envNum, std::vector &envChunks) { if(!envNum) return; for(auto &chunk : envChunks) { chunk.Rewind(); if(chunk.ReadUint16BE() != envNum) continue; chunk.Skip(20); // Name const uint16 keyoffOffset = chunk.ReadUint16BE(); uint16 jumpOffset = 0; std::map offsetToIndex; auto &events = synth.m_scripts.emplace_back(); events.push_back(InstrumentSynth::Event::GTK_KeyOff(keyoffOffset)); while(chunk.CanRead(1)) { const uint16 chunkPos = static_cast(chunk.GetPosition() - 24); if(!jumpOffset && chunkPos >= keyoffOffset) { events.push_back(InstrumentSynth::Event::StopScript()); jumpOffset = keyoffOffset; } offsetToIndex[chunkPos] = static_cast(events.size()); const uint8 command = chunk.ReadUint8(); switch(command) { case 0x00: // 00: End events.push_back(InstrumentSynth::Event::StopScript()); break; case 0x01: // 01: Unconditional Jump events.push_back(InstrumentSynth::Event::Jump(jumpOffset + chunk.ReadUint16BE())); break; case 0x02: // 02: Wait events.push_back(InstrumentSynth::Event::Delay(std::max(chunk.ReadUint16BE(), uint16(1)) - 1)); break; case 0x03: // 03: Set Counter events.push_back(InstrumentSynth::Event::SetLoopCounter(std::max(chunk.ReadUint8(), uint8(1)) - 1, true)); break; case 0x04: // 04: Loop events.push_back(InstrumentSynth::Event::EvaluateLoopCounter(jumpOffset + chunk.ReadUint16BE())); break; case 0x05: // 05: Key Off events.push_back(InstrumentSynth::Event::Jump(keyoffOffset)); break; case 0x80: // 80: Set Volume (16384 = 100%, max = 32767) events.push_back(InstrumentSynth::Event::GTK_SetVolume(chunk.ReadUint16BE())); break; case 0xA0: // A0: Set Tone (4096 = normal period) events.push_back(InstrumentSynth::Event::GTK_SetPitch(chunk.ReadUint16BE())); break; case 0xC0: // C0: Set Panning (2048 = normal position) events.push_back(InstrumentSynth::Event::GTK_SetPanning(chunk.ReadUint16BE())); break; case 0x81: // 81: Set Volume step events.push_back(InstrumentSynth::Event::GTK_SetVolumeStep(chunk.ReadInt16BE())); break; case 0xA1: // A1: Set Tone step events.push_back(InstrumentSynth::Event::GTK_SetPitchStep(chunk.ReadInt16BE())); break; case 0xC1: // C1: Set Pan step events.push_back(InstrumentSynth::Event::GTK_SetPanningStep(chunk.ReadInt16BE())); break; case 0x82: // 82: Set Volume speed case 0xA2: // A2: Set Tone speed case 0xC2: // C2: Set Pan speed events.push_back(InstrumentSynth::Event::GTK_SetSpeed(std::max(chunk.ReadUint8(), uint8(1)))); break; case 0x87: // 87: Tremor On events.push_back(InstrumentSynth::Event::GTK_EnableTremor(true)); break; case 0x88: // 88: Tremor Off events.push_back(InstrumentSynth::Event::GTK_EnableTremor(false)); break; case 0x89: // 89: Set Tremor Time 1 events.push_back(InstrumentSynth::Event::GTK_SetTremorTime(std::max(chunk.ReadUint8(), uint8(1)), 0)); break; case 0x8A: // 8A: Set Tremor Time 2 events.push_back(InstrumentSynth::Event::GTK_SetTremorTime(0, std::max(chunk.ReadUint8(), uint8(1)))); break; case 0x83: // 83: Tremolo On events.push_back(InstrumentSynth::Event::GTK_EnableTremolo(true)); break; case 0x84: // 84: Tremolo Off events.push_back(InstrumentSynth::Event::GTK_EnableTremolo(false)); break; case 0x85: // 85: Set Tremolo Width events.push_back(InstrumentSynth::Event::GTK_SetVibratoParams(std::max(chunk.ReadUint8(), uint8(1)), 0)); break; case 0x86: // 86: Set Tremolo Speed events.push_back(InstrumentSynth::Event::GTK_SetVibratoParams(0, std::max(chunk.ReadUint8(), uint8(1)))); break; case 0xA3: // A3: Vibrato On events.push_back(InstrumentSynth::Event::GTK_EnableVibrato(true)); break; case 0xA4: // A4: Vibrato Off events.push_back(InstrumentSynth::Event::GTK_EnableVibrato(false)); break; case 0xA5: // A5: Set Vibrato Width events.push_back(InstrumentSynth::Event::GTK_SetVibratoParams(std::max(chunk.ReadUint8(), uint8(1)), 0)); break; case 0xA6: // A6: Set Vibrato Speed events.push_back(InstrumentSynth::Event::GTK_SetVibratoParams(0, std::max(chunk.ReadUint8(), uint8(1)))); break; } } for(auto &event : events) { event.FixupJumpTarget(offsetToIndex); } break; } } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderGT2(MemoryFileReader file, const uint64 *pfilesize) { GT2FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.Validate()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadGT2(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); GT2FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return false; if(!fileHeader.Validate()) return false; if(!file.CanRead(mpt::saturate_cast(fileHeader.GetHeaderMinimumAdditionalSize()))) return false; if(loadFlags == onlyVerifyHeader) return true; std::vector pannedTracks; file.ReadVector(pannedTracks, fileHeader.numPannedTracks); ChunkReader chunkFile(file); auto chunks = chunkFile.ReadChunksUntil(1, GT2Chunk::idENDC); if(auto chunk = chunks.GetChunk(GT2Chunk::idPATS); chunk.CanRead(2)) { if(uint16 channels = chunk.ReadUint16BE(); channels >= 1 && channels <= MAX_BASECHANNELS) InitializeGlobals(MOD_TYPE_MPT, channels); else return false; } else { return false; } // Globals m_SongFlags.set(SONG_IMPORTED | SONG_EXFILTERRANGE); m_playBehaviour = GetDefaultPlaybackBehaviour(MOD_TYPE_IT); m_playBehaviour.set(kFT2ST3OffsetOutOfRange, fileHeader.fileVersion >= 6); m_playBehaviour.set(kApplyOffsetWithoutNote); FileHistory mptHistory; mptHistory.loadDate.day = Clamp(fileHeader.day, 1, 31); mptHistory.loadDate.month = Clamp(fileHeader.month, 1, 12); mptHistory.loadDate.year = fileHeader.year; m_FileHistory.push_back(mptHistory); m_modFormat.madeWithTracker = mpt::ToUnicode(mpt::Charset::ASCII, mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.trackerName)); m_modFormat.formatName = (fileHeader.fileVersion <= 5 ? MPT_UFORMAT("Graoumf Tracker v{}") : MPT_UFORMAT("Graoumf Tracker 2 v{}"))(fileHeader.fileVersion); m_modFormat.type = UL_("gt2"); m_modFormat.charset = mpt::Charset::ISO8859_1_no_C1; m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songName); m_nSamplePreAmp = 256; m_nDefaultGlobalVolume = 384 / (3 + GetNumChannels()); // See documentation on command 5xxx: Default linear master volume is 12288 / (3 + number of channels) if(fileHeader.fileVersion <= 5) { Order().SetDefaultSpeed(std::max(fileHeader.speed.get(), uint16(1))); Order().SetDefaultTempoInt(std::max(fileHeader.tempo.get(), uint16(1))); m_nDefaultGlobalVolume = std::min(Util::muldivr_unsigned(fileHeader.masterVol, MAX_GLOBAL_VOLUME, 4095), uint32(MAX_GLOBAL_VOLUME)); const CHANNELINDEX tracks = std::min(static_cast(pannedTracks.size()), GetNumChannels()); for(CHANNELINDEX chn = 0; chn < tracks; chn++) { ChnSettings[chn].nPan = std::min(static_cast(Util::muldivr_unsigned(pannedTracks[chn], 256, 4095)), uint16(256)); } } file.Seek(fileHeader.headerSize); if(auto chunk = chunks.GetChunk(GT2Chunk::idSONG); chunk.CanRead(2)) { ORDERINDEX numOrders = chunk.ReadUint16BE(); Order().SetRestartPos(chunk.ReadUint16BE()); LimitMax(numOrders, mpt::saturate_cast(chunk.BytesLeft() / 2u)); ReadOrderFromFile(Order(), chunk, numOrders); } else { return false; } if(auto chunk = chunks.GetChunk(GT2Chunk::idXCOM); chunk.CanRead(3)) { const uint16 length = chunk.ReadUint16BE(); m_songMessage.Read(chunk, length, SongMessage::leAutodetect); } else { size_t msgLength = sizeof(fileHeader.smallComment); while(msgLength > 0 && fileHeader.smallComment[msgLength - 1] == ' ') msgLength--; m_songMessage.Read(mpt::byte_cast(fileHeader.smallComment), msgLength, SongMessage::leAutodetect); } if(auto chunk = chunks.GetChunk(GT2Chunk::idTCN1); chunk.ReadUint8() == 0 && chunk.Seek(2648)) { // Only channel mute status is of interest here uint32 muteStatus = chunk.ReadUint32BE(); const CHANNELINDEX numChannels = std::min(GetNumChannels(), CHANNELINDEX(32)); for(CHANNELINDEX i = 0; i < numChannels; i++) { ChnSettings[i].dwFlags.set(CHN_MUTE, !(muteStatus & (1u << i))); } } if(auto chunk = chunks.GetChunk(GT2Chunk::idTCN2); chunk.CanRead(12)) { const auto [chunkVersion, bpmInt, bpmFract, speed, timeSigNum, timeSigDenum] = chunk.ReadArray(); Order().SetDefaultTempo(TEMPO(Clamp(bpmInt, 32, 999), Util::muldivr_unsigned(bpmFract, TEMPO::fractFact, 65536))); Order().SetDefaultSpeed(Clamp(speed, 1, 255)); m_nDefaultRowsPerBeat = 16 / Clamp(timeSigDenum, 1, 16); m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat * Clamp(timeSigNum, 1, 16); if(chunkVersion >= 1) { uint16 periodMode = chunk.ReadUint16BE(); m_SongFlags.set(SONG_LINEARSLIDES, !periodMode); } } if(auto chunk = chunks.GetChunk(GT2Chunk::idTVOL); chunk.CanRead(2)) { CHANNELINDEX numChannels = std::min(static_cast(chunk.ReadUint16BE()), GetNumChannels()); for(CHANNELINDEX chn = 0; chn < numChannels; chn++) { ChnSettings[chn].nVolume = static_cast(std::min(chunk.ReadUint16BE(), uint16(4096)) / 64u); } } // There can be more than one mix preset, but we only care about the first one (which appears to be the one that's always active when loading a file) if(auto chunk = chunks.GetChunk(GT2Chunk::idMIXP); chunk.CanRead(sizeof(GT2MixPreset))) { GT2MixPreset mixPreset; chunk.ReadStruct(mixPreset); if(mixPreset.trackType == 4 && mixPreset.version == 0x101) { m_nDefaultGlobalVolume = Util::muldivr_unsigned(std::min(mixPreset.volWet.get(), uint16(0x4000)), MAX_GLOBAL_VOLUME, 0x1000); for(uint16 i = 0 ; i < mixPreset.numTracks; i++) { GT2MixPresetTrack mixTrack; chunk.ReadStruct(mixTrack); if(mixTrack.trackType == 0 && mixTrack.trackIndex < GetNumChannels()) { auto &chnSetting = ChnSettings[mixTrack.trackIndex]; chnSetting.nPan = static_cast(Util::muldivr_unsigned(mixTrack.balance, 256, 0xFFF)); chnSetting.nVolume = static_cast(Util::muldivr_unsigned(mixTrack.volume, 64, 0x1000)); } } } } for(auto &smpChunk : chunks.GetAllChunks(GT2Chunk::idSAM2)) { GT2SampleV2 sample; if(!smpChunk.ReadStruct(sample) || !sample.smpNum || sample.smpNum >= MAX_SAMPLES || sample.sampleCoding > 1 || sample.type > 1) continue; if(sample.smpNum > m_nSamples) m_nSamples = sample.smpNum; ModSample &mptSmp = Samples[sample.smpNum]; sample.ConvertToMPT(mptSmp); m_szNames[sample.smpNum] = mpt::String::ReadBuf(mpt::String::spacePadded, sample.name); if((loadFlags & loadSampleData) && smpChunk.Seek(sample.dataOffset - 8)) { if(sample.type == 0) sample.GetSampleFormat().ReadSample(mptSmp, smpChunk); std::string filenameU8; smpChunk.ReadString(filenameU8, sample.filenameLen); mptSmp.filename = filenameU8; if(sample.type == 1) { #ifdef MPT_EXTERNAL_SAMPLES #if MPT_OS_WINDOWS std::transform(filenameU8.begin(), filenameU8.end(), filenameU8.begin(), [] (char c) { if(c == '/') return '\\'; else return c; }); #endif // MPT_OS_WINDOWS SetSamplePath(sample.smpNum, mpt::PathString::FromUTF8(filenameU8)); mptSmp.uFlags.set(SMP_KEEPONDISK); #else AddToLog(LogWarning, MPT_UFORMAT("Loading external sample {} ('{}') failed: External samples are not supported.")(sample.smpNum, mpt::ToUnicode(mpt::Charset::UTF8, filenameU8))); #endif // MPT_EXTERNAL_SAMPLES } } #if 0 if(fileHeader.fileVersion >= 9) { if(!(loadFlags & loadSampleData)) { smpChunk.Seek(sample.dataOffset - 8 + sample.filenameLen); if(sample.type == 0) smpChunk.Skip(sample.GetSampleFormat().CalculateEncodedSize(mptSmp.nLength)); } if(smpChunk.Seek((smpChunk.GetPosition() + 3u) & ~3u)) { const uint16 version = smpChunk.ReadUint16BE(); if(version <= 1) { const uint16 sampleGroup = smpChunk.ReadUint16BE(); } } } #endif } for(auto &smpChunk : chunks.GetAllChunks(GT2Chunk::idSAMP)) { GT2SampleV1 sample; if(!smpChunk.ReadStruct(sample) || !sample.smpNum || sample.smpNum >= MAX_SAMPLES || sample.sampleCoding != 0) continue; if(sample.smpNum > m_nSamples) m_nSamples = sample.smpNum; ModSample &mptSmp = Samples[sample.smpNum]; sample.ConvertToMPT(mptSmp); m_szNames[sample.smpNum] = mpt::String::ReadBuf(mpt::String::spacePadded, sample.name); if(loadFlags & loadSampleData) sample.GetSampleFormat().ReadSample(mptSmp, smpChunk); } auto volEnvChunks = chunks.GetAllChunks(GT2Chunk::idVENV), pitchEnvChunks = chunks.GetAllChunks(GT2Chunk::idTENV), panEnvChunks = chunks.GetAllChunks(GT2Chunk::idPENV); for(auto &insChunk : chunks.GetAllChunks(GT2Chunk::idINST)) { GT2Instrument instr; ModInstrument *mptIns; if(!insChunk.ReadStruct(instr) || instr.type != 0 || (mptIns = AllocateInstrument(instr.insNum)) == nullptr) continue; if(instr.insNum > m_nInstruments) m_nInstruments = instr.insNum; mptIns->name = mpt::String::ReadBuf(mpt::String::spacePadded, instr.name); mptIns->midiPWD = 2; if(instr.defaultPan > 0) { mptIns->dwFlags.set(INS_SETPANNING); mptIns->nPan = Util::muldivr_unsigned(instr.defaultPan, 256, 4095); } for(uint8 i = 0; i < std::min(std::size(mptIns->Keyboard), std::size(instr.samples)); i++) { mptIns->Keyboard[i] = instr.samples[i].num; mptIns->NoteMap[i] = static_cast(Clamp(mptIns->NoteMap[i] + instr.samples[i].transpose, NOTE_MIN, NOTE_MAX)); } for(SAMPLEINDEX smp : mptIns->GetSamples()) { if(smp > 0 && smp <= GetNumSamples()) Samples[smp].nVolume = instr.defaultVelocity; } mptIns->SetCutoff(0x7F, true); mptIns->SetResonance(0, true); if(instr.version == 0) { // Old "envelopes" mptIns->nFadeOut = instr.volEnv ? 0 : 32768; ConvertGT2Envelope(mptIns->synth, instr.volEnv, volEnvChunks); ConvertGT2Envelope(mptIns->synth, instr.panEnv, panEnvChunks); ConvertGT2Envelope(mptIns->synth, instr.toneEnv, pitchEnvChunks); } else { GT2InstrumentExt instrExt; insChunk.ReadStructPartial(instrExt, (instr.version == 1) ? offsetof(GT2InstrumentExt, pitchPanCenter) : sizeof(GT2InstrumentExt)); const bool filterEnabled = (instrExt.filterFlags & GT2InstrumentExt::fltEnabled); if(filterEnabled) { if(auto filterType = (instrExt.filterFlags & GT2InstrumentExt::fltTypeMask); filterType == GT2InstrumentExt::fltTypeLowpass) mptIns->filterMode = FilterMode::LowPass; else if(filterType == GT2InstrumentExt::fltTypeHighpass) mptIns->filterMode = FilterMode::HighPass; if(instrExt.filterFlags & GT2InstrumentExt::fltVelToCutoff) { // Note: we're missing the velocity to cutoff modulation here, and also the envelope is added on top of this in GT2, while we multiply it. const double maxCutoff = mpt::parse(std::string{instrExt.maxVelFreq, sizeof(instrExt.maxVelFreq)}); if(maxCutoff > 20) mptIns->SetCutoff(FrequencyToCutOff(maxCutoff), true); } if(instrExt.filterFlags & GT2InstrumentExt::fltVelToReso) { const double maxReso = mpt::parse(std::string{instrExt.maxVelReso, sizeof(instrExt.maxVelReso)}); mptIns->SetResonance(mpt::saturate_round(maxReso * 127.0 / 24.0), true); } } for(uint8 env = 0; env < instrExt.numEnvelopes; env++) { GT2Envelope envelope; insChunk.ReadStruct(envelope); const EnvelopeType envType[] = {ENV_VOLUME, ENV_PITCH, ENV_PANNING, ENV_PITCH}; const bool envEnabled[] = {instr.volEnv != 0, instr.toneEnv != 0, instr.panEnv != 0, instr.cutoffEnv != 0 && filterEnabled}; if(env >= std::size(envType) || !envEnabled[env]) continue; // Only import cutoff envelope if it wouldn't overwrite pitch envelope if(env == 3 && mptIns->PitchEnv.dwFlags[ENV_ENABLED]) continue; envelope.ConvertToMPT(*mptIns, envType[env]); if(env == 3) mptIns->PitchEnv.dwFlags.set(ENV_FILTER); if(envType[env] == ENV_VOLUME) { if(envelope.flags & GT2Envelope::envFadeOut) mptIns->nFadeOut = envelope.fadeOut & 0x7FFF; // High bit = logarithmic flag else mptIns->nFadeOut = 0; } else if(envType[env] == ENV_PITCH && (envelope.flags & GT2Envelope::envLFO)) { static constexpr VibratoType vibTyes[] = {VIB_SINE, VIB_SQUARE, VIB_SINE, VIB_RAMP_UP, VIB_RAMP_DOWN, VIB_RANDOM}; uint8 sweep = static_cast(255 / std::max(envelope.lfoSweep.get(), uint16(1))); uint8 depth = mpt::saturate_cast(Util::muldivr_unsigned(envelope.lfoDepth, 64, 100)); uint8 speed = mpt::saturate_cast(256 / std::max(envelope.lfoSpeed.get(), uint16(1))); PropagateXMAutoVibrato(instr.insNum, vibTyes[envelope.lfoWaveform < std::size(vibTyes) ? envelope.lfoWaveform : 0], sweep, depth, speed); } } } } auto patterns = chunks.GetAllChunks(GT2Chunk::idPATD); Patterns.ResizeArray(static_cast(patterns.size())); TEMPO currentTempo = Order().GetDefaultTempo(); uint32 currentSpeed = Order().GetDefaultSpeed(); for(auto &patChunk : patterns) { if(!(loadFlags & loadPatternData) || !patChunk.CanRead(24)) continue; const uint16 patNum = patChunk.ReadUint16BE(); char name[17]{}; patChunk.ReadString(name, 16); const uint16 codingVersion = patChunk.ReadUint16BE(); const ROWINDEX numRows = patChunk.ReadUint16BE(); const CHANNELINDEX numTracks = patChunk.ReadUint16BE(); if(!patChunk.CanRead(sizeof(GT2PatternCell) * numRows * numTracks)) continue; if(codingVersion > 1 || !Patterns.Insert(patNum, numRows)) continue; Patterns[patNum].SetName(name); std::vector> lastNoteInstr(numTracks, {NOTE_NONE, {}}); for(ROWINDEX row = 0; row < numRows; row++) { auto rowBase = Patterns[patNum].GetRow(row); for(CHANNELINDEX chn = 0; chn < numTracks; chn++) { ModCommand dummy; ModCommand &m = (chn < GetNumChannels()) ? rowBase[chn] : dummy; GT2PatternCell data; patChunk.ReadStruct(data); if(data.note > 0 && data.note <= NOTE_MAX - NOTE_MIN + 1) lastNoteInstr[chn].first = m.note = data.note + NOTE_MIN; if(data.instr) lastNoteInstr[chn].second = m.instr = data.instr; if(data.volume) { m.volcmd = VOLCMD_VOLUME; if(codingVersion == 0) m.vol = data.volume / 4u; else m.vol = (data.volume - 0x10); } TranslateGraoumfEffect(*this, m, data.effect, data.param, fileHeader.fileVersion, lastNoteInstr[chn].first, lastNoteInstr[chn].second, currentTempo, currentSpeed); } } } if(auto chunk = chunks.GetChunk(GT2Chunk::idTNAM); chunk.CanRead(2 + sizeof(GT2TrackName))) { uint16 numNames = chunk.ReadUint16BE(); for (uint16 i = 0; i < numNames && chunk.CanRead(sizeof(GT2TrackName)); i++) { GT2TrackName trackName; chunk.ReadStruct(trackName); if(trackName.type == 0 && trackName.trackNumber < GetNumChannels()) { ChnSettings[trackName.trackNumber].szName = mpt::String::ReadBuf(mpt::String::spacePadded, trackName.name); } } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_digi.cpp0000644000175000017500000001267514644610543020476 00000000000000/* * Load_digi.cpp * ------------- * Purpose: Digi Booster module loader * Notes : Basically these are like ProTracker MODs with a few extra features such as more channels, longer samples and a few more effects. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN // DIGI File Header struct DIGIFileHeader { char signature[20]; char versionStr[4]; // Supposed to be "V1.6" or similar, but other values like "TAP!" have been found as well. uint8be versionInt; // e.g. 0x16 = 1.6 uint8be numChannels; uint8be packEnable; char unknown[19]; uint8be lastPatIndex; uint8be lastOrdIndex; uint8be orders[128]; uint32be smpLength[31]; uint32be smpLoopStart[31]; uint32be smpLoopLength[31]; uint8be smpVolume[31]; uint8be smpFinetune[31]; }; MPT_BINARY_STRUCT(DIGIFileHeader, 610) static void ReadDIGIPatternEntry(FileReader &file, ModCommand &m) { const auto [command, param] = CSoundFile::ReadMODPatternEntry(file, m); CSoundFile::ConvertModCommand(m, command, param); if(m.command == CMD_MODCMDEX) { switch(m.param & 0xF0) { case 0x30: // E3x: Play sample backwards (E30 stops sample when it reaches the beginning, any other value plays it from the beginning including regular loop) // The play direction is also reset if a new note is played on the other channel linked to this channel. // The behaviour is rather broken when there is no note next to the ommand. m.command = CMD_DIGIREVERSESAMPLE; m.param &= 0x0F; break; case 0x40: // E40: Stop playing sample if(m.param == 0x40) { m.note = NOTE_NOTECUT; m.command = CMD_NONE; } break; case 0x80: // E8x: High sample offset m.command = CMD_S3MCMDEX; m.param = 0xA0 | (m.param & 0x0F); } } else if(m.command == CMD_PANNING8) { // 8xx "Robot" effect (not supported) m.command = CMD_NONE; } } static bool ValidateHeader(const DIGIFileHeader &fileHeader) { if(std::memcmp(fileHeader.signature, "DIGI Booster module\0", 20) || !fileHeader.numChannels || fileHeader.numChannels > 8 || fileHeader.lastOrdIndex > 127) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize) { DIGIFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadDIGI(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); DIGIFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } // Globals InitializeGlobals(MOD_TYPE_DIGI, fileHeader.numChannels); m_nSamples = 31; m_nSamplePreAmp = 256 / GetNumChannels(); m_modFormat.formatName = UL_("DigiBooster"); m_modFormat.type = UL_("digi"); m_modFormat.madeWithTracker = MPT_UFORMAT("Digi Booster {}.{}")(fileHeader.versionInt >> 4, fileHeader.versionInt & 0x0F); m_modFormat.charset = mpt::Charset::Amiga_no_C1; ReadOrderFromArray(Order(), fileHeader.orders, fileHeader.lastOrdIndex + 1); // Read sample headers for(SAMPLEINDEX smp = 0; smp < 31; smp++) { ModSample &sample = Samples[smp + 1]; sample.Initialize(MOD_TYPE_MOD); sample.nLength = fileHeader.smpLength[smp]; sample.nLoopStart = fileHeader.smpLoopStart[smp]; sample.nLoopEnd = sample.nLoopStart + fileHeader.smpLoopLength[smp]; if(fileHeader.smpLoopLength[smp]) { sample.uFlags.set(CHN_LOOP); } sample.SanitizeLoops(); sample.nVolume = std::min(fileHeader.smpVolume[smp].get(), uint8(64)) * 4; sample.nFineTune = MOD2XMFineTune(fileHeader.smpFinetune[smp]); } // Read song + sample names file.ReadString(m_songName, 32); for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { file.ReadString(m_szNames[smp], 30); } if(loadFlags & loadPatternData) Patterns.ResizeArray(fileHeader.lastPatIndex + 1); for(PATTERNINDEX pat = 0; pat <= fileHeader.lastPatIndex; pat++) { FileReader patternChunk; if(fileHeader.packEnable) { patternChunk = file.ReadChunk(file.ReadUint16BE()); } else { patternChunk = file.ReadChunk(4 * 64 * GetNumChannels()); } if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { continue; } if(fileHeader.packEnable) { uint8 eventMask[64]; patternChunk.ReadArray(eventMask); // Compressed patterns are stored in row-major order... for(ROWINDEX row = 0; row < 64; row++) { uint8 bit = 0x80; for(ModCommand &m : Patterns[pat].GetRow(row)) { if(eventMask[row] & bit) ReadDIGIPatternEntry(patternChunk, m); bit >>= 1; } } } else { // ...but uncompressed patterns are stored in column-major order. WTF! for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { for(ROWINDEX row = 0; row < 64; row++) { ReadDIGIPatternEntry(patternChunk, *Patterns[pat].GetpModCommand(row, chn)); } } } } if(loadFlags & loadSampleData) { // Reading Samples const SampleIO sampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM); for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { sampleIO.ReadSample(Samples[smp], file); } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/OPL.h0000644000175000017500000001037314615257735016723 00000000000000/* * OPL.h * ----- * Purpose: Translate data coming from OpenMPT's mixer into OPL commands to be sent to the Opal emulator. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" OPENMPT_NAMESPACE_BEGIN class Opal; class OPL { public: enum OPLRegisters : uint8 { // Operators (combine with result of OperatorToRegister) AM_VIB = 0x20, // AM / VIB / EG / KSR / Multiple (0x20 to 0x35) KSL_LEVEL = 0x40, // KSL / Total level (0x40 to 0x55) ATTACK_DECAY = 0x60, // Attack rate / Decay rate (0x60 to 0x75) SUSTAIN_RELEASE = 0x80, // Sustain level / Release rate (0x80 to 0x95) WAVE_SELECT = 0xE0, // Wave select (0xE0 to 0xF5) // Channels (combine with result of ChannelToRegister) FNUM_LOW = 0xA0, // F-number low bits (0xA0 to 0xA8) KEYON_BLOCK = 0xB0, // F-number high bits / Key on / Block (octave) (0xB0 to 0xB8) FEEDBACK_CONNECTION = 0xC0, // Feedback / Connection (0xC0 to 0xC8) TREMOLO_VIBRATO_DEPTH = 0xBD, // Tremolo Depth / Vibrato Depth / Percussion Mode / BD/SD/TT/CY/HH Key-On }; enum OPLValues : uint8 { // AM_VIB TREMOLO_ON = 0x80, VIBRATO_ON = 0x40, SUSTAIN_ON = 0x20, KSR = 0x10, // Key scaling rate MULTIPLE_MASK = 0x0F, // Frequency multiplier // KSL_LEVEL KSL_MASK = 0xC0, // Envelope scaling bits TOTAL_LEVEL_MASK = 0x3F, // Strength (volume) of OP // ATTACK_DECAY ATTACK_MASK = 0xF0, DECAY_MASK = 0x0F, // SUSTAIN_RELEASE SUSTAIN_MASK = 0xF0, RELEASE_MASK = 0x0F, // KEYON_BLOCK KEYON_BIT = 0x20, // FEEDBACK_CONNECTION FEEDBACK_MASK = 0x0E, // Valid just for first OP of a voice CONNECTION_BIT = 0x01, VOICE_TO_LEFT = 0x10, VOICE_TO_RIGHT = 0x20, STEREO_BITS = VOICE_TO_LEFT | VOICE_TO_RIGHT, }; using Register = uint16; using Value = uint8; class IRegisterLogger { public: virtual void Port(CHANNELINDEX c, Register reg, Value value) = 0; virtual void MoveChannel(CHANNELINDEX from, CHANNELINDEX to) = 0; virtual ~IRegisterLogger() {} }; explicit OPL(uint32 sampleRate); explicit OPL(IRegisterLogger &logger); ~OPL(); void Initialize(uint32 sampleRate); void Mix(int32 *buffer, size_t count, uint32 volumeFactorQ16); void NoteOff(CHANNELINDEX c); void NoteCut(CHANNELINDEX c, bool unassign = true); void Frequency(CHANNELINDEX c, uint32 milliHertz, bool keyOff, bool beatingOscillators); void Volume(CHANNELINDEX c, uint8 vol, bool applyToModulator); int8 Pan(CHANNELINDEX c, int32 pan); void Patch(CHANNELINDEX c, const OPLPatch &patch); bool IsActive(CHANNELINDEX c) const { return GetVoice(c) != OPL_CHANNEL_INVALID; } void MoveChannel(CHANNELINDEX from, CHANNELINDEX to); void Reset(); // A list of all registers for channels and operators if oplCh == 0xFF, otherwise all registers for the given channel and its operators static std::vector AllVoiceRegisters(uint8 oplCh = 0xFF); // Returns voice for given register, or 0xFF if it's not a voice-specific register static uint8 RegisterToVoice(Register reg); // Returns register without any voice offset, so as if it was triggering the first voice static Register StripVoiceFromRegister(Register reg); protected: static Register ChannelToRegister(uint8 oplCh); static Register OperatorToRegister(uint8 oplCh); static uint8 CalcVolume(uint8 trackerVol, uint8 kslVolume); uint8 GetVoice(CHANNELINDEX c) const; uint8 AllocateVoice(CHANNELINDEX c); void Port(CHANNELINDEX c, Register reg, Value value); enum { OPL_CHANNELS = 18, // 9 for OPL2 or 18 for OPL3 OPL_CHANNEL_CUT = 0x80, // Indicates that the channel has been cut and used as a hint to re-use the channel for the same tracker channel if possible OPL_CHANNEL_MASK = 0x7F, OPL_CHANNEL_INVALID = 0xFF, OPL_BASERATE = 49716, }; std::unique_ptr m_opl; IRegisterLogger *m_logger = nullptr; std::array m_KeyOnBlock; std::array m_OPLtoChan; std::array m_ChanToOPL; std::array m_Patches; bool m_isActive = false; }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ModChannel.cpp0000644000175000017500000001665414743273743020643 00000000000000/* * ModChannel.cpp * -------------- * Purpose: The ModChannel struct represents the state of one mixer channel. * ModChannelSettings represents the default settings of one pattern channel. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "ModChannel.h" #include "Sndfile.h" #include "tuning.h" OPENMPT_NAMESPACE_BEGIN void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel, ChannelFlags muteFlag) { // For "the ultimate beeper.mod" const ModSample *defaultSample = (sndFile.GetType() == MOD_TYPE_MOD && sndFile.GetSample(0).HasSampleData()) ? &sndFile.GetSample(0) : nullptr; if(resetMask & resetSetPosBasic) { // IT compatibility: Initial "last note memory" of channel is C-0 (so a lonely instrument number without note will play that note). // Test case: InitialNoteMemory.it nNote = nNewNote = (sndFile.m_playBehaviour[kITInitialNoteMemory] ? NOTE_MIN : NOTE_NONE); nArpeggioLastNote = lastMidiNoteWithoutArp = NOTE_NONE; nNewIns = nOldIns = 0; swapSampleIndex = 0; pModSample = defaultSample; pModInstrument = nullptr; nPortamentoDest = 0; nCommand = CMD_NONE; nPatternLoopCount = 0; nPatternLoop = 0; nFadeOutVol = 0; dwFlags.set(CHN_KEYOFF | CHN_NOTEFADE); dwOldFlags.reset(); autoSlide.Reset(); nInsVol = 64; nnaGeneration = 0; //IT compatibility 15. Retrigger if(sndFile.m_playBehaviour[kITRetrigger]) { nRetrigParam = 1; nRetrigCount = 0; } microTuning = 0; nTremorCount = 0; nEFxSpeed = 0; prevNoteOffset = 0; lastZxxParam = 0xFF; isFirstTick = false; triggerNote = false; isPreviewNote = false; isPaused = false; portaTargetReached = false; rowCommand.Clear(); mpt::reconstruct(synthState); } if(resetMask & resetSetPosAdvanced) { increment = SamplePosition(0); nPeriod = 0; position.Set(0); nLength = 0; nLoopStart = 0; nLoopEnd = 0; nROfs = nLOfs = 0; pModSample = defaultSample; pModInstrument = nullptr; nCutOff = 0x7F; nResonance = 0; nFilterMode = FilterMode::LowPass; rightVol = leftVol = 0; newRightVol = newLeftVol = 0; rightRamp = leftRamp = 0; nVolume = 0; // Needs to be 0 for SMP_NODEFAULTVOLUME flag nVibratoPos = nTremoloPos = nPanbrelloPos = 0; nOldHiOffset = 0; nLeftVU = nRightVU = 0; nOldExtraFinePortaUpDown = nOldFinePortaUpDown = nOldPortaDown = nOldPortaUp = 0; portamentoSlide = 0; nMasterChn = 0; // Custom tuning related m_ReCalculateFreqOnFirstTick = false; m_CalculateFreq = false; m_PortamentoFineSteps = 0; m_PortamentoTickSlide = 0; } if(resetMask & resetChannelSettings) { if(sourceChannel < sndFile.ChnSettings.size()) { dwFlags = sndFile.ChnSettings[sourceChannel].dwFlags; nPan = sndFile.ChnSettings[sourceChannel].nPan; nGlobalVol = sndFile.ChnSettings[sourceChannel].nVolume; if(dwFlags[CHN_MUTE]) { dwFlags.reset(CHN_MUTE); dwFlags.set(muteFlag); } } else { dwFlags.reset(); nPan = 128; nGlobalVol = 64; } nRestorePanOnNewNote = 0; nRestoreCutoffOnNewNote = 0; nRestoreResonanceOnNewNote = 0; } } void ModChannel::Stop() { nPeriod = 0; increment.Set(0); position.Set(0); nLeftVU = nRightVU = 0; nVolume = 0; pCurrentSample = nullptr; } void ModChannel::UpdateInstrumentVolume(const ModSample *smp, const ModInstrument *ins) { nInsVol = 64; if(smp != nullptr) nInsVol = static_cast(smp->nGlobalVol); if(ins != nullptr) nInsVol = static_cast((nInsVol * ins->nGlobalVol) / 64); } uint32 ModChannel::GetVSTVolume() const noexcept { return pModInstrument ? pModInstrument->nGlobalVol * 4 : nVolume; } ModCommand::NOTE ModChannel::GetPluginNote(bool ignoreArpeggio) const noexcept { if(nArpeggioLastNote != NOTE_NONE && !ignoreArpeggio) { // If an arpeggio is playing, this definitely the last playing note, which may be different from the arpeggio base note stored in nLastNote. return nArpeggioLastNote; } ModCommand::NOTE plugNote = nLastNote; if(pModInstrument != nullptr && plugNote >= NOTE_MIN && plugNote < (std::size(pModInstrument->NoteMap) + NOTE_MIN)) { plugNote = pModInstrument->NoteMap[plugNote - NOTE_MIN]; } return plugNote; } bool ModChannel::HasMIDIOutput() const noexcept { return pModInstrument != nullptr && pModInstrument->HasValidMIDIChannel(); } bool ModChannel::HasCustomTuning() const noexcept { return pModInstrument != nullptr && pModInstrument->pTuning != nullptr; } bool ModChannel::InSustainLoop() const noexcept { return (dwFlags & (CHN_LOOP | CHN_KEYOFF)) == CHN_LOOP && pModSample->uFlags[CHN_SUSTAINLOOP]; } void ModChannel::SetInstrumentPan(int32 pan, const CSoundFile &sndFile) { // IT compatibility: Instrument and sample panning does not override channel panning // Test case: PanResetInstr.it if(sndFile.m_playBehaviour[kITDoNotOverrideChannelPan]) { nRestorePanOnNewNote = static_cast(nPan + 1); if(dwFlags[CHN_SURROUND]) nRestorePanOnNewNote |= 0x8000; } nPan = pan; } void ModChannel::RestorePanAndFilter() { if(nRestorePanOnNewNote > 0) { nPan = (nRestorePanOnNewNote & 0x7FFF) - 1; if(nRestorePanOnNewNote & 0x8000) dwFlags.set(CHN_SURROUND); nRestorePanOnNewNote = 0; } if(nRestoreResonanceOnNewNote > 0) { nResonance = nRestoreResonanceOnNewNote - 1; nRestoreResonanceOnNewNote = 0; } if(nRestoreCutoffOnNewNote > 0) { nCutOff = nRestoreCutoffOnNewNote - 1; nRestoreCutoffOnNewNote = 0; } } void ModChannel::RecalcTuningFreq(Tuning::RATIOTYPE vibratoFactor, Tuning::NOTEINDEXTYPE arpeggioSteps, const CSoundFile &sndFile) { if(!HasCustomTuning()) return; ModCommand::NOTE note = ModCommand::IsNote(nNote) ? nNote : nLastNote; if(sndFile.m_playBehaviour[kITRealNoteMapping] && note >= NOTE_MIN && note <= NOTE_MAX) note = pModInstrument->NoteMap[note - NOTE_MIN]; nPeriod = mpt::saturate_round(static_cast(nC5Speed) * vibratoFactor * pModInstrument->pTuning->GetRatio(static_cast(note - NOTE_MIDDLEC + arpeggioSteps), nFineTune + m_PortamentoFineSteps) * (1 << FREQ_FRACBITS)); } // IT command S73-S7E void ModChannel::InstrumentControl(uint8 param, const CSoundFile &sndFile) { param &= 0x0F; switch(param) { case 0x3: nNNA = NewNoteAction::NoteCut; break; case 0x4: nNNA = NewNoteAction::Continue; break; case 0x5: nNNA = NewNoteAction::NoteOff; break; case 0x6: nNNA = NewNoteAction::NoteFade; break; case 0x7: VolEnv.flags.reset(ENV_ENABLED); break; case 0x8: VolEnv.flags.set(ENV_ENABLED); break; case 0x9: PanEnv.flags.reset(ENV_ENABLED); break; case 0xA: PanEnv.flags.set(ENV_ENABLED); break; case 0xB: PitchEnv.flags.reset(ENV_ENABLED); break; case 0xC: PitchEnv.flags.set(ENV_ENABLED); break; case 0xD: // S7D: Enable pitch envelope, force to play as pitch envelope case 0xE: // S7E: Enable pitch envelope, force to play as filter envelope if(sndFile.GetType() == MOD_TYPE_MPT) { PitchEnv.flags.set(ENV_ENABLED); PitchEnv.flags.set(ENV_FILTER, param != 0xD); } break; } } // Volume command :xx void ModChannel::PlayControl(uint8 param) { switch(param) { case 0: isPaused = true; break; case 1: isPaused = false; break; case 2: dwFlags.set(CHN_PINGPONGFLAG, false); break; case 3: dwFlags.set(CHN_PINGPONGFLAG, true); break; case 4: dwFlags.flip(CHN_PINGPONGFLAG); break; case 5: oldOffset = position.GetUInt(); break; case 6: position.Set(oldOffset); break; } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_fmt.cpp0000644000175000017500000001220314721715306020332 00000000000000/* * Load_fmt.cpp * ------------ * Purpose: Davey W Taylor's FM Tracker module loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct FMTChannelSetting { char name[8]; char settings[11]; }; MPT_BINARY_STRUCT(FMTChannelSetting, 19) struct FMTFileHeader { char magic[11]; // Includes format version number for simplicity char trackerName[20]; char songName[32]; FMTChannelSetting channels[8]; uint8 lastRow; uint8 lastOrder; uint8 lastPattern; }; MPT_BINARY_STRUCT(FMTFileHeader, 218) static uint64 GetHeaderMinimumAdditionalSize(const FMTFileHeader &fileHeader) { // Order list + pattern delays, pattern mapping + at least one byte per channel return (fileHeader.lastOrder + 1u) * 2u + (fileHeader.lastPattern + 1u) * 9u; } static bool ValidateHeader(const FMTFileHeader &fileHeader) { if(memcmp(fileHeader.magic, "FMTracker\x01\x01", 11)) return false; for(const auto &channel : fileHeader.channels) { // Reject anything that resembles OPL3 if((channel.settings[8] & 0xFC) || (channel.settings[9] & 0xFC) || (channel.settings[10] & 0xF0)) return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderFMT(MemoryFileReader file, const uint64 *pfilesize) { FMTFileHeader fileHeader; if(!file.Read(fileHeader)) return ProbeWantMoreData; if(!ValidateHeader(fileHeader)) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadFMT(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); FMTFileHeader fileHeader; if(!file.Read(fileHeader)) return false; if(!ValidateHeader(fileHeader)) return false; if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_S3M, 8); m_nSamples = 8; Order().SetDefaultTempo(TEMPO(45.5)); // 18.2 Hz timer m_playBehaviour.set(kOPLNoteStopWith0Hz); m_SongFlags.set(SONG_IMPORTED | SONG_FORMAT_NO_VOLCOL); m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songName); for(CHANNELINDEX chn = 0; chn < 8; chn++) { const auto name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.channels[chn].name); ChnSettings[chn].szName = name; ModSample &mptSmp = Samples[chn + 1]; mptSmp.Initialize(MOD_TYPE_S3M); OPLPatch patch{{}}; memcpy(patch.data(), fileHeader.channels[chn].settings, 11); mptSmp.SetAdlib(true, patch); mptSmp.nC5Speed = 8215; m_szNames[chn + 1] = name; } const ORDERINDEX numOrders = fileHeader.lastOrder + 1u; ReadOrderFromFile(Order(), file, numOrders); std::vector delays; file.ReadVector(delays, numOrders); for(uint8 delay : delays) { if(delay < 1 || delay > 8) return false; } Order().SetDefaultSpeed(delays[0]); const PATTERNINDEX numPatterns = fileHeader.lastPattern + 1u; const ROWINDEX numRows = fileHeader.lastRow + 1u; std::vector patternMap; file.ReadVector(patternMap, numPatterns); Patterns.ResizeArray(numPatterns); for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(patternMap[pat], numRows)) break; auto &pattern = Patterns[patternMap[pat]]; for(CHANNELINDEX chn = 0; chn < 8; chn++) { for(ROWINDEX row = 0; row < pattern.GetNumRows(); row++) { uint8 data = file.ReadUint8(); if(data & 0x80) { row += data & 0x7F; } else { ModCommand &m = *pattern.GetpModCommand(row, chn); if(data == 1) { m.note = NOTE_NOTECUT; } else if(data >= 2 && data <= 97) { m.note = data + NOTE_MIN + 11u; m.instr = static_cast(chn + 1u); } } } } } // Write song speed to patterns... due to a quirk in the original playback routine // (delays is applied before notes are triggered, not afterwards), a pattern's delay // already applies to the last row of the previous pattern. // In case you wonder if anyone would ever notice: My own songs written with this tracker // actively work around this issue and will sound wrong if tempo is changed on the first row. for(ORDERINDEX ord = 0; ord < numOrders; ord++) { if(!Order().IsValidPat(ord)) { if(PATTERNINDEX pat = Patterns.InsertAny(numRows); pat != PATTERNINDEX_INVALID) Order()[ord] = pat; else continue; } auto m = Patterns[Order()[ord]].end() - 1; auto delay = delays[(ord + 1u) % numOrders]; if(m->param == delay) continue; if(m->command == CMD_SPEED) { PATTERNINDEX newPat = Order().EnsureUnique(ord); if(newPat != PATTERNINDEX_INVALID) m = Patterns[newPat].end() - 1; } m->command = CMD_SPEED; m->param = delay; } m_modFormat.formatName = UL_("FM Tracker"); m_modFormat.type = UL_("fmt"); m_modFormat.madeWithTracker = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.trackerName)); m_modFormat.charset = mpt::Charset::CP437; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/modsmp_ctrl.h0000644000175000017500000000336614462772602020613 00000000000000/* * modsmp_ctrl.h * ------------- * Purpose: Basic sample editing code * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" OPENMPT_NAMESPACE_BEGIN class CSoundFile; struct ModSample; struct ModChannel; namespace ctrlSmp { // Reverse sample data bool ReverseSample(ModSample &smp, SmpLength start, SmpLength end, CSoundFile &sndFile); // Invert sample data (flip by 180 degrees) bool InvertSample(ModSample &smp, SmpLength start, SmpLength end, CSoundFile &sndFile); // Crossfade sample data to create smooth loops bool XFadeSample(ModSample &smp, SmpLength fadeLength, int fadeLaw, bool afterloopFade, bool useSustainLoop, CSoundFile &sndFile); enum StereoToMonoMode { mixChannels, onlyLeft, onlyRight, splitSample, }; // Convert a sample with any number of channels to mono bool ConvertToMono(ModSample &smp, CSoundFile &sndFile, StereoToMonoMode conversionMode); // Converts a stereo sample into two mono samples. Source sample will not be deleted. // Either of the two target samples may be identical to the source sample. bool SplitStereo(const ModSample &source, ModSample &left, ModSample &right, CSoundFile &sndFile); // Convert a mono sample to stereo bool ConvertToStereo(ModSample &smp, CSoundFile &sndFile); } // Namespace ctrlSmp namespace ctrlChn { // Replaces sample from sound channels by given sample. void ReplaceSample( CSoundFile &sndFile, const ModSample &sample, const void * const pNewSample, const SmpLength newLength, FlagSet setFlags, FlagSet resetFlags); } // namespace ctrlChn OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/load_j2b.cpp0000644000175000017500000006734514705542154020303 00000000000000/* * load_j2b.cpp * ------------ * Purpose: RIFF AM and RIFF AMFF (Galaxy Sound System) module loader * Notes : J2B is a compressed variant of RIFF AM and RIFF AMFF files used in Jazz Jackrabbit 2. * It seems like no other game used the AM(FF) format. * RIFF AM is the newer version of the format, generally following the RIFF "standard" closely. * Authors: Johannes Schultz (OpenMPT port, reverse engineering + loader implementation of the instrument format) * Largely based on the J2B loader of kode54's DUMB fork * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "mpt/io/base.hpp" #if defined(MPT_WITH_ZLIB) #include #elif defined(MPT_WITH_MINIZ) #include #endif #ifdef MPT_ALL_LOGGING #define J2B_LOG #endif OPENMPT_NAMESPACE_BEGIN // First off, a nice vibrato translation LUT. static constexpr VibratoType j2bAutoVibratoTrans[] = { VIB_SINE, VIB_SQUARE, VIB_RAMP_UP, VIB_RAMP_DOWN, VIB_RANDOM, }; // header for compressed j2b files struct J2BFileHeader { // Magic Bytes // 32-Bit J2B header identifiers enum : uint32 { magicDEADBEAF = 0xAFBEADDEu, magicDEADBABE = 0xBEBAADDEu }; char signature[4]; // MUSE uint32le deadbeaf; // 0xDEADBEAF (AM) or 0xDEADBABE (AMFF) uint32le fileLength; // complete filesize uint32le crc32; // checksum of the compressed data block uint32le packedLength; // length of the compressed data block uint32le unpackedLength; // length of the decompressed module }; MPT_BINARY_STRUCT(J2BFileHeader, 24) // AM(FF) stuff struct AMFFRiffChunk { // 32-Bit chunk identifiers enum ChunkIdentifiers { idRIFF = MagicLE("RIFF"), idAMFF = MagicLE("AMFF"), idAM__ = MagicLE("AM "), idMAIN = MagicLE("MAIN"), idINIT = MagicLE("INIT"), idORDR = MagicLE("ORDR"), idPATT = MagicLE("PATT"), idINST = MagicLE("INST"), idSAMP = MagicLE("SAMP"), idAI__ = MagicLE("AI "), idAS__ = MagicLE("AS "), }; uint32le id; // See ChunkIdentifiers uint32le length; // Chunk size without header size_t GetLength() const { return length; } ChunkIdentifiers GetID() const { return static_cast(id.get()); } }; MPT_BINARY_STRUCT(AMFFRiffChunk, 8) // This header is used for both AM's "INIT" as well as AMFF's "MAIN" chunk struct AMFFMainChunk { // Main Chunk flags enum MainFlags { amigaSlides = 0x01, }; char songname[64]; uint8le flags; uint8le channels; uint8le speed; uint8le tempo; uint16le minPeriod; // 16x Amiga periods, but we should ignore them - otherwise some high notes in Medivo.j2b won't sound correct. uint16le maxPeriod; // Ditto uint8le globalvolume; }; MPT_BINARY_STRUCT(AMFFMainChunk, 73) // AMFF instrument envelope (old format) struct AMFFEnvelope { // Envelope flags (also used for RIFF AM) enum EnvelopeFlags { envEnabled = 0x01, envSustain = 0x02, envLoop = 0x04, }; struct EnvPoint { uint16le tick; uint8le value; // 0...64 }; uint8le envFlags; // high nibble = pan env flags, low nibble = vol env flags (both nibbles work the same way) uint8le envNumPoints; // high nibble = pan env length, low nibble = vol env length uint8le envSustainPoints; // you guessed it... high nibble = pan env sustain point, low nibble = vol env sustain point uint8le envLoopStarts; // I guess you know the pattern now. uint8le envLoopEnds; // same here. EnvPoint volEnv[10]; EnvPoint panEnv[10]; // Convert weird envelope data to OpenMPT's internal format. void ConvertEnvelope(uint8 flags, uint8 numPoints, uint8 sustainPoint, uint8 loopStart, uint8 loopEnd, const EnvPoint (&points)[10], InstrumentEnvelope &mptEnv) const { // The buggy mod2j2b converter will actually NOT limit this to 10 points if the envelope is longer. mptEnv.resize(std::min(numPoints, static_cast(10))); mptEnv.nSustainStart = mptEnv.nSustainEnd = sustainPoint; mptEnv.nLoopStart = loopStart; mptEnv.nLoopEnd = loopEnd; for(uint32 i = 0; i < mptEnv.size(); i++) { mptEnv[i].tick = points[i].tick >> 4; if(i == 0) mptEnv[0].tick = 0; else if(mptEnv[i].tick < mptEnv[i - 1].tick) mptEnv[i].tick = mptEnv[i - 1].tick + 1; mptEnv[i].value = Clamp(points[i].value, 0, 64); } mptEnv.dwFlags.set(ENV_ENABLED, (flags & AMFFEnvelope::envEnabled) != 0); mptEnv.dwFlags.set(ENV_SUSTAIN, (flags & AMFFEnvelope::envSustain) && mptEnv.nSustainStart <= mptEnv.size()); mptEnv.dwFlags.set(ENV_LOOP, (flags & AMFFEnvelope::envLoop) && mptEnv.nLoopStart <= mptEnv.nLoopEnd && mptEnv.nLoopStart <= mptEnv.size()); } void ConvertToMPT(ModInstrument &mptIns) const { // interleaved envelope data... meh. gotta split it up here and decode it separately. // note: mod2j2b is BUGGY and always writes ($original_num_points & 0x0F) in the header, // but just has room for 10 envelope points. That means that long (>= 16 points) // envelopes are cut off, and envelopes have to be trimmed to 10 points, even if // the header claims that they are longer. // For XM files the number of points also appears to be off by one, // but luckily there are no official J2Bs using envelopes anyway. ConvertEnvelope(envFlags & 0x0F, envNumPoints & 0x0F, envSustainPoints & 0x0F, envLoopStarts & 0x0F, envLoopEnds & 0x0F, volEnv, mptIns.VolEnv); ConvertEnvelope(envFlags >> 4, envNumPoints >> 4, envSustainPoints >> 4, envLoopStarts >> 4, envLoopEnds >> 4, panEnv, mptIns.PanEnv); } }; MPT_BINARY_STRUCT(AMFFEnvelope::EnvPoint, 3) MPT_BINARY_STRUCT(AMFFEnvelope, 65) // AMFF instrument header (old format) struct AMFFInstrumentHeader { uint8le unknown; // 0x00 uint8le index; // actual instrument number char name[28]; uint8le numSamples; uint8le sampleMap[120]; uint8le vibratoType; uint16le vibratoSweep; uint16le vibratoDepth; uint16le vibratoRate; AMFFEnvelope envelopes; uint16le fadeout; // Convert instrument data to OpenMPT's internal format. void ConvertToMPT(ModInstrument &mptIns, SAMPLEINDEX baseSample) { mptIns.name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, name); static_assert(mpt::array_size::size <= mpt::array_size::size); for(size_t i = 0; i < std::size(sampleMap); i++) { mptIns.Keyboard[i] = static_cast(sampleMap[i] + baseSample + 1); } mptIns.nFadeOut = fadeout << 5; envelopes.ConvertToMPT(mptIns); } }; MPT_BINARY_STRUCT(AMFFInstrumentHeader, 225) // AMFF sample header (old format) struct AMFFSampleHeader { // Sample flags (also used for RIFF AM) enum SampleFlags { smp16Bit = 0x04, smpLoop = 0x08, smpPingPong = 0x10, smpPanning = 0x20, smpExists = 0x80, // some flags are still missing... what is e.g. 0x8000? }; uint32le id; // "SAMP" uint32le chunkSize; // header + sample size char name[28]; uint8le pan; uint8le volume; uint16le flags; uint32le length; uint32le loopStart; uint32le loopEnd; uint32le sampleRate; uint32le reserved1; uint32le reserved2; // Convert sample header to OpenMPT's internal format. void ConvertToMPT(AMFFInstrumentHeader &instrHeader, ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.nPan = pan * 4; mptSmp.nVolume = volume * 4; mptSmp.nGlobalVol = 64; mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; mptSmp.nC5Speed = sampleRate; if(instrHeader.vibratoType < std::size(j2bAutoVibratoTrans)) mptSmp.nVibType = j2bAutoVibratoTrans[instrHeader.vibratoType]; mptSmp.nVibSweep = static_cast(instrHeader.vibratoSweep); mptSmp.nVibRate = static_cast(instrHeader.vibratoRate / 16); mptSmp.nVibDepth = static_cast(instrHeader.vibratoDepth / 4); if((mptSmp.nVibRate | mptSmp.nVibDepth) != 0) { // Convert XM-style vibrato sweep to IT mptSmp.nVibSweep = 255 - mptSmp.nVibSweep; } if(flags & AMFFSampleHeader::smp16Bit) mptSmp.uFlags.set(CHN_16BIT); if(flags & AMFFSampleHeader::smpLoop) mptSmp.uFlags.set(CHN_LOOP); if(flags & AMFFSampleHeader::smpPingPong) mptSmp.uFlags.set(CHN_PINGPONGLOOP); if(flags & AMFFSampleHeader::smpPanning) mptSmp.uFlags.set(CHN_PANNING); } // Retrieve the internal sample format flags for this sample. SampleIO GetSampleFormat() const { return SampleIO( (flags & AMFFSampleHeader::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM); } }; MPT_BINARY_STRUCT(AMFFSampleHeader, 64) // AM instrument envelope (new format) struct AMEnvelope { struct EnvPoint { uint16le tick; int16le value; }; uint16le flags; uint8le numPoints; // actually, it's num. points - 1, and 0xFF if there is no envelope uint8le sustainPoint; uint8le loopStart; uint8le loopEnd; EnvPoint values[10]; uint16le fadeout; // why is this here? it's only needed for the volume envelope... // Convert envelope data to OpenMPT's internal format. void ConvertToMPT(InstrumentEnvelope &mptEnv, EnvelopeType envType) const { if(numPoints == 0xFF || numPoints == 0) return; mptEnv.resize(std::min(numPoints + 1, 10)); mptEnv.nSustainStart = mptEnv.nSustainEnd = sustainPoint; mptEnv.nLoopStart = loopStart; mptEnv.nLoopEnd = loopEnd; int32 scale = 0, offset = 0; switch(envType) { case ENV_VOLUME: // 0....32767 default: scale = 32767 / ENVELOPE_MAX; break; case ENV_PITCH: // -4096....4096 scale = 8192 / ENVELOPE_MAX; offset = 4096; break; case ENV_PANNING: // -32768...32767 scale = 65536 / ENVELOPE_MAX; offset = 32768; break; } for(uint32 i = 0; i < mptEnv.size(); i++) { mptEnv[i].tick = values[i].tick >> 4; if(i == 0) mptEnv[i].tick = 0; else if(mptEnv[i].tick < mptEnv[i - 1].tick) mptEnv[i].tick = mptEnv[i - 1].tick + 1; int32 val = values[i].value + offset; val = (val + scale / 2) / scale; mptEnv[i].value = static_cast(std::clamp(val, int32(ENVELOPE_MIN), int32(ENVELOPE_MAX))); } mptEnv.dwFlags.set(ENV_ENABLED, (flags & AMFFEnvelope::envEnabled) != 0); mptEnv.dwFlags.set(ENV_SUSTAIN, (flags & AMFFEnvelope::envSustain) && mptEnv.nSustainStart <= mptEnv.size()); mptEnv.dwFlags.set(ENV_LOOP, (flags & AMFFEnvelope::envLoop) && mptEnv.nLoopStart <= mptEnv.nLoopEnd && mptEnv.nLoopStart <= mptEnv.size()); } }; MPT_BINARY_STRUCT(AMEnvelope, 48) // AM instrument header (new format) struct AMInstrumentHeader { uint32le headSize; // Header size (i.e. the size of this struct) uint8le unknown1; // 0x00 uint8le index; // Actual instrument number char name[32]; uint8le sampleMap[128]; uint8le vibratoType; uint16le vibratoSweep; uint16le vibratoDepth; uint16le vibratoRate; uint8le unknown2[7]; AMEnvelope volEnv; AMEnvelope pitchEnv; AMEnvelope panEnv; uint16le numSamples; // Convert instrument data to OpenMPT's internal format. void ConvertToMPT(ModInstrument &mptIns, SAMPLEINDEX baseSample) { mptIns.name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, name); static_assert(mpt::array_size::size <= mpt::array_size::size); for(uint8 i = 0; i < std::size(sampleMap); i++) { mptIns.Keyboard[i] = static_cast(sampleMap[i] + baseSample + 1); } mptIns.nFadeOut = volEnv.fadeout << 5; volEnv.ConvertToMPT(mptIns.VolEnv, ENV_VOLUME); pitchEnv.ConvertToMPT(mptIns.PitchEnv, ENV_PITCH); panEnv.ConvertToMPT(mptIns.PanEnv, ENV_PANNING); if(numSamples == 0) { MemsetZero(mptIns.Keyboard); } } }; MPT_BINARY_STRUCT(AMInstrumentHeader, 326) // AM sample header (new format) struct AMSampleHeader { uint32le headSize; // Header size (i.e. the size of this struct), apparently not including headSize. char name[32]; uint16le pan; uint16le volume; uint16le flags; uint16le unknown; // 0x0000 / 0x0080? uint32le length; uint32le loopStart; uint32le loopEnd; uint32le sampleRate; // Convert sample header to OpenMPT's internal format. void ConvertToMPT(AMInstrumentHeader &instrHeader, ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.nPan = static_cast(std::min(pan.get(), uint16(32767)) * 256 / 32767); mptSmp.nVolume = static_cast(std::min(volume.get(), uint16(32767)) * 256 / 32767); mptSmp.nGlobalVol = 64; mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; mptSmp.nC5Speed = sampleRate; if(instrHeader.vibratoType < std::size(j2bAutoVibratoTrans)) mptSmp.nVibType = j2bAutoVibratoTrans[instrHeader.vibratoType]; mptSmp.nVibSweep = static_cast(instrHeader.vibratoSweep); mptSmp.nVibRate = static_cast(instrHeader.vibratoRate / 16); mptSmp.nVibDepth = static_cast(instrHeader.vibratoDepth / 4); if((mptSmp.nVibRate | mptSmp.nVibDepth) != 0) { // Convert XM-style vibrato sweep to IT mptSmp.nVibSweep = 255 - mptSmp.nVibSweep; } if(flags & AMFFSampleHeader::smp16Bit) mptSmp.uFlags.set(CHN_16BIT); if(flags & AMFFSampleHeader::smpLoop) mptSmp.uFlags.set(CHN_LOOP); if(flags & AMFFSampleHeader::smpPingPong) mptSmp.uFlags.set(CHN_PINGPONGLOOP); if(flags & AMFFSampleHeader::smpPanning) mptSmp.uFlags.set(CHN_PANNING); } // Retrieve the internal sample format flags for this sample. SampleIO GetSampleFormat() const { return SampleIO( (flags & AMFFSampleHeader::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM); } }; MPT_BINARY_STRUCT(AMSampleHeader, 60) // Convert RIFF AM(FF) pattern data to MPT pattern data. static bool ConvertAMPattern(FileReader chunk, PATTERNINDEX pat, bool isAM, CSoundFile &sndFile) { // Effect translation LUT static constexpr EffectCommand amEffTrans[] = { CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, CMD_PANNING8, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_POSITIONJUMP, CMD_VOLUME, CMD_PATTERNBREAK, CMD_MODCMDEX, CMD_TEMPO, CMD_GLOBALVOLUME, CMD_GLOBALVOLSLIDE, CMD_KEYOFF, CMD_SETENVPOSITION, CMD_CHANNELVOLUME, CMD_CHANNELVOLSLIDE, CMD_PANNINGSLIDE, CMD_RETRIG, CMD_TREMOR, CMD_XFINEPORTAUPDOWN, }; enum { rowDone = 0x00, // Advance to next row channelMask = 0x1F, // Mask for retrieving channel information volFlag = 0x20, // Volume effect present noteFlag = 0x40, // Note + instr present effectFlag = 0x80, // Effect information present dataFlag = 0xE0, // Channel data present }; if(chunk.NoBytesLeft()) return false; const ROWINDEX numRows = std::min(static_cast(chunk.ReadUint8() + 1), MAX_PATTERN_ROWS); if(!sndFile.Patterns.Insert(pat, numRows)) return false; const CHANNELINDEX lastChannel = sndFile.GetNumChannels() - 1; ROWINDEX row = 0; while(row < numRows && chunk.CanRead(1)) { const uint8 flags = chunk.ReadUint8(); if(flags == rowDone) { row++; continue; } if(!(flags & dataFlag)) continue; ModCommand &m = *sndFile.Patterns[pat].GetpModCommand(row, std::min(static_cast(flags & channelMask), lastChannel)); if(flags & effectFlag) // effect { const auto [param, command] = chunk.ReadArray(); if(command < std::size(amEffTrans)) { m.SetEffectCommand(amEffTrans[command], param); } else { #ifdef J2B_LOG MPT_LOG_GLOBAL(LogDebug, "J2B", MPT_UFORMAT("J2B: Unknown command: 0x{}, param 0x{}")(mpt::ufmt::HEX0<2>(command), mpt::ufmt::HEX0<2>(m.param))); #endif m.command = CMD_NONE; } // Handling special commands switch(m.command) { case CMD_ARPEGGIO: if(m.param == 0) m.command = CMD_NONE; break; case CMD_VOLUME: if(m.volcmd == VOLCMD_NONE && !(flags & volFlag)) { m.SetVolumeCommand(VOLCMD_VOLUME, Clamp(m.param, uint8(0), uint8(64))); m.command = CMD_NONE; } break; case CMD_TONEPORTAVOL: case CMD_VIBRATOVOL: case CMD_VOLUMESLIDE: case CMD_GLOBALVOLSLIDE: case CMD_PANNINGSLIDE: if(m.param & 0xF0) m.param &= 0xF0; break; case CMD_PANNING8: if(m.param <= 0x80) m.param = mpt::saturate_cast(m.param * 2); else if(m.param == 0xA4) m.SetEffectCommand(CMD_S3MCMDEX, 0x91u); break; case CMD_PATTERNBREAK: m.param = static_cast(((m.param >> 4) * 10u) + (m.param & 0x0Fu)); break; case CMD_MODCMDEX: m.ExtendedMODtoS3MEffect(); break; case CMD_TEMPO: if(m.param <= 0x1F) m.command = CMD_SPEED; break; case CMD_XFINEPORTAUPDOWN: switch(m.param & 0xF0) { case 0x10: m.command = CMD_PORTAMENTOUP; break; case 0x20: m.command = CMD_PORTAMENTODOWN; break; } m.param = (m.param & 0x0F) | 0xE0; break; default: break; } } if(flags & noteFlag) // note + ins { const auto [instr, note] = chunk.ReadArray(); m.instr = instr; m.note = note; if(m.note == 0x80) m.note = NOTE_KEYOFF; else if(m.note > 0x80) m.note = NOTE_FADE; // I guess the support for IT "note fade" notes was not intended in mod2j2b, but hey, it works! :-D } if(flags & volFlag) // volume { m.SetVolumeCommand(VOLCMD_VOLUME, chunk.ReadUint8()); if(isAM) m.vol = static_cast(m.vol * 64u / 127u); } } return true; } struct AMFFRiffChunkFormat { uint32le format; }; MPT_BINARY_STRUCT(AMFFRiffChunkFormat, 4) static bool ValidateHeader(const AMFFRiffChunk &fileHeader) { if(fileHeader.id != AMFFRiffChunk::idRIFF) { return false; } if(fileHeader.GetLength() < 8 + sizeof(AMFFMainChunk)) { return false; } return true; } static bool ValidateHeader(const AMFFRiffChunkFormat &formatHeader) { if(formatHeader.format != AMFFRiffChunk::idAMFF && formatHeader.format != AMFFRiffChunk::idAM__) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize) { AMFFRiffChunk fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } AMFFRiffChunkFormat formatHeader; if(!file.ReadStruct(formatHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(formatHeader)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); AMFFRiffChunk fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } AMFFRiffChunkFormat formatHeader; if(!file.ReadStruct(formatHeader)) { return false; } if(!ValidateHeader(formatHeader)) { return false; } bool isAM; // false: AMFF, true: AM uint32 format = formatHeader.format; if(format == AMFFRiffChunk::idAMFF) isAM = false; // "AMFF" else if(format == AMFFRiffChunk::idAM__) isAM = true; // "AM " else return false; ChunkReader chunkFile(file); // The main chunk is almost identical in both formats but uses different chunk IDs. // "MAIN" - Song info (AMFF) // "INIT" - Song info (AM) AMFFRiffChunk::ChunkIdentifiers mainChunkID = isAM ? AMFFRiffChunk::idINIT : AMFFRiffChunk::idMAIN; // RIFF AM has a padding byte so that all chunks have an even size. ChunkReader::ChunkList chunks; if(loadFlags == onlyVerifyHeader) chunks = chunkFile.ReadChunksUntil(isAM ? 2 : 1, mainChunkID); else chunks = chunkFile.ReadChunks(isAM ? 2 : 1); FileReader chunkMain(chunks.GetChunk(mainChunkID)); AMFFMainChunk mainChunk; if(!chunkMain.IsValid() || !chunkMain.ReadStruct(mainChunk) || mainChunk.channels < 1 || !chunkMain.CanRead(mainChunk.channels)) { return false; } else if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_J2B, std::min(static_cast(mainChunk.channels), static_cast(MAX_BASECHANNELS))); m_SongFlags = SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX; m_SongFlags.set(SONG_LINEARSLIDES, !(mainChunk.flags & AMFFMainChunk::amigaSlides)); Order().SetDefaultSpeed(mainChunk.speed); Order().SetDefaultTempoInt(mainChunk.tempo); m_nDefaultGlobalVolume = mainChunk.globalvolume * 2; m_modFormat.formatName = isAM ? UL_("Galaxy Sound System (new version)") : UL_("Galaxy Sound System (old version)"); m_modFormat.type = UL_("j2b"); m_modFormat.charset = mpt::Charset::CP437; m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, mainChunk.songname); // It seems like there's no way to differentiate between // Muted and Surround channels (they're all 0xA0) - might // be a limitation in mod2j2b. for(auto &chn : ChnSettings) { uint8 pan = chunkMain.ReadUint8(); if(isAM) { if(pan > 128) chn.dwFlags = CHN_MUTE; else chn.nPan = pan * 2; } else { if(pan >= 128) chn.dwFlags = CHN_MUTE; else chn.nPan = static_cast(std::min(pan * 4, 256)); } } if(chunks.ChunkExists(AMFFRiffChunk::idORDR)) { // "ORDR" - Order list FileReader chunk(chunks.GetChunk(AMFFRiffChunk::idORDR)); uint8 numOrders = chunk.ReadUint8() + 1; ReadOrderFromFile(Order(), chunk, numOrders, 0xFF, 0xFE); } // "PATT" - Pattern data for one pattern if(loadFlags & loadPatternData) { PATTERNINDEX maxPattern = 0; auto pattChunks = chunks.GetAllChunks(AMFFRiffChunk::idPATT); Patterns.ResizeArray(static_cast(pattChunks.size())); for(auto chunk : pattChunks) { PATTERNINDEX pat = chunk.ReadUint8(); size_t patternSize = chunk.ReadUint32LE(); ConvertAMPattern(chunk.ReadChunk(patternSize), pat, isAM, *this); maxPattern = std::max(maxPattern, pat); } for(PATTERNINDEX pat = 0; pat < maxPattern; pat++) { if(!Patterns.IsValidPat(pat)) Patterns.Insert(pat, 64); } } if(!isAM) { // "INST" - Instrument (only in RIFF AMFF) auto instChunks = chunks.GetAllChunks(AMFFRiffChunk::idINST); for(auto chunk : instChunks) { AMFFInstrumentHeader instrHeader; if(!chunk.ReadStruct(instrHeader)) { continue; } const INSTRUMENTINDEX instr = instrHeader.index + 1; if(instr >= MAX_INSTRUMENTS) continue; ModInstrument *pIns = AllocateInstrument(instr); if(pIns == nullptr) { continue; } instrHeader.ConvertToMPT(*pIns, m_nSamples); // read sample sub-chunks - this is a rather "flat" format compared to RIFF AM and has no nested RIFF chunks. for(size_t samples = 0; samples < instrHeader.numSamples; samples++) { AMFFSampleHeader sampleHeader; if(!CanAddMoreSamples() || !chunk.ReadStruct(sampleHeader)) { continue; } const SAMPLEINDEX smp = ++m_nSamples; if(sampleHeader.id != AMFFRiffChunk::idSAMP) { continue; } m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name); sampleHeader.ConvertToMPT(instrHeader, Samples[smp]); if(loadFlags & loadSampleData) sampleHeader.GetSampleFormat().ReadSample(Samples[smp], chunk); else chunk.Skip(Samples[smp].GetSampleSizeInBytes()); } } } else { // "RIFF" - Instrument (only in RIFF AM) auto instChunks = chunks.GetAllChunks(AMFFRiffChunk::idRIFF); for(ChunkReader chunk : instChunks) { if(chunk.ReadUint32LE() != AMFFRiffChunk::idAI__) { continue; } AMFFRiffChunk instChunk; if(!chunk.ReadStruct(instChunk) || instChunk.id != AMFFRiffChunk::idINST) { continue; } AMInstrumentHeader instrHeader; if(!chunk.ReadStruct(instrHeader)) { continue; } MPT_ASSERT(instrHeader.headSize + 4 == sizeof(instrHeader)); const INSTRUMENTINDEX instr = instrHeader.index + 1; if(instr >= MAX_INSTRUMENTS) continue; ModInstrument *pIns = AllocateInstrument(instr); if(pIns == nullptr) { continue; } instrHeader.ConvertToMPT(*pIns, m_nSamples); // Read sample sub-chunks (RIFF nesting ftw) auto sampleChunks = chunk.ReadChunks(2).GetAllChunks(AMFFRiffChunk::idRIFF); MPT_ASSERT(sampleChunks.size() == instrHeader.numSamples); for(auto sampleChunk : sampleChunks) { if(sampleChunk.ReadUint32LE() != AMFFRiffChunk::idAS__ || !CanAddMoreSamples()) { continue; } // Don't read more samples than the instrument header claims to have. if((instrHeader.numSamples--) == 0) { break; } const SAMPLEINDEX smp = ++m_nSamples; // Aaand even more nested chunks! Great, innit? AMFFRiffChunk sampleHeaderChunk; if(!sampleChunk.ReadStruct(sampleHeaderChunk) || sampleHeaderChunk.id != AMFFRiffChunk::idSAMP) { break; } FileReader sampleFileChunk = sampleChunk.ReadChunk(sampleHeaderChunk.length); AMSampleHeader sampleHeader; if(!sampleFileChunk.ReadStruct(sampleHeader)) { break; } m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name); sampleHeader.ConvertToMPT(instrHeader, Samples[smp]); if(loadFlags & loadSampleData) { sampleFileChunk.Seek(sampleHeader.headSize + 4); sampleHeader.GetSampleFormat().ReadSample(Samples[smp], sampleFileChunk); } } } } return true; } static bool ValidateHeader(const J2BFileHeader &fileHeader) { if(std::memcmp(fileHeader.signature, "MUSE", 4) || (fileHeader.deadbeaf != J2BFileHeader::magicDEADBEAF // 0xDEADBEAF (RIFF AM) && fileHeader.deadbeaf != J2BFileHeader::magicDEADBABE) // 0xDEADBABE (RIFF AMFF) ) { return false; } if(fileHeader.packedLength == 0) { return false; } if(fileHeader.fileLength != fileHeader.packedLength + sizeof(J2BFileHeader)) { return false; } return true; } static bool ValidateHeaderFileSize(const J2BFileHeader &fileHeader, uint64 filesize) { if(filesize != fileHeader.fileLength) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize) { J2BFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } if(pfilesize) { if(!ValidateHeaderFileSize(fileHeader, *pfilesize)) { return ProbeFailure; } } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags) { #if !defined(MPT_WITH_ZLIB) && !defined(MPT_WITH_MINIZ) MPT_UNREFERENCED_PARAMETER(file); MPT_UNREFERENCED_PARAMETER(loadFlags); return false; #else file.Rewind(); J2BFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(fileHeader.fileLength != file.GetLength() || fileHeader.packedLength != file.BytesLeft() ) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } // Header is valid, now unpack the RIFF AM file using inflate z_stream strm{}; if(inflateInit(&strm) != Z_OK) return false; uint32 remainRead = fileHeader.packedLength, remainWrite = fileHeader.unpackedLength, totalWritten = 0; uint32 crc = 0; std::vector amFileData(remainWrite); int retVal = Z_OK; while(remainRead && remainWrite && retVal != Z_STREAM_END) { Bytef buffer[mpt::IO::BUFFERSIZE_TINY]; uint32 readSize = std::min(static_cast(sizeof(buffer)), remainRead); file.ReadRaw(mpt::span(buffer, readSize)); crc = static_cast(crc32(crc, buffer, readSize)); strm.avail_in = readSize; strm.next_in = buffer; do { strm.avail_out = remainWrite; strm.next_out = amFileData.data() + totalWritten; retVal = inflate(&strm, Z_NO_FLUSH); uint32 written = remainWrite - strm.avail_out; totalWritten += written; remainWrite -= written; } while(remainWrite && strm.avail_out == 0); remainRead -= readSize; } inflateEnd(&strm); bool result = false; #ifndef MPT_BUILD_FUZZER if(fileHeader.crc32 == crc && !remainWrite && retVal == Z_STREAM_END) #endif { // Success, now load the RIFF AM(FF) module. FileReader amFile(mpt::as_span(amFileData)); result = ReadAM(amFile, loadFlags); } return result; #endif } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Dlsbank.h0000644000175000017500000001274114655206020017631 00000000000000/* * DLSBank.h * --------- * Purpose: Sound bank loading. * Notes : Supported sound bank types: DLS (including embedded DLS in MSS & RMI), SF2 * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" OPENMPT_NAMESPACE_BEGIN #ifdef MODPLUG_TRACKER class CSoundFile; struct InstrumentEnvelope; struct DLSREGION { uint32 ulLoopStart = 0; uint32 ulLoopEnd = 0; uint32 uPercEnv = 0; uint16 nWaveLink = 0; uint16 usVolume = 256; // 0..256 uint16 fuOptions = 0; // flags + key group int16 sFineTune = 0; // +128 = +1 semitone int16 panning = -1; // -1= unset (DLS), otherwise 0...256 uint8 uKeyMin = 0; uint8 uKeyMax = 0; uint8 uUnityNote = 0xFF; uint8 tuning = 100; constexpr bool IsDummy() const noexcept { return uKeyMin == 0xFF || nWaveLink == Util::MaxValueOfType(nWaveLink); } }; struct DLSENVELOPE { struct Envelope { uint16 delay = 0; // Delay Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] uint16 attack = 0; // Attack Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] uint16 hold = 0; // Hold Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] uint16 decay = 0; // Decay Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] uint16 release = 0; // Release Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] uint8 sustainLevel = 128; // Sustain Level: 0-128, 128=100% uint32 ConvertToMPT(InstrumentEnvelope &mptEnv, const EnvelopeType envType, const float tempoScale, const int16 valueScale) const; }; Envelope volumeEnv, pitchEnv; int16 pitchEnvDepth = 0; // Cents uint8 defaultPan = 128; }; // Special Bank bits #define F_INSTRUMENT_DRUMS 0x80000000 struct DLSINSTRUMENT { uint32 ulBank = 0, ulInstrument = 0; uint32 nMelodicEnv = 0; std::vector Regions; char szName[32]; // SF2 stuff (DO NOT USE! -> used internally by the SF2 loader) uint16 wPresetBagNdx = 0, wPresetBagNum = 0; constexpr bool operator<(const DLSINSTRUMENT &other) const { return std::tie(ulBank, ulInstrument) < std::tie(other.ulBank, other.ulInstrument); } }; struct DLSSAMPLEEX { char szName[20]; uint32 dwLen; uint32 dwStartloop; uint32 dwEndloop; uint32 dwSampleRate; uint8 byOriginalPitch; int8 chPitchCorrection; bool compressed = false; }; #define SOUNDBANK_TYPE_INVALID 0 #define SOUNDBANK_TYPE_DLS 0x01 #define SOUNDBANK_TYPE_SF2 0x02 struct SOUNDBANKINFO { std::string szBankName, szCopyRight, szComments, szEngineer, szSoftware, // ISFT: Software szDescription; // ISBJ: Subject }; struct IFFCHUNK; struct SF2LoaderInfo; class CDLSBank { protected: SOUNDBANKINFO m_BankInfo; mpt::PathString m_szFileName; size_t m_dwWavePoolOffset; uint32 m_nType; // DLS Information uint32 m_nMaxWaveLink; uint32 m_sf2version = 0; std::vector m_WaveForms; std::vector m_Instruments; std::vector m_SamplesEx; std::vector m_Envelopes; public: CDLSBank(); bool operator==(const CDLSBank &other) const noexcept { return !mpt::PathCompareNoCase(m_szFileName, other.m_szFileName); } static bool IsDLSBank(const mpt::PathString &filename); static bool IsDLSBank(FileReader file); static uint32 MakeMelodicCode(uint32 bank, uint32 instr) { return ((bank << 16) | (instr));} static uint32 MakeDrumCode(uint32 rgn, uint32 instr) { return (0x80000000 | (rgn << 16) | (instr));} public: bool Open(const mpt::PathString &filename); bool Open(FileReader file); mpt::PathString GetFileName() const { return m_szFileName; } uint32 GetBankType() const { return m_nType; } const SOUNDBANKINFO &GetBankInfo() const { return m_BankInfo; } public: uint32 GetNumInstruments() const { return static_cast(m_Instruments.size()); } uint32 GetNumSamples() const { return static_cast(m_WaveForms.size()); } const DLSINSTRUMENT *GetInstrument(uint32 iIns) const { return iIns < m_Instruments.size() ? &m_Instruments[iIns] : nullptr; } [[nodiscard]] const DLSINSTRUMENT *FindInstrument(bool isDrum, uint32 bank = 0xFF, uint32 program = 0xFF, uint32 key = 0xFF, uint32 *pInsNo = nullptr) const; bool FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum, FileReader *file = nullptr) const; uint32 GetRegionFromKey(uint32 nIns, uint32 nKey) const; bool ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose = 0, FileReader *file = nullptr) const; bool ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn, FileReader *file = nullptr) const; const char *GetRegionName(uint32 nIns, uint32 nRgn) const; uint16 GetPanning(uint32 ins, uint32 region) const; // Internal Loader Functions protected: std::vector ExtractWaveForm(uint32 nIns, uint32 nRgn, FileReader *file) const; bool UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, FileReader chunk); bool UpdateSF2PresetData(SF2LoaderInfo &sf2info, const IFFCHUNK &header, FileReader &chunk); bool ConvertSF2ToDLS(SF2LoaderInfo &sf2info); public: // DLS Unit conversion static int32 DLS32BitTimeCentsToMilliseconds(int32 lTimeCents); static uint16 DLSEnvelopeTimeCentsToMilliseconds(int32 lTimeCents); static int32 DLS32BitRelativeGainToLinear(int32 lCentibels); // 0dB = 0x10000 static int32 DLS32BitRelativeLinearToGain(int32 lGain); // 0dB = 0x10000 static int32 DLSMidiVolumeToLinear(uint32 nMidiVolume); // [0-127] -> [0-0x10000] }; #endif // MODPLUG_TRACKER OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Tables.cpp0000644000175000017500000011456515017401256020030 00000000000000/* * Tables.cpp * ---------- * Purpose: Effect, interpolation, data and other pre-calculated tables. * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Tables.h" #include "Sndfile.h" #include "Resampler.h" #include "WindowedFIR.h" #include OPENMPT_NAMESPACE_BEGIN ///////////////////////////////////////////////////////////////////////////// // Note Name Tables const mpt::uchar NoteNamesSharp[12][4] = { UL_("C-"), UL_("C#"), UL_("D-"), UL_("D#"), UL_("E-"), UL_("F-"), UL_("F#"), UL_("G-"), UL_("G#"), UL_("A-"), UL_("A#"), UL_("B-") }; const mpt::uchar NoteNamesFlat[12][4] = { UL_("C-"), UL_("Db"), UL_("D-"), UL_("Eb"), UL_("E-"), UL_("F-"), UL_("Gb"), UL_("G-"), UL_("Ab"), UL_("A-"), UL_("Bb"), UL_("B-") }; /////////////////////////////////////////////////////////// // File Formats Information (name, extension, etc) struct ModFormatInfo { const mpt::uchar *name; // "ProTracker" const char *extension; // "mod" }; // Note: Formats with identical extensions must be grouped together. static constexpr ModFormatInfo modFormatInfo[] = { { UL_("OpenMPT"), "mptm" }, { UL_("ProTracker"), "mod" }, { UL_("ChipTracker"), "mod" }, { UL_("TCB Tracker"), "mod" }, { UL_("Scream Tracker 3"), "s3m" }, { UL_("FastTracker 2"), "xm" }, { UL_("Impulse Tracker"), "it" }, { UL_("Composer 667"), "667" }, { UL_("Composer 669 / UNIS 669"), "669" }, { UL_("ASYLUM Music Format"), "amf" }, { UL_("DSMI Advanced Music Format"), "amf" }, { UL_("Extreme's Tracker"), "ams" }, { UL_("Velvet Studio"), "ams" }, { UL_("CDFM / Composer 670"), "c67" }, { UL_("Chuck Biscuits / Black Artist"), "cba" }, { UL_("DigiBooster Pro"), "dbm" }, { UL_("DigiBooster"), "digi" }, { UL_("X-Tracker"), "dmf" }, { UL_("DSMI Advanced Music Format (Compact)"), "dmf" }, { UL_("DSIK Format"), "dsm" }, { UL_("Dynamic Studio"), "dsm" }, { UL_("Digital Symphony"), "dsym" }, { UL_("Digital Tracker"), "dtm" }, { UL_("EasyTrax"), "etx" }, { UL_("Farandole Composer"), "far" }, { UL_("Future Composer"), "fc" }, { UL_("Future Composer"), "fc13" }, { UL_("Future Composer"), "fc14" }, { UL_("FM Tracker"), "fmt" }, { UL_("ProTracker"), "fst" }, { UL_("Face The Music"), "ftm" }, { UL_("Imago Orpheus"), "imf" }, { UL_("Images Music System"), "ims" }, { UL_("Ice Tracker"), "ice" }, #ifdef MPT_EXTERNAL_SAMPLES { UL_("Impulse Tracker Project"), "itp" }, #endif { UL_("Galaxy Sound System"), "j2b" }, { UL_("Soundtracker"), "m15" }, { UL_("Digitrakker"), "mdl" }, { UL_("OctaMED"), "med" }, { UL_("MultiMedia Sound"), "mms" }, { UL_("MadTracker 2"), "mt2" }, { UL_("MultiTracker"), "mtm" }, { UL_("Karl Morton Music Format"), "mus" }, { UL_("NoiseTracker"), "nst" }, { UL_("Oktalyzer"), "okt" }, { UL_("Disorder Tracker 2"), "plm" }, { UL_("Epic Megagames MASI"), "psm" }, { UL_("ProTracker"), "pt36" }, { UL_("PolyTracker"), "ptm" }, { UL_("Puma Tracker"), "puma" }, { UL_("Real Tracker 2"), "rtm" }, { UL_("SoundFX"), "sfx" }, { UL_("SoundFX"), "sfx2" }, { UL_("Future Composer"), "smod" }, { UL_("SoundTracker 2.6"), "st26" }, { UL_("Soundtracker"), "stk" }, { UL_("Scream Tracker 2"), "stm" }, { UL_("Scream Tracker Music Interface Kit"), "stx" }, { UL_("Soundtracker Pro II"), "stp" }, { UL_("Symphonie"), "symmod"}, { UL_("TCB Tracker"), "tcb" }, { UL_("Game Music Creator"), "gmc" }, { UL_("Graoumf Tracker"), "gtk" }, { UL_("Graoumf Tracker 1 / 2"), "gt2" }, { UL_("UltraTracker"), "ult" }, { UL_("UNIC Tracker"), "unic" }, { UL_("Mod's Grave"), "wow" }, { UL_("Astroidea XMF"), "xmf" }, // converted formats (no MODTYPE) { UL_("General Digital Music"), "gdm" }, { UL_("Un4seen MO3"), "mo3" }, { UL_("OggMod FastTracker 2"), "oxm" }, #ifndef NO_ARCHIVE_SUPPORT // Compressed modules { UL_("Compressed ProTracker"), "mdz" }, { UL_("Compressed Module"), "mdr" }, { UL_("Compressed Scream Tracker 3"), "s3z" }, { UL_("Compressed FastTracker 2"), "xmz" }, { UL_("Compressed Impulse Tracker"), "itz" }, { UL_("Compressed OpenMPT"), "mptmz" }, #endif }; struct ModContainerInfo { ModContainerType format; // ModContainerType::XXX const mpt::uchar *name; // "Unreal Music" const char *extension; // "umx" }; static constexpr ModContainerInfo modContainerInfo[] = { // Container formats { ModContainerType::UMX, UL_("Unreal Music"), "umx" }, { ModContainerType::XPK, UL_("XPK packed"), "xpk" }, { ModContainerType::PP20, UL_("PowerPack PP20"), "ppm" }, { ModContainerType::MMCMP, UL_("Music Module Compressor"), "mmcmp" }, #ifdef MODPLUG_TRACKER { ModContainerType::WAV, UL_("Wave"), "wav" }, { ModContainerType::UAX, UL_("Unreal Sounds"), "uax" }, { ModContainerType::Generic, UL_("Generic Archive"), "" }, #endif }; #ifdef MODPLUG_TRACKER static constexpr ModFormatInfo otherFormatInfo[] = { { UL_("MIDI"), "mid" }, { UL_("MIDI"), "rmi" }, { UL_("MIDI"), "smf" } }; #endif std::vector CSoundFile::GetSupportedExtensions(bool otherFormats) { std::vector exts; for(const auto &formatInfo : modFormatInfo) { // Avoid dupes in list const std::string_view ext = formatInfo.extension; if(ext.empty()) continue; if(exts.empty() || ext != exts.back()) exts.push_back(formatInfo.extension); } for(const auto &containerInfo : modContainerInfo) { // Avoid dupes in list const std::string_view ext = containerInfo.extension; if(ext.empty()) continue; if(exts.empty() || ext != exts.back()) exts.push_back(ext.data()); } #ifdef MODPLUG_TRACKER if(otherFormats) { for(const auto &formatInfo : otherFormatInfo) { exts.push_back(formatInfo.extension); } } #else MPT_UNREFERENCED_PARAMETER(otherFormats); #endif return exts; } static bool IsEqualExtension(std::string_view a, std::string_view b) { if(a.length() != b.length()) { return false; } return mpt::CompareNoCaseAscii(a, b) == 0; } bool CSoundFile::IsExtensionSupported(std::string_view ext) { if(ext.length() == 0) { return false; } for(const auto &formatInfo : modFormatInfo) { if(IsEqualExtension(ext, formatInfo.extension)) { return true; } } for(const auto &containerInfo : modContainerInfo) { if(IsEqualExtension(ext, containerInfo.extension)) { return true; } } return false; } mpt::ustring CSoundFile::ModContainerTypeToString(ModContainerType containertype) { for(const auto &containerInfo : modContainerInfo) { if(containerInfo.format == containertype) { return mpt::ToUnicode(mpt::Charset::UTF8, containerInfo.extension); } } return mpt::ustring(); } mpt::ustring CSoundFile::ModContainerTypeToTracker(ModContainerType containertype) { std::set retvals; mpt::ustring retval; for(const auto &containerInfo : modContainerInfo) { if(containerInfo.format == containertype) { mpt::ustring name = containerInfo.name; if(retvals.insert(name).second) { if(!retval.empty()) { retval += U_(" / "); } retval += name; } } } return retval; } /////////////////////////////////////////////////////////////////////// const uint8 ImpulseTrackerPortaVolCmd[16] = { 0x00, 0x01, 0x04, 0x08, 0x10, 0x20, 0x40, 0x60, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; // Period table for ProTracker octaves (1-7 in FastTracker 2, also used for file I/O): const uint16 ProTrackerPeriodTable[7*12] = { 2*1712,2*1616,2*1524,2*1440,2*1356,2*1280,2*1208,2*1140,2*1076,2*1016,2*960,2*906, 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907, 856,808,762,720,678,640,604,570,538,508,480,453, 428,404,381,360,339,320,302,285,269,254,240,226, 214,202,190,180,170,160,151,143,135,127,120,113, 107,101,95,90,85,80,75,71,67,63,60,56, 53,50,47,45,42,40,37,35,33,31,30,28 }; const uint16 ProTrackerTunedPeriods[16*12] = { 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907, 1700,1604,1514,1430,1348,1274,1202,1134,1070,1010,954,900, 1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,894, 1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,888, 1664,1570,1482,1398,1320,1246,1176,1110,1048,990,934,882, 1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,874, 1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,868, 1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914,862, 1814,1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960, 1800,1700,1604,1514,1430,1350,1272,1202,1134,1070,1010,954, 1788,1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948, 1774,1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940, 1762,1664,1570,1482,1398,1320,1246,1176,1110,1048,988,934, 1750,1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926, 1736,1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920, 1724,1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914 }; // Table for Invert Loop and Funk Repeat effects (EFx, .MOD only) const uint8 ModEFxTable[16] = { 0, 5, 6, 7, 8, 10, 11, 13, 16, 19, 22, 26, 32, 43, 64, 128 }; // S3M C-4 periods const uint16 FreqS3MTable[12] = { 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907 }; // S3M FineTune frequencies const uint16 S3MFineTuneTable[16] = { 7895,7941,7985,8046,8107,8169,8232,8280, 8363,8413,8463,8529,8581,8651,8723,8757, // 8363*2^((i-8)/(12*8)) }; // Sinus table const int8 ModSinusTable[64] = { 0,12,25,37,49,60,71,81,90,98,106,112,117,122,125,126, 127,126,125,122,117,112,106,98,90,81,71,60,49,37,25,12, 0,-12,-25,-37,-49,-60,-71,-81,-90,-98,-106,-112,-117,-122,-125,-126, -127,-126,-125,-122,-117,-112,-106,-98,-90,-81,-71,-60,-49,-37,-25,-12 }; // Random wave table const int8 ModRandomTable[64] = { 98,-127,-43,88,102,41,-65,-94,125,20,-71,-86,-70,-32,-16,-96, 17,72,107,-5,116,-69,-62,-40,10,-61,65,109,-18,-38,-13,-76, -23,88,21,-94,8,106,21,-112,6,109,20,-88,-30,9,-127,118, 42,-34,89,-4,-51,-72,21,-29,112,123,84,-101,-92,98,-54,-95 }; // Impulse Tracker sinus table (ITTECH.TXT) const int8 ITSinusTable[256] = { 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23, 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60, 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26, 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2, 0, -2, -3, -5, -6, -8, -9,-11,-12,-14,-16,-17,-19,-20,-22,-23, -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44, -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59, -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64, -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60, -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46, -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26, -24,-23,-22,-20,-19,-17,-16,-14,-12,-11, -9, -8, -6, -5, -3, -2, }; // volume fade tables for Retrig Note: const int8 retrigTable1[16] = { 0, 0, 0, 0, 0, 0, 10, 8, 0, 0, 0, 0, 0, 0, 24, 32 }; const int8 retrigTable2[16] = { 0, -1, -2, -4, -8, -16, 0, 0, 0, 1, 2, 4, 8, 16, 0, 0 }; const uint16 XMPeriodTable[104] = { 907,900,894,887,881,875,868,862,856,850,844,838,832,826,820,814, 808,802,796,791,785,779,774,768,762,757,752,746,741,736,730,725, 720,715,709,704,699,694,689,684,678,675,670,665,660,655,651,646, 640,636,632,628,623,619,614,610,604,601,597,592,588,584,580,575, 570,567,563,559,555,551,547,543,538,535,532,528,524,520,516,513, 508,505,502,498,494,491,487,484,480,477,474,470,467,463,460,457, 453,450,447,443,440,437,434,431 }; // floor(8363 * 64 * 2**(-n/768)) // 768 = 64 period steps for 12 notes // Table is for highest possible octave const uint32 XMLinearTable[768] = { 535232,534749,534266,533784,533303,532822,532341,531861, 531381,530902,530423,529944,529466,528988,528511,528034, 527558,527082,526607,526131,525657,525183,524709,524236, 523763,523290,522818,522346,521875,521404,520934,520464, 519994,519525,519057,518588,518121,517653,517186,516720, 516253,515788,515322,514858,514393,513929,513465,513002, 512539,512077,511615,511154,510692,510232,509771,509312, 508852,508393,507934,507476,507018,506561,506104,505647, 505191,504735,504280,503825,503371,502917,502463,502010, 501557,501104,500652,500201,499749,499298,498848,498398, 497948,497499,497050,496602,496154,495706,495259,494812, 494366,493920,493474,493029,492585,492140,491696,491253, 490809,490367,489924,489482,489041,488600,488159,487718, 487278,486839,486400,485961,485522,485084,484647,484210, 483773,483336,482900,482465,482029,481595,481160,480726, 480292,479859,479426,478994,478562,478130,477699,477268, 476837,476407,475977,475548,475119,474690,474262,473834, 473407,472979,472553,472126,471701,471275,470850,470425, 470001,469577,469153,468730,468307,467884,467462,467041, 466619,466198,465778,465358,464938,464518,464099,463681, 463262,462844,462427,462010,461593,461177,460760,460345, 459930,459515,459100,458686,458272,457859,457446,457033, 456621,456209,455797,455386,454975,454565,454155,453745, 453336,452927,452518,452110,451702,451294,450887,450481, 450074,449668,449262,448857,448452,448048,447644,447240, 446836,446433,446030,445628,445226,444824,444423,444022, 443622,443221,442821,442422,442023,441624,441226,440828, 440430,440033,439636,439239,438843,438447,438051,437656, 437261,436867,436473,436079,435686,435293,434900,434508, 434116,433724,433333,432942,432551,432161,431771,431382, 430992,430604,430215,429827,429439,429052,428665,428278, 427892,427506,427120,426735,426350,425965,425581,425197, 424813,424430,424047,423665,423283,422901,422519,422138, 421757,421377,420997,420617,420237,419858,419479,419101, 418723,418345,417968,417591,417214,416838,416462,416086, 415711,415336,414961,414586,414212,413839,413465,413092, 412720,412347,411975,411604,411232,410862,410491,410121, 409751,409381,409012,408643,408274,407906,407538,407170, 406803,406436,406069,405703,405337,404971,404606,404241, 403876,403512,403148,402784,402421,402058,401695,401333, 400970,400609,400247,399886,399525,399165,398805,398445, 398086,397727,397368,397009,396651,396293,395936,395579, 395222,394865,394509,394153,393798,393442,393087,392733, 392378,392024,391671,391317,390964,390612,390259,389907, 389556,389204,388853,388502,388152,387802,387452,387102, 386753,386404,386056,385707,385359,385012,384664,384317, 383971,383624,383278,382932,382587,382242,381897,381552, 381208,380864,380521,380177,379834,379492,379149,378807, 378466,378124,377783,377442,377102,376762,376422,376082, 375743,375404,375065,374727,374389,374051,373714,373377, 373040,372703,372367,372031,371695,371360,371025,370690, 370356,370022,369688,369355,369021,368688,368356,368023, 367691,367360,367028,366697,366366,366036,365706,365376, 365046,364717,364388,364059,363731,363403,363075,362747, 362420,362093,361766,361440,361114,360788,360463,360137, 359813,359488,359164,358840,358516,358193,357869,357547, 357224,356902,356580,356258,355937,355616,355295,354974, 354654,354334,354014,353695,353376,353057,352739,352420, 352103,351785,351468,351150,350834,350517,350201,349885, 349569,349254,348939,348624,348310,347995,347682,347368, 347055,346741,346429,346116,345804,345492,345180,344869, 344558,344247,343936,343626,343316,343006,342697,342388, 342079,341770,341462,341154,340846,340539,340231,339924, 339618,339311,339005,338700,338394,338089,337784,337479, 337175,336870,336566,336263,335959,335656,335354,335051, 334749,334447,334145,333844,333542,333242,332941,332641, 332341,332041,331741,331442,331143,330844,330546,330247, 329950,329652,329355,329057,328761,328464,328168,327872, 327576,327280,326985,326690,326395,326101,325807,325513, 325219,324926,324633,324340,324047,323755,323463,323171, 322879,322588,322297,322006,321716,321426,321136,320846, 320557,320267,319978,319690,319401,319113,318825,318538, 318250,317963,317676,317390,317103,316817,316532,316246, 315961,315676,315391,315106,314822,314538,314254,313971, 313688,313405,313122,312839,312557,312275,311994,311712, 311431,311150,310869,310589,310309,310029,309749,309470, 309190,308911,308633,308354,308076,307798,307521,307243, 306966,306689,306412,306136,305860,305584,305308,305033, 304758,304483,304208,303934,303659,303385,303112,302838, 302565,302292,302019,301747,301475,301203,300931,300660, 300388,300117,299847,299576,299306,299036,298766,298497, 298227,297958,297689,297421,297153,296884,296617,296349, 296082,295815,295548,295281,295015,294749,294483,294217, 293952,293686,293421,293157,292892,292628,292364,292100, 291837,291574,291311,291048,290785,290523,290261,289999, 289737,289476,289215,288954,288693,288433,288173,287913, 287653,287393,287134,286875,286616,286358,286099,285841, 285583,285326,285068,284811,284554,284298,284041,283785, 283529,283273,283017,282762,282507,282252,281998,281743, 281489,281235,280981,280728,280475,280222,279969,279716, 279464,279212,278960,278708,278457,278206,277955,277704, 277453,277203,276953,276703,276453,276204,275955,275706, 275457,275209,274960,274712,274465,274217,273970,273722, 273476,273229,272982,272736,272490,272244,271999,271753, 271508,271263,271018,270774,270530,270286,270042,269798, 269555,269312,269069,268826,268583,268341,268099,267857 }; // round(65536 * 2**(n/768)) // 768 = 64 extra-fine finetune steps for 12 notes // Table content is in 16.16 format const uint32 FineLinearSlideUpTable[16] = { 65536, 65595, 65654, 65714, 65773, 65832, 65892, 65951, 66011, 66071, 66130, 66190, 66250, 66309, 66369, 66429 }; // round(65536 * 2**(-n/768)) // 768 = 64 extra-fine finetune steps for 12 notes // Table content is in 16.16 format // Note that there are a few errors in this table (typos?), but well, this table comes straight from Impulse Tracker's source... // Entry 0 (65535) should be 65536 (this value is unused and most likely stored this way so that it fits in a 16-bit integer) // Entry 11 (64888) should be 64889 - rounding error? // Entry 15 (64645) should be 64655 - typo? const uint32 FineLinearSlideDownTable[16] = { 65535, 65477, 65418, 65359, 65300, 65241, 65182, 65123, 65065, 65006, 64947, 64888, 64830, 64772, 64713, 64645 }; // round(65536 * 2**(n/192)) // 192 = 16 finetune steps for 12 notes // Table content is in 16.16 format const uint32 LinearSlideUpTable[256] = { 65536, 65773, 66011, 66250, 66489, 66730, 66971, 67213, 67456, 67700, 67945, 68191, 68438, 68685, 68933, 69183, 69433, 69684, 69936, 70189, 70443, 70698, 70953, 71210, 71468, 71726, 71985, 72246, 72507, 72769, 73032, 73297, 73562, 73828, 74095, 74363, 74632, 74902, 75172, 75444, 75717, 75991, 76266, 76542, 76819, 77096, 77375, 77655, 77936, 78218, 78501, 78785, 79069, 79355, 79642, 79930, 80220, 80510, 80801, 81093, 81386, 81681, 81976, 82273, 82570, 82869, 83169, 83469, 83771, 84074, 84378, 84683, 84990, 85297, 85606, 85915, 86226, 86538, 86851, 87165, 87480, 87796, 88114, 88433, 88752, 89073, 89396, 89719, 90043, 90369, 90696, 91024, 91353, 91684, 92015, 92348, 92682, 93017, 93354, 93691, 94030, 94370, 94711, 95054, 95398, 95743, 96089, 96436, 96785, 97135, 97487, 97839, 98193, 98548, 98905, 99262, 99621, 99982, 100343, 100706, 101070, 101436, 101803, 102171, 102540, 102911, 103283, 103657, 104032, 104408, 104786, 105165, 105545, 105927, 106310, 106694, 107080, 107468, 107856, 108246, 108638, 109031, 109425, 109821, 110218, 110617, 111017, 111418, 111821, 112226, 112631, 113039, 113448, 113858, 114270, 114683, 115098, 115514, 115932, 116351, 116772, 117194, 117618, 118043, 118470, 118899, 119329, 119760, 120194, 120628, 121065, 121502, 121942, 122383, 122825, 123270, 123715, 124163, 124612, 125063, 125515, 125969, 126425, 126882, 127341, 127801, 128263, 128727, 129193, 129660, 130129, 130600, 131072, 131546, 132022, 132499, 132978, 133459, 133942, 134427, 134913, 135401, 135890, 136382, 136875, 137370, 137867, 138366, 138866, 139368, 139872, 140378, 140886, 141395, 141907, 142420, 142935, 143452, 143971, 144491, 145014, 145539, 146065, 146593, 147123, 147655, 148189, 148725, 149263, 149803, 150345, 150889, 151434, 151982, 152532, 153083, 153637, 154193, 154750, 155310, 155872, 156435, 157001, 157569, 158139, 158711, 159285, 159861, 160439, 161019, 161602, 162186, 162773, 163361, 163952, 164545 }; // round(65536 * 2**(-n/192)) // 192 = 16 finetune steps for 12 notes // Table content is in 16.16 format const uint32 LinearSlideDownTable[256] = { 65536, 65300, 65065, 64830, 64596, 64364, 64132, 63901, 63670, 63441, 63212, 62984, 62757, 62531, 62306, 62081, 61858, 61635, 61413, 61191, 60971, 60751, 60532, 60314, 60097, 59880, 59664, 59449, 59235, 59022, 58809, 58597, 58386, 58176, 57966, 57757, 57549, 57341, 57135, 56929, 56724, 56519, 56316, 56113, 55911, 55709, 55508, 55308, 55109, 54910, 54713, 54515, 54319, 54123, 53928, 53734, 53540, 53347, 53155, 52963, 52773, 52582, 52393, 52204, 52016, 51829, 51642, 51456, 51270, 51085, 50901, 50718, 50535, 50353, 50172, 49991, 49811, 49631, 49452, 49274, 49097, 48920, 48743, 48568, 48393, 48218, 48044, 47871, 47699, 47527, 47356, 47185, 47015, 46846, 46677, 46509, 46341, 46174, 46008, 45842, 45677, 45512, 45348, 45185, 45022, 44859, 44698, 44537, 44376, 44216, 44057, 43898, 43740, 43582, 43425, 43269, 43113, 42958, 42803, 42649, 42495, 42342, 42189, 42037, 41886, 41735, 41584, 41434, 41285, 41136, 40988, 40840, 40693, 40547, 40400, 40255, 40110, 39965, 39821, 39678, 39535, 39392, 39250, 39109, 38968, 38828, 38688, 38548, 38409, 38271, 38133, 37996, 37859, 37722, 37586, 37451, 37316, 37181, 37047, 36914, 36781, 36648, 36516, 36385, 36254, 36123, 35993, 35863, 35734, 35605, 35477, 35349, 35221, 35095, 34968, 34842, 34716, 34591, 34467, 34343, 34219, 34095, 33973, 33850, 33728, 33607, 33486, 33365, 33245, 33125, 33005, 32887, 32768, 32650, 32532, 32415, 32298, 32182, 32066, 31950, 31835, 31720, 31606, 31492, 31379, 31266, 31153, 31041, 30929, 30817, 30706, 30596, 30485, 30376, 30266, 30157, 30048, 29940, 29832, 29725, 29618, 29511, 29405, 29299, 29193, 29088, 28983, 28879, 28774, 28671, 28567, 28464, 28362, 28260, 28158, 28056, 27955, 27855, 27754, 27654, 27554, 27455, 27356, 27258, 27159, 27062, 26964, 26867, 26770, 26674, 26577, 26482, 26386, 26291, 26196, 26102 }; // FT2's square root panning law LUT. // Formula to generate this table: round(65536 * sqrt(n / 256)) const uint16 XMPanningTable[256] = { 0, 4096, 5793, 7094, 8192, 9159, 10033, 10837, 11585, 12288, 12953, 13585, 14189, 14768, 15326, 15864, 16384, 16888, 17378, 17854, 18318, 18770, 19212, 19644, 20066, 20480, 20886, 21283, 21674, 22058, 22435, 22806, 23170, 23530, 23884, 24232, 24576, 24915, 25249, 25580, 25905, 26227, 26545, 26859, 27170, 27477, 27780, 28081, 28378, 28672, 28963, 29251, 29537, 29819, 30099, 30377, 30652, 30924, 31194, 31462, 31727, 31991, 32252, 32511, 32768, 33023, 33276, 33527, 33776, 34024, 34270, 34514, 34756, 34996, 35235, 35472, 35708, 35942, 36175, 36406, 36636, 36864, 37091, 37316, 37540, 37763, 37985, 38205, 38424, 38642, 38858, 39073, 39287, 39500, 39712, 39923, 40132, 40341, 40548, 40755, 40960, 41164, 41368, 41570, 41771, 41972, 42171, 42369, 42567, 42763, 42959, 43154, 43348, 43541, 43733, 43925, 44115, 44305, 44494, 44682, 44869, 45056, 45242, 45427, 45611, 45795, 45977, 46160, 46341, 46522, 46702, 46881, 47059, 47237, 47415, 47591, 47767, 47942, 48117, 48291, 48465, 48637, 48809, 48981, 49152, 49322, 49492, 49661, 49830, 49998, 50166, 50332, 50499, 50665, 50830, 50995, 51159, 51323, 51486, 51649, 51811, 51972, 52134, 52294, 52454, 52614, 52773, 52932, 53090, 53248, 53405, 53562, 53719, 53874, 54030, 54185, 54340, 54494, 54647, 54801, 54954, 55106, 55258, 55410, 55561, 55712, 55862, 56012, 56162, 56311, 56459, 56608, 56756, 56903, 57051, 57198, 57344, 57490, 57636, 57781, 57926, 58071, 58215, 58359, 58503, 58646, 58789, 58931, 59073, 59215, 59357, 59498, 59639, 59779, 59919, 60059, 60199, 60338, 60477, 60615, 60753, 60891, 61029, 61166, 61303, 61440, 61576, 61712, 61848, 61984, 62119, 62254, 62388, 62523, 62657, 62790, 62924, 63057, 63190, 63323, 63455, 63587, 63719, 63850, 63982, 64113, 64243, 64374, 64504, 64634, 64763, 64893, 65022, 65151, 65279, 65408, }; // IT Vibrato -> OpenMPT/XM VibratoType const uint8 AutoVibratoIT2XM[8] = { VIB_SINE, VIB_RAMP_DOWN, VIB_SQUARE, VIB_RANDOM, VIB_RAMP_UP, 0, 0, 0 }; // OpenMPT/XM VibratoType -> IT Vibrato const uint8 AutoVibratoXM2IT[8] = { 0, 2, 4, 1, 3, 0, 0, 0 }; // Reversed sinc coefficients for 4x256 taps polyphase FIR resampling filter (SchismTracker's lutgen.c should generate a very similar table, but it's more precise) const int16 CResampler::FastSincTable[256*4] = { // Cubic Spline 0, 16384, 0, 0, -31, 16383, 32, 0, -63, 16381, 65, 0, -93, 16378, 100, -1, -124, 16374, 135, -1, -153, 16368, 172, -3, -183, 16361, 209, -4, -211, 16353, 247, -5, -240, 16344, 287, -7, -268, 16334, 327, -9, -295, 16322, 368, -12, -322, 16310, 410, -14, -348, 16296, 453, -17, -374, 16281, 497, -20, -400, 16265, 541, -23, -425, 16248, 587, -26, -450, 16230, 634, -30, -474, 16210, 681, -33, -497, 16190, 729, -37, -521, 16168, 778, -41, -543, 16145, 828, -46, -566, 16121, 878, -50, -588, 16097, 930, -55, -609, 16071, 982, -60, -630, 16044, 1035, -65, -651, 16016, 1089, -70, -671, 15987, 1144, -75, -691, 15957, 1199, -81, -710, 15926, 1255, -87, -729, 15894, 1312, -93, -748, 15861, 1370, -99, -766, 15827, 1428, -105, -784, 15792, 1488, -112, -801, 15756, 1547, -118, -818, 15719, 1608, -125, -834, 15681, 1669, -132, -850, 15642, 1731, -139, -866, 15602, 1794, -146, -881, 15561, 1857, -153, -896, 15520, 1921, -161, -911, 15477, 1986, -168, -925, 15434, 2051, -176, -939, 15390, 2117, -184, -952, 15344, 2184, -192, -965, 15298, 2251, -200, -978, 15251, 2319, -208, -990, 15204, 2387, -216, -1002, 15155, 2456, -225, -1014, 15106, 2526, -234, -1025, 15055, 2596, -242, -1036, 15004, 2666, -251, -1046, 14952, 2738, -260, -1056, 14899, 2810, -269, -1066, 14846, 2882, -278, -1075, 14792, 2955, -287, -1084, 14737, 3028, -296, -1093, 14681, 3102, -306, -1102, 14624, 3177, -315, -1110, 14567, 3252, -325, -1118, 14509, 3327, -334, -1125, 14450, 3403, -344, -1132, 14390, 3480, -354, -1139, 14330, 3556, -364, -1145, 14269, 3634, -374, -1152, 14208, 3712, -384, -1157, 14145, 3790, -394, -1163, 14082, 3868, -404, -1168, 14018, 3947, -414, -1173, 13954, 4027, -424, -1178, 13889, 4107, -434, -1182, 13823, 4187, -445, -1186, 13757, 4268, -455, -1190, 13690, 4349, -465, -1193, 13623, 4430, -476, -1196, 13555, 4512, -486, -1199, 13486, 4594, -497, -1202, 13417, 4676, -507, -1204, 13347, 4759, -518, -1206, 13276, 4842, -528, -1208, 13205, 4926, -539, -1210, 13134, 5010, -550, -1211, 13061, 5094, -560, -1212, 12989, 5178, -571, -1212, 12915, 5262, -581, -1213, 12842, 5347, -592, -1213, 12767, 5432, -603, -1213, 12693, 5518, -613, -1213, 12617, 5603, -624, -1212, 12542, 5689, -635, -1211, 12466, 5775, -645, -1210, 12389, 5862, -656, -1209, 12312, 5948, -667, -1208, 12234, 6035, -677, -1206, 12156, 6122, -688, -1204, 12078, 6209, -698, -1202, 11999, 6296, -709, -1200, 11920, 6384, -720, -1197, 11840, 6471, -730, -1194, 11760, 6559, -740, -1191, 11679, 6647, -751, -1188, 11598, 6735, -761, -1184, 11517, 6823, -772, -1181, 11436, 6911, -782, -1177, 11354, 6999, -792, -1173, 11271, 7088, -802, -1168, 11189, 7176, -812, -1164, 11106, 7265, -822, -1159, 11022, 7354, -832, -1155, 10939, 7442, -842, -1150, 10855, 7531, -852, -1144, 10771, 7620, -862, -1139, 10686, 7709, -872, -1134, 10602, 7798, -882, -1128, 10516, 7886, -891, -1122, 10431, 7975, -901, -1116, 10346, 8064, -910, -1110, 10260, 8153, -919, -1103, 10174, 8242, -929, -1097, 10088, 8331, -938, -1090, 10001, 8420, -947, -1083, 9915, 8508, -956, -1076, 9828, 8597, -965, -1069, 9741, 8686, -973, -1062, 9654, 8774, -982, -1054, 9566, 8863, -991, -1047, 9479, 8951, -999, -1039, 9391, 9039, -1007, -1031, 9303, 9127, -1015, -1024, 9216, 9216, -1024, -1015, 9127, 9303, -1031, -1007, 9039, 9391, -1039, -999, 8951, 9479, -1047, -991, 8863, 9566, -1054, -982, 8774, 9654, -1062, -973, 8686, 9741, -1069, -965, 8597, 9828, -1076, -956, 8508, 9915, -1083, -947, 8420, 10001, -1090, -938, 8331, 10088, -1097, -929, 8242, 10174, -1103, -919, 8153, 10260, -1110, -910, 8064, 10346, -1116, -901, 7975, 10431, -1122, -891, 7886, 10516, -1128, -882, 7798, 10602, -1134, -872, 7709, 10686, -1139, -862, 7620, 10771, -1144, -852, 7531, 10855, -1150, -842, 7442, 10939, -1155, -832, 7354, 11022, -1159, -822, 7265, 11106, -1164, -812, 7176, 11189, -1168, -802, 7088, 11271, -1173, -792, 6999, 11354, -1177, -782, 6911, 11436, -1181, -772, 6823, 11517, -1184, -761, 6735, 11598, -1188, -751, 6647, 11679, -1191, -740, 6559, 11760, -1194, -730, 6471, 11840, -1197, -720, 6384, 11920, -1200, -709, 6296, 11999, -1202, -698, 6209, 12078, -1204, -688, 6122, 12156, -1206, -677, 6035, 12234, -1208, -667, 5948, 12312, -1209, -656, 5862, 12389, -1210, -645, 5775, 12466, -1211, -635, 5689, 12542, -1212, -624, 5603, 12617, -1213, -613, 5518, 12693, -1213, -603, 5432, 12767, -1213, -592, 5347, 12842, -1213, -581, 5262, 12915, -1212, -571, 5178, 12989, -1212, -560, 5094, 13061, -1211, -550, 5010, 13134, -1210, -539, 4926, 13205, -1208, -528, 4842, 13276, -1206, -518, 4759, 13347, -1204, -507, 4676, 13417, -1202, -497, 4594, 13486, -1199, -486, 4512, 13555, -1196, -476, 4430, 13623, -1193, -465, 4349, 13690, -1190, -455, 4268, 13757, -1186, -445, 4187, 13823, -1182, -434, 4107, 13889, -1178, -424, 4027, 13954, -1173, -414, 3947, 14018, -1168, -404, 3868, 14082, -1163, -394, 3790, 14145, -1157, -384, 3712, 14208, -1152, -374, 3634, 14269, -1145, -364, 3556, 14330, -1139, -354, 3480, 14390, -1132, -344, 3403, 14450, -1125, -334, 3327, 14509, -1118, -325, 3252, 14567, -1110, -315, 3177, 14624, -1102, -306, 3102, 14681, -1093, -296, 3028, 14737, -1084, -287, 2955, 14792, -1075, -278, 2882, 14846, -1066, -269, 2810, 14899, -1056, -260, 2738, 14952, -1046, -251, 2666, 15004, -1036, -242, 2596, 15055, -1025, -234, 2526, 15106, -1014, -225, 2456, 15155, -1002, -216, 2387, 15204, -990, -208, 2319, 15251, -978, -200, 2251, 15298, -965, -192, 2184, 15344, -952, -184, 2117, 15390, -939, -176, 2051, 15434, -925, -168, 1986, 15477, -911, -161, 1921, 15520, -896, -153, 1857, 15561, -881, -146, 1794, 15602, -866, -139, 1731, 15642, -850, -132, 1669, 15681, -834, -125, 1608, 15719, -818, -118, 1547, 15756, -801, -112, 1488, 15792, -784, -105, 1428, 15827, -766, -99, 1370, 15861, -748, -93, 1312, 15894, -729, -87, 1255, 15926, -710, -81, 1199, 15957, -691, -75, 1144, 15987, -671, -70, 1089, 16016, -651, -65, 1035, 16044, -630, -60, 982, 16071, -609, -55, 930, 16097, -588, -50, 878, 16121, -566, -46, 828, 16145, -543, -41, 778, 16168, -521, -37, 729, 16190, -497, -33, 681, 16210, -474, -30, 634, 16230, -450, -26, 587, 16248, -425, -23, 541, 16265, -400, -20, 497, 16281, -374, -17, 453, 16296, -348, -14, 410, 16310, -322, -12, 368, 16322, -295, -9, 327, 16334, -268, -7, 287, 16344, -240, -5, 247, 16353, -211, -4, 209, 16361, -183, -3, 172, 16368, -153, -1, 135, 16374, -124, -1, 100, 16378, -93, 0, 65, 16381, -63, 0, 32, 16383, -31, }; // Note LUT for His Master's Noise command 7 (Mega-Arp) const std::array HisMastersNoiseMegaArp[16] = { {0, 3, 7, 12, 15, 12, 7, 3, 0, 3, 7, 12, 15, 12, 7, 3 }, {0, 4, 7, 12, 16, 12, 7, 4, 0, 4, 7, 12, 16, 12, 7, 4 }, {0, 3, 8, 12, 15, 12, 8, 3, 0, 3, 8, 12, 15, 12, 8, 3 }, {0, 4, 8, 12, 16, 12, 8, 4, 0, 4, 8, 12, 16, 12, 8, 4 }, {0, 5, 8, 12, 17, 12, 8, 5, 0, 5, 8, 12, 17, 12, 8, 5 }, {0, 5, 9, 12, 17, 12, 9, 5, 0, 5, 9, 12, 17, 12, 9, 5 }, {12, 0, 7, 0, 3, 0, 7, 0, 12, 0, 7, 0, 3, 0, 7, 0 }, {12, 0, 7, 0, 4, 0, 7, 0, 12, 0, 7, 0, 4, 0, 7, 0 }, {0, 3, 7, 3, 7, 12, 7, 12, 15, 12, 7, 12, 7, 3, 7, 3 }, {0, 4, 7, 4, 7, 12, 7, 12, 16, 12, 7, 12, 7, 4, 7, 4 }, {31, 27, 24, 19, 15, 12, 7, 3, 0, 3, 7, 12, 15, 19, 24, 27}, {31, 28, 24, 19, 16, 12, 7, 4, 0, 4, 7, 12, 16, 19, 24, 28}, {0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12}, {0, 12, 24, 12, 0, 12, 24, 12, 0, 12, 24, 12, 0, 12, 24, 12}, {0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3 }, {0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4 } }; ///////////////////////////////////////////////////////////////////////////////////////////// // Compute Bessel function Izero(y) using a series approximation double Izero(double y) { double s = 1, ds = 1, d = 0; do { d = d + 2; ds = ds * (y * y) / (d * d); s = s + ds; } while(ds > 1E-7 * s); return s; } static void getsinc(SINC_TYPE *psinc, double beta, double cutoff) { if(cutoff >= 0.999) { // Avoid mixer overflows. // 1.0 itself does not make much sense. cutoff = 0.999; } const double izeroBeta = Izero(beta); const double kPi = 4.0 * std::atan(1.0) * cutoff; for(int isrc = 0; isrc < 8 * SINC_PHASES; isrc++) { double fsinc; int ix = 7 - (isrc & 7); ix = (ix * SINC_PHASES) + (isrc >> 3); if(ix == (4 * SINC_PHASES)) { fsinc = 1.0; } else { const double x = (double)(ix - (4 * SINC_PHASES)) * (double)(1.0 / SINC_PHASES); const double xPi = x * kPi; fsinc = std::sin(xPi) * Izero(beta * std::sqrt(1 - x * x * (1.0 / 16.0))) / (izeroBeta * xPi); // Kaiser window } double coeff = fsinc * cutoff; #ifdef MPT_INTMIXER *psinc++ = mpt::saturate_round(coeff * (1 << SINC_QUANTSHIFT)); #else *psinc++ = static_cast(coeff); #endif } } #ifdef MODPLUG_TRACKER bool CResampler::StaticTablesInitialized = false; SINC_TYPE CResampler::gKaiserSinc[SINC_PHASES * 8]; // Upsampling SINC_TYPE CResampler::gDownsample13x[SINC_PHASES * 8]; // Downsample 1.333x SINC_TYPE CResampler::gDownsample2x[SINC_PHASES * 8]; // Downsample 2x Paula::BlepTables CResampler::blepTables; // Amiga BLEP resampler #ifndef MPT_INTMIXER mixsample_t CResampler::FastSincTablef[256 * 4]; // Cubic spline LUT #endif // !defined(MPT_INTMIXER) #endif // MODPLUG_TRACKER void CResampler::InitFloatmixerTables() { #ifdef MPT_BUILD_FUZZER // Creating resampling tables can take a little while which we really should not spend // when fuzzing OpenMPT for crashes and hangs. This content of the tables is not really // relevant for any kind of possible crashes or hangs. return; #endif // MPT_BUILD_FUZZER #ifndef MPT_INTMIXER // Prepare fast sinc coefficients for floating point mixer for(std::size_t i = 0; i < std::size(FastSincTable); i++) { FastSincTablef[i] = static_cast(FastSincTable[i] * mixsample_t(1.0f / 16384.0f)); } #endif // !defined(MPT_INTMIXER) } void CResampler::InitializeTablesFromScratch(bool force) { bool initParameterIndependentTables = false; if(force) { initParameterIndependentTables = true; } #ifdef MODPLUG_TRACKER initParameterIndependentTables = !StaticTablesInitialized; #endif // MODPLUG_TRACKER MPT_MAYBE_CONSTANT_IF(initParameterIndependentTables) { InitFloatmixerTables(); blepTables.InitTables(); getsinc(gKaiserSinc, 9.6377, 0.97); getsinc(gDownsample13x, 8.5, 0.5); getsinc(gDownsample2x, 7.0, 0.425); #ifdef MODPLUG_TRACKER StaticTablesInitialized = true; #endif // MODPLUG_TRACKER } if((m_OldSettings == m_Settings) && !force) { return; } m_WindowedFIR.InitTable(m_Settings.gdWFIRCutoff, m_Settings.gbWFIRType); m_OldSettings = m_Settings; } #ifdef MPT_RESAMPLER_TABLES_CACHED static const CResampler & GetCachedResampler() { static CResampler s_CachedResampler(true); return s_CachedResampler; } void CResampler::InitializeTablesFromCache() { const CResampler & s_CachedResampler = GetCachedResampler(); InitFloatmixerTables(); std::copy(s_CachedResampler.gKaiserSinc, s_CachedResampler.gKaiserSinc + SINC_PHASES*8, gKaiserSinc); std::copy(s_CachedResampler.gDownsample13x, s_CachedResampler.gDownsample13x + SINC_PHASES*8, gDownsample13x); std::copy(s_CachedResampler.gDownsample2x, s_CachedResampler.gDownsample2x + SINC_PHASES*8, gDownsample2x); std::copy(s_CachedResampler.m_WindowedFIR.lut, s_CachedResampler.m_WindowedFIR.lut + WFIR_LUTLEN*WFIR_WIDTH, m_WindowedFIR.lut); blepTables = s_CachedResampler.blepTables; } #endif // MPT_RESAMPLER_TABLES_CACHED #ifdef MPT_RESAMPLER_TABLES_CACHED_ONSTARTUP struct ResampleCacheInitializer { ResampleCacheInitializer() { GetCachedResampler(); } }; #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif // MPT_COMPILER_CLANG static ResampleCacheInitializer g_ResamplerCachePrimer; #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #endif // MPT_RESAMPLER_TABLES_CACHED_ONSTARTUP OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_dbm.cpp0000644000175000017500000005067414717445260020330 00000000000000/* * Load_dbm.cpp * ------------ * Purpose: DigiBooster Pro module Loader (DBM) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "../common/mptStringBuffer.h" #ifndef NO_PLUGINS #include "plugins/DigiBoosterEcho.h" #endif // NO_PLUGINS #ifdef LIBOPENMPT_BUILD #define MPT_DBM_USE_REAL_SUBSONGS #endif OPENMPT_NAMESPACE_BEGIN struct DBMFileHeader { char dbm0[4]; uint8 trkVerHi; uint8 trkVerLo; char reserved[2]; }; MPT_BINARY_STRUCT(DBMFileHeader, 8) // IFF-style Chunk struct DBMChunk { // 32-Bit chunk identifiers enum ChunkIdentifiers { idNAME = MagicBE("NAME"), idINFO = MagicBE("INFO"), idSONG = MagicBE("SONG"), idINST = MagicBE("INST"), idVENV = MagicBE("VENV"), idPENV = MagicBE("PENV"), idPATT = MagicBE("PATT"), idPNAM = MagicBE("PNAM"), idSMPL = MagicBE("SMPL"), idDSPE = MagicBE("DSPE"), idMPEG = MagicBE("MPEG"), }; uint32be id; uint32be length; size_t GetLength() const { return length; } ChunkIdentifiers GetID() const { return static_cast(id.get()); } }; MPT_BINARY_STRUCT(DBMChunk, 8) struct DBMInfoChunk { uint16be instruments; uint16be samples; uint16be songs; uint16be patterns; uint16be channels; }; MPT_BINARY_STRUCT(DBMInfoChunk, 10) // Instrument header struct DBMInstrument { enum DBMInstrFlags { smpLoop = 0x01, smpPingPongLoop = 0x02, }; char name[30]; uint16be sample; // Sample reference uint16be volume; // 0...64 uint32be sampleRate; uint32be loopStart; uint32be loopLength; int16be panning; // -128...128 uint16be flags; // See DBMInstrFlags void ConvertToMPT(ModInstrument &mptIns) const { mptIns.name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, name); mptIns.nFadeOut = 0; mptIns.nPan = static_cast(panning + 128); LimitMax(mptIns.nPan, uint32(256)); mptIns.dwFlags.set(INS_SETPANNING); } void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(MOD_TYPE_DBM); mptSmp.nVolume = std::min(static_cast(volume), uint16(64)) * 4u; mptSmp.nC5Speed = Util::muldivr(sampleRate, 8303, 8363); if(loopLength && (flags & (smpLoop | smpPingPongLoop))) { mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = mptSmp.nLoopStart + loopLength; mptSmp.uFlags.set(CHN_LOOP); if(flags & smpPingPongLoop) mptSmp.uFlags.set(CHN_PINGPONGLOOP); } } }; MPT_BINARY_STRUCT(DBMInstrument, 50) // Volume or panning envelope struct DBMEnvelope { enum DBMEnvelopeFlags { envEnabled = 0x01, envSustain1 = 0x02, envLoop = 0x04, envSustain2 = 0x08, }; uint16be instrument; uint8be flags; // See DBMEnvelopeFlags uint8be numSegments; // Number of envelope points - 1 uint8be sustain1; uint8be loopBegin; uint8be loopEnd; uint8be sustain2; // Second sustain point uint16be data[2 * 32]; void ConvertToMPT(InstrumentEnvelope &mptEnv, bool scaleEnv) const { if(numSegments) { if(flags & envEnabled) mptEnv.dwFlags.set(ENV_ENABLED); if(flags & (envSustain1 | envSustain2)) mptEnv.dwFlags.set(ENV_SUSTAIN); if(flags & envLoop) mptEnv.dwFlags.set(ENV_LOOP); } uint8 numPoints = std::min(numSegments.get(), uint8(31)) + 1; mptEnv.resize(numPoints); mptEnv.nLoopStart = loopBegin; mptEnv.nLoopEnd = loopEnd; if((flags & (envSustain1 | envSustain2)) == envSustain1) mptEnv.nSustainStart = mptEnv.nSustainEnd = sustain1; else if((flags & (envSustain1 | envSustain2)) == envSustain2) mptEnv.nSustainStart = mptEnv.nSustainEnd = sustain2; else mptEnv.nSustainStart = mptEnv.nSustainEnd = std::min(sustain1, sustain2); for(uint8 i = 0; i < numPoints; i++) { mptEnv[i].tick = data[i * 2]; uint16 val = data[i * 2 + 1]; if(scaleEnv) { // Panning envelopes are -128...128 in DigiBooster Pro 3.x val = static_cast((val + 128) / 4); } LimitMax(val, uint16(64)); mptEnv[i].value = static_cast(val); } } }; MPT_BINARY_STRUCT(DBMEnvelope, 136) // Note: Unlike in MOD, 1Fx, 2Fx, 5Fx / 5xF, 6Fx / 6xF and AFx / AxF are fine slides. static constexpr EffectCommand dbmEffects[] = { CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, CMD_PANNING8, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_POSITIONJUMP, CMD_VOLUME, CMD_PATTERNBREAK, CMD_MODCMDEX, CMD_TEMPO, CMD_GLOBALVOLUME, CMD_GLOBALVOLSLIDE, CMD_NONE, CMD_NONE, CMD_KEYOFF, CMD_SETENVPOSITION, CMD_NONE, CMD_NONE, CMD_NONE, CMD_PANNINGSLIDE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, #ifndef NO_PLUGINS CMD_DBMECHO, // Toggle DSP CMD_MIDI, // Wxx Echo Delay CMD_MIDI, // Xxx Echo Feedback CMD_MIDI, // Yxx Echo Mix CMD_MIDI, // Zxx Echo Cross #endif // NO_PLUGINS }; static std::pair ConvertDBMEffect(const uint8 cmd, uint8 param) { EffectCommand command = CMD_NONE; if(cmd < std::size(dbmEffects)) command = dbmEffects[cmd]; switch(command) { case CMD_ARPEGGIO: if(param == 0) command = CMD_NONE; break; case CMD_PATTERNBREAK: param = static_cast(((param >> 4) * 10) + (param & 0x0F)); break; #ifdef MODPLUG_TRACKER case CMD_VIBRATO: if(param & 0x0F) { // DBM vibrato is half as deep as most other trackers. Convert it to IT fine vibrato range if possible. uint8 depth = (param & 0x0F) * 2u; param &= 0xF0; if(depth < 16) command = CMD_FINEVIBRATO; else depth = (depth + 2u) / 4u; param |= depth; } break; #endif // Volume slide nibble priority - first nibble (slide up) has precedence. case CMD_VOLUMESLIDE: case CMD_TONEPORTAVOL: case CMD_VIBRATOVOL: if((param & 0xF0) != 0x00 && (param & 0xF0) != 0xF0 && (param & 0x0F) != 0x0F) param &= 0xF0; break; case CMD_GLOBALVOLUME: if(param <= 64) param *= 2; else param = 128; break; case CMD_MODCMDEX: switch(param & 0xF0) { case 0x30: // Play backwards command = CMD_S3MCMDEX; param = 0x9F; break; case 0x40: // Turn off sound in channel (volume / portamento commands after this can't pick up the note anymore) command = CMD_S3MCMDEX; param = 0xC0; break; case 0x50: // Turn on/off channel // TODO: Apparently this should also kill the playing note. if((param & 0x0F) <= 0x01) { command = CMD_CHANNELVOLUME; param = (param == 0x50) ? 0x00 : 0x40; } break; case 0x70: // Coarse offset command = CMD_S3MCMDEX; param = 0xA0 | (param & 0x0F); break; default: // Rest will be converted later from CMD_MODCMDEX to CMD_S3MCMDEX. break; } break; case CMD_TEMPO: if(param <= 0x1F) command = CMD_SPEED; break; case CMD_KEYOFF: if(param == 0) { // TODO key off at tick 0 } break; case CMD_MIDI: // Encode echo parameters into fixed MIDI macros param = static_cast(128 + (cmd - 32) * 32 + param / 8); break; default: break; } return {command, param}; } // Read a chunk of volume or panning envelopes static void ReadDBMEnvelopeChunk(FileReader chunk, EnvelopeType envType, CSoundFile &sndFile, bool scaleEnv) { uint16 numEnvs = chunk.ReadUint16BE(); for(uint16 env = 0; env < numEnvs; env++) { DBMEnvelope dbmEnv; chunk.ReadStruct(dbmEnv); uint16 dbmIns = dbmEnv.instrument; if(dbmIns > 0 && dbmIns <= sndFile.GetNumInstruments() && (sndFile.Instruments[dbmIns] != nullptr)) { dbmEnv.ConvertToMPT(sndFile.Instruments[dbmIns]->GetEnvelope(envType), scaleEnv); } } } static bool ValidateHeader(const DBMFileHeader &fileHeader) { if(std::memcmp(fileHeader.dbm0, "DBM0", 4) || fileHeader.trkVerHi > 3) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDBM(MemoryFileReader file, const uint64 *pfilesize) { DBMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); DBMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } ChunkReader chunkFile(file); auto chunks = chunkFile.ReadChunks(1); // Globals DBMInfoChunk infoData; if(!chunks.GetChunk(DBMChunk::idINFO).ReadStruct(infoData)) { return false; } InitializeGlobals(MOD_TYPE_DBM, Clamp(infoData.channels, 1, MAX_BASECHANNELS)); // Note: MAX_BASECHANNELS is currently 192, but DBPro 3 apparently supports up to 254 channels. m_SongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS; m_nInstruments = std::min(static_cast(infoData.instruments), static_cast(MAX_INSTRUMENTS - 1)); m_nSamples = std::min(static_cast(infoData.samples), static_cast(MAX_SAMPLES - 1)); m_playBehaviour.set(kSlidesAtSpeed1); m_playBehaviour.reset(kITVibratoTremoloPanbrello); m_playBehaviour.reset(kITArpeggio); m_playBehaviour.reset(kITInstrWithNoteOff); m_playBehaviour.reset(kITInstrWithNoteOffOldEffects); m_modFormat.formatName = UL_("DigiBooster Pro"); m_modFormat.type = UL_("dbm"); m_modFormat.madeWithTracker = MPT_UFORMAT("DigiBooster Pro {}.{}")(mpt::ufmt::hex(fileHeader.trkVerHi), mpt::ufmt::hex(fileHeader.trkVerLo)); m_modFormat.charset = mpt::Charset::Amiga_no_C1; // Name chunk FileReader nameChunk = chunks.GetChunk(DBMChunk::idNAME); nameChunk.ReadString(m_songName, nameChunk.GetLength()); // Song chunk FileReader songChunk = chunks.GetChunk(DBMChunk::idSONG); Order().clear(); uint16 numSongs = infoData.songs; for(uint16 i = 0; i < numSongs && songChunk.CanRead(46); i++) { char name[44]; songChunk.ReadString(name, 44); if(m_songName.empty()) { m_songName = name; } uint16 numOrders = songChunk.ReadUint16BE(); #ifdef MPT_DBM_USE_REAL_SUBSONGS if(!Order().empty()) { // Add a new sequence for this song if(Order.AddSequence() == SEQUENCEINDEX_INVALID) break; } Order().SetName(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, name)); ReadOrderFromFile(Order(), songChunk, numOrders); #else const ORDERINDEX startIndex = Order().GetLength(); if(startIndex < MAX_ORDERS && songChunk.CanRead(numOrders * 2u)) { LimitMax(numOrders, static_cast(MAX_ORDERS - startIndex - 1)); Order().resize(startIndex + numOrders + 1); for(uint16 ord = 0; ord < numOrders; ord++) { Order()[startIndex + ord] = static_cast(songChunk.ReadUint16BE()); } } #endif // MPT_DBM_USE_REAL_SUBSONGS } #ifdef MPT_DBM_USE_REAL_SUBSONGS Order.SetSequence(0); #endif // MPT_DBM_USE_REAL_SUBSONGS // Read instruments std::map copySample; if(FileReader instChunk = chunks.GetChunk(DBMChunk::idINST)) { std::set sampleUsed; for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { DBMInstrument instrHeader; instChunk.ReadStruct(instrHeader); SAMPLEINDEX mappedSample = instrHeader.sample; if(sampleUsed.count(mappedSample) && CanAddMoreSamples()) { ModSample mptSmp; instrHeader.ConvertToMPT(mptSmp); const ModSample &origSmp = Samples[mappedSample]; if(mptSmp.nVolume != origSmp.nVolume || mptSmp.uFlags != origSmp.uFlags || mptSmp.nLoopStart != origSmp.nLoopStart || mptSmp.nLoopEnd != origSmp.nLoopEnd || mptSmp.nC5Speed != origSmp.nC5Speed) { // Need to duplicate mappedSample = ++m_nSamples; copySample.emplace(mappedSample, instrHeader.sample); } } ModInstrument *mptIns = AllocateInstrument(i, mappedSample); if(mptIns == nullptr || mappedSample >= MAX_SAMPLES) continue; instrHeader.ConvertToMPT(*mptIns); // Sample Info instrHeader.ConvertToMPT(Samples[mappedSample]); m_szNames[mappedSample] = mptIns->name; sampleUsed.insert(mappedSample); } // Read envelopes ReadDBMEnvelopeChunk(chunks.GetChunk(DBMChunk::idVENV), ENV_VOLUME, *this, false); ReadDBMEnvelopeChunk(chunks.GetChunk(DBMChunk::idPENV), ENV_PANNING, *this, fileHeader.trkVerHi > 2); // Note-Off cuts samples if there's no envelope. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { if(Instruments[i] != nullptr && !Instruments[i]->VolEnv.dwFlags[ENV_ENABLED]) { Instruments[i]->nFadeOut = 32767; } } } // Patterns FileReader patternChunk = chunks.GetChunk(DBMChunk::idPATT); #ifndef NO_PLUGINS bool hasEchoEnable = false, hasEchoParams = false; #endif // NO_PLUGINS if(patternChunk.IsValid() && (loadFlags & loadPatternData)) { FileReader patternNameChunk = chunks.GetChunk(DBMChunk::idPNAM); patternNameChunk.Skip(1); // Encoding (0 = unspecified ASCII-compatible 8-bit encoding, 106 = UTF-8) Patterns.ResizeArray(infoData.patterns); std::vector> lostGlobalCommands; for(PATTERNINDEX pat = 0; pat < infoData.patterns; pat++) { uint16 numRows = patternChunk.ReadUint16BE(); uint32 packedSize = patternChunk.ReadUint32BE(); FileReader chunk = patternChunk.ReadChunk(packedSize); if(!Patterns.Insert(pat, numRows)) continue; std::string patName; patternNameChunk.ReadSizedString(patName); Patterns[pat].SetName(patName); auto patRow = Patterns[pat].GetRow(0); ROWINDEX row = 0; lostGlobalCommands.clear(); while(chunk.CanRead(1)) { const uint8 ch = chunk.ReadUint8(); if(!ch) { // End Of Row for(const auto &cmd : lostGlobalCommands) { Patterns[pat].WriteEffect(EffectWriter(cmd.first, cmd.second).Row(row)); } lostGlobalCommands.clear(); if(++row >= numRows) break; patRow = Patterns[pat].GetRow(row); continue; } ModCommand dummy{}; ModCommand &m = ch <= GetNumChannels() ? patRow[ch - 1] : dummy; const uint8 b = chunk.ReadUint8(); if(b & 0x01) { uint8 note = chunk.ReadUint8(); if(note == 0x1F) m.note = NOTE_KEYOFF; else if(note > 0 && note < 0xFE) m.note = static_cast(((note >> 4) * 12) + (note & 0x0F) + 13); } if(b & 0x02) { m.instr = chunk.ReadUint8(); } if(b & 0x3C) { uint8 c1 = 0, p1 = 0, c2 = 0, p2 = 0; if(b & 0x04) c2 = chunk.ReadUint8(); if(b & 0x08) p2 = chunk.ReadUint8(); if(b & 0x10) c1 = chunk.ReadUint8(); if(b & 0x20) p1 = chunk.ReadUint8(); auto [cmd1, param1] = ConvertDBMEffect(c1, p1); auto [cmd2, param2] = ConvertDBMEffect(c2, p2); if(cmd2 == CMD_VOLUME || (cmd2 == CMD_NONE && cmd1 != CMD_VOLUME)) { std::swap(cmd1, cmd2); std::swap(param1, param2); } else if(cmd1 == CMD_TONEPORTAMENTO && cmd2 == CMD_OFFSET && param2 == 0) { // Offset + Portamento: Ignore portamento. If the offset command has a non-zero parameter, keep it for effect memory. cmd2 = CMD_NONE; } else if(cmd2 == CMD_TONEPORTAMENTO && cmd1 == CMD_OFFSET && param1 == 0) { // Ditto cmd1 = CMD_NONE; } const auto lostCommand = m.FillInTwoCommands(cmd1, param1, cmd2, param2, true); if(ModCommand::IsGlobalCommand(lostCommand.first, lostCommand.second)) lostGlobalCommands.insert(lostGlobalCommands.begin(), lostCommand); // Insert at front so that the last command of same type "wins" #ifdef MODPLUG_TRACKER m.ExtendedMODtoS3MEffect(); #endif // MODPLUG_TRACKER #ifndef NO_PLUGINS if(m.command == CMD_DBMECHO) hasEchoEnable = true; else if(m.command == CMD_MIDI) hasEchoParams = true; #endif // NO_PLUGINS } } } } #ifndef NO_PLUGINS // Echo DSP if(loadFlags & loadPluginData) { if(hasEchoEnable) { // If there are any Vxx effects to dynamically enable / disable echo, use the CHN_NOFX flag. for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { ChnSettings[i].nMixPlugin = 1; ChnSettings[i].dwFlags.set(CHN_NOFX); } } bool anyEnabled = hasEchoEnable; // DBP 3 Documentation says that the defaults are 64/128/128/255, but they appear to be 80/150/80/255 in DBP 2.21 uint8 settings[8] = { 0, 80, 0, 150, 0, 80, 0, 255 }; if(FileReader dspChunk = chunks.GetChunk(DBMChunk::idDSPE)) { uint16 maskLen = dspChunk.ReadUint16BE(); for(uint16 i = 0; i < maskLen; i++) { bool enabled = (dspChunk.ReadUint8() == 0); if(i < GetNumChannels()) { if(hasEchoEnable) { // If there are any Vxx effects to dynamically enable / disable echo, use the CHN_NOFX flag. ChnSettings[i].dwFlags.set(CHN_NOFX, !enabled); } else if(enabled) { ChnSettings[i].nMixPlugin = 1; anyEnabled = true; } } } dspChunk.ReadArray(settings); } if(anyEnabled) { // Note: DigiBooster Pro 3 has a more versatile per-channel echo effect. // In this case, we'd have to create one plugin per channel. SNDMIXPLUGIN &plugin = m_MixPlugins[0]; plugin.Destroy(); memcpy(&plugin.Info.dwPluginId1, "DBM0", 4); memcpy(&plugin.Info.dwPluginId2, "Echo", 4); plugin.Info.routingFlags = SNDMIXPLUGININFO::irAutoSuspend; plugin.Info.mixMode = 0; plugin.Info.gain = 10; plugin.Info.reserved = 0; plugin.Info.dwOutputRouting = 0; std::fill(plugin.Info.dwReserved, plugin.Info.dwReserved + std::size(plugin.Info.dwReserved), 0); plugin.Info.szName = "Echo"; plugin.Info.szLibraryName = "DigiBooster Pro Echo"; plugin.pluginData.resize(sizeof(DigiBoosterEcho::PluginChunk)); DigiBoosterEcho::PluginChunk chunk = DigiBoosterEcho::PluginChunk::Create(settings[1], settings[3], settings[5], settings[7]); new (plugin.pluginData.data()) DigiBoosterEcho::PluginChunk(chunk); } } // Encode echo parameters into fixed MIDI macros if(hasEchoParams) { for(uint32 i = 0; i < 32; i++) { uint32 param = (i * 127u) / 32u; m_MidiCfg.Zxx[i ] = MPT_AFORMAT("F0F080{}")(mpt::afmt::HEX0<2>(param)); m_MidiCfg.Zxx[i + 32] = MPT_AFORMAT("F0F081{}")(mpt::afmt::HEX0<2>(param)); m_MidiCfg.Zxx[i + 64] = MPT_AFORMAT("F0F082{}")(mpt::afmt::HEX0<2>(param)); m_MidiCfg.Zxx[i + 96] = MPT_AFORMAT("F0F083{}")(mpt::afmt::HEX0<2>(param)); } } #endif // NO_PLUGINS // Samples FileReader sampleChunk = chunks.GetChunk(DBMChunk::idSMPL); if(sampleChunk.IsValid() && (loadFlags & loadSampleData)) { for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { if(auto copyFrom = copySample.find(smp); copyFrom != copySample.end()) { Samples[smp].nLength = Samples[copyFrom->second].nLength; Samples[smp].CopyWaveform(Samples[copyFrom->second]); continue; } uint32 sampleFlags = sampleChunk.ReadUint32BE(); uint32 sampleLength = sampleChunk.ReadUint32BE(); if(sampleFlags & 7) { ModSample &sample = Samples[smp]; sample.nLength = sampleLength; SampleIO( (sampleFlags & 4) ? SampleIO::_32bit : ((sampleFlags & 2) ? SampleIO::_16bit : SampleIO::_8bit), SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM) .ReadSample(sample, sampleChunk); } } } #if defined(MPT_ENABLE_MP3_SAMPLES) && 0 // Compressed samples - this does not quite work yet... FileReader mpegChunk = chunks.GetChunk(DBMChunk::idMPEG); if(mpegChunk.IsValid() && (loadFlags & loadSampleData)) { for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { Samples[smp].nLength = mpegChunk.ReadUint32BE(); } mpegChunk.Skip(2); // 0x00 0x40 // Read whole MPEG stream into one sample and then split it up. FileReader chunk = mpegChunk.GetChunk(mpegChunk.BytesLeft()); if(ReadMP3Sample(0, chunk, true)) { ModSample &srcSample = Samples[0]; const std::byte *smpData = srcSample.sampleb(); SmpLength predelay = Util::muldiv_unsigned(20116, srcSample.nC5Speed, 100000); LimitMax(predelay, srcSample.nLength); smpData += predelay * srcSample.GetBytesPerSample(); srcSample.nLength -= predelay; for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { ModSample &sample = Samples[smp]; sample.uFlags.set(srcSample.uFlags); LimitMax(sample.nLength, srcSample.nLength); if(sample.nLength) { sample.AllocateSample(); memcpy(sample.sampleb(), smpData, sample.GetSampleSizeInBytes()); smpData += sample.GetSampleSizeInBytes(); srcSample.nLength -= sample.nLength; SmpLength gap = Util::muldiv_unsigned(454, srcSample.nC5Speed, 10000); LimitMax(gap, srcSample.nLength); smpData += gap * srcSample.GetBytesPerSample(); srcSample.nLength -= gap; } } srcSample.FreeSample(); } } #endif // MPT_ENABLE_MP3_SAMPLES return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/patternContainer.cpp0000644000175000017500000001171714610011735022126 00000000000000/* * PatternContainer.cpp * -------------------- * Purpose: Container class for managing patterns. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "patternContainer.h" #include "Sndfile.h" #include "mod_specifications.h" #include "../common/serialization_utils.h" #include "../common/version.h" OPENMPT_NAMESPACE_BEGIN CPatternContainer &CPatternContainer::operator=(const CPatternContainer &other) { if(this == &other || m_rSndFile.GetNumChannels() != other.m_rSndFile.GetNumChannels()) return *this; m_Patterns = other.m_Patterns; return *this; } CPatternContainer &CPatternContainer::operator=(CPatternContainer &&other) noexcept { if(this == &other || m_rSndFile.GetNumChannels() != other.m_rSndFile.GetNumChannels()) return *this; m_Patterns = std::move(other.m_Patterns); return *this; } void CPatternContainer::DestroyPatterns() { m_Patterns.clear(); } PATTERNINDEX CPatternContainer::Duplicate(PATTERNINDEX from, bool respectQtyLimits) { if(!IsValidPat(from)) { return PATTERNINDEX_INVALID; } PATTERNINDEX newPatIndex = InsertAny(m_Patterns[from].GetNumRows(), respectQtyLimits); if(newPatIndex != PATTERNINDEX_INVALID) { m_Patterns[newPatIndex] = m_Patterns[from]; } return newPatIndex; } PATTERNINDEX CPatternContainer::InsertAny(const ROWINDEX rows, bool respectQtyLimits) { PATTERNINDEX i = 0; for(i = 0; i < m_Patterns.size(); i++) if(!m_Patterns[i].IsValid()) break; if(respectQtyLimits && i >= m_rSndFile.GetModSpecifications().patternsMax) return PATTERNINDEX_INVALID; if(!Insert(i, rows)) return PATTERNINDEX_INVALID; else return i; } bool CPatternContainer::Insert(const PATTERNINDEX index, const ROWINDEX rows) { if(rows > MAX_PATTERN_ROWS || rows == 0 || index >= PATTERNINDEX_INVALID) return false; if(IsValidPat(index)) return false; try { if(index >= m_Patterns.size()) { m_Patterns.resize(index + 1, CPattern(*this)); } m_Patterns[index].AllocatePattern(rows); m_Patterns[index].RemoveSignature(); m_Patterns[index].SetName(""); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); return false; } return m_Patterns[index].IsValid(); } void CPatternContainer::Remove(const PATTERNINDEX ipat) { if(ipat < m_Patterns.size()) m_Patterns[ipat].Deallocate(); } bool CPatternContainer::IsPatternEmpty(const PATTERNINDEX nPat) const noexcept { if(!IsValidPat(nPat)) return false; for(const auto &m : m_Patterns[nPat].m_ModCommands) { if(!m.IsEmpty()) return false; } return true; } void CPatternContainer::ResizeArray(const PATTERNINDEX newSize) { m_Patterns.resize(newSize, CPattern(*this)); } void CPatternContainer::OnModTypeChanged(const MODTYPE /*oldtype*/) { const CModSpecifications specs = m_rSndFile.GetModSpecifications(); //if(specs.patternsMax < Size()) // ResizeArray(specs.patternsMax); // remove pattern time signatures if(!specs.hasPatternSignatures) { for(PATTERNINDEX nPat = 0; nPat < m_Patterns.size(); nPat++) { m_Patterns[nPat].RemoveSignature(); m_Patterns[nPat].RemoveTempoSwing(); } } } PATTERNINDEX CPatternContainer::GetNumPatterns() const noexcept { for(PATTERNINDEX pat = Size(); pat > 0; pat--) { if(IsValidPat(pat - 1)) { return pat; } } return 0; } PATTERNINDEX CPatternContainer::GetNumNamedPatterns() const noexcept { if(Size() == 0) { return 0; } for(PATTERNINDEX nPat = Size(); nPat > 0; nPat--) { if(!m_Patterns[nPat - 1].m_PatternName.empty()) { return nPat; } } return 0; } PATTERNINDEX CPatternContainer::GetRemainingCapacity() const noexcept { PATTERNINDEX numRemaining = m_rSndFile.GetModSpecifications().patternsMax; const PATTERNINDEX size = std::min(Size(), numRemaining); for(PATTERNINDEX pat = 0; pat < size; pat++) { if(m_Patterns[pat].IsValid()) numRemaining--; } return numRemaining; } void WriteModPatterns(std::ostream& oStrm, const CPatternContainer& patc) { srlztn::SsbWrite ssb(oStrm); ssb.BeginWrite(FileIdPatterns, Version::Current().GetRawVersion()); const PATTERNINDEX nPatterns = patc.Size(); uint16 nCount = 0; for(uint16 i = 0; i < nPatterns; i++) if (patc[i].IsValid()) { ssb.WriteItem(patc[i], srlztn::ID::FromInt(i), &WriteModPattern); nCount = i + 1; } ssb.WriteItem(nCount, "num"); // Index of last pattern + 1. ssb.FinishWrite(); } void ReadModPatterns(std::istream& iStrm, CPatternContainer& patc, const size_t) { srlztn::SsbRead ssb(iStrm); ssb.BeginRead(FileIdPatterns, Version::Current().GetRawVersion()); if(ssb.HasFailed()) { return; } PATTERNINDEX nPatterns = patc.Size(); uint16 nCount = uint16_max; if(ssb.ReadItem(nCount, "num")) { nPatterns = nCount; } LimitMax(nPatterns, ModSpecs::mptm.patternsMax); if (nPatterns > patc.Size()) patc.ResizeArray(nPatterns); for(uint16 i = 0; i < nPatterns; i++) { ssb.ReadItem(patc[i], srlztn::ID::FromInt(i), &ReadModPattern); } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/tuningcollection.h0000644000175000017500000000535714552441313021642 00000000000000/* * tuningCollection.h * ------------------ * Purpose: Alternative sample tuning collection class. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "tuning.h" #include #include OPENMPT_NAMESPACE_BEGIN namespace Tuning { class CTuningCollection { public: static constexpr char s_FileExtension[4] = ".tc"; // OpenMPT <= 1.26 had to following limits: // * 255 built-in tunings (only 2 were ever actually provided) // * 255 local tunings // * 255 tune-specific tunings // As 1.27 copies all used tunings into the module, the limit of 255 is no // longer sufficient. In the worst case scenario, the module contains 255 // unused tunings and uses 255 local ones. In addition to that, allow the // user to additionally import both built-in tunings. // Older OpenMPT versions will silently skip loading tunings beyond index // 255. static constexpr size_t s_nMaxTuningCount = 255 + 255 + 2 ; public: // returns observer ptr if successful CTuning* AddTuning(std::unique_ptr pT); CTuning* AddTuning(std::istream &inStrm, mpt::Charset defaultCharset); bool Remove(const std::size_t i); bool Remove(const CTuning *pT); std::size_t GetNumTunings() const { return m_Tunings.size(); } CTuning* GetTuning(std::size_t i) { if(i >= m_Tunings.size()) { return nullptr; } return m_Tunings[i].get(); } const CTuning* GetTuning(std::size_t i) const { if (i >= m_Tunings.size()) { return nullptr; } return m_Tunings[i].get(); } CTuning* GetTuning(const mpt::ustring &name); const CTuning* GetTuning(const mpt::ustring &name) const; CTuning* FindIdenticalTuning(const CTuning &tuning); const CTuning* FindIdenticalTuning(const CTuning& tuning) const; Tuning::SerializationResult Serialize(std::ostream &oStrm, const mpt::ustring &name) const; Tuning::SerializationResult Deserialize(std::istream &iStrm, mpt::ustring &name, mpt::Charset defaultCharset); auto begin() { return m_Tunings.begin(); } auto begin() const { return m_Tunings.begin(); } auto cbegin() { return m_Tunings.cbegin(); } auto end() { return m_Tunings.end(); } auto end() const { return m_Tunings.end(); } auto cend() { return m_Tunings.cend(); } private: std::vector > m_Tunings; private: Tuning::SerializationResult DeserializeOLD(std::istream &inStrm, mpt::ustring &uname, mpt::Charset defaultCharset); }; #ifdef MODPLUG_TRACKER bool UnpackTuningCollection(const CTuningCollection &tc, const mpt::PathString &prefix); #endif } // namespace Tuning using CTuningCollection = Tuning::CTuningCollection; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/tuning.cpp0000644000175000017500000006741314771711752020134 00000000000000/* * tuning.cpp * ---------- * Purpose: Alternative sample tuning. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "tuning.h" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "../common/serialization_utils.h" #include "../common/misc_util.h" #include #include OPENMPT_NAMESPACE_BEGIN namespace Tuning { static RATIOTYPE SanitizeGroupRatio(RATIOTYPE ratio) { return std::clamp(std::abs(ratio), 1e-15f, 1e+07f); } namespace CTuningS11n { void ReadStr(std::istream &iStrm, mpt::ustring &ustr, const std::size_t dummy, mpt::Charset charset); void ReadNoteMap(std::istream &iStrm, std::map &m, const std::size_t dummy, mpt::Charset charset); void ReadRatioTable(std::istream& iStrm, std::vector& v, const size_t); void WriteNoteMap(std::ostream &oStrm, const std::map &m); void WriteStr(std::ostream &oStrm, const mpt::ustring &ustr); struct RatioWriter { RatioWriter(uint16 nWriteCount = s_nDefaultWriteCount) : m_nWriteCount(nWriteCount) {} void operator()(std::ostream& oStrm, const std::vector& v); uint16 m_nWriteCount; enum : uint16 { s_nDefaultWriteCount = (uint16_max >> 2) }; }; } using namespace CTuningS11n; /* Version history: 4->5: Lots of changes, finestep interpretation revamp, fileformat revamp. 3->4: Changed sizetypes in serialisation from size_t(uint32) to smaller types (uint8, USTEPTYPE) (March 2007) */ /* Version changes: 3->4: Finetune related internal structure and serialization revamp. 2->3: The type for the size_type in the serialisation changed from default(size_t, uint32) to unsigned STEPTYPE. (March 2007) */ static_assert(CTuning::s_RatioTableFineSizeMaxDefault < static_cast(FINESTEPCOUNT_MAX)); CTuning::CTuning() { #if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(12, 3, 0) // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109455 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100366 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-overflow" #endif m_RatioTable.resize(s_RatioTableSizeDefault, 1); #if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(12, 3, 0) #pragma GCC diagnostic pop #endif } bool CTuning::operator==(const CTuning &other) const noexcept { return m_TuningType == other.m_TuningType && m_NoteMin == other.m_NoteMin && m_GroupSize == other.m_GroupSize && m_GroupRatio == other.m_GroupRatio && m_FineStepCount == other.m_FineStepCount && m_RatioTable == other.m_RatioTable && m_RatioTableFine == other.m_RatioTableFine && m_TuningName == other.m_TuningName && m_NoteNameMap == other.m_NoteNameMap; } bool CTuning::CreateGroupGeometric(const NOTEINDEXTYPE &s, const RATIOTYPE &r, const NOTEINDEXTYPE &startindex) { if(s < 1 || !IsValidRatio(r) || startindex < GetNoteRange().first) { return false; } std::vector v; v.reserve(s); for(NOTEINDEXTYPE i = startindex; i < startindex + s; i++) { v.push_back(GetRatio(i)); } return CreateGroupGeometric(v, r, GetNoteRange(), startindex); } bool CTuning::CreateGroupGeometric(const std::vector &v, const RATIOTYPE &r, const NoteRange &range, const NOTEINDEXTYPE &ratiostartpos) { if(range.first > range.last || v.size() == 0) { return false; } if(ratiostartpos < range.first || range.last < ratiostartpos || static_cast(range.last - ratiostartpos) < static_cast(v.size() - 1)) { return false; } if(GetFineStepCount() > FINESTEPCOUNT_MAX) { return false; } for(size_t i = 0; i < v.size(); i++) { if(v[i] < 0) { return false; } } if(r <= 0) { return false; } m_TuningType = Type::GROUPGEOMETRIC; m_NoteMin = range.first; m_GroupSize = mpt::saturate_cast(v.size()); m_GroupRatio = std::fabs(r); m_RatioTable.resize(range.last - range.first + 1); std::copy(v.begin(), v.end(), m_RatioTable.begin() + (ratiostartpos - range.first)); for(int32 i = ratiostartpos - 1; i >= m_NoteMin && ratiostartpos > NOTEINDEXTYPE_MIN; i--) { m_RatioTable[i - m_NoteMin] = m_RatioTable[i - m_NoteMin + m_GroupSize] / m_GroupRatio; } for(int32 i = ratiostartpos + m_GroupSize; i <= range.last && ratiostartpos <= (NOTEINDEXTYPE_MAX - m_GroupSize); i++) { m_RatioTable[i - m_NoteMin] = m_GroupRatio * m_RatioTable[i - m_NoteMin - m_GroupSize]; } UpdateFineStepTable(); return true; } bool CTuning::CreateGeometric(const UNOTEINDEXTYPE &p, const RATIOTYPE &r) { return CreateGeometric(p, r, GetNoteRange()); } bool CTuning::CreateGeometric(const UNOTEINDEXTYPE &s, const RATIOTYPE &r, const NoteRange &range) { if(range.first > range.last) { return false; } if(s < 1 || !IsValidRatio(r)) { return false; } if(range.last - range.first + 1 > NOTEINDEXTYPE_MAX) { return false; } m_TuningType = Type::GEOMETRIC; m_RatioTable.clear(); m_NoteMin = s_NoteMinDefault; m_RatioTable.resize(s_RatioTableSizeDefault, static_cast(1.0)); m_GroupSize = 0; m_GroupRatio = 0; m_RatioTableFine.clear(); m_NoteMin = range.first; m_GroupSize = mpt::saturate_cast(s); m_GroupRatio = std::fabs(r); const RATIOTYPE stepRatio = std::pow(m_GroupRatio, static_cast(1.0) / static_cast(m_GroupSize)); m_RatioTable.resize(range.last - range.first + 1); for(int32 i = range.first; i <= range.last; i++) { m_RatioTable[i - m_NoteMin] = std::pow(stepRatio, static_cast(i)); } UpdateFineStepTable(); return true; } mpt::ustring CTuning::GetNoteName(const NOTEINDEXTYPE &x, bool addOctave) const { if(!IsValidNote(x)) { return mpt::ustring(); } if(GetGroupSize() < 1) { const auto i = m_NoteNameMap.find(x); if(i != m_NoteNameMap.end()) return i->second; else return mpt::ufmt::val(x); } else { const NOTEINDEXTYPE pos = static_cast(mpt::wrapping_modulo(x, m_GroupSize)); const NOTEINDEXTYPE middlePeriodNumber = 5; mpt::ustring rValue; const auto nmi = m_NoteNameMap.find(pos); if(nmi != m_NoteNameMap.end()) { rValue = nmi->second; if(addOctave) { rValue += mpt::ufmt::val(middlePeriodNumber + mpt::wrapping_divide(x, m_GroupSize)); } } else { //By default, using notation nnP for notes; nn <-> note character starting //from 'A' with char ':' as fill char, and P is period integer. For example: //C:5, D:3, R:7 if(m_GroupSize <= 26) { rValue = mpt::ToUnicode(mpt::Charset::UTF8, std::string(1, static_cast(pos + 'A'))); rValue += UL_(":"); } else { rValue = mpt::ufmt::HEX0<1>(pos % 16) + mpt::ufmt::HEX0<1>((pos / 16) % 16); if(pos > 0xff) { rValue = mpt::ToUnicode(mpt::Charset::UTF8, mpt::ToLowerCaseAscii(mpt::ToCharset(mpt::Charset::UTF8, rValue))); } } if(addOctave) { rValue += mpt::ufmt::val(middlePeriodNumber + mpt::wrapping_divide(x, m_GroupSize)); } } return rValue; } } void CTuning::SetNoteName(const NOTEINDEXTYPE &n, const mpt::ustring &str) { const NOTEINDEXTYPE pos = (GetGroupSize() < 1) ? n : static_cast(mpt::wrapping_modulo(n, m_GroupSize)); if(!str.empty()) { m_NoteNameMap[pos] = str; } else { const auto iter = m_NoteNameMap.find(pos); if(iter != m_NoteNameMap.end()) { m_NoteNameMap.erase(iter); } } } // Without finetune RATIOTYPE CTuning::GetRatio(const NOTEINDEXTYPE note) const { if(!IsValidNote(note)) { return s_DefaultFallbackRatio; } const auto ratio = m_RatioTable[note - m_NoteMin]; if(ratio <= 1e-15f) { return s_DefaultFallbackRatio; } return ratio; } // With finetune RATIOTYPE CTuning::GetRatio(const NOTEINDEXTYPE baseNote, const STEPINDEXTYPE baseFineSteps) const { const STEPINDEXTYPE fineStepCount = static_cast(GetFineStepCount()); if(fineStepCount == 0 || baseFineSteps == 0) { return GetRatio(static_cast(baseNote + baseFineSteps)); } // If baseFineSteps is more than the number of finesteps between notes, note is increased. // So first figuring out what note and fineStep values to actually use. // Interpreting finestep==-1 on note x so that it is the same as finestep==fineStepCount on note x-1. // Note: If fineStepCount is n, n+1 steps are needed to get to next note. const NOTEINDEXTYPE note = static_cast(baseNote + mpt::wrapping_divide(baseFineSteps, (fineStepCount + 1))); const STEPINDEXTYPE fineStep = mpt::wrapping_modulo(baseFineSteps, (fineStepCount + 1)); if(!IsValidNote(note)) { return s_DefaultFallbackRatio; } if(fineStep == 0) { return m_RatioTable[note - m_NoteMin]; } RATIOTYPE fineRatio = static_cast(1.0); if(GetType() == Type::GEOMETRIC && m_RatioTableFine.size() > 0) { fineRatio = m_RatioTableFine[fineStep - 1]; } else if(GetType() == Type::GROUPGEOMETRIC && m_RatioTableFine.size() > 0) { fineRatio = m_RatioTableFine[GetRefNote(note) * fineStepCount + fineStep - 1]; } else { // Geometric finestepping fineRatio = std::pow(GetRatio(note + 1) / GetRatio(note), static_cast(fineStep) / static_cast(fineStepCount + 1)); } return m_RatioTable[note - m_NoteMin] * fineRatio; } bool CTuning::SetRatio(const NOTEINDEXTYPE& s, const RATIOTYPE& r) { if(GetType() != Type::GROUPGEOMETRIC && GetType() != Type::GENERAL) { return false; } //Creating ratio table if doesn't exist. if(m_RatioTable.empty()) { m_RatioTable.assign(s_RatioTableSizeDefault, 1); m_NoteMin = s_NoteMinDefault; } if(!IsValidNote(s)) { return false; } m_RatioTable[s - m_NoteMin] = std::fabs(r); if(GetType() == Type::GROUPGEOMETRIC) { // update other groups for(NOTEINDEXTYPE n = m_NoteMin; n < m_NoteMin + static_cast(m_RatioTable.size()); ++n) { if(n == s) { // nothing } else if(std::abs(n - s) % m_GroupSize == 0) { m_RatioTable[n - m_NoteMin] = std::pow(m_GroupRatio, static_cast(n - s) / static_cast(m_GroupSize)) * m_RatioTable[s - m_NoteMin]; } } UpdateFineStepTable(); } return true; } void CTuning::SetFineStepCount(const USTEPINDEXTYPE& fs) { m_FineStepCount = std::clamp(mpt::saturate_cast(fs), STEPINDEXTYPE(0), FINESTEPCOUNT_MAX); UpdateFineStepTable(); } void CTuning::UpdateFineStepTable() { if(m_FineStepCount <= 0) { m_RatioTableFine.clear(); return; } if(GetType() == Type::GEOMETRIC) { if(m_FineStepCount > s_RatioTableFineSizeMaxDefault) { m_RatioTableFine.clear(); return; } m_RatioTableFine.resize(m_FineStepCount); const RATIOTYPE q = GetRatio(GetNoteRange().first + 1) / GetRatio(GetNoteRange().first); const RATIOTYPE rFineStep = std::pow(q, static_cast(1) / static_cast(m_FineStepCount + 1)); for(USTEPINDEXTYPE i = 1; i<=m_FineStepCount; i++) m_RatioTableFine[i-1] = std::pow(rFineStep, static_cast(i)); return; } if(GetType() == Type::GROUPGEOMETRIC) { const UNOTEINDEXTYPE p = GetGroupSize(); if(p > s_RatioTableFineSizeMaxDefault / m_FineStepCount) { //In case fineratiotable would become too large, not using //table for it. m_RatioTableFine.clear(); return; } else { //Creating 'geometric' finestepping between notes. m_RatioTableFine.resize(p * m_FineStepCount); const NOTEINDEXTYPE startnote = GetRefNote(GetNoteRange().first); for(UNOTEINDEXTYPE i = 0; i(startnote + i)); const RATIOTYPE rFineStep = std::pow(GetRatio(refnote+1) / GetRatio(refnote), static_cast(1) / static_cast(m_FineStepCount + 1)); for(UNOTEINDEXTYPE j = 1; j<=m_FineStepCount; j++) { m_RatioTableFine[m_FineStepCount * refnote + (j-1)] = std::pow(rFineStep, static_cast(j)); } } return; } } if(GetType() == Type::GENERAL) { //Not using table with tuning of type general. m_RatioTableFine.clear(); return; } //Should not reach here. m_RatioTableFine.clear(); m_FineStepCount = 0; } bool CTuning::Multiply(const RATIOTYPE r) { if(!IsValidRatio(r)) { return false; } for(auto & ratio : m_RatioTable) { ratio *= r; } return true; } bool CTuning::ChangeGroupsize(const NOTEINDEXTYPE& s) { if(s < 1) return false; if(m_TuningType == Type::GROUPGEOMETRIC) return CreateGroupGeometric(s, GetGroupRatio(), 0); if(m_TuningType == Type::GEOMETRIC) return CreateGeometric(s, GetGroupRatio()); return false; } bool CTuning::ChangeGroupRatio(const RATIOTYPE& r) { if(!IsValidRatio(r)) return false; if(m_TuningType == Type::GROUPGEOMETRIC) return CreateGroupGeometric(GetGroupSize(), r, 0); if(m_TuningType == Type::GEOMETRIC) return CreateGeometric(GetGroupSize(), r); return false; } SerializationResult CTuning::InitDeserialize(std::istream &iStrm, mpt::Charset defaultCharset) { // Note: OpenMPT since at least r323 writes version number (4<<24)+4 while it // reads version number (5<<24)+4 or earlier. // We keep this behaviour. if(iStrm.fail()) return SerializationResult::Failure; srlztn::SsbRead ssb(iStrm); ssb.BeginRead("CTB244RTI", (5 << 24) + 4); // version int8 use_utf8 = 0; ssb.ReadItem(use_utf8, "UTF8"); const mpt::Charset charset = use_utf8 ? mpt::Charset::UTF8 : defaultCharset; ssb.ReadItem(m_TuningName, "0", [charset](std::istream &iStrm, mpt::ustring &ustr, const std::size_t dummy){ return ReadStr(iStrm, ustr, dummy, charset); }); uint16 dummyEditMask = 0xffff; ssb.ReadItem(dummyEditMask, "1"); std::underlying_type::type type = 0; ssb.ReadItem(type, "2"); m_TuningType = static_cast(type); ssb.ReadItem(m_NoteNameMap, "3", [charset](std::istream &iStrm, std::map &m, const std::size_t dummy){ return ReadNoteMap(iStrm, m, dummy, charset); }); ssb.ReadItem(m_FineStepCount, "4"); // RTI entries. ssb.ReadItem(m_RatioTable, "RTI0", ReadRatioTable); ssb.ReadItem(m_NoteMin, "RTI1"); ssb.ReadItem(m_GroupSize, "RTI2"); ssb.ReadItem(m_GroupRatio, "RTI3"); UNOTEINDEXTYPE ratiotableSize = 0; ssb.ReadItem(ratiotableSize, "RTI4"); m_GroupRatio = SanitizeGroupRatio(m_GroupRatio); if(!std::isfinite(m_GroupRatio)) { return SerializationResult::Failure; } for(auto ratio : m_RatioTable) { if(!std::isfinite(ratio)) return SerializationResult::Failure; } // If reader status is ok and m_NoteMin is somewhat reasonable, process data. if(ssb.HasFailed() || (m_NoteMin < -300) || (m_NoteMin > 300)) { return SerializationResult::Failure; } // reject unknown types if(m_TuningType != Type::GENERAL && m_TuningType != Type::GROUPGEOMETRIC && m_TuningType != Type::GEOMETRIC) { return SerializationResult::Failure; } if(m_GroupSize < 0) { return SerializationResult::Failure; } m_FineStepCount = std::clamp(mpt::saturate_cast(m_FineStepCount), STEPINDEXTYPE(0), FINESTEPCOUNT_MAX); if(m_RatioTable.size() > static_cast(NOTEINDEXTYPE_MAX)) { return SerializationResult::Failure; } if((GetType() == Type::GROUPGEOMETRIC) || (GetType() == Type::GEOMETRIC)) { if(ratiotableSize < 1 || ratiotableSize > NOTEINDEXTYPE_MAX) { return SerializationResult::Failure; } if(GetType() == Type::GEOMETRIC) { if(!CreateGeometric(GetGroupSize(), GetGroupRatio(), NoteRange{m_NoteMin, static_cast(m_NoteMin + ratiotableSize - 1)})) { return SerializationResult::Failure; } } else { if(!CreateGroupGeometric(m_RatioTable, GetGroupRatio(), NoteRange{m_NoteMin, static_cast(m_NoteMin + ratiotableSize - 1)}, m_NoteMin)) { return SerializationResult::Failure; } } } else { UpdateFineStepTable(); } return SerializationResult::Success; } template static bool VectorFromBinaryStream(std::istream& inStrm, std::vector& v, const SIZETYPE maxSize = (std::numeric_limits::max)()) { if(!inStrm.good()) return false; SIZETYPE size = 0; mpt::IO::ReadIntLE(inStrm, size); if(size > maxSize) return false; v.resize(size); for(std::size_t i = 0; i(inStrm.tellg()); //First checking is there expected begin sequence. char begin[8]; MemsetZero(begin); inStrm.read(begin, sizeof(begin)); if(std::memcmp(begin, "CTRTI_B.", 8)) { //Returning stream position if beginmarker was not found. inStrm.seekg(startPos, std::ios::beg); return SerializationResult::Failure; } //Version int16 version = 0; mpt::IO::ReadIntLE(inStrm, version); if(version != 2 && version != 3) return SerializationResult::Failure; char begin2[8]; MemsetZero(begin2); inStrm.read(begin2, sizeof(begin2)); if(std::memcmp(begin2, "CTB", 8)) { return SerializationResult::Failure; } int16 version2 = 0; mpt::IO::ReadIntLE(inStrm, version2); if(version2 != 3 && version2 != 4) { return SerializationResult::Failure; } //Tuning name if(version2 <= 3) { std::string tmpName; if(!mpt::IO::ReadSizedStringLE(inStrm, tmpName, 0xffff)) { return SerializationResult::Failure; } m_TuningName = mpt::ToUnicode(defaultCharset, tmpName); } else { std::string tmpName; if(!mpt::IO::ReadSizedStringLE(inStrm, tmpName)) { return SerializationResult::Failure; } m_TuningName = mpt::ToUnicode(defaultCharset, tmpName); } //Const mask int16 em = 0; mpt::IO::ReadIntLE(inStrm, em); //Tuning type int16 tt = 0; mpt::IO::ReadIntLE(inStrm, tt); m_TuningType = static_cast(tt); //Notemap uint16 size = 0; if(version2 <= 3) { uint32 tempsize = 0; mpt::IO::ReadIntLE(inStrm, tempsize); if(tempsize > 0xffff) { return SerializationResult::Failure; } size = mpt::saturate_cast(tempsize); } else { mpt::IO::ReadIntLE(inStrm, size); } for(UNOTEINDEXTYPE i = 0; i(inStrm, n); if(version2 <= 3) { if(!mpt::IO::ReadSizedStringLE(inStrm, str, 0xffff)) { return SerializationResult::Failure; } } else { if(!mpt::IO::ReadSizedStringLE(inStrm, str)) { return SerializationResult::Failure; } } m_NoteNameMap[n] = mpt::ToUnicode(defaultCharset, str); } //End marker char end2[8]; MemsetZero(end2); inStrm.read(end2, sizeof(end2)); if(std::memcmp(end2, "CTE", 8)) { return SerializationResult::Failure; } // reject unknown types if(m_TuningType != Type::GENERAL && m_TuningType != Type::GROUPGEOMETRIC && m_TuningType != Type::GEOMETRIC) { return SerializationResult::Failure; } //Ratiotable if(version <= 2) { if(!VectorFromBinaryStream(inStrm, m_RatioTable, 0xffff)) { return SerializationResult::Failure; } } else { if(!VectorFromBinaryStream(inStrm, m_RatioTable)) { return SerializationResult::Failure; } } for(auto ratio : m_RatioTable) { if(!std::isfinite(ratio)) return SerializationResult::Failure; } //Fineratios if(version <= 2) { if(!VectorFromBinaryStream(inStrm, m_RatioTableFine, 0xffff)) { return SerializationResult::Failure; } } else { if(!VectorFromBinaryStream(inStrm, m_RatioTableFine)) { return SerializationResult::Failure; } } for(auto ratio : m_RatioTableFine) { if(!std::isfinite(ratio)) return SerializationResult::Failure; } m_FineStepCount = mpt::saturate_cast(m_RatioTableFine.size()); // m_NoteMin int16 notemin = 0; mpt::IO::ReadIntLE(inStrm, notemin); m_NoteMin = notemin; if(m_NoteMin < -200 || m_NoteMin > 200) { return SerializationResult::Failure; } //m_GroupSize int16 groupsize = 0; mpt::IO::ReadIntLE(inStrm, groupsize); m_GroupSize = groupsize; if(m_GroupSize < 0) { return SerializationResult::Failure; } //m_GroupRatio IEEE754binary32LE groupratio = IEEE754binary32LE(0.0f); mpt::IO::Read(inStrm, groupratio); m_GroupRatio = SanitizeGroupRatio(groupratio); if(!std::isfinite(m_GroupRatio)) { return SerializationResult::Failure; } std::array end = {}; mpt::IO::Read(inStrm, end); if(std::memcmp(end.data(), "CTRTI_E.", 8)) { return SerializationResult::Failure; } // reject corrupt tunings if(m_RatioTable.size() > static_cast(NOTEINDEXTYPE_MAX)) { return SerializationResult::Failure; } if((m_GroupSize <= 0 || m_GroupRatio <= 0) && m_TuningType != Type::GENERAL) { return SerializationResult::Failure; } if(m_TuningType == Type::GROUPGEOMETRIC || m_TuningType == Type::GEOMETRIC) { if(m_RatioTable.size() < static_cast(m_GroupSize)) { return SerializationResult::Failure; } } // convert old finestepcount if(m_FineStepCount > 0) { m_FineStepCount -= 1; } m_FineStepCount = std::clamp(mpt::saturate_cast(m_FineStepCount), STEPINDEXTYPE(0), FINESTEPCOUNT_MAX); UpdateFineStepTable(); if(m_TuningType == Type::GEOMETRIC) { // Convert old geometric to new groupgeometric because old geometric tunings // can have ratio(0) != 1.0, which would get lost when saving nowadays. if(mpt::saturate_cast(m_RatioTable.size()) >= m_GroupSize - m_NoteMin) { std::vector ratios; for(NOTEINDEXTYPE n = 0; n < m_GroupSize; ++n) { ratios.push_back(m_RatioTable[n - m_NoteMin]); } CreateGroupGeometric(ratios, m_GroupRatio, GetNoteRange(), 0); } } return SerializationResult::Success; } Tuning::SerializationResult CTuning::Serialize(std::ostream& outStrm) const { // Note: OpenMPT since at least r323 writes version number (4<<24)+4 while it // reads version number (5<<24)+4. // We keep this behaviour. srlztn::SsbWrite ssb(outStrm); ssb.BeginWrite("CTB244RTI", (4 << 24) + 4); // version ssb.WriteItem(int8(1), "UTF8"); if (m_TuningName.length() > 0) ssb.WriteItem(m_TuningName, "0", WriteStr); uint16 dummyEditMask = 0xffff; ssb.WriteItem(dummyEditMask, "1"); ssb.WriteItem(mpt::to_underlying(m_TuningType), "2"); if (m_NoteNameMap.size() > 0) ssb.WriteItem(m_NoteNameMap, "3", WriteNoteMap); if (GetFineStepCount() > 0) ssb.WriteItem(m_FineStepCount, "4"); const Tuning::Type tt = GetType(); if (GetGroupRatio() > 0) ssb.WriteItem(m_GroupRatio, "RTI3"); if (tt == Type::GROUPGEOMETRIC) ssb.WriteItem(m_RatioTable, "RTI0", RatioWriter(GetGroupSize())); if (tt == Type::GENERAL) ssb.WriteItem(m_RatioTable, "RTI0", RatioWriter()); if (tt == Type::GEOMETRIC) ssb.WriteItem(m_GroupSize, "RTI2"); if(tt == Type::GEOMETRIC || tt == Type::GROUPGEOMETRIC) { //For Groupgeometric this data is the number of ratios in ratiotable. UNOTEINDEXTYPE ratiotableSize = static_cast(m_RatioTable.size()); ssb.WriteItem(ratiotableSize, "RTI4"); } // m_NoteMin ssb.WriteItem(m_NoteMin, "RTI1"); ssb.FinishWrite(); return ssb.HasFailed() ? Tuning::SerializationResult::Failure : Tuning::SerializationResult::Success; } #ifdef MODPLUG_TRACKER bool CTuning::WriteSCL(std::ostream &f, const mpt::PathString &filename) const { mpt::IO::WriteTextCRLF(f, MPT_AFORMAT("! {}")(mpt::ToCharset(mpt::Charset::ISO8859_1, (filename.GetFilenameBase() + filename.GetFilenameExtension()).ToUnicode()))); mpt::IO::WriteTextCRLF(f, "!"); std::string name = mpt::ToCharset(mpt::Charset::ISO8859_1, GetName()); for(auto & c : name) { if(static_cast(c) < 32) c = ' '; } // remove control characters if(name.length() >= 1 && name[0] == '!') name[0] = '?'; // do not confuse description with comment mpt::IO::WriteTextCRLF(f, name); if(GetType() == Type::GEOMETRIC) { mpt::IO::WriteTextCRLF(f, MPT_AFORMAT(" {}")(m_GroupSize)); mpt::IO::WriteTextCRLF(f, "!"); for(NOTEINDEXTYPE n = 0; n < m_GroupSize; ++n) { double ratio = std::pow(static_cast(m_GroupRatio), static_cast(n + 1) / static_cast(m_GroupSize)); double cents = std::log2(ratio) * 1200.0; mpt::IO::WriteTextCRLF(f, MPT_AFORMAT(" {} ! {}")( mpt::afmt::fix(cents), mpt::ToCharset(mpt::Charset::ISO8859_1, GetNoteName((n + 1) % m_GroupSize, false)) )); } } else if(GetType() == Type::GROUPGEOMETRIC) { mpt::IO::WriteTextCRLF(f, MPT_AFORMAT(" {}")(m_GroupSize)); mpt::IO::WriteTextCRLF(f, "!"); for(NOTEINDEXTYPE n = 0; n < m_GroupSize; ++n) { bool last = (n == (m_GroupSize - 1)); double baseratio = static_cast(GetRatio(0)); double ratio = static_cast(last ? m_GroupRatio : GetRatio(n + 1)) / baseratio; double cents = std::log2(ratio) * 1200.0; mpt::IO::WriteTextCRLF(f, MPT_AFORMAT(" {} ! {}")( mpt::afmt::fix(cents), mpt::ToCharset(mpt::Charset::ISO8859_1, GetNoteName((n + 1) % m_GroupSize, false)) )); } } else if(GetType() == Type::GENERAL) { mpt::IO::WriteTextCRLF(f, MPT_AFORMAT(" {}")(m_RatioTable.size() + 1)); mpt::IO::WriteTextCRLF(f, "!"); double baseratio = 1.0; for(NOTEINDEXTYPE n = 0; n < mpt::saturate_cast(m_RatioTable.size()); ++n) { baseratio = std::min(baseratio, static_cast(m_RatioTable[n])); } for(NOTEINDEXTYPE n = 0; n < mpt::saturate_cast(m_RatioTable.size()); ++n) { double ratio = static_cast(m_RatioTable[n]) / baseratio; double cents = std::log2(ratio) * 1200.0; mpt::IO::WriteTextCRLF(f, MPT_AFORMAT(" {} ! {}")( mpt::afmt::fix(cents), mpt::ToCharset(mpt::Charset::ISO8859_1, GetNoteName(n + m_NoteMin, false)) )); } mpt::IO::WriteTextCRLF(f, MPT_AFORMAT(" {} ! {}")( mpt::afmt::val(1), std::string() )); } else { return false; } return true; } #endif namespace CTuningS11n { void RatioWriter::operator()(std::ostream& oStrm, const std::vector& v) { const std::size_t nWriteCount = std::min(v.size(), static_cast(m_nWriteCount)); mpt::IO::WriteAdaptiveInt64LE(oStrm, nWriteCount); for(size_t i = 0; i < nWriteCount; i++) mpt::IO::Write(oStrm, IEEE754binary32LE(v[i])); } void ReadNoteMap(std::istream &iStrm, std::map &m, const std::size_t dummy, mpt::Charset charset) { MPT_UNREFERENCED_PARAMETER(dummy); uint64 val; mpt::IO::ReadAdaptiveInt64LE(iStrm, val); LimitMax(val, 256u); // Read 256 at max. for(size_t i = 0; i < val; i++) { int16 key; mpt::IO::ReadIntLE(iStrm, key); std::string str; mpt::IO::ReadSizedStringLE(iStrm, str); m[key] = mpt::ToUnicode(charset, str); } } void ReadRatioTable(std::istream& iStrm, std::vector& v, const size_t) { uint64 val; mpt::IO::ReadAdaptiveInt64LE(iStrm, val); v.resize(std::min(mpt::saturate_cast(val), std::size_t(256))); // Read 256 vals at max. for(size_t i = 0; i < v.size(); i++) { IEEE754binary32LE tmp(0.0f); mpt::IO::Read(iStrm, tmp); v[i] = tmp; } } void ReadStr(std::istream &iStrm, mpt::ustring &ustr, const std::size_t dummy, mpt::Charset charset) { MPT_UNREFERENCED_PARAMETER(dummy); std::string str; uint64 val; mpt::IO::ReadAdaptiveInt64LE(iStrm, val); size_t nSize = (val > 255) ? 255 : static_cast(val); // Read 255 characters at max. str.clear(); str.resize(nSize); for(size_t i = 0; i < nSize; i++) mpt::IO::ReadIntLE(iStrm, str[i]); if(str.find_first_of('\0') != std::string::npos) { // trim \0 at the end str.resize(str.find_first_of('\0')); } ustr = mpt::ToUnicode(charset, str); } void WriteNoteMap(std::ostream &oStrm, const std::map &m) { mpt::IO::WriteAdaptiveInt64LE(oStrm, m.size()); for(auto &mi : m) { mpt::IO::WriteIntLE(oStrm, mi.first); mpt::IO::WriteSizedStringLE(oStrm, mpt::ToCharset(mpt::Charset::UTF8, mi.second)); } } void WriteStr(std::ostream &oStrm, const mpt::ustring &ustr) { std::string str = mpt::ToCharset(mpt::Charset::UTF8, ustr); mpt::IO::WriteAdaptiveInt64LE(oStrm, str.size()); oStrm.write(str.c_str(), str.size()); } } // namespace CTuningS11n. } // namespace Tuning OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Tagging.h0000644000175000017500000000076414657643661017657 00000000000000/* * Tagging.h * --------- * Purpose: Structure holding a superset of tags for all supported output sample or stream files or types. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/soundfile_data/tags.hpp" OPENMPT_NAMESPACE_BEGIN mpt::ustring GetSampleNameFromTags(const FileTags &tags); OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MPEGFrame.h0000644000175000017500000000131314353564167017765 00000000000000/* * MPEGFrame.h * ----------- * Purpose: Basic MPEG frame parsing functionality * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "../common/FileReaderFwd.h" OPENMPT_NAMESPACE_BEGIN class MPEGFrame { public: uint16 frameSize; // Complete frame size in bytes uint16 numSamples; // Number of samples in this frame (multiplied by number of channels) bool isValid; // Is a valid frame at all bool isLAME; // Has Xing/LAME header MPEGFrame(FileCursor &file); static bool IsMPEGHeader(const uint8 (&header)[3]); }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_dmf.cpp0000644000175000017500000010672414674265644020342 00000000000000/* * load_dmf.cpp * ------------ * Purpose: DMF module loader (X-Tracker by D-LUSiON). * Notes : If it wasn't already outdated when the tracker left beta state, this would be a rather interesting * and in some parts even sophisticated format - effect columns are separated by effect type, an easy to * understand BPM tempo mode, effect durations are always divided into a 256th row, vibrato effects are * specified by period length and the same 8-Bit granularity is used for both volume and panning. * Unluckily, this format does not offer any envelopes or multi-sample instruments, and bidi sample loops * are missing as well, so it was already well behind FT2 back then. * Authors: Johannes Schultz (mostly based on DMF.TXT, DMF_EFFC.TXT, trial and error and some invaluable hints by Zatzen) * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "BitReader.h" OPENMPT_NAMESPACE_BEGIN // DMF header struct DMFFileHeader { char signature[4]; // "DDMF" uint8 version; // 1 - 7 are beta versions, 8 is the official thing, 10 is xtracker32 char tracker[8]; // "XTRACKER", or "SCREAM 3" when converting from S3M, etc. char songname[30]; char composer[20]; uint8 creationDay; uint8 creationMonth; uint8 creationYear; }; MPT_BINARY_STRUCT(DMFFileHeader, 66) struct DMFChunk { // 32-Bit chunk identifiers enum ChunkIdentifiers { idCMSG = MagicLE("CMSG"), // Song message idSEQU = MagicLE("SEQU"), // Order list idPATT = MagicLE("PATT"), // Patterns idSMPI = MagicLE("SMPI"), // Sample headers idSMPD = MagicLE("SMPD"), // Sample data idSMPJ = MagicLE("SMPJ"), // Sample jump table (XTracker 32 only) idENDE = MagicLE("ENDE"), // Last four bytes of DMF file idSETT = MagicLE("SETT"), // Probably contains GUI settings }; uint32le id; uint32le length; size_t GetLength() const { return length; } ChunkIdentifiers GetID() const { return static_cast(id.get()); } }; MPT_BINARY_STRUCT(DMFChunk, 8) // Pattern header (global) struct DMFPatterns { uint16le numPatterns; // 1..1024 patterns uint8le numTracks; // 1..32 channels }; MPT_BINARY_STRUCT(DMFPatterns, 3) // Pattern header (for each pattern) struct DMFPatternHeader { uint8le numTracks; // 1..32 channels uint8le beat; // [hi|lo] -> hi = rows per beat, lo = reserved uint16le numRows; uint32le patternLength; // patttern data follows here ... }; MPT_BINARY_STRUCT(DMFPatternHeader, 8) // Sample header struct DMFSampleHeader { enum SampleFlags { // Sample flags smpLoop = 0x01, smp16Bit = 0x02, smpCompMask = 0x0C, smpComp1 = 0x04, // Compression type 1 smpComp2 = 0x08, // Compression type 2 (unused) smpComp3 = 0x0C, // Compression type 3 (ditto) smpLibrary = 0x80, // Sample is stored in a library }; uint32le length; uint32le loopStart; uint32le loopEnd; uint16le c3freq; // 1000..45000hz uint8le volume; // 0 = ignore uint8le flags; // Convert an DMFSampleHeader to OpenMPT's internal sample representation. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.nLength = length; mptSmp.nSustainStart = loopStart; mptSmp.nSustainEnd = loopEnd; mptSmp.nC5Speed = c3freq; mptSmp.nGlobalVol = 64; if(volume) mptSmp.nVolume = volume + 1; else mptSmp.nVolume = 256; mptSmp.uFlags.set(SMP_NODEFAULTVOLUME, volume == 0); if((flags & smpLoop) != 0 && mptSmp.nSustainEnd > mptSmp.nSustainStart) { mptSmp.uFlags.set(CHN_SUSTAINLOOP); } if((flags & smp16Bit) != 0) { mptSmp.uFlags.set(CHN_16BIT); mptSmp.nLength /= 2; mptSmp.nSustainStart /= 2; mptSmp.nSustainEnd /= 2; } } }; MPT_BINARY_STRUCT(DMFSampleHeader, 16) // Pattern translation memory struct DMFPatternSettings { struct ChannelState { ModCommand::NOTE noteBuffer = NOTE_NONE; // Note buffer ModCommand::NOTE lastNote = NOTE_NONE; // Last played note on channel uint8 vibratoType = 8; // Last used vibrato type on channel uint8 tremoloType = 4; // Last used tremolo type on channel uint8 highOffset = 6; // Last used high offset on channel bool playDir = false; // Sample play direction... false = forward (default) }; std::vector channels; // Memory for each channel's state bool realBPMmode = false; // true = BPM mode uint8 beat = 0; // Rows per beat uint8 tempoTicks = 32; // Tick mode param uint8 tempoBPM = 120; // BPM mode param uint8 internalTicks = 6; // Ticks per row in final pattern DMFPatternSettings(CHANNELINDEX numChannels) : channels(numChannels) { } }; // Convert portamento value (not very accurate due to X-Tracker's higher granularity, to say the least) static uint8 DMFporta2MPT(uint8 val, const uint8 internalTicks, const bool hasFine) { if(val == 0) return 0; else if((val <= 0x0F && hasFine) || internalTicks < 2) return (val | 0xF0); else return std::max(uint8(1), static_cast((val / (internalTicks - 1)))); // no porta on first tick! } // Convert portamento / volume slide value (not very accurate due to X-Tracker's higher granularity, to say the least) static uint8 DMFslide2MPT(uint8 val, const uint8 internalTicks, const bool up) { val = std::max(uint8(1), static_cast(val / 4)); const bool isFine = (val < 0x0F) || (internalTicks < 2); if(!isFine) val = std::max(uint8(1), static_cast((val + internalTicks - 2) / (internalTicks - 1))); // no slides on first tick! "+ internalTicks - 2" for rounding precision if(up) return (isFine ? 0x0F : 0x00) | (val << 4); else return (isFine ? 0xF0 : 0x00) | (val & 0x0F); } // Calculate tremor on/off param static uint8 DMFtremor2MPT(uint8 val, const uint8 internalTicks) { uint8 ontime = (val >> 4); uint8 offtime = (val & 0x0F); ontime = static_cast(Clamp(ontime * internalTicks / 15, 1, 15)); offtime = static_cast(Clamp(offtime * internalTicks / 15, 1, 15)); return (ontime << 4) | offtime; } // Calculate delay parameter for note cuts / delays static uint8 DMFdelay2MPT(uint8 val, const uint8 internalTicks) { int newval = (int)val * (int)internalTicks / 255; Limit(newval, 0, 15); return (uint8)newval; } // Convert vibrato-style command parameters static uint8 DMFvibrato2MPT(uint8 val, const uint8 internalTicks) { // MPT: 1 vibrato period == 64 ticks... we have internalTicks ticks per row. // X-Tracker: Period length specified in rows! const int periodInTicks = std::max(1, (val >> 4)) * internalTicks; const uint8 matchingPeriod = static_cast(Clamp((128 / periodInTicks), 1, 15)); return (matchingPeriod << 4) | std::max(uint8(1), static_cast(val & 0x0F)); } // Try using effect memory (zero paramer) to give the effect swapper some optimization hints. static void ApplyEffectMemory(const ModCommand *m, ROWINDEX row, CHANNELINDEX numChannels, EffectCommand effect, uint8 ¶m) { if(effect == CMD_NONE || param == 0) return; const bool isTonePortaEffect = (effect == CMD_PORTAMENTOUP || effect == CMD_PORTAMENTODOWN || effect == CMD_TONEPORTAMENTO); const bool isVolSlideEffect = (effect == CMD_VOLUMESLIDE || effect == CMD_TONEPORTAVOL || effect == CMD_VIBRATOVOL); while(row > 0) { m -= numChannels; row--; // First, keep some extra rules in mind for portamento, where effect memory is shared between various commands. bool isSame = (effect == m->command); if(isTonePortaEffect && (m->command == CMD_PORTAMENTOUP || m->command == CMD_PORTAMENTODOWN || m->command == CMD_TONEPORTAMENTO)) { if(m->param < 0xE0) { // Avoid effect param for fine slides, or else we could accidentally put this command in the volume column, where fine slides won't work! isSame = true; } else { return; } } else if(isVolSlideEffect && (m->command == CMD_VOLUMESLIDE || m->command == CMD_TONEPORTAVOL || m->command == CMD_VIBRATOVOL)) { isSame = true; } if(isTonePortaEffect && (m->volcmd == VOLCMD_PORTAUP || m->volcmd == VOLCMD_PORTADOWN || m->volcmd == VOLCMD_TONEPORTAMENTO) && m->vol != 0) { // Uuh... Don't even try return; } else if(isVolSlideEffect && (m->volcmd == VOLCMD_FINEVOLUP || m->volcmd == VOLCMD_FINEVOLDOWN || m->volcmd == VOLCMD_VOLSLIDEUP || m->volcmd == VOLCMD_VOLSLIDEDOWN) && m->vol != 0) { // Same! return; } if(isSame) { if(param != m->param && m->param != 0) { // No way to optimize this return; } else if(param == m->param) { // Yay! param = 0; return; } } } } static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, DMFPatternSettings &settings, CSoundFile &sndFile) { // Pattern flags enum PatternFlags { // Global Track patGlobPack = 0x80, // Pack information for global track follows patGlobMask = 0x3F, // Mask for global effects // Note tracks patCounter = 0x80, // Pack information for current channel follows patInstr = 0x40, // Instrument number present patNote = 0x20, // Note present patVolume = 0x10, // Volume present patInsEff = 0x08, // Instrument effect present patNoteEff = 0x04, // Note effect present patVolEff = 0x02, // Volume effect stored }; file.Rewind(); DMFPatternHeader patHead; if(fileVersion < 3) { patHead.numTracks = file.ReadUint8(); file.Skip(2); // not sure what this is, later X-Tracker versions just skip over it patHead.numRows = file.ReadUint16LE(); patHead.patternLength = file.ReadUint32LE(); } else { file.ReadStruct(patHead); } if(fileVersion < 6) patHead.beat = 0; const ROWINDEX numRows = Clamp(ROWINDEX(patHead.numRows), ROWINDEX(1), MAX_PATTERN_ROWS); const PATTERNINDEX pat = sndFile.Patterns.InsertAny(numRows); if(pat == PATTERNINDEX_INVALID) { return pat; } ModCommand *m = sndFile.Patterns[pat].GetpModCommand(0, 0); const CHANNELINDEX numChannels = std::min(static_cast(sndFile.GetNumChannels() - 1), static_cast(patHead.numTracks)); // When breaking to a pattern with less channels that the previous pattern, // all voices in the now unused channels are killed: for(CHANNELINDEX chn = numChannels + 1; chn < sndFile.GetNumChannels(); chn++) { m[chn].note = NOTE_NOTECUT; } // Initialize tempo stuff settings.beat = (patHead.beat >> 4); bool tempoChange = settings.realBPMmode; uint8 writeDelay = 0; // Counters for channel packing (including global track) std::vector channelCounter(numChannels + 1, 0); for(ROWINDEX row = 0; row < numRows && file.CanRead(1); row++) { // Global track info counter reached 0 => read global track data if(channelCounter[0] == 0) { uint8 globalInfo = file.ReadUint8(); // 0x80: Packing counter (if not present, counter stays at 0) if((globalInfo & patGlobPack) != 0) { channelCounter[0] = file.ReadUint8(); } globalInfo &= patGlobMask; uint8 globalData = 0; if(globalInfo != 0) { globalData = file.ReadUint8(); } switch(globalInfo) { case 1: // Set Tick Frame Speed settings.realBPMmode = false; settings.tempoTicks = std::max(uint8(1), globalData); // Tempo in 1/4 rows per second settings.tempoBPM = 0; // Automatically updated by X-Tracker tempoChange = true; break; case 2: // Set BPM Speed (real BPM mode) if(globalData) // DATA = 0 doesn't do anything { settings.realBPMmode = true; settings.tempoBPM = globalData; // Tempo in real BPM (depends on rows per beat) if(settings.beat != 0) { settings.tempoTicks = static_cast(globalData * settings.beat * 15); // Automatically updated by X-Tracker } tempoChange = true; } break; case 3: // Set Beat settings.beat = (globalData >> 4); if(settings.beat != 0) { // Tempo changes only if we're in real BPM mode tempoChange = settings.realBPMmode; } else { // If beat is 0, change to tick speed mode, but keep current tempo settings.realBPMmode = false; } break; case 4: // Tick Delay writeDelay = globalData; break; case 5: // Set External Flag break; case 6: // Slide Speed Up if(globalData > 0) { uint8 &tempoData = (settings.realBPMmode) ? settings.tempoBPM : settings.tempoTicks; if(tempoData < 256 - globalData) { tempoData += globalData; } else { tempoData = 255; } tempoChange = true; } break; case 7: // Slide Speed Down if(globalData > 0) { uint8 &tempoData = (settings.realBPMmode) ? settings.tempoBPM : settings.tempoTicks; if(tempoData > 1 + globalData) { tempoData -= globalData; } else { tempoData = 1; } tempoChange = true; } break; } } else { channelCounter[0]--; } // These will eventually be written to the pattern int speed = 0, tempo = 0; if(tempoChange) { // Can't do anything if we're in BPM mode and there's no rows per beat set... if(!settings.realBPMmode || settings.beat) { // My approach to convert X-Tracker's "tick speed" (1/4 rows per second): // Tempo * 6 / Speed = Beats per Minute // => Tempo * 6 / (Speed * 60) = Beats per Second // => Tempo * 24 / (Speed * 60) = Rows per Second (4 rows per beat at tempo 6) // => Tempo = 60 * Rows per Second * Speed / 24 // For some reason, using settings.tempoTicks + 1 gives more accurate results than just settings.tempoTicks... (same problem in the old libmodplug DMF loader) // Original unoptimized formula: //const int tickspeed = (tempoRealBPMmode) ? std::max(1, (tempoData * beat * 4) / 60) : tempoData; const int tickspeed = (settings.realBPMmode) ? std::max(1, settings.tempoBPM * settings.beat * 2) : ((settings.tempoTicks + 1) * 30); // Try to find matching speed - try higher speeds first, so that effects like arpeggio and tremor work better. for(speed = 255; speed >= 1; speed--) { // Original unoptimized formula: // tempo = 30 * tickspeed * speed / 48; tempo = tickspeed * speed / 48; if(tempo >= 32 && tempo <= 255) break; } Limit(tempo, 32, 255); settings.internalTicks = static_cast(std::max(1, speed)); } else { tempoChange = false; } } m = sndFile.Patterns[pat].GetpModCommand(row, 1); // Reserve first channel for global effects for(CHANNELINDEX chn = 1; chn <= numChannels; chn++, m++) { // Track info counter reached 0 => read track data if(channelCounter[chn] == 0) { const uint8 channelInfo = file.ReadUint8(); //////////////////////////////////////////////////////////////// // 0x80: Packing counter (if not present, counter stays at 0) if((channelInfo & patCounter) != 0) { channelCounter[chn] = file.ReadUint8(); } //////////////////////////////////////////////////////////////// // 0x40: Instrument bool slideNote = true; // If there is no instrument number next to a note, the note is not retriggered! if((channelInfo & patInstr) != 0) { m->instr = file.ReadUint8(); if(m->instr != 0) { slideNote = false; } } //////////////////////////////////////////////////////////////// // 0x20: Note if((channelInfo & patNote) != 0) { m->note = file.ReadUint8(); if(m->note >= 1 && m->note <= 108) { m->note = Clamp(static_cast(m->note + 24), NOTE_MIN, NOTE_MAX); settings.channels[chn].lastNote = m->note; } else if(m->note >= 129 && m->note <= 236) { // "Buffer notes" for portamento (and other effects?) that are actually not played, but just "queued"... m->note = Clamp(static_cast((m->note & 0x7F) + 24), NOTE_MIN, NOTE_MAX); settings.channels[chn].noteBuffer = m->note; m->note = NOTE_NONE; } else if(m->note == 255) { m->note = NOTE_NOTECUT; } } // If there's just an instrument number, but no note, retrigger sample. if(m->note == NOTE_NONE && m->instr > 0) { m->note = settings.channels[chn].lastNote; m->instr = 0; } if(m->IsNote()) { settings.channels[chn].playDir = false; } EffectCommand effect1 = CMD_NONE, effect2 = CMD_NONE, effect3 = CMD_NONE; uint8 effectParam1 = 0, effectParam2 = 0, effectParam3 = 0; bool useMem2 = false, useMem3 = false; // Effect can use memory if necessary //////////////////////////////////////////////////////////////// // 0x10: Volume if((channelInfo & patVolume) != 0) { m->volcmd = VOLCMD_VOLUME; m->vol = static_cast((file.ReadUint8() + 2) / 4); // Should be + 3 instead of + 2, but volume 1 is silent in X-Tracker. } //////////////////////////////////////////////////////////////// // 0x08: Instrument effect if((channelInfo & patInsEff) != 0) { const uint8 command = file.ReadUint8(); effectParam1 = file.ReadUint8(); switch(command) { case 1: // Stop Sample m->note = NOTE_NOTECUT; effect1 = CMD_NONE; break; case 2: // Stop Sample Loop m->note = NOTE_KEYOFF; effect1 = CMD_NONE; break; case 3: // Instrument Volume Override (aka "Restart") m->note = settings.channels[chn].lastNote; settings.channels[chn].playDir = false; effect1 = CMD_NONE; break; case 4: // Sample Delay effectParam1 = DMFdelay2MPT(effectParam1, settings.internalTicks); if(effectParam1) { effect1 = CMD_S3MCMDEX; effectParam1 = 0xD0 | (effectParam1); } else { effect1 = CMD_NONE; } if(m->note == NOTE_NONE) { m->note = settings.channels[chn].lastNote; settings.channels[chn].playDir = false; } break; case 5: // Tremolo Retrig Sample (who invented those stupid effect names?) effectParam1 = std::max(uint8(1), DMFdelay2MPT(effectParam1, settings.internalTicks)); effect1 = CMD_RETRIG; settings.channels[chn].playDir = false; break; case 6: // Offset case 7: // Offset + 64k case 8: // Offset + 128k case 9: // Offset + 192k // Put high offset on previous row if(row > 0 && command != settings.channels[chn].highOffset) { if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0xA0 | (command - 6))).Row(row - 1).Channel(chn).RetryPreviousRow())) { settings.channels[chn].highOffset = command; } } effect1 = CMD_OFFSET; if(m->note == NOTE_NONE) { // Offset without note does also work in DMF. m->note = settings.channels[chn].lastNote; } settings.channels[chn].playDir = false; break; case 10: // Invert Sample play direction ("Tekkno Invert") effect1 = CMD_S3MCMDEX; if(settings.channels[chn].playDir == false) effectParam1 = 0x9F; else effectParam1 = 0x9E; settings.channels[chn].playDir = !settings.channels[chn].playDir; break; default: effect1 = CMD_NONE; break; } } //////////////////////////////////////////////////////////////// // 0x04: Note effect if((channelInfo & patNoteEff) != 0) { const uint8 command = file.ReadUint8(); effectParam2 = file.ReadUint8(); switch(command) { case 1: // Note Finetune (1/16th of a semitone signed 8-bit value, not 1/128th as the interface claims) { const auto fine = std::div(static_cast(effectParam2) * 8, 128); if(m->IsNote()) m->note = static_cast(Clamp(m->note + fine.quot, NOTE_MIN, NOTE_MAX)); effect2 = CMD_FINETUNE; effectParam2 = static_cast(fine.rem) ^ 0x80; } break; case 2: // Note Delay (wtf is the difference to Sample Delay?) effectParam2 = DMFdelay2MPT(effectParam2, settings.internalTicks); if(effectParam2) { effect2 = CMD_S3MCMDEX; effectParam2 = 0xD0 | (effectParam2); } else { effect2 = CMD_NONE; } useMem2 = true; break; case 3: // Arpeggio effect2 = CMD_ARPEGGIO; useMem2 = true; break; case 4: // Portamento Up case 5: // Portamento Down effectParam2 = DMFporta2MPT(effectParam2, settings.internalTicks, true); effect2 = (command == 4) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN; useMem2 = true; break; case 6: // Portamento to Note if(m->note == NOTE_NONE) { m->note = settings.channels[chn].noteBuffer; } effectParam2 = DMFporta2MPT(effectParam2, settings.internalTicks, false); effect2 = CMD_TONEPORTAMENTO; useMem2 = true; break; case 7: // Scratch to Note (neat! but we don't have such an effect...) m->note = static_cast(Clamp(effectParam2 + 25, NOTE_MIN, NOTE_MAX)); effect2 = CMD_TONEPORTAMENTO; effectParam2 = 0xFF; useMem2 = true; break; case 8: // Vibrato Sine case 9: // Vibrato Triangle (ramp down should be close enough) case 10: // Vibrato Square // Put vibrato type on previous row if(row > 0 && command != settings.channels[chn].vibratoType) { if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x30 | (command - 8))).Row(row - 1).Channel(chn).RetryPreviousRow())) { settings.channels[chn].vibratoType = command; } } effect2 = CMD_VIBRATO; effectParam2 = DMFvibrato2MPT(effectParam2, settings.internalTicks); useMem2 = true; break; case 11: // Note Tremolo effectParam2 = DMFtremor2MPT(effectParam2, settings.internalTicks); effect2 = CMD_TREMOR; useMem2 = true; break; case 12: // Note Cut effectParam2 = DMFdelay2MPT(effectParam2, settings.internalTicks); if(effectParam2) { effect2 = CMD_S3MCMDEX; effectParam2 = 0xC0 | (effectParam2); } else { effect2 = CMD_NONE; m->note = NOTE_NOTECUT; } useMem2 = true; break; default: effect2 = CMD_NONE; break; } } //////////////////////////////////////////////////////////////// // 0x02: Volume effect if((channelInfo & patVolEff) != 0) { const uint8 command = file.ReadUint8(); effectParam3 = file.ReadUint8(); switch(command) { case 1: // Volume Slide Up case 2: // Volume Slide Down effectParam3 = DMFslide2MPT(effectParam3, settings.internalTicks, (command == 1)); effect3 = CMD_VOLUMESLIDE; useMem3 = true; break; case 3: // Volume Tremolo (actually this is Tremor) effectParam3 = DMFtremor2MPT(effectParam3, settings.internalTicks); effect3 = CMD_TREMOR; useMem3 = true; break; case 4: // Tremolo Sine case 5: // Tremolo Triangle (ramp down should be close enough) case 6: // Tremolo Square // Put tremolo type on previous row if(row > 0 && command != settings.channels[chn].tremoloType) { if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x40 | (command - 4))).Row(row - 1).Channel(chn).RetryPreviousRow())) { settings.channels[chn].tremoloType = command; } } effect3 = CMD_TREMOLO; effectParam3 = DMFvibrato2MPT(effectParam3, settings.internalTicks); useMem3 = true; break; case 7: // Set Balance effect3 = CMD_PANNING8; break; case 8: // Slide Balance Left case 9: // Slide Balance Right effectParam3 = DMFslide2MPT(effectParam3, settings.internalTicks, (command == 8)); effect3 = CMD_PANNINGSLIDE; useMem3 = true; break; case 10: // Balance Vibrato Left/Right (always sine modulated) effect3 = CMD_PANBRELLO; effectParam3 = DMFvibrato2MPT(effectParam3, settings.internalTicks); useMem3 = true; break; default: effect3 = CMD_NONE; break; } } // Let's see if we can help the effect swapper by reducing some effect parameters to "continue" parameters. if(useMem2) ApplyEffectMemory(m, row, sndFile.GetNumChannels(), effect2, effectParam2); if(useMem3) ApplyEffectMemory(m, row, sndFile.GetNumChannels(), effect3, effectParam3); // I guess this is close enough to "not retriggering the note" if(slideNote && m->IsNote()) { if(effect2 == CMD_NONE) { effect2 = CMD_TONEPORTAMENTO; effectParam2 = 0xFF; } else if(effect3 == CMD_NONE && effect2 != CMD_TONEPORTAMENTO) // Tone portamentos normally go in effect #2 { effect3 = CMD_TONEPORTAMENTO; effectParam3 = 0xFF; } } // If one of the effects is unused, temporarily put volume commands in there if(m->volcmd == VOLCMD_VOLUME) { if(effect2 == CMD_NONE) { effect2 = CMD_VOLUME; effectParam2 = m->vol; m->volcmd = VOLCMD_NONE; } else if(effect3 == CMD_NONE) { effect3 = CMD_VOLUME; effectParam3 = m->vol; m->volcmd = VOLCMD_NONE; } } ModCommand combinedCmd; combinedCmd.FillInTwoCommands(effect2, effectParam2, effect3, effectParam3); if(m->volcmd == VOLCMD_NONE && combinedCmd.volcmd != VOLCMD_NONE) { m->SetVolumeCommand(combinedCmd); } // Prefer instrument effects over any other effects if(effect1 != CMD_NONE) { combinedCmd.FillInTwoCommands(combinedCmd.command, combinedCmd.param, effect1, effectParam1); if(m->volcmd == VOLCMD_NONE && combinedCmd.volcmd != VOLCMD_NONE) { m->SetVolumeCommand(combinedCmd); } m->SetEffectCommand(combinedCmd); } else if(combinedCmd.command != CMD_NONE) { m->SetEffectCommand(combinedCmd); } } else { channelCounter[chn]--; } } // End for all channels // Now we can try to write tempo information. if(tempoChange) { tempoChange = false; sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_TEMPO, static_cast(tempo)).Row(row).Channel(0).RetryNextRow()); sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, static_cast(speed)).Row(row).RetryNextRow()); } // Try to put delay effects somewhere as well if(writeDelay & 0xF0) { sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0xE0 | (writeDelay >> 4)).Row(row).AllowMultiple()); } if(writeDelay & 0x0F) { const uint8 param = static_cast((writeDelay & 0x0F) * settings.internalTicks / 15); sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0x60u | Clamp(param, uint8(1), uint8(15))).Row(row).AllowMultiple()); } writeDelay = 0; } // End for all rows return pat; } static bool ValidateHeader(const DMFFileHeader &fileHeader) { if(std::memcmp(fileHeader.signature, "DDMF", 4) || !fileHeader.version || fileHeader.version > 10) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize) { DMFFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); DMFFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } // Go through all chunks now... cannot use our standard IFF chunk reader here because early X-Tracker versions write some malformed chunk headers... fun code ahead! ChunkReader::ChunkList chunks; while(file.CanRead(sizeof(DMFChunk))) { DMFChunk chunkHeader; file.Read(chunkHeader); uint32 chunkLength = chunkHeader.length, chunkSkip = 0; // When loop start was added to version 3, the chunk size was not updated... if(fileHeader.version == 3 && chunkHeader.GetID() == DMFChunk::idSEQU) chunkSkip = 2; // ...and when the loop end was added to version 4, it was also note updated! Luckily they fixed it in version 5. else if(fileHeader.version == 4 && chunkHeader.GetID() == DMFChunk::idSEQU) chunkSkip = 4; // Earlier X-Tracker versions also write a garbage length for the SMPD chunk if samples are compressed. // I don't know when exactly this stopped, but I have no version 5-7 files to check (and no X-Tracker version that writes those versions). // Since this is practically always the last chunk in the file, the following code is safe for those versions, though. else if(fileHeader.version < 8 && chunkHeader.GetID() == DMFChunk::idSMPD) chunkLength = mpt::saturate_cast(file.BytesLeft()); chunks.chunks.push_back(ChunkReader::Item{chunkHeader, file.ReadChunk(chunkLength)}); file.Skip(chunkSkip); } FileReader chunk; // Read pattern chunk first so that we know how many channels there are chunk = chunks.GetChunk(DMFChunk::idPATT); if(!chunk.IsValid()) return false; DMFPatterns patHeader; chunk.ReadStruct(patHeader); // First, find out where all of our patterns are... std::vector patternChunks; if(loadFlags & loadPatternData) { patternChunks.resize(patHeader.numPatterns); const uint8 headerSize = fileHeader.version < 3 ? 9 : 8; for(auto &patternChunk : patternChunks) { chunk.Skip(headerSize - sizeof(uint32le)); const uint32 patLength = chunk.ReadUint32LE(); if(!chunk.CanRead(patLength)) return false; chunk.SkipBack(headerSize); patternChunk = chunk.ReadChunk(headerSize + patLength); } } InitializeGlobals(MOD_TYPE_DMF, Clamp(patHeader.numTracks, 1, 32) + 1); // + 1 for global track (used for tempo stuff) m_modFormat.formatName = MPT_UFORMAT("Delusion Digital Music Format v{}")(fileHeader.version); m_modFormat.madeWithTracker = fileHeader.version == 10 ? UL_("X-Tracker 32") : UL_("X-Tracker"); m_modFormat.type = UL_("dmf"); m_modFormat.charset = mpt::Charset::CP437; m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songname); m_songArtist = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.composer)); FileHistory mptHistory; mptHistory.loadDate.day = Clamp(fileHeader.creationDay, uint8(1), uint8(31)); mptHistory.loadDate.month = Clamp(fileHeader.creationMonth, uint8(1), uint8(12)); mptHistory.loadDate.year = 1900 + fileHeader.creationYear; m_FileHistory.clear(); m_FileHistory.push_back(mptHistory); // Read order list chunk = chunks.GetChunk(DMFChunk::idSEQU); ORDERINDEX seqLoopStart = 0, seqLoopEnd = ORDERINDEX_MAX; if(fileHeader.version >= 3) seqLoopStart = chunk.ReadUint16LE(); if(fileHeader.version >= 4) seqLoopEnd = chunk.ReadUint16LE(); // HIPOMATK.DMF has a loop end of 0, other v4 files have proper loop ends. Later X-Tracker versions import it as-is but it cannot be intentional. // We just assume that this feature might have been buggy in early v4 versions and ignore the loop end in that case. if(fileHeader.version == 4 && seqLoopEnd == 0) seqLoopEnd = ORDERINDEX_MAX; ReadOrderFromFile(Order(), chunk, chunk.BytesLeft() / 2); LimitMax(seqLoopStart, Order().GetLastIndex()); LimitMax(seqLoopEnd, Order().GetLastIndex()); if(loadFlags & loadPatternData) { // Now go through the order list and load them. DMFPatternSettings settings(GetNumChannels()); Patterns.ResizeArray(Order().GetLength()); for(PATTERNINDEX &pat : Order()) { // Create one pattern for each order item, as the same pattern can be played with different settings if(pat < patternChunks.size()) { pat = ConvertDMFPattern(patternChunks[pat], fileHeader.version, settings, *this); } } // Write loop end if necessary if(Order().IsValidPat(seqLoopEnd) && (seqLoopStart > 0 || seqLoopEnd < Order().GetLastIndex())) { PATTERNINDEX pat = Order()[seqLoopEnd]; Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast(seqLoopStart)).Row(Patterns[pat].GetNumRows() - 1).RetryPreviousRow()); } } // Read song message chunk = chunks.GetChunk(DMFChunk::idCMSG); if(chunk.IsValid()) { // The song message seems to start at a 1 byte offset. // The skipped byte seems to always be 0. // This also matches how XT 1.03 itself displays the song message. chunk.Skip(1); m_songMessage.ReadFixedLineLength(chunk, chunk.BytesLeft(), 40, 0); } // Read sample headers + data FileReader sampleDataChunk = chunks.GetChunk(DMFChunk::idSMPD); chunk = chunks.GetChunk(DMFChunk::idSMPI); m_nSamples = chunk.ReadUint8(); for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { const uint8 nameLength = (fileHeader.version < 2) ? 30 : chunk.ReadUint8(); chunk.ReadString(m_szNames[smp], nameLength); DMFSampleHeader sampleHeader; ModSample &sample = Samples[smp]; chunk.ReadStruct(sampleHeader); sampleHeader.ConvertToMPT(sample); // Read library name in version 8 files if(fileHeader.version >= 8) chunk.ReadString(sample.filename, 8); // Filler + CRC chunk.Skip(fileHeader.version > 1 ? 6 : 2); // Now read the sample data from the data chunk FileReader sampleData = sampleDataChunk.ReadChunk(sampleDataChunk.ReadUint32LE()); if(sampleData.IsValid() && (loadFlags & loadSampleData)) { SampleIO( sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, (sampleHeader.flags & DMFSampleHeader::smpCompMask) == DMFSampleHeader::smpComp1 ? SampleIO::DMF : SampleIO::signedPCM) .ReadSample(sample, sampleData); } } m_SongFlags = SONG_LINEARSLIDES | SONG_ITCOMPATGXX; // this will be converted to IT format by MPT. SONG_ITOLDEFFECTS is not set because of tremor and vibrato. Order().SetDefaultSpeed(6); Order().SetDefaultTempoInt(120); m_nDefaultGlobalVolume = 256; m_nSamplePreAmp = m_nVSTiVolume = 48; m_playBehaviour.set(kApplyOffsetWithoutNote); return true; } /////////////////////////////////////////////////////////////////////// // DMF Compression struct DMFHNode { int16 left, right; uint8 value; }; struct DMFHTree { BitReader file; int lastnode = 0, nodecount = 0; DMFHNode nodes[256]{}; DMFHTree(FileReader &file) : file(file) { } // // tree: [8-bit value][12-bit index][12-bit index] = 32-bit // void DMFNewNode() { int actnode = nodecount; if(actnode > 255) return; nodes[actnode].value = static_cast(file.ReadBits(7)); bool isLeft = file.ReadBits(1) != 0; bool isRight = file.ReadBits(1) != 0; actnode = lastnode; if(actnode > 255) return; nodecount++; lastnode = nodecount; if(isLeft) { nodes[actnode].left = (int16)lastnode; DMFNewNode(); } else { nodes[actnode].left = -1; } lastnode = nodecount; if(isRight) { nodes[actnode].right = (int16)lastnode; DMFNewNode(); } else { nodes[actnode].right = -1; } } }; uintptr_t DMFUnpack(FileReader &file, uint8 *psample, uint32 maxlen) { DMFHTree tree(file); uint8 value = 0, delta = 0; try { tree.DMFNewNode(); if(tree.nodes[0].left < 0 || tree.nodes[0].right < 0) return tree.file.GetPosition(); for(uint32 i = 0; i < maxlen; i++) { int actnode = 0; bool sign = tree.file.ReadBits(1) != 0; do { if(tree.file.ReadBits(1)) actnode = tree.nodes[actnode].right; else actnode = tree.nodes[actnode].left; if(actnode > 255) break; delta = tree.nodes[actnode].value; } while((tree.nodes[actnode].left >= 0) && (tree.nodes[actnode].right >= 0)); if(sign) delta ^= 0xFF; value += delta; psample[i] = value; } } catch(const BitReader::eof &) { //AddToLog(LogWarning, "Truncated DMF sample block"); } return tree.file.GetPosition(); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MIDIMacros.h0000644000175000017500000001456214722674176020165 00000000000000/* * MIDIMacros.h * ------------ * Purpose: Helper functions / classes for MIDI Macro functionality. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" #include "openmpt/base/Endian.hpp" OPENMPT_NAMESPACE_BEGIN class IMixPlugin; enum { kGlobalMacros = 9, // Number of global macros kSFxMacros = 16, // Number of parametered macros kZxxMacros = 128, // Number of fixed macros kMacroLength = 32, // Max number of chars per macro }; // Parametered macro presets enum ParameteredMacro { kSFxUnused = 0, kSFxCutoff, // Z00 - Z7F controls resonant filter cutoff kSFxReso, // Z00 - Z7F controls resonant filter resonance kSFxFltMode, // Z00 - Z7F controls resonant filter mode (lowpass / highpass) kSFxDryWet, // Z00 - Z7F controls plugin Dry / Wet ratio kSFxPlugParam, // Z00 - Z7F controls a plugin parameter kSFxCC, // Z00 - Z7F controls MIDI CC kSFxChannelAT, // Z00 - Z7F controls Channel Aftertouch kSFxPolyAT, // Z00 - Z7F controls Poly Aftertouch kSFxPitch, // Z00 - Z7F controls Pitch Bend kSFxProgChange, // Z00 - Z7F controls MIDI Program Change kSFxCustom, kSFxMax }; // Fixed macro presets enum FixedMacro { kZxxUnused = 0, kZxxReso4Bit, // Z80 - Z8F controls resonant filter resonance kZxxReso7Bit, // Z80 - ZFF controls resonant filter resonance kZxxCutoff, // Z80 - ZFF controls resonant filter cutoff kZxxFltMode, // Z80 - ZFF controls resonant filter mode (lowpass / highpass) kZxxResoFltMode, // Z80 - Z9F controls resonance + filter mode kZxxChannelAT, // Z80 - ZFF controls Channel Aftertouch kZxxPolyAT, // Z80 - ZFF controls Poly Aftertouch kZxxPitch, // Z80 - ZFF controls Pitch Bend kZxxProgChange, // Z80 - ZFF controls MIDI Program Change kZxxCustom, kZxxMax }; // Global macro types enum GlobalMacro { MIDIOUT_START = 0, MIDIOUT_STOP, MIDIOUT_TICK, MIDIOUT_NOTEON, MIDIOUT_NOTEOFF, MIDIOUT_VOLUME, MIDIOUT_PAN, MIDIOUT_BANKSEL, MIDIOUT_PROGRAM, }; struct MIDIMacroConfigData { struct Macro { public: Macro() = default; Macro(const Macro &other) = default; Macro &operator=(const Macro &other) = default; Macro &operator=(const std::string_view other) noexcept { const size_t copyLength = std::min({m_data.size() - 1u, other.size(), other.find('\0')}); std::copy(other.begin(), other.begin() + copyLength, m_data.begin()); m_data[copyLength] = '\0'; Sanitize(); return *this; } bool operator==(const Macro &other) const noexcept { return m_data == other.m_data; // Don't care about data past null-terminator as operator= and Sanitize() ensure there is no data behind it. } bool operator!=(const Macro &other) const noexcept { return !(*this == other); } operator mpt::span() const noexcept { return {m_data.data(), Length()}; } operator std::string_view() const noexcept { return {m_data.data(), Length()}; } operator std::string() const { return {m_data.data(), Length()}; } MPT_CONSTEXPR20_FUN size_t Length() const noexcept { return static_cast(std::distance(m_data.begin(), std::find(m_data.begin(), m_data.end(), '\0'))); } MPT_CONSTEXPR20_FUN void Clear() noexcept { m_data.fill('\0'); } // Remove blanks and other unwanted characters from macro strings for internal usage. std::string NormalizedString() const; void Sanitize() noexcept; void UpgradeLegacyMacro() noexcept; private: std::array m_data; }; std::array Global; std::array SFx; // Parametered macros for Z00...Z7F std::array Zxx; // Fixed macros Z80...ZFF constexpr Macro *begin() noexcept {return Global.data(); } constexpr const Macro *begin() const noexcept { return Global.data(); } constexpr Macro *end() noexcept { return Zxx.data() + Zxx.size(); } constexpr const Macro *end() const noexcept { return Zxx.data() + Zxx.size(); } }; // This is directly written to files, so the size must be correct! MPT_BINARY_STRUCT(MIDIMacroConfigData::Macro, 32) MPT_BINARY_STRUCT(MIDIMacroConfigData, 4896) class MIDIMacroConfig : public MIDIMacroConfigData { public: MIDIMacroConfig() { Reset(); } // Get macro type from a macro string ParameteredMacro GetParameteredMacroType(uint32 macroIndex) const; FixedMacro GetFixedMacroType() const; // Create a new macro protected: void CreateParameteredMacro(Macro ¶meteredMacro, ParameteredMacro macroType, int subType) const; public: void CreateParameteredMacro(uint32 macroIndex, ParameteredMacro macroType, int subType = 0) { if(macroIndex < std::size(SFx)) CreateParameteredMacro(SFx[macroIndex], macroType, subType); } std::string CreateParameteredMacro(ParameteredMacro macroType, int subType = 0) const; protected: void CreateFixedMacro(std::array &fixedMacros, FixedMacro macroType) const; public: void CreateFixedMacro(FixedMacro macroType) { CreateFixedMacro(Zxx, macroType); } bool operator==(const MIDIMacroConfig &other) const; bool operator!=(const MIDIMacroConfig &other) const { return !(*this == other); } #ifdef MODPLUG_TRACKER // Translate macro type or macro string to macro name CString GetParameteredMacroName(uint32 macroIndex, IMixPlugin *plugin = nullptr) const; CString GetParameteredMacroName(ParameteredMacro macroType) const; CString GetFixedMacroName(FixedMacro macroType) const; // Extract information from a parametered macro string. PlugParamIndex MacroToPlugParam(uint32 macroIndex) const; int MacroToMidiCC(uint32 macroIndex) const; // Check if any macro can automate a given plugin parameter int FindMacroForParam(PlugParamIndex param) const; #endif // MODPLUG_TRACKER // Check if a given set of macros is the default IT macro set. bool IsMacroDefaultSetupUsed() const; // Reset MIDI macro config to default values. void Reset(); // Clear all Zxx macros so that they do nothing. void ClearZxxMacros(); // Sanitize all macro config strings. void Sanitize(); // Fix old-format (not conforming to IT's MIDI macro definitions) MIDI config strings. void UpgradeMacros(); }; static_assert(sizeof(MIDIMacroConfig) == sizeof(MIDIMacroConfigData)); // this is directly written to files, so the size must be correct! OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_fc.cpp0000644000175000017500000006221415015401723020133 00000000000000/* * Load_fc.cpp * ------------- * Purpose: Future Composer 1.0 - 1.4 module loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "InstrumentSynth.h" OPENMPT_NAMESPACE_BEGIN struct FCPlaylistEntry { struct Entry { uint8 pattern; int8 noteTranspose; int8 instrTranspose; }; std::array channels; uint8 speed; }; MPT_BINARY_STRUCT(FCPlaylistEntry, 13) struct FCSampleInfo { uint16be length; // In words uint16be loopStart; // In bytes uint16be loopLength; // In words void ConvertToMPT(ModSample &mptSmp, FileReader &file, bool isFC14, bool loadSampleData) const { mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.nLength = length * 2; if(isFC14 && mptSmp.nLength) mptSmp.nLength += 2; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = mptSmp.nLoopStart + loopLength * 2; mptSmp.uFlags.set(CHN_LOOP, loopLength > 1); // Fix for axel foley remix.smod (loop extends into next sample) auto nextSampleStart = file.GetPosition() + mptSmp.nLength; if(mptSmp.uFlags[CHN_LOOP] && mptSmp.nLoopEnd > mptSmp.nLength) mptSmp.nLength = mptSmp.nLoopEnd; if(loadSampleData) { SampleIO{SampleIO::_8bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM} .ReadSample(mptSmp, file); } file.Seek(nextSampleStart); } }; MPT_BINARY_STRUCT(FCSampleInfo, 6) struct FCFileHeader { char magic[4]; // "SMOD" (Future Composer 1.0 - 1.3) or "FC14" (Future Composer 1.4) uint32be sequenceSize; // All sizes in bytes uint32be patternsOffset; uint32be patternsSize; uint32be freqSequenceOffset; uint32be freqSequenceSize; uint32be volSequenceOffset; uint32be volSequenceSize; uint32be sampleDataOffset; uint32be waveTableOffset; // or sample data size if version < 1.4 std::array sampleInfo; bool IsValid() const { if(memcmp(magic, "SMOD", 4) && memcmp(magic, "FC14", 4)) return false; static constexpr uint32 MAX_FC_SIZE = 0x8'0000; // According to manual: Sample memory allocated = 100,000 bytes if(sequenceSize % sizeof(FCPlaylistEntry) > 1 // Some files have a mysterious extra byte || sequenceSize < sizeof(FCPlaylistEntry) || sequenceSize > 256 * 13 || patternsSize % 64u || !patternsSize || patternsSize > 64 * 256 || patternsOffset > MAX_FC_SIZE || freqSequenceSize % 64u || !freqSequenceSize || freqSequenceSize > 64 * 256 || freqSequenceOffset > MAX_FC_SIZE || volSequenceSize % 64u || !volSequenceSize || volSequenceSize > 64 * 256 || volSequenceOffset > MAX_FC_SIZE || sampleDataOffset > MAX_FC_SIZE || waveTableOffset > MAX_FC_SIZE) return false; return true; } bool IsFC14() const { return !memcmp(magic, "FC14", 4); } ORDERINDEX NumOrders() const { return static_cast(sequenceSize / sizeof(FCPlaylistEntry)); } uint32 GetHeaderMinimumAdditionalSize() const { return sequenceSize + (IsFC14() ? 80 : 0); } }; MPT_BINARY_STRUCT(FCFileHeader, 100) static void TranslateFCScript(InstrumentSynth::Events &events, const mpt::span script, const bool isFC14, const uint16 startSequence = uint16_max) { FileReader file{script}; const bool isVolume = startSequence > 255; const uint8 volScriptSpeed = (script[0] > 0) ? script[0] : uint8_max; if(isVolume) events.push_back(InstrumentSynth::Event::SetStepSpeed(volScriptSpeed, true)); std::vector sequencesToParse(1, static_cast(isVolume ? 0 : startSequence)); std::bitset<256> parsedSequences; parsedSequences.set(sequencesToParse.back()); std::map entryFromByte; events.push_back(InstrumentSynth::Event::JumpMarker(0)); while(!sequencesToParse.empty()) { const uint16 currentSequenceOffset = sequencesToParse.back() * 64u; sequencesToParse.pop_back(); file.Seek(currentSequenceOffset); if(isVolume) file.Skip(5); // Due to an underflow bug in the volume command E0, it can jump up to 260 bytes from the start of the chosen volume sequence. // Luckily this is not possible with frequency sequences - as multiple frequency sequences can be chained using command E7, // not having to care for that bug there makes the book-keeping a bit easier for us, as jumps will always be "local" within the currently selected sequence, // and a jump target address cannot belong to two parsed sequences. const uint16 maxScriptJumpPos = static_cast(currentSequenceOffset + (isVolume ? 260 : 63)); uint16 maxJump = 0; bool nextByteIsPitch = false; while(file.CanRead(1)) { uint16 scriptPos = static_cast(file.GetPosition()); if(scriptPos <= maxScriptJumpPos) entryFromByte[scriptPos] = static_cast(events.size()); const uint8 b = file.ReadUint8(); // After several pitch Ex commands, the next byte is always interpreted as Set Pitch if(nextByteIsPitch) { events.push_back(InstrumentSynth::Event::FC_SetPitch(b)); nextByteIsPitch = false; continue; } const auto volumeCommand = InstrumentSynth::Event::MED_SetVolume(static_cast(std::min(b & 0x7F, 64))); switch(b) { case 0xE0: // Loop (position) { uint16 target = file.ReadUint8() & 0x3F; if(isVolume && target < 5) // Volume sequence offset is relative to first volume command at offset 5, so FC subtracts 5 from the jump target and happily underflows the byte value target += 256; target += currentSequenceOffset; if(!isVolume && target < script.size() && (script[target] == 0xE0 || script[target] == 0xE1)) { // The first byte that is executed after an E0 jump is never interpreted as command E0 or E1. events.push_back(InstrumentSynth::Event::FC_SetPitch(script[target])); target++; if(target < script.size() && script[target - 1] == 0xE0) { events.push_back(InstrumentSynth::Event::FC_SetPitch(script[target])); target++; } } maxJump = std::max(maxJump, target); events.push_back(InstrumentSynth::Event::Jump(target)); } break; case 0xE1: // End (none) events.push_back(InstrumentSynth::Event::StopScript()); break; case 0xE2: // Set waveform (waveform) if(!isVolume) events.push_back(InstrumentSynth::Event::MED_JumpScript(1, 0)); [[fallthrough]]; case 0xE4: // Change waveform (waveform) if(isVolume) events.push_back(volumeCommand); else events.push_back(InstrumentSynth::Event::FC_SetWaveform(b, file.ReadUint8(), 0)); break; case 0xE3: // Set new vibrato (speed, amplitude) if(isVolume) { events.push_back(volumeCommand); } else { const auto [speed, depth] = file.ReadArray(); events.push_back(InstrumentSynth::Event::FC_SetVibrato(speed, depth, 0)); } break; case 0xE7: // Jump to freq. sequence (sequence) if(isVolume) { events.push_back(volumeCommand); } else { uint8 sequence = file.ReadUint8(); events.push_back(InstrumentSynth::Event::Jump(sequence * 64u)); if(!parsedSequences[sequence]) { parsedSequences.set(sequence); sequencesToParse.push_back(sequence); } } break; case 0xE8: // Sustain (time) { const uint8 delay = file.ReadUint8(); if(isVolume && volScriptSpeed > 1) { events.push_back(InstrumentSynth::Event::SetStepSpeed(1, true)); events.push_back(InstrumentSynth::Event::Delay(static_cast(delay + volScriptSpeed - 2))); events.push_back(InstrumentSynth::Event::SetStepSpeed(volScriptSpeed, true)); } else if(delay) { events.push_back(InstrumentSynth::Event::Delay(delay - 1)); } } break; case 0xE9: // Set waveform (waveform, number) if(isVolume) { events.push_back(volumeCommand); } else if(isFC14) { const auto [waveform, subSample] = file.ReadArray(); events.push_back(InstrumentSynth::Event::MED_JumpScript(1, 0)); events.push_back(InstrumentSynth::Event::FC_SetWaveform(b, subSample, waveform)); } else { events.push_back(InstrumentSynth::Event::FC_SetPitch(b)); } break; case 0xEA: // Volume slide / Pitch bend (step, time) if(isFC14) { const auto [speed, time] = file.ReadArray(); if(isVolume) events.push_back(InstrumentSynth::Event::FC_VolumeSlide(speed, time)); else events.push_back(InstrumentSynth::Event::FC_PitchSlide(speed, time)); break; } [[fallthrough]]; default: if(isVolume) events.push_back(volumeCommand); else events.push_back(InstrumentSynth::Event::FC_SetPitch(b)); break; } if(!isVolume) nextByteIsPitch = (b >= 0xE2 && b <= 0xE4) || (isFC14 && (b == 0xE9 || b == 0xEA)); // If a sequence doesn't end with an E0/E1/E7 command, execution will continue in the next sequence. // In the general case, we cannot stop translating the script at an E0/E1 command because we might jump beyond it with an E0 command. // However, E0 commands cannot jump beyond the end of the initial sequence (modulo underflow, see above), so we can stop translating additonal sequences when we hit command E0/E1 there. if((b == 0xE0 || b == 0xE1 || (b == 0xE7 && !isVolume)) && (maxJump <= scriptPos || scriptPos >= maxScriptJumpPos)) break; } } for(auto &event : events) { event.FixupJumpTarget(entryFromByte); } } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderFC(MemoryFileReader file, const uint64 *pfilesize) { FCFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadFC(FileReader &file, ModLoadingFlags loadFlags) { FCFileHeader fileHeader; file.Rewind(); if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) return false; if(!file.CanRead(fileHeader.GetHeaderMinimumAdditionalSize())) return false; if(loadFlags == onlyVerifyHeader) return true; const bool isFC14 = fileHeader.IsFC14(); InitializeGlobals(MOD_TYPE_MOD, 4); SetupMODPanning(true); m_SongFlags.set(SONG_IMPORTED | SONG_ISAMIGA); m_nSamples = isFC14 ? 90 : 57; m_nInstruments = std::min(static_cast(fileHeader.volSequenceSize / 64u + 1), static_cast(MAX_INSTRUMENTS - 1)); m_playBehaviour.set(kMODSampleSwap); m_playBehaviour.set(kApplyUpperPeriodLimit); m_nMinPeriod = 113 * 4; m_nMaxPeriod = 3424 * 4; m_modFormat.formatName = isFC14 ? UL_("Future Composer 1.4") : UL_("Future Composer 1.0 - 1.3"); m_modFormat.type = isFC14 ? UL_("fc") : UL_("smod"); m_modFormat.madeWithTracker = m_modFormat.formatName; m_modFormat.charset = mpt::Charset::Amiga_no_C1; // No strings in this format... std::array waveTableLengths; if(isFC14) file.ReadArray(waveTableLengths); const ORDERINDEX numOrders = fileHeader.NumOrders(); std::vector orderData; file.ReadVector(orderData, numOrders); std::vector> patternData(fileHeader.patternsSize / 2u); file.Seek(fileHeader.patternsOffset); if(!file.ReadVector(patternData, fileHeader.patternsSize / 2u)) return false; Order().SetDefaultSpeed(3); Order().resize(numOrders); if(loadFlags & loadPatternData) Patterns.ResizeArray(numOrders); std::array prevNote = {{}}; for(ORDERINDEX ord = 0; ord < numOrders; ord++) { Order()[ord] = ord; static constexpr uint16 numRows = 32; if(!(loadFlags & loadPatternData) || !Patterns.Insert(ord, numRows)) continue; ROWINDEX lastRow = numRows; for(CHANNELINDEX chn = 0; chn < 4; chn++) { const auto &chnInfo = orderData[ord].channels[chn]; const uint16 patternOffset = chnInfo.pattern * numRows; if(patternOffset >= patternData.size()) continue; ModCommand *m = Patterns[ord].GetpModCommand(0, chn); const auto &pattern = mpt::as_span(patternData).subspan(patternOffset); for(ROWINDEX row = 0; row < numRows; row++, m += GetNumChannels()) { const auto p = pattern[row]; // Channels should be broken independently, but no tune in the wild relies on it, I think. // (Vim's blue-funk has inconsistent pattern lengths in the very last order item but that's all I could find) if(p[0] == 0x49) lastRow = std::min(lastRow, row); if(p[0] > 0 && p[0] != 0x49) { prevNote[chn] = p[0]; m->note = NOTE_MIN + ((chnInfo.noteTranspose + p[0]) & 0x7F); if(int instr = (p[1] & 0x3F) + chnInfo.instrTranspose + 1; instr >= 1 && instr <= m_nInstruments) m->instr = static_cast(instr); else m->instr = static_cast(m_nInstruments); } else if(row == 0 && ord > 0 && orderData[ord - 1].channels[chn].noteTranspose != chnInfo.noteTranspose && prevNote[chn] > 0) { m->note = NOTE_MIN + ((chnInfo.noteTranspose + prevNote[chn]) & 0x7F); if(p[1] & 0xC0) m->SetVolumeCommand(VOLCMD_TONEPORTAMENTO, 9); else m->SetEffectCommand(CMD_TONEPORTA_DURATION, 0); } if(p[1] & 0xC0) m->SetEffectCommand(CMD_AUTO_PORTAMENTO_FC, 0); if(p[1] & 0x80) { const uint8 data = ((row + 1) < pattern.size()) ? pattern[row + 1][1] : uint8(0); int8 param = data & 0x1F; if(!isFC14) param *= 2; if(data > 0x1F) param = -param; m->param = static_cast(param); } } } if(orderData[ord].speed) Patterns[ord].WriteEffect(EffectWriter(CMD_SPEED, orderData[ord].speed).RetryNextRow()); if(lastRow < numRows) Patterns[ord].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(std::max(lastRow, ROWINDEX(1)) - 1).RetryNextRow()); } std::vector freqSequences, volSequences; freqSequences.reserve(64 * 256); if(!file.Seek(fileHeader.freqSequenceOffset) || !file.ReadVector(freqSequences, fileHeader.freqSequenceSize)) return false; freqSequences.resize(64 * 256); volSequences.reserve(fileHeader.volSequenceSize + 8); if(!file.Seek(fileHeader.volSequenceOffset) || !file.ReadVector(volSequences, fileHeader.volSequenceSize)) return false; // Add an empty instrument for out-of-range instrument numbers static constexpr std::array EmptyInstr = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1}; volSequences.insert(volSequences.end(), EmptyInstr.begin(), EmptyInstr.end()); for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++) { const auto volSeq = mpt::as_span(volSequences).subspan((ins - 1) * 64u); const auto freqSeq = mpt::as_span(freqSequences).subspan(volSeq[1] * 64u); uint8 defaultSample = freqSeq[1]; if(freqSeq[0] == 0xE9) defaultSample = static_cast(90 + defaultSample * 10 + freqSeq[2]); ModInstrument *instr = AllocateInstrument(ins, defaultSample + 1); if(!instr) return false; static_assert(NOTE_MAX - NOTE_MIN + 1 >= 128, "Need at least a note range of 128 for correct emulation of note wrap-around logic in Future Composer"); for(uint8 note = 0; note < static_cast(instr->NoteMap.size()); note++) { if(note < 48) instr->NoteMap[note] = note + NOTE_MIDDLEC - 24; else if(note < 60 || note >= 120) instr->NoteMap[note] = NOTE_MIDDLEC + 23; else instr->NoteMap[note] = note + NOTE_MIDDLEC - 36 - 60; } instr->synth.m_scripts.resize(2); instr->synth.m_scripts[0].push_back(InstrumentSynth::Event::FC_SetVibrato(volSeq[2], volSeq[3], volSeq[4])); TranslateFCScript(instr->synth.m_scripts[0], mpt::as_span(freqSequences), isFC14, volSeq[1]); TranslateFCScript(instr->synth.m_scripts[1], volSeq, isFC14); } if(!file.Seek(fileHeader.sampleDataOffset)) return false; for(SAMPLEINDEX smp = 0; smp < 10; smp++) { if(!fileHeader.sampleInfo[smp].length) continue; if(isFC14 && file.ReadMagic("SSMP")) { m_nSamples = 190; FileReader sampleHeaders = file.ReadChunk(160); for(SAMPLEINDEX subSmp = 0; subSmp < 10; subSmp++) { FCSampleInfo sampleInfo; sampleHeaders.Skip(4); sampleHeaders.Read(sampleInfo); sampleHeaders.Skip(6); sampleInfo.ConvertToMPT(Samples[91 + (smp * 10) + subSmp], file, true, (loadFlags & loadSampleData) != 0); } } else { fileHeader.sampleInfo[smp].ConvertToMPT(Samples[smp + 1], file, isFC14, (loadFlags& loadSampleData) != 0); } } if(!(loadFlags & loadSampleData)) return true; static constexpr uint8 SampleLengths[] = { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 16, 8, 16, 16, 8, 8, 24, // Future Composer 1.4 imports the last sample with a length of 32 instead of 48, causing some older FC files to be detuned. }; static constexpr uint8 SampleData[] = { 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0x3F, 0x37, 0x2F, 0x27, 0x1F, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0x37, 0x2F, 0x27, 0x1F, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0x2F, 0x27, 0x1F, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0x27, 0x1F, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0x1F, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x98, 0x1F, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x98, 0xA0, 0x27, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x98, 0xA0, 0xA8, 0x2F, 0x37, 0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x98, 0xA0, 0xA8, 0xB0, 0x37, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x90, 0x98, 0xA0, 0xA8, 0xB0, 0xB8, 0xC0, 0xC8, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x7F, 0x80, 0x80, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x45, 0x45, 0x79, 0x7D, 0x7A, 0x77, 0x70, 0x66, 0x61, 0x58, 0x53, 0x4D, 0x2C, 0x20, 0x18, 0x12, 0x04, 0xDB, 0xD3, 0xCD, 0xC6, 0xBC, 0xB5, 0xAE, 0xA8, 0xA3, 0x9D, 0x99, 0x93, 0x8E, 0x8B, 0x8A, 0x45, 0x45, 0x79, 0x7D, 0x7A, 0x77, 0x70, 0x66, 0x5B, 0x4B, 0x43, 0x37, 0x2C, 0x20, 0x18, 0x12, 0x04, 0xF8, 0xE8, 0xDB, 0xCF, 0xC6, 0xBE, 0xB0, 0xA8, 0xA4, 0x9E, 0x9A, 0x95, 0x94, 0x8D, 0x83, 0x00, 0x00, 0x40, 0x60, 0x7F, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0xA0, 0xC0, 0xE0, 0x00, 0x00, 0x40, 0x60, 0x7F, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0xA0, 0xC0, 0xE0, 0x80, 0x80, 0x90, 0x98, 0xA0, 0xA8, 0xB0, 0xB8, 0xC0, 0xC8, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x7F, 0x80, 0x80, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, }; if(isFC14 && !file.Seek(fileHeader.waveTableOffset)) return false; FileReader smpFile{mpt::as_span(SampleData)}; const auto sampleLengths = isFC14 ? mpt::span(waveTableLengths) : mpt::as_span(SampleLengths); SampleIO sampleIO{SampleIO::_8bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM}; for(SAMPLEINDEX smp = 0; smp < sampleLengths.size(); smp++) { ModSample &mptSmp = Samples[smp + 11]; mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.nLength = sampleLengths[smp] * 2u; mptSmp.nLoopStart = 0; mptSmp.nLoopEnd = mptSmp.nLength; mptSmp.uFlags.set(CHN_LOOP); sampleIO.ReadSample(mptSmp, isFC14 ? file : smpFile); } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/tuningbase.h0000644000175000017500000000373514657606142020430 00000000000000/* * tuningbase.h * ------------ * Purpose: Alternative sample tuning. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include OPENMPT_NAMESPACE_BEGIN namespace Tuning { enum class SerializationResult : int { Success = 1, NoMagic = 0, Failure = -1 }; using NOTEINDEXTYPE = int16; // Some signed integer-type. using UNOTEINDEXTYPE = uint16; // Unsigned NOTEINDEXTYPE. using RATIOTYPE = somefloat32; // Some 'real figure' type able to present ratios. If changing RATIOTYPE, serialization methods may need modifications. // Counter of steps between notes. If there is no 'finetune'(finestepcount == 0), // then 'step difference' between notes is the // same as differences in NOTEINDEXTYPE. In a way similar to ticks and rows in pattern - // ticks <-> STEPINDEX, rows <-> NOTEINDEX using STEPINDEXTYPE = int32; using USTEPINDEXTYPE = uint32; struct NoteRange { NOTEINDEXTYPE first; NOTEINDEXTYPE last; }; // Derived from old IsStepCountRangeSufficient(), this is actually a more // sensible value than what was calculated in earlier versions. inline constexpr STEPINDEXTYPE FINESTEPCOUNT_MAX = 0xffff; inline constexpr auto NOTEINDEXTYPE_MIN = std::numeric_limits::min(); inline constexpr auto NOTEINDEXTYPE_MAX = std::numeric_limits::max(); inline constexpr auto UNOTEINDEXTYPE_MAX = std::numeric_limits::max(); inline constexpr auto STEPINDEXTYPE_MIN = std::numeric_limits::min(); inline constexpr auto STEPINDEXTYPE_MAX = std::numeric_limits::max(); inline constexpr auto USTEPINDEXTYPE_MAX = std::numeric_limits::max(); enum class Type : uint16 { GENERAL = 0, GROUPGEOMETRIC = 1, GEOMETRIC = 3, }; class CTuning; } // namespace Tuning using CTuning = Tuning::CTuning; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Container.h0000644000175000017500000000217714052707103020176 00000000000000/* * Container.h * ----------- * Purpose: General interface for MDO container and/or packers. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "../common/FileReader.h" #include OPENMPT_NAMESPACE_BEGIN struct ContainerItem { mpt::ustring name; FileReader file; std::unique_ptr > data_cache; // may be empty }; enum ContainerLoadingFlags { ContainerOnlyVerifyHeader = 0x00, ContainerUnwrapData = 0x01, }; #if !defined(MPT_WITH_ANCIENT) bool UnpackXPK(std::vector &containerItems, FileReader &file, ContainerLoadingFlags loadFlags); bool UnpackPP20(std::vector &containerItems, FileReader &file, ContainerLoadingFlags loadFlags); bool UnpackMMCMP(std::vector &containerItems, FileReader &file, ContainerLoadingFlags loadFlags); #endif // !MPT_WITH_ANCIENT bool UnpackUMX(std::vector &containerItems, FileReader &file, ContainerLoadingFlags loadFlags); OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/OPL.cpp0000644000175000017500000002422214615431500017234 00000000000000/* * OPL.cpp * ------- * Purpose: Translate data coming from OpenMPT's mixer into OPL commands to be sent to the Opal emulator. * Notes : (currently none) * Authors: OpenMPT Devs * Schism Tracker contributors (bisqwit, JosepMa, Malvineous, code relicensed from GPL to BSD with permission) * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "OPL.h" #include "../common/misc_util.h" #include #if MPT_COMPILER_GCC #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #endif #include "opal.h" #if MPT_COMPILER_GCC #pragma GCC diagnostic pop #endif OPENMPT_NAMESPACE_BEGIN OPL::OPL(uint32 sampleRate) { Initialize(sampleRate); } OPL::OPL(IRegisterLogger &logger) : m_logger{&logger} { Initialize(OPL_BASERATE); } OPL::~OPL() { // This destructor is put here so that we can forward-declare the Opal emulator class. } void OPL::Initialize(uint32 sampleRate) { if(m_opl == nullptr) m_opl = std::make_unique(sampleRate); else m_opl->SetSampleRate(sampleRate); Reset(); } void OPL::Mix(int32 *target, size_t count, uint32 volumeFactorQ16) { if(!m_isActive) return; // This factor causes a sample voice to be more or less as loud as an OPL voice const int32 factor = Util::muldiv_unsigned(volumeFactorQ16, 6169, (1 << 16)); while(count--) { int16 l, r; m_opl->Sample(&l, &r); target[0] += l * factor; target[1] += r * factor; target += 2; } } OPL::Register OPL::ChannelToRegister(uint8 oplCh) { if(oplCh < 9) return oplCh; else return (oplCh - 9) | 0x100; } // Translate a channel's first operator address into a register OPL::Register OPL::OperatorToRegister(uint8 oplCh) { static constexpr uint8 OPLChannelToOperator[] = { 0, 1, 2, 8, 9, 10, 16, 17, 18 }; if(oplCh < 9) return OPLChannelToOperator[oplCh]; else return OPLChannelToOperator[oplCh - 9] | 0x100; } uint8 OPL::GetVoice(CHANNELINDEX c) const { if((m_ChanToOPL[c] & OPL_CHANNEL_CUT) || m_ChanToOPL[c] == OPL_CHANNEL_INVALID) return OPL_CHANNEL_INVALID; return m_ChanToOPL[c] & OPL_CHANNEL_MASK; } uint8 OPL::AllocateVoice(CHANNELINDEX c) { // Can we re-use a previous channel? if(auto oplCh = m_ChanToOPL[c]; oplCh != OPL_CHANNEL_INVALID) { if(!(m_ChanToOPL[c] & OPL_CHANNEL_CUT)) return oplCh; // Check re-use hint oplCh &= OPL_CHANNEL_MASK; if(m_OPLtoChan[oplCh] == CHANNELINDEX_INVALID || m_OPLtoChan[oplCh] == c) { m_OPLtoChan[oplCh] = c; m_ChanToOPL[c] = oplCh; return oplCh; } } // Search for unused channel or channel with released note uint8 releasedChn = OPL_CHANNEL_INVALID, releasedCutChn = OPL_CHANNEL_INVALID; for(uint8 oplCh = 0; oplCh < OPL_CHANNELS; oplCh++) { if(m_OPLtoChan[oplCh] == CHANNELINDEX_INVALID) { m_OPLtoChan[oplCh] = c; m_ChanToOPL[c] = oplCh; return oplCh; } else if(!(m_KeyOnBlock[oplCh] & KEYON_BIT)) { releasedChn = oplCh; if(m_ChanToOPL[m_OPLtoChan[oplCh]] & OPL_CHANNEL_CUT) releasedCutChn = oplCh; } } if(releasedChn != OPL_CHANNEL_INVALID) { // Prefer channel that has been marked as cut over channel that has just been released if(releasedCutChn != OPL_CHANNEL_INVALID) releasedChn = releasedCutChn; m_ChanToOPL[m_OPLtoChan[releasedChn]] = OPL_CHANNEL_INVALID; m_OPLtoChan[releasedChn] = c; m_ChanToOPL[c] = releasedChn; } return GetVoice(c); } void OPL::MoveChannel(CHANNELINDEX from, CHANNELINDEX to) { uint8 oplCh = GetVoice(from); if(oplCh == OPL_CHANNEL_INVALID) return; m_OPLtoChan[oplCh] = to; m_ChanToOPL[from] = OPL_CHANNEL_INVALID; m_ChanToOPL[to] = oplCh; if(m_logger) m_logger->MoveChannel(from, to); } void OPL::NoteOff(CHANNELINDEX c) { uint8 oplCh = GetVoice(c); if(oplCh == OPL_CHANNEL_INVALID || m_opl == nullptr) return; if(!(m_KeyOnBlock[oplCh] & KEYON_BIT)) return; m_KeyOnBlock[oplCh] &= ~KEYON_BIT; Port(c, KEYON_BLOCK | ChannelToRegister(oplCh), m_KeyOnBlock[oplCh]); } void OPL::NoteCut(CHANNELINDEX c, bool unassign) { uint8 oplCh = GetVoice(c); if(oplCh == OPL_CHANNEL_INVALID) return; NoteOff(c); Volume(c, 0, false); // Note that a volume of 0 is not complete silence; the release portion of the sound will still be heard at -48dB if(unassign) { m_OPLtoChan[oplCh] = CHANNELINDEX_INVALID; m_ChanToOPL[c] |= OPL_CHANNEL_CUT; } } void OPL::Frequency(CHANNELINDEX c, uint32 milliHertz, bool keyOff, bool beatingOscillators) { uint8 oplCh = GetVoice(c); if(oplCh == OPL_CHANNEL_INVALID || m_opl == nullptr) return; uint16 fnum = 1023; uint8 block = 7; if(milliHertz <= 6208431) { if(milliHertz > 3104215) block = 7; else if(milliHertz > 1552107) block = 6; else if(milliHertz > 776053) block = 5; else if(milliHertz > 388026) block = 4; else if(milliHertz > 194013) block = 3; else if(milliHertz > 97006) block = 2; else if(milliHertz > 48503) block = 1; else block = 0; fnum = static_cast(Util::muldivr_unsigned(milliHertz, 1 << (20 - block), OPL_BASERATE * 1000)); MPT_ASSERT(fnum < 1024); } // Evil CDFM hack! Composer 670 slightly detunes each note based on the OPL channel number modulo 4. // We allocate our OPL channels dynamically, which would result in slightly different beating characteristics, // but we can just take the pattern channel number instead, as the pattern channel layout is always identical. if(beatingOscillators) fnum = std::min(static_cast(fnum + (c & 3)), uint16(1023)); fnum |= (block << 10); OPL::Register channel = ChannelToRegister(oplCh); m_KeyOnBlock[oplCh] = static_cast((keyOff ? 0 : KEYON_BIT) | (fnum >> 8)); // Key on bit + Octave (block) + F-number high 2 bits Port(c, FNUM_LOW | channel, fnum & 0xFFu); // F-Number low 8 bits Port(c, KEYON_BLOCK | channel, m_KeyOnBlock[oplCh]); m_isActive = true; } uint8 OPL::CalcVolume(uint8 trackerVol, uint8 kslVolume) { if(trackerVol >= 63u) return kslVolume; if(trackerVol > 0) trackerVol++; return static_cast((kslVolume & KSL_MASK) | (63u - ((63u - (kslVolume & TOTAL_LEVEL_MASK)) * trackerVol) / 64u)); } void OPL::Volume(CHANNELINDEX c, uint8 vol, bool applyToModulator) { uint8 oplCh = GetVoice(c); if(oplCh == OPL_CHANNEL_INVALID || m_opl == nullptr) return; const auto &patch = m_Patches[oplCh]; const OPL::Register modulator = OperatorToRegister(oplCh), carrier = modulator + 3; if((patch[10] & CONNECTION_BIT) || applyToModulator) { // Set volume of both operators in additive mode Port(c, KSL_LEVEL + modulator, CalcVolume(vol, patch[2])); } if(!applyToModulator) { Port(c, KSL_LEVEL + carrier, CalcVolume(vol, patch[3])); } } int8 OPL::Pan(CHANNELINDEX c, int32 pan) { uint8 oplCh = GetVoice(c); if(oplCh == OPL_CHANNEL_INVALID || m_opl == nullptr) return 0; const auto &patch = m_Patches[oplCh]; uint8 fbConn = patch[10] & ~STEREO_BITS; // OPL3 only knows hard left, center and right, so we need to translate our // continuous panning range into one of those three states. // 0...84 = left, 85...170 = center, 171...256 = right if(pan <= 170) fbConn |= VOICE_TO_LEFT; if(pan >= 85) fbConn |= VOICE_TO_RIGHT; Port(c, FEEDBACK_CONNECTION | ChannelToRegister(oplCh), fbConn); return static_cast(((fbConn & VOICE_TO_LEFT) ? -1 : 0) + ((fbConn & VOICE_TO_RIGHT) ? 1 : 0)); } void OPL::Patch(CHANNELINDEX c, const OPLPatch &patch) { uint8 oplCh = AllocateVoice(c); if(oplCh == OPL_CHANNEL_INVALID || m_opl == nullptr) return; m_Patches[oplCh] = patch; const OPL::Register modulator = OperatorToRegister(oplCh), carrier = modulator + 3; for(uint8 op = 0; op < 2; op++) { const auto opReg = op ? carrier : modulator; Port(c, AM_VIB | opReg, patch[0 + op]); Port(c, KSL_LEVEL | opReg, patch[2 + op]); Port(c, ATTACK_DECAY | opReg, patch[4 + op]); Port(c, SUSTAIN_RELEASE | opReg, patch[6 + op]); Port(c, WAVE_SELECT | opReg, patch[8 + op]); } Port(c, FEEDBACK_CONNECTION | ChannelToRegister(oplCh), patch[10]); } void OPL::Reset() { if(m_isActive) { for(CHANNELINDEX chn = 0; chn < MAX_CHANNELS; chn++) { NoteCut(chn); } m_isActive = false; } m_KeyOnBlock.fill(0); m_OPLtoChan.fill(CHANNELINDEX_INVALID); m_ChanToOPL.fill(OPL_CHANNEL_INVALID); Port(CHANNELINDEX_INVALID, 0x105, 1); // Enable OPL3 Port(CHANNELINDEX_INVALID, 0x104, 0); // No 4-op voices } void OPL::Port(CHANNELINDEX c, OPL::Register reg, OPL::Value value) { if(!m_logger) m_opl->Port(reg, value); else m_logger->Port(c, reg, value); } std::vector OPL::AllVoiceRegisters(uint8 oplCh) { static constexpr uint8 opRegisters[] = {AM_VIB, KSL_LEVEL, ATTACK_DECAY, SUSTAIN_RELEASE, WAVE_SELECT}; static constexpr uint8 chnRegisters[] = {FNUM_LOW, KEYON_BLOCK, FEEDBACK_CONNECTION}; std::vector result; uint8 minVoice = 0, maxVoice = OPL_CHANNELS; if(oplCh < OPL_CHANNELS) { minVoice = oplCh; maxVoice = oplCh + 1; } result.reserve(13 * (maxVoice - minVoice)); for(uint8 voice = minVoice; voice < maxVoice; voice++) { const Register opBaseReg = OperatorToRegister(voice); for(uint8 opReg : opRegisters) { for(uint8 op = 0; op <= 3; op += 3) { result.push_back(opReg | (opBaseReg + op)); MPT_ASSERT(RegisterToVoice(result.back()) == voice); } } const Register chnBaseReg = ChannelToRegister(voice); for(uint8 chnReg : chnRegisters) { result.push_back(chnReg | chnBaseReg); MPT_ASSERT(RegisterToVoice(result.back()) == voice); } } return result; } uint8 OPL::RegisterToVoice(OPL::Register reg) { const OPL::Register regLo = reg & 0xE0; const uint8 baseCh = (reg > 0xFF) ? 9 : 0; if(reg == TREMOLO_VIBRATO_DEPTH) return 0xFF; if(regLo >= FNUM_LOW && regLo <= FEEDBACK_CONNECTION) return baseCh + static_cast(reg & 0x0F); if(regLo >= AM_VIB && regLo <= WAVE_SELECT) return static_cast(baseCh + (reg & 0x07) % 3u + ((reg & 0x1F) >> 3) * 3); return 0xFF; } OPL::Register OPL::StripVoiceFromRegister(OPL::Register reg) { const OPL::Register regLo = reg & 0xE0; if(reg == TREMOLO_VIBRATO_DEPTH) return reg; if(regLo >= FNUM_LOW && regLo <= FEEDBACK_CONNECTION) return (reg & 0xF0); if(regLo >= AM_VIB && regLo <= WAVE_SELECT) return static_cast(regLo + ((reg & 0x07) >= 3 ? 3 : 0)); return reg; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ContainerMMCMP.cpp0000644000175000017500000002367314716721075021342 00000000000000/* * ContainerMMCMP.cpp * ------------------ * Purpose: Handling of MMCMP compressed modules * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "../common/FileReader.h" #include "Container.h" #include "Sndfile.h" #include "BitReader.h" OPENMPT_NAMESPACE_BEGIN #if !defined(MPT_WITH_ANCIENT) #ifdef MPT_ALL_LOGGING #define MMCMP_LOG #endif struct MMCMPFileHeader { char id[8]; // "ziRCONia" uint16le hdrsize; // size of all the remaining header data uint16le version; uint16le nblocks; uint32le filesize; uint32le blktable; uint8le glb_comp; uint8le fmt_comp; bool Validate() const { if(std::memcmp(id, "ziRCONia", 8) != 0) return false; if(hdrsize != 14) return false; if(nblocks == 0) return false; if(filesize == 0) return false; if(filesize >= 0x80000000) return false; if(blktable < sizeof(MMCMPFileHeader)) return false; return true; } }; MPT_BINARY_STRUCT(MMCMPFileHeader, 24) struct MMCMPBlock { uint32le unpk_size; uint32le pk_size; uint32le xor_chk; uint16le sub_blk; uint16le flags; uint16le tt_entries; uint16le num_bits; }; MPT_BINARY_STRUCT(MMCMPBlock, 20) struct MMCMPSubBlock { uint32le position; uint32le size; bool Validate(std::vector &unpackedData, const uint32 unpackedSize) const { if(position >= unpackedSize) return false; if(size > unpackedSize) return false; if(size > unpackedSize - position) return false; if(size == 0) return false; if(unpackedData.size() < position + size) unpackedData.resize(position + size); return true; } }; MPT_BINARY_STRUCT(MMCMPSubBlock, 8) enum MMCMPFlags : uint16 { MMCMP_COMP = 0x0001, MMCMP_DELTA = 0x0002, MMCMP_16BIT = 0x0004, MMCMP_STEREO = 0x0100, MMCMP_ABS16 = 0x0200, MMCMP_ENDIAN = 0x0400, }; static constexpr uint8 MMCMP8BitCommands[8] = { 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF8 }; static constexpr uint8 MMCMP8BitFetch[8] = { 3, 3, 3, 3, 2, 1, 0, 0 }; static constexpr uint16 MMCMP16BitCommands[16] = { 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0 }; static constexpr uint8 MMCMP16BitFetch[16] = { 4, 4, 4, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMMCMP(MemoryFileReader file, const uint64 *pfilesize) { MMCMPFileHeader mfh; if(!file.ReadStruct(mfh)) return ProbeWantMoreData; if(!mfh.Validate()) return ProbeFailure; MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool UnpackMMCMP(std::vector &containerItems, FileReader &file, ContainerLoadingFlags loadFlags) { file.Rewind(); containerItems.clear(); MMCMPFileHeader mfh; if(!file.ReadStruct(mfh)) return false; if(!mfh.Validate()) return false; if(loadFlags == ContainerOnlyVerifyHeader) return true; if(!file.LengthIsAtLeast(mfh.blktable)) return false; if(!file.LengthIsAtLeast(mfh.blktable + 4 * mfh.nblocks)) return false; containerItems.emplace_back(); containerItems.back().data_cache = std::make_unique >(); auto &unpackedData = *(containerItems.back().data_cache); // Generally it's not so simple to establish an upper limit for the uncompressed data size (blocks can be reused, etc.), // so we just reserve a realistic amount of memory. const uint32 unpackedSize = mfh.filesize; unpackedData.reserve(std::min(unpackedSize, std::min(mpt::saturate_cast(file.GetLength()), uint32_max / 20u) * 20u)); // 8-bit deltas uint8 ptable[256] = { 0 }; std::vector subblks; for(uint32 nBlock = 0; nBlock < mfh.nblocks; nBlock++) { if(!file.Seek(mfh.blktable + 4 * nBlock)) return false; if(!file.CanRead(4)) return false; uint32 blkPos = file.ReadUint32LE(); if(!file.Seek(blkPos)) return false; MMCMPBlock blk; if(!file.ReadStruct(blk)) return false; if(!file.ReadVector(subblks, blk.sub_blk)) return false; const MMCMPSubBlock *psubblk = blk.sub_blk > 0 ? subblks.data() : nullptr; if(blkPos + sizeof(MMCMPBlock) + blk.sub_blk * sizeof(MMCMPSubBlock) >= file.GetLength()) return false; uint32 memPos = blkPos + static_cast(sizeof(MMCMPBlock)) + blk.sub_blk * static_cast(sizeof(MMCMPSubBlock)); #ifdef MMCMP_LOG MPT_LOG_GLOBAL(LogDebug, "MMCMP", MPT_UFORMAT("block {}: flags={} sub_blocks={}")(nBlock, mpt::ufmt::HEX0<4>(static_cast(blk.flags)), static_cast(blk.sub_blk))); MPT_LOG_GLOBAL(LogDebug, "MMCMP", MPT_UFORMAT(" pksize={} unpksize={}")(static_cast(blk.pk_size), static_cast(blk.unpk_size))); MPT_LOG_GLOBAL(LogDebug, "MMCMP", MPT_UFORMAT(" tt_entries={} num_bits={}")(static_cast(blk.tt_entries), static_cast(blk.num_bits))); #endif if(!(blk.flags & MMCMP_COMP)) { // Data is not packed for(uint32 i = 0; i < blk.sub_blk; i++) { if(!psubblk) return false; if(!psubblk->Validate(unpackedData, unpackedSize)) return false; #ifdef MMCMP_LOG MPT_LOG_GLOBAL(LogDebug, "MMCMP", MPT_UFORMAT(" Unpacked sub-block {}: offset {}, size={}")(i, static_cast(psubblk->position), static_cast(psubblk->size))); #endif if(!file.Seek(memPos)) return false; if(file.ReadRaw(mpt::span(&(unpackedData[psubblk->position]), psubblk->size)).size() != psubblk->size) return false; psubblk++; } } else if(blk.flags & MMCMP_16BIT) { // Data is 16-bit packed uint32 subblk = 0; if(!psubblk) return false; if(!psubblk[subblk].Validate(unpackedData, unpackedSize)) return false; char *pDest = &(unpackedData[psubblk[subblk].position]); uint32 dwSize = psubblk[subblk].size & ~1u; if(!dwSize) return false; uint32 dwPos = 0; uint32 numbits = blk.num_bits; uint32 oldval = 0; #ifdef MMCMP_LOG MPT_LOG_GLOBAL(LogDebug, "MMCMP", MPT_UFORMAT(" 16-bit block: pos={} size={} {} {}")(psubblk->position, psubblk->size, (blk.flags & MMCMP_DELTA) ? U_("DELTA ") : U_(""), (blk.flags & MMCMP_ABS16) ? U_("ABS16 ") : U_(""))); #endif if(numbits > 15) return false; if(!file.Seek(memPos + blk.tt_entries)) return false; if(!file.CanRead(blk.pk_size - blk.tt_entries)) return false; BitReader bitFile{ file.GetChunk(blk.pk_size - blk.tt_entries) }; try { while (subblk < blk.sub_blk) { uint32 newval = 0x10000; uint32 d = bitFile.ReadBits(numbits + 1); uint32 command = MMCMP16BitCommands[numbits & 0x0F]; if(d >= command) { uint32 nFetch = MMCMP16BitFetch[numbits & 0x0F]; uint32 newbits = bitFile.ReadBits(nFetch) + ((d - command) << nFetch); if(newbits != numbits) { numbits = newbits & 0x0F; } else if((d = bitFile.ReadBits(4)) == 0x0F) { if(bitFile.ReadBits(1)) break; newval = 0xFFFF; } else { newval = 0xFFF0 + d; } } else { newval = d; } if(newval < 0x10000) { newval = (newval & 1) ? (uint32)(-(int32)((newval + 1) >> 1)) : (uint32)(newval >> 1); if(blk.flags & MMCMP_DELTA) { newval += oldval; oldval = newval; } else if(!(blk.flags & MMCMP_ABS16)) { newval ^= 0x8000; } if(blk.flags & MMCMP_ENDIAN) { pDest[dwPos + 0] = static_cast(newval >> 8); pDest[dwPos + 1] = static_cast(newval & 0xFF); } else { pDest[dwPos + 0] = static_cast(newval & 0xFF); pDest[dwPos + 1] = static_cast(newval >> 8); } dwPos += 2; } if(dwPos >= dwSize) { subblk++; dwPos = 0; if(!(subblk < blk.sub_blk)) break; if(!psubblk[subblk].Validate(unpackedData, unpackedSize)) return false; dwSize = psubblk[subblk].size & ~1u; if(!dwSize) return false; pDest = &(unpackedData[psubblk[subblk].position]); } } } catch(const BitReader::eof &) { } } else { // Data is 8-bit packed uint32 subblk = 0; if(!psubblk) return false; if(!psubblk[subblk].Validate(unpackedData, unpackedSize)) return false; char *pDest = &(unpackedData[psubblk[subblk].position]); uint32 dwSize = psubblk[subblk].size; uint32 dwPos = 0; uint32 numbits = blk.num_bits; uint32 oldval = 0; if(blk.tt_entries > sizeof(ptable) || numbits > 7 || !file.Seek(memPos) || file.ReadRaw(mpt::span(ptable, blk.tt_entries)).size() < blk.tt_entries) return false; if(!file.CanRead(blk.pk_size - blk.tt_entries)) return false; BitReader bitFile{ file.GetChunk(blk.pk_size - blk.tt_entries) }; try { while (subblk < blk.sub_blk) { uint32 newval = 0x100; uint32 d = bitFile.ReadBits(numbits + 1); uint32 command = MMCMP8BitCommands[numbits & 0x07]; if(d >= command) { uint32 nFetch = MMCMP8BitFetch[numbits & 0x07]; uint32 newbits = bitFile.ReadBits(nFetch) + ((d - command) << nFetch); if(newbits != numbits) { numbits = newbits & 0x07; } else if((d = bitFile.ReadBits(3)) == 7) { if(bitFile.ReadBits(1)) break; newval = 0xFF; } else { newval = 0xF8 + d; } } else { newval = d; } if(newval < sizeof(ptable)) { int n = ptable[newval]; if(blk.flags & MMCMP_DELTA) { n += oldval; oldval = n; } pDest[dwPos++] = static_cast(n); } if(dwPos >= dwSize) { subblk++; dwPos = 0; if(!(subblk < blk.sub_blk)) break; if(!psubblk[subblk].Validate(unpackedData, unpackedSize)) return false; dwSize = psubblk[subblk].size; pDest = &(unpackedData[psubblk[subblk].position]); } } } catch(const BitReader::eof &) { } } } containerItems.back().file = FileReader(mpt::byte_cast(mpt::as_span(unpackedData))); return true; } #endif // !MPT_WITH_ANCIENT OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/OggStream.cpp0000644000175000017500000001032414405571342020476 00000000000000/* * OggStream.cpp * ------------- * Purpose: Basic Ogg stream parsing functionality * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "OggStream.h" #include "mpt/crc/crc.hpp" #include "mpt/io_read/filereader.hpp" #include "../common/FileReader.h" OPENMPT_NAMESPACE_BEGIN namespace Ogg { uint16 PageInfo::GetPagePhysicalSize() const { uint16 size = 0; size += sizeof(PageHeader); size += header.page_segments; for(uint8 segment = 0; segment < header.page_segments; ++segment) { size += segment_table[segment]; } return size; } uint16 PageInfo::GetPageHeaderSize() const { uint16 size = 0; size += sizeof(PageHeader); size += header.page_segments; return size; } uint16 PageInfo::GetPageDataSize() const { uint16 size = 0; for(uint8 segment = 0; segment < header.page_segments; ++segment) { size += segment_table[segment]; } return size; } bool AdvanceToPageMagic(FileCursor &file) { while(mpt::FR::CanRead(file, 4)) { if(mpt::FR::ReadMagic(file, "OggS")) { mpt::FR::SkipBack(file, 4); return true; } mpt::FR::Skip(file, 1); } return false; } bool ReadPage(FileCursor &file, PageInfo &pageInfo, std::vector *pageData) { pageInfo = PageInfo(); if(pageData) { (*pageData).clear(); } if(!mpt::FR::ReadMagic(file, "OggS")) { return false; } mpt::FR::SkipBack(file, 4); FileCursor filePageCursor = file; // do not modify original file read position if(!mpt::FR::ReadStruct(filePageCursor, pageInfo.header)) { return false; } if(!mpt::FR::CanRead(filePageCursor, pageInfo.header.page_segments)) { return false; } uint16 pageDataSize = 0; for(uint8 segment = 0; segment < pageInfo.header.page_segments; ++segment) { pageInfo.segment_table[segment] = mpt::FR::ReadIntLE(filePageCursor); pageDataSize += pageInfo.segment_table[segment]; } if(!mpt::FR::CanRead(filePageCursor, pageDataSize)) { return false; } if(pageData) { mpt::FR::ReadVector(filePageCursor , *pageData, pageDataSize); } else { mpt::FR::Skip(filePageCursor, pageDataSize); } mpt::FR::SkipBack(filePageCursor, pageInfo.GetPagePhysicalSize()); { mpt::crc32_ogg calculatedCRC; uint8 rawHeader[sizeof(PageHeader)]; MemsetZero(rawHeader); mpt::FR::ReadArray(filePageCursor, rawHeader); std::memset(rawHeader + 22, 0, 4); // clear out old crc calculatedCRC.process(rawHeader, rawHeader + sizeof(rawHeader)); mpt::FR::Skip(filePageCursor, pageInfo.header.page_segments); calculatedCRC.process(pageInfo.segment_table, pageInfo.segment_table + pageInfo.header.page_segments); if(pageData) { mpt::FR::Skip(filePageCursor, pageDataSize); calculatedCRC.process(*pageData); } else { FileCursor pageDataReader = mpt::FR::ReadChunk(filePageCursor, pageDataSize); auto pageDataView = pageDataReader.GetPinnedView(); calculatedCRC.process(pageDataView.GetSpan()); } if(calculatedCRC != pageInfo.header.CRC_checksum) { return false; } } mpt::FR::Skip(file, pageInfo.GetPagePhysicalSize()); return true; } bool ReadPage(FileCursor &file, PageInfo &pageInfo, std::vector &pageData) { return ReadPage(file, pageInfo, &pageData); } bool ReadPage(FileCursor &file) { PageInfo pageInfo; return ReadPage(file, pageInfo); } bool ReadPageAndSkipJunk(FileCursor &file, PageInfo &pageInfo, std::vector &pageData) { pageInfo = PageInfo(); pageData.clear(); while(AdvanceToPageMagic(file)) { if(ReadPage(file, pageInfo, pageData)) { return true; } else { pageInfo = PageInfo(); pageData.clear(); } mpt::FR::Skip(file, 4); } return false; } bool UpdatePageCRC(PageInfo &pageInfo, const std::vector &pageData) { if(pageData.size() != pageInfo.GetPageDataSize()) { return false; } mpt::crc32_ogg crc; pageInfo.header.CRC_checksum = 0; std::byte rawHeader[sizeof(PageHeader)] = {}; std::memcpy(rawHeader, &pageInfo.header, sizeof(PageHeader)); crc.process(rawHeader, rawHeader + sizeof(PageHeader)); crc.process(pageInfo.segment_table, pageInfo.segment_table + pageInfo.header.page_segments); crc.process(pageData); pageInfo.header.CRC_checksum = crc; return true; } } // namespace Ogg OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/InstrumentSynth.cpp0000644000175000017500000010425115017416060022002 00000000000000/* * InstrumentSynth.cpp * ------------------- * Purpose: "Script" / "Synth" processor for various file formats (MED, GT2, Puma, His Master's Noise, Face The Music, Future Composer) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "InstrumentSynth.h" #include "ModChannel.h" #include "Sndfile.h" #include "Tables.h" OPENMPT_NAMESPACE_BEGIN struct InstrumentSynth::States::State { static constexpr uint16 STOP_ROW = uint16_max; enum Flags { kJumpConditionSet, kGTKTremorEnabled, kGTKTremorMute, kGTKTremoloEnabled, kGTKVibratoEnabled, kFCVibratoDelaySet, kFCVibratoStep, kFCPitchBendStep, kFCVolumeBendStep, kNumFlags, }; std::bitset m_flags; uint16 m_currentRow = STOP_ROW; uint16 m_nextRow = 0; uint16 m_ticksRemain = 0; uint8 m_stepSpeed = 1; uint8 m_stepsRemain = 0; uint16 m_volumeFactor = 16384; int16 m_volumeAdd = int16_min; uint16 m_panning = 2048; int16 m_linearPitchFactor = 0; int16 m_periodFreqSlide = 0; int16 m_periodAdd = 0; uint16 m_loopCount = 0; uint16 m_gtkKeyOffOffset = STOP_ROW; int16 m_gtkVolumeStep = 0, m_gtkPitchStep = 0, m_gtkPanningStep = 0; uint16 m_gtkPitch = 4096; uint8 m_gtkSpeed = 1, m_gtkSpeedRemain = 1; uint8 m_gtkTremorOnTime = 3, m_gtkTremorOffTime = 3, m_gtkTremorPos = 0; uint8 m_gtkVibratoWidth = 0, m_gtkVibratoSpeed = 0, m_gtkVibratoPos = 0; uint8 m_pumaStartWaveform = 0, m_pumaEndWaveform = 0, m_pumaWaveform = 0; int8 m_pumaWaveformStep = 0; uint8 m_medVibratoEnvelope = uint8_max, m_medVibratoSpeed = 0, m_medVibratoDepth = 0; int8 m_medVibratoValue = 0; uint16 m_medVibratoPos = 0; int16 m_medVolumeStep = 0; int16 m_medPeriodStep = 0; uint16 m_medArpOffset = STOP_ROW; uint8 m_medArpPos = 0; uint8 m_medHold = uint8_max; uint16 m_medDecay = STOP_ROW; uint8 m_medVolumeEnv = uint8_max, m_medVolumeEnvPos = 0; uint32 m_ftmSampleStart = 0; int16 m_ftmDetune = 1; uint16 m_ftmVolumeChangeJump = STOP_ROW; uint16 m_ftmPitchChangeJump = STOP_ROW; uint16 m_ftmSampleChangeJump = STOP_ROW; uint16 m_ftmReleaseJump = STOP_ROW; uint16 m_ftmVolumeDownJump = STOP_ROW; uint16 m_ftmPortamentoJump = STOP_ROW; struct LFO { uint8 targetWaveform = 0, speed = 0, depth = 0, position = 0; }; std::array m_ftmLFO; uint8 m_ftmWorkTrack = 0; int8 m_fcPitch = 0; int16 m_fcVibratoValue = 0; uint8 m_fcVibratoDelay = 0, m_fcVibratoSpeed = 0, m_fcVibratoDepth = 0; int8 m_fcVolumeBendSpeed = 0, m_fcPitchBendSpeed = 0; uint8 m_fcVolumeBendRemain = 0, m_fcPitchBendRemain = 0; void JumpToPosition(const Events &events, uint16 position); void NextTick(const Events &events, PlayState &playState, CHANNELINDEX channel, const CSoundFile &sndFile, States &states); void ApplyChannelState(ModChannel &chn, int32 &period, const CSoundFile &sndFile); bool EvaluateEvent(const Event &event, PlayState &playState, CHANNELINDEX channel, const CSoundFile &sndFile, States &states); void EvaluateRunningEvent(const Event &event); void HandleFTMInterrupt(uint16 &target, const bool condition); bool HandleFCVolumeBend(bool forceRun = false); CHANNELINDEX FTMRealChannel(CHANNELINDEX channel, const CSoundFile &sndFile) const noexcept { if(m_ftmWorkTrack) return static_cast(m_ftmWorkTrack - 1) % sndFile.GetNumChannels(); else return channel; } }; static int32 ApplyLinearPitchSlide(int32 target, const int32 totalAmount, const bool periodsAreFrequencies) { const auto &table = (periodsAreFrequencies ^ (totalAmount < 0)) ? LinearSlideUpTable : LinearSlideDownTable; size_t value = std::abs(totalAmount); while(value > 0) { const size_t amount = std::min(value, std::size(table) - size_t(1)); target = Util::muldivr(target, table[amount], 65536); value -= amount; } return target; } static int16 TranslateGT2Pitch(uint16 pitch) { // 4096 = normal, 8192 = one octave up return mpt::saturate_round((mpt::log2(8192.0 / std::max(pitch, uint16(1))) - 1.0) * (16 * 12)); } static int32 TranslateFTMPitch(uint16 pitch, ModChannel &chn, const CSoundFile &sndFile) { int32 period = sndFile.GetPeriodFromNote(NOTE_MIDDLEC - 12 + pitch / 16, chn.nFineTune, chn.nC5Speed); sndFile.DoFreqSlide(chn, period, (pitch % 16) * 4); return period; } static int8 MEDEnvelopeFromSample(const ModInstrument &instr, const CSoundFile &sndFile, uint8 envelope, uint16 envelopePos) { SAMPLEINDEX smp = instr.Keyboard[NOTE_MIDDLEC - NOTE_MIN] + envelope; if(smp < 1 || smp > sndFile.GetNumSamples()) return 0; const auto &mptSmp = sndFile.GetSample(smp); if(envelopePos >= mptSmp.nLength || mptSmp.uFlags[CHN_16BIT] || !mptSmp.sample8()) return 0; return mptSmp.sample8()[envelopePos]; } static void ChannelSetSample(ModChannel &chn, const CSoundFile &sndFile, SAMPLEINDEX smp, bool swapAtEnd = true) { if(smp < 1 || smp > sndFile.GetNumSamples()) return; const bool channelIsActive = chn.pCurrentSample && chn.nLength; if(sndFile.m_playBehaviour[kMODSampleSwap] && smp <= uint8_max && swapAtEnd && channelIsActive) { chn.swapSampleIndex = smp; return; } const ModSample &sample = sndFile.GetSample(smp); if(chn.pModSample == &sample && channelIsActive) return; if(chn.increment.IsZero() && chn.nLength == 0 && chn.nVolume == 0) chn.nVolume = 256; chn.pModSample = &sample; chn.pCurrentSample = sample.samplev(); chn.dwFlags = (chn.dwFlags & CHN_CHANNELFLAGS) | sample.uFlags; chn.nLength = sample.uFlags[CHN_LOOP] ? sample.nLoopEnd : sample.nLength; chn.nLoopStart = sample.nLoopStart; chn.nLoopEnd = sample.nLoopEnd; if(chn.position.GetUInt() >= chn.nLength) chn.position.Set(0); } // To allow State to be forward-declared InstrumentSynth::States::States() = default; InstrumentSynth::States::States(const States &other) = default; InstrumentSynth::States::States(States &&other) noexcept = default; InstrumentSynth::States::~States() = default; InstrumentSynth::States &InstrumentSynth::States::operator=(const States &other) = default; InstrumentSynth::States &InstrumentSynth::States::operator=(States &&other) noexcept = default; void InstrumentSynth::States::Stop() { for(auto &state : states) state.m_currentRow = state.m_nextRow = State::STOP_ROW; } void InstrumentSynth::States::NextTick(PlayState &playState, CHANNELINDEX channel, const CSoundFile &sndFile) { ModChannel &chn = playState.Chn[channel]; if(!chn.pModInstrument || !chn.pModInstrument->synth.HasScripts()) return; const auto &scripts = chn.pModInstrument->synth.m_scripts; states.resize(scripts.size()); for(size_t i = 0; i < scripts.size(); i++) { auto &script = scripts[i]; auto &state = states[i]; if(chn.triggerNote) mpt::reconstruct(state); if(i == 1 && chn.rowCommand.command == CMD_MED_SYNTH_JUMP && chn.isFirstTick) { // Ugly special case: If the script didn't run yet (not triggered on same row), we need to run at least the first SetStepSpeed command. if(state.m_nextRow == 0 && !script.empty() && script[0].type == Event::Type::SetStepSpeed) { state.EvaluateEvent(script[0], playState, channel, sndFile, *this); state.m_stepsRemain = 0; } state.JumpToPosition(script, chn.rowCommand.param); } state.NextTick(script, playState, channel, sndFile, *this); } } void InstrumentSynth::States::ApplyChannelState(ModChannel &chn, int32 &period, const CSoundFile &sndFile) { if(!chn.pModInstrument || !chn.pModInstrument->synth.HasScripts()) return; for(auto &state : states) { state.ApplyChannelState(chn, period, sndFile); } } void InstrumentSynth::States::State::JumpToPosition(const Events &events, uint16 position) { for(size_t pos = 0; pos < events.size(); pos++) { if(events[pos].type == Event::Type::JumpMarker && events[pos].u16 >= position) { m_nextRow = static_cast(pos); m_ticksRemain = 0; return; } } } void InstrumentSynth::States::State::NextTick(const Events &events, PlayState &playState, CHANNELINDEX channel, const CSoundFile &sndFile, States &states) { if(events.empty()) return; const CHANNELINDEX origChannel = channel; channel = FTMRealChannel(channel, sndFile); ModChannel *chn = &playState.Chn[channel]; if(m_gtkKeyOffOffset != STOP_ROW && chn->dwFlags[CHN_KEYOFF]) { m_nextRow = m_gtkKeyOffOffset; m_ticksRemain = 0; m_gtkKeyOffOffset = STOP_ROW; } if(m_pumaWaveformStep) { m_pumaWaveform = static_cast(Clamp(m_pumaWaveform + m_pumaWaveformStep, m_pumaStartWaveform, m_pumaEndWaveform)); if(m_pumaWaveform <= m_pumaStartWaveform || m_pumaWaveform >= m_pumaEndWaveform) m_pumaWaveformStep = -m_pumaWaveformStep; ChannelSetSample(*chn, sndFile, m_pumaWaveform); } if(m_medHold != uint8_max) { if(!m_medHold--) m_nextRow = m_medDecay; } const ModCommand &m = chn->rowCommand; HandleFTMInterrupt(m_ftmPitchChangeJump, m.IsNote()); HandleFTMInterrupt(m_ftmVolumeChangeJump, m.command == CMD_CHANNELVOLUME); HandleFTMInterrupt(m_ftmSampleChangeJump, m.instr != 0); HandleFTMInterrupt(m_ftmReleaseJump, m.note == NOTE_KEYOFF); HandleFTMInterrupt(m_ftmVolumeDownJump, m.command == CMD_VOLUMEDOWN_DURATION); HandleFTMInterrupt(m_ftmPortamentoJump, m.command == CMD_TONEPORTA_DURATION); if(!HandleFCVolumeBend() && m_stepSpeed && !m_stepsRemain--) { // Yep, MED executes this before a potential SPD command may change the step speed on this very row... m_stepsRemain = m_stepSpeed - 1; if(m_medVolumeStep) m_volumeFactor = static_cast(std::clamp(m_volumeFactor + m_medVolumeStep, 0, 16384)); if(m_medPeriodStep) m_periodAdd = mpt::saturate_cast(m_periodAdd - m_medPeriodStep); if(m_medVolumeEnv != uint8_max && chn->pModInstrument) { m_volumeFactor = static_cast(std::clamp((MEDEnvelopeFromSample(*chn->pModInstrument, sndFile, m_medVolumeEnv & 0x7F, m_medVolumeEnvPos) + 128) * 64, 0, 16384)); if(m_medVolumeEnvPos < 127) m_medVolumeEnvPos++; else if(m_medVolumeEnv & 0x80) m_medVolumeEnvPos = 0; } if(m_ticksRemain) { if(m_currentRow < events.size()) EvaluateRunningEvent(events[m_currentRow]); m_ticksRemain--; } else { uint8 jumpCount = 0; while(!m_ticksRemain) { m_currentRow = m_nextRow; if(m_currentRow >= std::min(events.size(), static_cast(STOP_ROW))) break; m_nextRow++; if(EvaluateEvent(events[m_currentRow], playState, channel, sndFile, states)) break; MPT_ASSERT(m_nextRow == STOP_ROW || m_nextRow == m_currentRow + 1 || events[m_currentRow].IsJumpEvent()); if(events[m_currentRow].IsJumpEvent()) { // This smells like an infinite loop if(jumpCount++ > 10) break; } channel = FTMRealChannel(origChannel, sndFile); chn = &playState.Chn[channel]; } } } // MED stuff if(m_medArpOffset < events.size() && events[m_medArpOffset].u16) { m_linearPitchFactor = 16 * events[m_medArpOffset + m_medArpPos].u8; m_medArpPos = static_cast((m_medArpPos + 1) % events[m_medArpOffset].u16); } if(m_medVibratoDepth) { static_assert(std::size(ModSinusTable) == 64); uint16 offset = m_medVibratoPos / 16u; if(m_medVibratoEnvelope == uint8_max) m_medVibratoValue = ModSinusTable[(offset * 2) % std::size(ModSinusTable)]; else if(chn->pModInstrument) m_medVibratoValue = MEDEnvelopeFromSample(*chn->pModInstrument, sndFile, m_medVibratoEnvelope, offset); m_medVibratoPos = (m_medVibratoPos + m_medVibratoSpeed) % (32u * 16u); } // GTK stuff if(m_currentRow < events.size() && m_gtkSpeed && !--m_gtkSpeedRemain) { m_gtkSpeedRemain = m_gtkSpeed; if(m_gtkVolumeStep) m_volumeFactor = static_cast(std::clamp(m_volumeFactor + m_gtkVolumeStep, 0, 16384)); if(m_gtkPanningStep) m_panning = static_cast(std::clamp(m_panning + m_gtkPanningStep, 0, 4096)); if(m_gtkPitchStep) { m_gtkPitch = static_cast(std::clamp(m_gtkPitch + m_gtkPitchStep, 0, 32768)); m_linearPitchFactor = TranslateGT2Pitch(m_gtkPitch); } } if(m_flags[kGTKTremorEnabled]) { if(m_gtkTremorPos >= m_gtkTremorOnTime + m_gtkTremorOffTime) m_gtkTremorPos = 0; m_flags.set(kGTKTremorMute, m_gtkTremorPos >= m_gtkTremorOnTime); m_gtkTremorPos++; } if(m_flags[kGTKTremoloEnabled]) { m_volumeAdd = static_cast(ModSinusTable[(m_gtkVibratoPos / 4u) % std::size(ModSinusTable)] * m_gtkVibratoWidth / 2); m_gtkVibratoPos += m_gtkVibratoSpeed; } if(m_flags[kGTKVibratoEnabled]) { m_periodFreqSlide = static_cast(-ModSinusTable[(m_gtkVibratoPos / 4u) % std::size(ModSinusTable)] * m_gtkVibratoWidth / 96); m_gtkVibratoPos += m_gtkVibratoSpeed; } // FTM LFOs for(auto &lfo : m_ftmLFO) { if(!lfo.speed && !lfo.depth) continue; const uint8 lutPos = static_cast(Util::muldivr_unsigned(lfo.position, 256, 192)); int32 value = 0; switch(lfo.targetWaveform & 0x07) { case 0: value = ITSinusTable[lutPos]; break; case 1: value = lutPos < 128 ? 64 : -64; break; case 2: value = 64 - std::abs(((lutPos + 64) % 256) - 128); break; case 3: value = 64 - lutPos / 2; break; case 4: value = lutPos / 2 - 64; break; } if((lfo.targetWaveform & 0xF0) < 0xA0) value += 64; value *= lfo.depth; // -8192...+8192 or 0...16384 for LFO targets switch(lfo.targetWaveform & 0xF0) { case 0x10: m_ftmLFO[0].speed = static_cast(value / 64); break; case 0x20: m_ftmLFO[1].speed = static_cast(value / 64); break; case 0x30: m_ftmLFO[2].speed = static_cast(value / 64); break; case 0x40: m_ftmLFO[3].speed = static_cast(value / 64); break; case 0x50: m_ftmLFO[0].depth = static_cast(value / 64); break; case 0x60: m_ftmLFO[1].depth = static_cast(value / 64); break; case 0x70: m_ftmLFO[2].depth = static_cast(value / 64); break; case 0x80: m_ftmLFO[3].depth = static_cast(value / 64); break; case 0xA0: m_volumeAdd = mpt::saturate_cast(value * 4); break; case 0xF0: m_periodFreqSlide = static_cast(value / 8); break; } uint16 newPos = lfo.position + lfo.speed; if(newPos >= 192) { newPos -= 192; if(lfo.targetWaveform & 0x08) { lfo.speed = 0; newPos = 191; } } lfo.position = static_cast(newPos); } // Future Composer stuff if(m_flags[kFCVibratoDelaySet] && m_fcVibratoDelay > 0) { m_fcVibratoDelay--; } else if(m_fcVibratoDepth) { if(m_flags[kFCVibratoStep]) { int16 delta = m_fcVibratoDepth * 2; m_fcVibratoValue += m_fcVibratoSpeed; if(m_fcVibratoValue > delta) { m_fcVibratoValue = delta; m_flags.flip(kFCVibratoStep); } } else { m_fcVibratoValue -= m_fcVibratoSpeed; if(m_fcVibratoValue < 0) { m_fcVibratoValue = 0; m_flags.flip(kFCVibratoStep); } } } if(m_fcPitchBendRemain) { m_flags.flip(kFCPitchBendStep); if(m_flags[kFCPitchBendStep]) { m_fcPitchBendRemain--; m_periodAdd -= static_cast(m_fcPitchBendSpeed * 4); } } } void InstrumentSynth::States::State::ApplyChannelState(ModChannel &chn, int32 &period, const CSoundFile &sndFile) { if(m_volumeFactor != 16384) chn.nRealVolume = Util::muldivr(chn.nRealVolume, m_volumeFactor, 16384); if(m_volumeAdd != int16_min) chn.nRealVolume = std::clamp(chn.nRealVolume + m_volumeAdd, int32(0), int32(16384)); if(m_flags[kGTKTremorEnabled] && m_flags[kGTKTremorMute]) chn.nRealVolume = 0; if(m_panning != 2048) { if(chn.nRealPan >= 128) chn.nRealPan += ((m_panning - 2048) * (256 - chn.nRealPan)) / 2048; else chn.nRealPan += ((m_panning - 2048) * (chn.nRealPan)) / 2048; } const bool periodsAreFrequencies = sndFile.PeriodsAreFrequencies(); if(m_linearPitchFactor != 0) period = ApplyLinearPitchSlide(period, m_linearPitchFactor, periodsAreFrequencies); if(m_periodFreqSlide != 0) sndFile.DoFreqSlide(chn, period, m_periodFreqSlide); if(periodsAreFrequencies) period -= m_periodAdd; else period += m_periodAdd; if(m_medVibratoDepth) period += m_medVibratoValue * m_medVibratoDepth / 64; int16 vibratoFC = m_fcVibratoValue - m_fcVibratoDepth; const bool doVibratoFC = vibratoFC != 0 && m_fcVibratoDelay < 1; if(m_fcPitch || doVibratoFC) { uint8 fcNote = static_cast(m_fcPitch >= 0 ? m_fcPitch + chn.nLastNote - NOTE_MIN : m_fcPitch) & 0x7F; static_assert(mpt::array_sizeNoteMap)>::size > 0x7F); if(m_fcPitch && ModCommand::IsNote(chn.nLastNote)) period += (sndFile.GetPeriodFromNote(chn.pModInstrument->NoteMap[fcNote], chn.nFineTune, chn.nC5Speed) - sndFile.GetPeriodFromNote(chn.pModInstrument->NoteMap[chn.nLastNote - NOTE_MIN], chn.nFineTune, chn.nC5Speed)); if(doVibratoFC) { int note = (fcNote * 2) + 160; while(note < 256) { vibratoFC *= 2; note += 24; } period += vibratoFC * 4; } } if((m_linearPitchFactor || m_periodFreqSlide || m_periodAdd) && !sndFile.PeriodsAreFrequencies()) { if(period < sndFile.m_nMinPeriod) period = sndFile.m_nMinPeriod; else if(period > sndFile.m_nMaxPeriod && sndFile.m_playBehaviour[kApplyUpperPeriodLimit]) period = sndFile.m_nMaxPeriod; } if(period < 1) period = 1; if(m_ftmDetune != 1) chn.microTuning = m_ftmDetune; } bool InstrumentSynth::States::State::EvaluateEvent(const Event &event, PlayState &playState, CHANNELINDEX channel, const CSoundFile &sndFile, States &states) { // Return true to indicate end of processing for this tick ModChannel &chn = playState.Chn[channel]; switch(event.type) { case Event::Type::StopScript: m_nextRow = STOP_ROW; return true; case Event::Type::Jump: m_nextRow = event.u16; return false; case Event::Type::JumpIfTrue: if(m_flags[kJumpConditionSet]) m_nextRow = event.u16; return false; case Event::Type::Delay: m_ticksRemain = event.u16; return true; case Event::Type::SetStepSpeed: m_stepSpeed = event.u8; if(event.Byte1()) m_stepsRemain = m_stepSpeed - 1; return false; case Event::Type::JumpMarker: return false; case Event::Type::SampleOffset: case Event::Type::SampleOffsetAdd: case Event::Type::SampleOffsetSub: { int64 pos = event.Value24Bit(); if(event.type == Event::Type::SampleOffsetAdd) pos += chn.position.GetInt(); else if(event.type == Event::Type::SampleOffsetSub) pos = chn.position.GetInt() - pos; else pos += m_ftmSampleStart; chn.position.Set(std::min(chn.nLength, mpt::saturate_cast(pos)), 0); } return false; case Event::Type::SetLoopCounter: if(!m_loopCount || event.u8) m_loopCount = 1 + std::min(event.u16, uint16(0xFFFE)); return false; case Event::Type::EvaluateLoopCounter: if(m_loopCount > 1) m_nextRow = event.u16; if(m_loopCount) m_loopCount--; return false; case Event::Type::NoteCut: chn.nFadeOutVol = 0; chn.dwFlags.set(CHN_NOTEFADE); return false; case Event::Type::GTK_KeyOff: m_gtkKeyOffOffset = event.u16; return false; case Event::Type::GTK_SetVolume: m_volumeFactor = event.u16; chn.dwFlags.set(CHN_FASTVOLRAMP); return false; case Event::Type::GTK_SetPitch: m_gtkPitch = event.u16; m_linearPitchFactor = TranslateGT2Pitch(event.u16); m_periodAdd = 0; return false; case Event::Type::GTK_SetPanning: m_panning = event.u16; return false; case Event::Type::GTK_SetVolumeStep: m_gtkVolumeStep = event.i16; return false; case Event::Type::GTK_SetPitchStep: m_gtkPitchStep = event.i16; return false; case Event::Type::GTK_SetPanningStep: m_gtkPanningStep = event.i16; return false; case Event::Type::GTK_SetSpeed: m_gtkSpeed = m_gtkSpeedRemain = event.u8; return false; case Event::Type::GTK_EnableTremor: m_flags.set(kGTKTremorEnabled, event.u8 != 0); return false; case Event::Type::GTK_SetTremorTime: if(event.Byte0()) m_gtkTremorOnTime = event.Byte0(); if(event.Byte1()) m_gtkTremorOffTime = event.Byte1(); m_gtkTremorPos = 0; return false; case Event::Type::GTK_EnableTremolo: m_flags.set(kGTKTremoloEnabled, event.u8 != 0); m_gtkVibratoPos = 0; if(!m_gtkVibratoWidth) m_gtkVibratoWidth = 8; if(!m_gtkVibratoSpeed) m_gtkVibratoSpeed = 16; return false; case Event::Type::GTK_EnableVibrato: m_flags.set(kGTKVibratoEnabled, event.u8 != 0); m_periodFreqSlide = 0; m_gtkVibratoPos = 0; if(!m_gtkVibratoWidth) m_gtkVibratoWidth = 3; if(!m_gtkVibratoSpeed) m_gtkVibratoSpeed = 8; return false; case Event::Type::GTK_SetVibratoParams: if(event.Byte0()) m_gtkVibratoWidth = event.Byte0(); if(event.Byte1()) m_gtkVibratoSpeed = event.Byte1(); return false; case Event::Type::Puma_SetWaveform: m_pumaWaveform = m_pumaStartWaveform = event.Byte0() + 1; if(event.Byte0() < 10) { m_pumaWaveformStep = 0; } else { m_pumaWaveformStep = static_cast(event.Byte1()); m_pumaEndWaveform = event.Byte2() + m_pumaStartWaveform; } ChannelSetSample(chn, sndFile, m_pumaWaveform); return false; case Event::Type::Puma_VolumeRamp: m_ticksRemain = event.Byte2(); m_volumeAdd = static_cast(event.Byte0() * 256 - 16384); chn.dwFlags.set(CHN_FASTVOLRAMP); return true; case Event::Type::Puma_StopVoice: chn.Stop(); m_nextRow = STOP_ROW; return true; case Event::Type::Puma_SetPitch: m_linearPitchFactor = event.i8 * 8; m_periodAdd = 0; m_ticksRemain = std::max(event.Byte2(), uint8(1)) - 1; return true; case Event::Type::Puma_PitchRamp: m_linearPitchFactor = 0; m_periodAdd = event.i8 * 4; m_ticksRemain = std::max(event.Byte2(), uint8(1)) - 1; return true; case Event::Type::Mupp_SetWaveform: ChannelSetSample(chn, sndFile, static_cast(32 + event.Byte0() * 28 + event.Byte1())); m_volumeFactor = static_cast(std::min(event.Byte2() & 0x7F, 64) * 256u); chn.dwFlags.set(CHN_FASTVOLRAMP); return true; case Event::Type::MED_DefineArpeggio: if(!event.u16) return false; m_nextRow = m_currentRow + event.u16; m_medArpOffset = m_currentRow; m_medArpPos = 0; return true; case Event::Type::MED_JumpScript: if(event.u8 < chn.synthState.states.size() && chn.pModInstrument && event.u8 < chn.pModInstrument->synth.m_scripts.size()) { chn.synthState.states[event.u8].JumpToPosition(chn.pModInstrument->synth.m_scripts[event.u8], event.u16); chn.synthState.states[event.u8].m_stepsRemain = 0; } return false; case Event::Type::MED_SetEnvelope: if(event.Byte2()) m_medVolumeEnv = (event.Byte0() & 0x3F) | (event.Byte1() ? 0x80 : 0x00); else m_medVibratoEnvelope = event.Byte0(); m_medVolumeEnvPos = 0; return false; case Event::Type::MED_SetVolume: m_volumeFactor = event.u8 * 256u; chn.dwFlags.set(CHN_FASTVOLRAMP); return true; case Event::Type::MED_SetWaveform: if(chn.pModInstrument) ChannelSetSample(chn, sndFile, chn.pModInstrument->Keyboard[NOTE_MIDDLEC - NOTE_MIN] + event.u8); return true; case Event::Type::MED_SetVibratoSpeed: m_medVibratoSpeed = event.u8; return false; case Event::Type::MED_SetVibratoDepth: m_medVibratoDepth = event.u8; return false; case Event::Type::MED_SetVolumeStep: m_medVolumeStep = static_cast(event.i16 * 256); return false; case Event::Type::MED_SetPeriodStep: m_medPeriodStep = static_cast(event.i16 * 4); return false; case Event::Type::MED_HoldDecay: m_medHold = event.u8; m_medDecay = event.u16; return false; case Event::Type::FTM_SetCondition: { MPT_ASSERT(!sndFile.PeriodsAreFrequencies()); const int32 threshold = (event.u8 < 3) ? int32_max - TranslateFTMPitch(event.u16, chn, sndFile) : event.u16; const int32 compare = (event.u8 < 3) ? int32_max - chn.nPeriod : chn.nGlobalVol; switch(event.u8 % 3u) { case 0: m_flags.set(kJumpConditionSet, compare == threshold); break; case 1: m_flags.set(kJumpConditionSet, compare < threshold); break; case 2: m_flags.set(kJumpConditionSet, compare > threshold); break; } } return false; case Event::Type::FTM_SetInterrupt: if(event.u8 & 0x01) m_ftmPitchChangeJump = event.u16; if(event.u8 & 0x02) m_ftmVolumeChangeJump = event.u16; if(event.u8 & 0x04) m_ftmSampleChangeJump = event.u16; if(event.u8 & 0x08) m_ftmReleaseJump = event.u16; if(event.u8 & 0x10) m_ftmPortamentoJump = event.u16; if(event.u8 & 0x20) m_ftmVolumeDownJump = event.u16; return false; case Event::Type::FTM_PlaySample: if(chn.nNewIns > 0 && chn.nNewIns <= sndFile.GetNumSamples()) chn.pModSample = &sndFile.GetSample(chn.nNewIns); if(chn.pModSample) { const ModSample &sample = *chn.pModSample; chn.nVolume = sample.nVolume; chn.UpdateInstrumentVolume(&sample, nullptr); chn.nC5Speed = sample.nC5Speed; chn.dwFlags = (chn.dwFlags & (CHN_CHANNELFLAGS ^ CHN_NOTEFADE)) | sample.uFlags; chn.nLength = chn.pModSample->uFlags[CHN_LOOP] ? sample.nLoopEnd : sample.nLength; chn.nLoopStart = sample.nLoopStart; chn.nLoopEnd = sample.nLoopEnd; } chn.position.Set(0); return false; case Event::Type::FTM_SetPitch: chn.nPeriod = TranslateFTMPitch(event.u16 * 2, chn, sndFile); return false; case Event::Type::FTM_SetDetune: // Detune always applies to the first channel of a channel pair (and only if the other channel is playing a sample) states.states[channel & ~1].m_ftmDetune = static_cast(event.u16 * -8); return false; case Event::Type::FTM_AddDetune: states.states[channel & ~1].m_ftmDetune -= static_cast(event.i16 * 8); return false; case Event::Type::FTM_AddPitch: if(event.i16) { sndFile.DoFreqSlide(chn, chn.nPeriod, event.i16 * 8); const int32 limit = TranslateFTMPitch((event.i16 < 0) ? 0 : 0x21E, chn, sndFile); if((event.i16 > 0) == sndFile.PeriodsAreFrequencies()) chn.nPeriod = std::min(chn.nPeriod, limit); else chn.nPeriod = std::max(chn.nPeriod, limit); } return false; case Event::Type::FTM_SetVolume: chn.nGlobalVol = std::min(event.u8, uint8(64)); chn.dwFlags.set(CHN_FASTVOLRAMP); return false; case Event::Type::FTM_AddVolume: chn.nGlobalVol = static_cast(std::clamp(chn.nGlobalVol + event.i16, 0, 64)); return false; case Event::Type::FTM_SetSample: chn.swapSampleIndex = event.u8 + 1; return false; case Event::Type::FTM_SetSampleStart: // Documentation says this should be in words, but it really appears to work with bytes. // The relative variants appear to be completely broken. if(event.u8 == 1) m_ftmSampleStart += std::min(static_cast(event.u16), Util::MaxValueOfType(m_ftmSampleStart) - m_ftmSampleStart); else if(event.u8 == 2) m_ftmSampleStart -= std::min(static_cast(event.u16), m_ftmSampleStart); else m_ftmSampleStart = event.u16 * 2u; return false; case Event::Type::FTM_SetOneshotLength: if(chn.pModSample) { const SmpLength loopLength = chn.nLoopEnd - chn.nLoopStart; int64 loopStart = event.u16 * 2; if(event.u8 == 1) loopStart += chn.nLoopStart; else if(event.u8 == 2) loopStart = chn.nLoopStart - loopStart; loopStart = std::clamp(loopStart, int64(0), static_cast(chn.pModSample->nLength)); chn.nLoopStart = static_cast(loopStart); chn.nLoopEnd = chn.nLoopStart + loopLength; LimitMax(chn.nLoopEnd, chn.pModSample->nLength); chn.nLength = chn.nLoopEnd; chn.dwFlags.set(CHN_LOOP, chn.nLoopEnd > chn.nLoopStart); if(chn.position.GetUInt() >= chn.nLength && chn.dwFlags[CHN_LOOP]) chn.position.SetInt(chn.nLoopStart); } return false; case Event::Type::FTM_SetRepeatLength: if(chn.pModSample) { int64 loopEnd = chn.nLoopStart + event.u16 * 2; if(event.u8 == 1) loopEnd = chn.nLoopEnd + event.u16 * 2; else if(event.u8 == 2) loopEnd = chn.nLoopEnd - event.u16 * 2; loopEnd = std::clamp(loopEnd, static_cast(chn.nLoopStart), static_cast(chn.pModSample->nLength)); chn.nLoopEnd = static_cast(loopEnd); chn.nLength = chn.nLoopEnd; chn.dwFlags.set(CHN_LOOP, chn.nLoopEnd > chn.nLoopStart); if(chn.position.GetUInt() >= chn.nLength && chn.dwFlags[CHN_LOOP]) chn.position.SetInt(chn.nLoopStart); } return false; case Event::Type::FTM_CloneTrack: if(event.Byte0() < sndFile.GetNumChannels()) { const ModChannel &srcChn = playState.Chn[event.Byte0()]; if(event.Byte1() & (0x01 | 0x08)) chn.nPeriod = srcChn.nPeriod; if(event.Byte1() & (0x02 | 0x08)) chn.nGlobalVol = srcChn.nGlobalVol; if(event.Byte1() & (0x04 | 0x08)) { chn.nNewIns = srcChn.nNewIns; chn.swapSampleIndex = srcChn.swapSampleIndex; chn.pModSample = srcChn.pModSample; chn.position = srcChn.position; chn.dwFlags = (chn.dwFlags & CHN_CHANNELFLAGS) | (srcChn.dwFlags & CHN_SAMPLEFLAGS); chn.nLength = srcChn.nLength; chn.nLoopStart = srcChn.nLoopStart; chn.nLoopEnd = srcChn.nLoopEnd; } if(event.Byte1() & 0x08) { // Note: This does not appear to behave entirely as documented. // When the command is triggered, it copies frequency, volume, sample and the state of running slide commands. // Running LFOs are not copied. But any notes and effects (including newly triggered LFOs) on the source track on following rows are copied. // There appears to be no way to stop this cloning once it has started. // As no FTM in the wild makes use of this command, we will glance over this ugly detail. chn.position = srcChn.position; chn.portamentoSlide = srcChn.portamentoSlide; chn.nPortamentoDest = srcChn.nPortamentoDest; chn.volSlideDownStart = srcChn.volSlideDownStart; chn.volSlideDownTotal = srcChn.volSlideDownTotal; chn.volSlideDownRemain = srcChn.volSlideDownRemain; chn.autoSlide.SetActive(AutoSlideCommand::TonePortamentoWithDuration, srcChn.autoSlide.IsActive(AutoSlideCommand::TonePortamentoWithDuration)); chn.autoSlide.SetActive(AutoSlideCommand::VolumeDownWithDuration, srcChn.autoSlide.IsActive(AutoSlideCommand::VolumeDownWithDuration)); } } return false; case Event::Type::FTM_StartLFO: { auto &lfo = m_ftmLFO[event.Byte0() & 3]; lfo.targetWaveform = event.Byte1(); lfo.speed = lfo.depth = lfo.position = 0; } return false; case Event::Type::FTM_LFOAddSub: { auto &lfo = m_ftmLFO[event.Byte0() & 3]; int factor = (event.Byte0() & 4) ? -1 : 1; lfo.speed = std::min(mpt::saturate_cast(lfo.speed + event.Byte1() * factor), uint8(0xBF)); lfo.depth = std::min(mpt::saturate_cast(lfo.depth + event.Byte2() * factor), uint8(0x7F)); } return false; case Event::Type::FTM_SetWorkTrack: if(event.Byte0() == uint8_max) { m_ftmWorkTrack = 0; } else if(const bool isRelative = event.Byte1() != 0; isRelative && event.Byte0()) { if(!m_ftmWorkTrack) m_ftmWorkTrack = static_cast(channel + 1); m_ftmWorkTrack = static_cast((m_ftmWorkTrack - 1u + event.Byte0()) % sndFile.GetNumChannels() + 1); } else if(!isRelative) { m_ftmWorkTrack = event.Byte0() + 1; } return false; case Event::Type::FTM_SetGlobalVolume: playState.m_nGlobalVolume = event.u16; return false; case Event::Type::FTM_SetTempo: playState.m_nMusicTempo = TEMPO(1777517.482 / std::clamp(event.u16, uint16(0x1000), uint16(0x4FFF))); return false; case Event::Type::FTM_SetSpeed: if(event.u16) playState.m_nMusicSpeed = event.u16; else playState.m_nMusicSpeed = uint16_max; return false; case Event::Type::FTM_SetPlayPosition: if(ORDERINDEX playPos = sndFile.Order().FindOrder(event.u16, event.u16); playPos != ORDERINDEX_INVALID) { playState.m_nNextOrder = playPos; playState.m_nNextRow = event.u8; } return false; case Event::Type::FC_SetWaveform: { uint8 waveform = event.Byte1() + 1; if(event.Byte0() == 0xE9) waveform += static_cast(event.Byte2() * 10 + 90); ChannelSetSample(chn, sndFile, waveform, event.Byte0() == 0xE4); } return false; case Event::Type::FC_SetPitch: m_fcPitch = event.i8; return true; case Event::Type::FC_SetVibrato: m_fcVibratoSpeed = event.Byte0(); m_fcVibratoDepth = event.Byte1(); if(!m_flags[kFCVibratoDelaySet]) { m_flags.set(kFCVibratoDelaySet); m_fcVibratoDelay = event.Byte2(); m_fcVibratoValue = m_fcVibratoDepth; } return false; case Event::Type::FC_PitchSlide: m_fcPitchBendSpeed = event.Byte0(); m_fcPitchBendRemain = event.Byte1(); return false; case Event::Type::FC_VolumeSlide: m_fcVolumeBendSpeed = event.Byte0(); m_fcVolumeBendRemain = event.Byte1(); HandleFCVolumeBend(true); return true; } MPT_ASSERT_NOTREACHED(); return false; } void InstrumentSynth::States::State::EvaluateRunningEvent(const Event &event) { switch(event.type) { case Event::Type::Puma_VolumeRamp: if(event.Byte2() > 0) m_volumeAdd = static_cast((event.Byte1() + Util::muldivr(event.Byte0() - event.Byte1(), m_ticksRemain, event.Byte2())) * 256 - 16384); break; case Event::Type::Puma_PitchRamp: if(event.Byte2() > 0) m_periodAdd = static_cast((static_cast(event.Byte1()) + Util::muldivr(static_cast(event.Byte0()) - static_cast(event.Byte1()), m_ticksRemain, event.Byte2())) * 4); break; default: break; } } void InstrumentSynth::States::State::HandleFTMInterrupt(uint16 &target, const bool condition) { if(target == STOP_ROW || !condition) return; m_nextRow = target; m_ticksRemain = 0; m_stepsRemain = 0; target = STOP_ROW; } bool InstrumentSynth::States::State::HandleFCVolumeBend(bool forceRun) { if(!m_fcVolumeBendRemain && !forceRun) return false; m_flags.flip(kFCVolumeBendStep); if(m_flags[kFCVolumeBendStep]) { m_fcVolumeBendRemain--; int32 target = m_volumeFactor + m_fcVolumeBendSpeed * 256; if(target < 0 || target >= 32768) m_fcVolumeBendRemain = 0; m_volumeFactor = static_cast(std::clamp(target, int32(0), int32(16384))); } return true; } void GlobalScriptState::Initialize(const CSoundFile &sndFile) { if(!sndFile.m_globalScript.empty()) states.assign(sndFile.GetNumChannels(), {}); } void GlobalScriptState::NextTick(PlayState &playState, const CSoundFile &sndFile) { if(sndFile.m_globalScript.empty()) return; states.resize(sndFile.GetNumChannels()); for(CHANNELINDEX chn = 0; chn < sndFile.GetNumChannels(); chn++) { auto &state = states[chn]; auto &modChn = playState.Chn[chn]; if(modChn.rowCommand.command == CMD_MED_SYNTH_JUMP && !playState.m_nTickCount) states[chn].JumpToPosition(sndFile.m_globalScript, modChn.rowCommand.param); state.NextTick(sndFile.m_globalScript, playState, chn, sndFile, *this); } } void GlobalScriptState::ApplyChannelState(PlayState &playState, CHANNELINDEX chn, int32 &period, const CSoundFile &sndFile) { if(sndFile.m_globalScript.empty()) return; for(CHANNELINDEX s = 0; s < states.size(); s++) { if(states[s].FTMRealChannel(s, sndFile) == chn) { states[s].ApplyChannelState(playState.Chn[chn], period, sndFile); } } } void InstrumentSynth::Sanitize() { for(auto &script : m_scripts) { if(script.size() >= States::State::STOP_ROW) script.resize(States::State::STOP_ROW - 1); } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_stp.cpp0000644000175000017500000004374214644610543020367 00000000000000/* * Load_stp.cpp * ------------ * Purpose: STP (Soundtracker Pro II) module loader * Notes : A few exotic effects aren't supported. * Multiple sample loops are supported, but only the first 10 can be used as cue points * (with 16xx and 18xx). * Fractional speed values and combined auto effects are handled whenever possible, * but some effects may be omitted (and there may be tempo accuracy issues). * Authors: Devin Acker * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. * * Wisdom from the Soundtracker Pro II manual: * "To create shorter patterns, simply create shorter patterns." */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN // File header struct STPFileHeader { char magic[4]; uint16be version; uint8be numOrders; uint8be patternLength; uint8be orderList[128]; uint16be speed; uint16be speedFrac; uint16be timerCount; uint16be flags; uint32be reserved; uint16be midiCount; // always 50 uint8be midi[50]; uint16be numSamples; uint16be sampleStructSize; }; MPT_BINARY_STRUCT(STPFileHeader, 204) // Sample header (common part between all versions) struct STPSampleHeader { uint32be length; uint8be volume; uint8be reserved1; uint32be loopStart; uint32be loopLength; uint16be defaultCommand; // Default command to put next to note when editing patterns; not relevant for playback // The following 4 bytes are reserved in version 0 and 1. uint16be defaultPeriod; uint8be finetune; uint8be reserved2; void ConvertToMPT(ModSample &mptSmp) const { mptSmp.nLength = length; mptSmp.nVolume = 4u * std::min(volume.get(), uint8(64)); mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopStart + loopLength; if(mptSmp.nLoopStart >= mptSmp.nLength) { mptSmp.nLoopStart = mptSmp.nLength - 1; } if(mptSmp.nLoopEnd > mptSmp.nLength) { mptSmp.nLoopEnd = mptSmp.nLength; } if(mptSmp.nLoopStart > mptSmp.nLoopEnd) { mptSmp.nLoopStart = 0; mptSmp.nLoopEnd = 0; } else if(mptSmp.nLoopEnd > mptSmp.nLoopStart) { mptSmp.uFlags.set(CHN_LOOP); mptSmp.cues[0] = mptSmp.nLoopStart; } } }; MPT_BINARY_STRUCT(STPSampleHeader, 20) struct STPLoopInfo { SmpLength loopStart; SmpLength loopLength; SAMPLEINDEX looped; SAMPLEINDEX nonLooped; }; using STPLoopList = std::vector; static TEMPO ConvertTempo(uint16 ciaSpeed) { // 3546 is the resulting CIA timer value when using 4F7D (tempo 125 bpm) command in STProII return TEMPO((125.0 * 3546.0) / ciaSpeed); } static void ConvertLoopSlice(ModSample &src, ModSample &dest, SmpLength start, SmpLength len, bool loop) { if(!src.HasSampleData() || start >= src.nLength || src.nLength - start < len) { return; } dest.FreeSample(); dest = src; dest.nLength = len; dest.pData.pSample = nullptr; if(!dest.AllocateSample()) { return; } // only preserve cue points if the target sample length is the same if(len != src.nLength) MemsetZero(dest.cues); std::memcpy(dest.sampleb(), src.sampleb() + start, len); dest.uFlags.set(CHN_LOOP, loop); if(loop) { dest.nLoopStart = 0; dest.nLoopEnd = len; } else { dest.nLoopStart = 0; dest.nLoopEnd = 0; } } static void ConvertLoopSequence(ModSample &smp, STPLoopList &loopList) { // This should only modify a sample if it has more than one loop // (otherwise, it behaves like a normal sample loop) if(!smp.HasSampleData() || loopList.size() < 2) return; ModSample newSmp = smp; newSmp.nLength = 0; newSmp.pData.pSample = nullptr; size_t numLoops = loopList.size(); // Get the total length of the sample after combining all looped sections for(size_t i = 0; i < numLoops; i++) { STPLoopInfo &info = loopList[i]; // If adding this loop would cause the sample length to exceed maximum, // then limit and bail out if(info.loopStart >= smp.nLength || smp.nLength - info.loopStart < info.loopLength || newSmp.nLength > MAX_SAMPLE_LENGTH - info.loopLength) { numLoops = i; break; } newSmp.nLength += info.loopLength; } if(!newSmp.AllocateSample()) { return; } // start copying the looped sample data parts SmpLength start = 0; for(size_t i = 0; i < numLoops; i++) { STPLoopInfo &info = loopList[i]; memcpy(newSmp.sampleb() + start, smp.sampleb() + info.loopStart, info.loopLength); // update loop info based on position in edited sample info.loopStart = start; if(i > 0 && i <= std::size(newSmp.cues)) { newSmp.cues[i - 1] = start; } start += info.loopLength; } // replace old sample with new one smp.FreeSample(); smp = newSmp; smp.nLoopStart = 0; smp.nLoopEnd = smp.nLength; smp.uFlags.set(CHN_LOOP); } static bool ValidateHeader(const STPFileHeader &fileHeader) { if(std::memcmp(fileHeader.magic, "STP3", 4) || fileHeader.version > 2 || fileHeader.numOrders > 128 || fileHeader.numSamples >= MAX_SAMPLES || fileHeader.timerCount == 0 || fileHeader.midiCount != 50) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize) { STPFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); STPFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_STP, 4); m_modFormat.formatName = MPT_UFORMAT("Soundtracker Pro II v{}")(fileHeader.version); m_modFormat.type = UL_("stp"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; m_nSamples = 0; m_SongFlags.set(SONG_AUTO_TONEPORTA | SONG_AUTO_GLOBALVOL | SONG_AUTO_VIBRATO | SONG_AUTO_TREMOLO); Order().SetDefaultSpeed(fileHeader.speed); Order().SetDefaultTempo(ConvertTempo(fileHeader.timerCount)); m_nMinPeriod = 14 * 4; m_nMaxPeriod = 3424 * 4; ReadOrderFromArray(Order(), fileHeader.orderList, fileHeader.numOrders); std::vector loopInfo; // Non-looped versions of samples with loops (when needed) std::vector nonLooped; // Load sample headers SAMPLEINDEX samplesInFile = 0; for(SAMPLEINDEX smp = 0; smp < fileHeader.numSamples; smp++) { SAMPLEINDEX actualSmp = file.ReadUint16BE(); if(actualSmp == 0 || actualSmp >= MAX_SAMPLES) return false; uint32 chunkSize = fileHeader.sampleStructSize; if(fileHeader.version == 2) chunkSize = file.ReadUint32BE() - 2; FileReader chunk = file.ReadChunk(chunkSize); samplesInFile = m_nSamples = std::max(m_nSamples, actualSmp); ModSample &mptSmp = Samples[actualSmp]; mptSmp.Initialize(MOD_TYPE_MOD); if(fileHeader.version < 2) { // Read path chunk.ReadString(mptSmp.filename, 31); // Ignore flags, they are all not relevant for us chunk.Skip(1); // Read filename / sample text chunk.ReadString(m_szNames[actualSmp], 30); } else { std::string str; // Read path chunk.ReadNullString(str, 257); mptSmp.filename = str; // Ignore flags, they are all not relevant for us chunk.Skip(1); // Read filename / sample text chunk.ReadNullString(str, 31); m_szNames[actualSmp] = str; // Seek to even boundary if(chunk.GetPosition() % 2u) chunk.Skip(1); } STPSampleHeader sampleHeader; chunk.ReadStruct(sampleHeader); sampleHeader.ConvertToMPT(mptSmp); if(fileHeader.version == 2) { mptSmp.nFineTune = static_cast(sampleHeader.finetune << 3); } if(fileHeader.version >= 1) { nonLooped.resize(samplesInFile); loopInfo.resize(samplesInFile); STPLoopList &loopList = loopInfo[actualSmp - 1]; loopList.clear(); const uint16 numLoops = file.ReadUint16BE(); if(!file.CanRead(numLoops * 8u)) return false; loopList.reserve(numLoops); STPLoopInfo loop; loop.looped = loop.nonLooped = 0; if(numLoops == 0 && mptSmp.uFlags[CHN_LOOP]) { loop.loopStart = mptSmp.nLoopStart; loop.loopLength = mptSmp.nLoopEnd - mptSmp.nLoopStart; loopList.push_back(loop); } else for(uint16 i = 0; i < numLoops; i++) { loop.loopStart = file.ReadUint32BE(); loop.loopLength = file.ReadUint32BE(); loopList.push_back(loop); } } } // Load patterns uint16 numPatterns = 128; if(fileHeader.version == 0) numPatterns = file.ReadUint16BE(); uint16 patternLength = fileHeader.patternLength; CHANNELINDEX channels = 4; if(fileHeader.version > 0) { // Scan for total number of channels FileReader::pos_type patOffset = file.GetPosition(); for(uint16 pat = 0; pat < numPatterns; pat++) { PATTERNINDEX actualPat = file.ReadUint16BE(); if(actualPat == 0xFFFF) break; patternLength = file.ReadUint16BE(); channels = file.ReadUint16BE(); if(channels > MAX_BASECHANNELS) return false; ChnSettings.resize(std::max(GetNumChannels(), channels)); file.Skip(channels * patternLength * 4u); } file.Seek(patOffset); } uint8 speedFrac = static_cast(fileHeader.speedFrac); for(uint16 pat = 0; pat < numPatterns; pat++) { PATTERNINDEX actualPat = pat; if(fileHeader.version > 0) { actualPat = file.ReadUint16BE(); if(actualPat == 0xFFFF) break; patternLength = file.ReadUint16BE(); channels = file.ReadUint16BE(); } if(!file.CanRead(channels * patternLength * 4u)) break; if(!(loadFlags & loadPatternData) || !Patterns.Insert(actualPat, patternLength)) { file.Skip(channels * patternLength * 4u); continue; } for(ROWINDEX row = 0; row < patternLength; row++) { auto rowBase = Patterns[actualPat].GetRow(row); // if a fractional speed value is in use then determine if we should stick a fine pattern delay somewhere bool shouldDelay; switch(speedFrac & 3) { default: shouldDelay = false; break; // 1/4 case 1: shouldDelay = (row & 3) == 0; break; // 1/2 case 2: shouldDelay = (row & 1) == 0; break; // 3/4 case 3: shouldDelay = (row & 3) != 3; break; } for(CHANNELINDEX chn = 0; chn < channels; chn++) { ModCommand &m = rowBase[chn]; const auto [instr, note, command, param] = file.ReadArray(); m.instr = instr; m.param = param; if(note) m.note = NOTE_MIDDLEC - 36 + note; // Volume slides not only have their nibbles swapped, but the up and down parameters also add up const int totalSlide = -static_cast(m.param >> 4) + (m.param & 0x0F); const uint8 slideParam = static_cast((totalSlide > 0) ? totalSlide << 4 : -totalSlide); if((command & 0xF0) == 0xF0) { // 12-bit CIA tempo uint16 ciaTempo = (static_cast(command & 0x0F) << 8) | m.param; if(ciaTempo) { m.SetEffectCommand(CMD_TEMPO, mpt::saturate_round(ConvertTempo(ciaTempo).ToDouble())); } } else switch(command) { case 0x00: // arpeggio if(m.param) m.command = CMD_ARPEGGIO; break; case 0x01: // portamento up if(m.param) m.command = CMD_PORTAMENTOUP; break; case 0x02: // portamento down if(m.param) m.command = CMD_PORTAMENTODOWN; break; case 0x03: // auto fine portamento up m.command = CMD_AUTO_PORTAUP_FINE; break; case 0x04: // auto fine portamento down m.command = CMD_AUTO_PORTADOWN_FINE; break; case 0x05: // auto portamento up m.command = CMD_AUTO_PORTAUP; break; case 0x06: // auto portamento down m.command = CMD_AUTO_PORTADOWN; break; case 0x07: // set global volume m.command = CMD_GLOBALVOLUME; break; case 0x08: // auto global fine volume slide if(totalSlide < 0) m.SetEffectCommand(CMD_GLOBALVOLSLIDE, 0xF0 | slideParam); else if(totalSlide > 0) m.SetEffectCommand(CMD_GLOBALVOLSLIDE, slideParam | 0x0F); break; case 0x09: // fine portamento up m.SetEffectCommand(CMD_MODCMDEX, 0x10 | std::min(m.param, ModCommand::PARAM(15))); break; case 0x0A: // fine portamento down m.SetEffectCommand(CMD_MODCMDEX, 0x20 | std::min(m.param, ModCommand::PARAM(15))); break; case 0x0B: // auto fine volume slide m.SetEffectCommand(CMD_AUTO_VOLUMESLIDE, slideParam); break; case 0x0C: // set volume m.SetVolumeCommand(VOLCMD_VOLUME, std::min(m.param, ModCommand::PARAM(64))); break; case 0x0D: // volume slide (param is swapped compared to .mod) if(totalSlide < 0) m.SetVolumeCommand(VOLCMD_VOLSLIDEDOWN, slideParam & 0x0F); else if(totalSlide > 0) m.SetVolumeCommand(VOLCMD_VOLSLIDEUP, slideParam >> 4); break; case 0x0E: // set filter (also uses opposite value compared to .mod) m.SetEffectCommand(CMD_MODCMDEX, 1 ^ (m.param ? 1 : 0)); break; case 0x0F: // set speed speedFrac = m.param & 0x0F; m.SetEffectCommand(CMD_SPEED, m.param >> 4); break; case 0x10: // auto vibrato m.command = CMD_VIBRATO; break; case 0x11: // auto tremolo m.command = CMD_TREMOLO; break; case 0x12: // pattern break m.command = CMD_PATTERNBREAK; break; case 0x13: // auto tone portamento m.command = CMD_TONEPORTAMENTO; break; case 0x14: // position jump m.command = CMD_POSITIONJUMP; break; case 0x16: // start loop sequence if(m.instr && m.instr <= loopInfo.size()) { const STPLoopList &loopList = loopInfo[m.instr - 1]; m.param--; if(m.param < std::min(std::size(ModSample().cues), loopList.size())) { m.SetVolumeCommand(VOLCMD_OFFSET, m.param); } } break; case 0x17: // play only loop nn if(m.instr && m.instr <= loopInfo.size()) { STPLoopList &loopList = loopInfo[m.instr - 1]; m.param--; if(m.param < loopList.size()) { if(!loopList[m.param].looped && CanAddMoreSamples()) loopList[m.param].looped = ++m_nSamples; m.instr = static_cast(loopList[m.param].looped); } } break; case 0x18: // play sequence without loop if(m.instr && m.instr <= loopInfo.size()) { const STPLoopList &loopList = loopInfo[m.instr - 1]; m.param--; if(m.param < std::min(std::size(ModSample().cues), loopList.size())) { m.SetVolumeCommand(VOLCMD_OFFSET, m.param); } // switch to non-looped version of sample and create it if needed if(!nonLooped[m.instr - 1] && CanAddMoreSamples()) nonLooped[m.instr - 1] = ++m_nSamples; m.instr = static_cast(nonLooped[m.instr - 1]); } break; case 0x19: // play only loop nn without loop if(m.instr && m.instr <= loopInfo.size()) { STPLoopList &loopList = loopInfo[m.instr - 1]; m.param--; if(m.param < loopList.size()) { if(!loopList[m.param].nonLooped && CanAddMoreSamples()) loopList[m.param].nonLooped = ++m_nSamples; m.instr = static_cast(loopList[m.param].nonLooped); } } break; case 0x1D: // fine volume slide (nibble order also swapped) if(totalSlide < 0) // slide down m.SetEffectCommand(CMD_MODCMDEX, 0xB0 | (slideParam & 0x0F)); else if(totalSlide > 0) m.SetEffectCommand(CMD_MODCMDEX, 0xA0 | (slideParam >> 4)); break; case 0x20: // "delayed fade" // just behave like either a normal fade or a notecut // depending on the speed if(m.param & 0xF0) m.SetEffectCommand(CMD_AUTO_VOLUMESLIDE, m.param >> 4); else m.SetEffectCommand(CMD_MODCMDEX, 0xC0 | (m.param & 0x0F)); break; case 0x21: // note delay m.SetEffectCommand(CMD_MODCMDEX, 0xD0 | std::min(m.param, ModCommand::PARAM(15))); break; case 0x22: // retrigger note m.SetEffectCommand(CMD_MODCMDEX, 0x90 | std::min(m.param, ModCommand::PARAM(15))); break; case 0x49: // set sample offset m.command = CMD_OFFSET; break; case 0x4E: // other protracker commands (pattern loop / delay) if((m.param & 0xF0) == 0x60 || (m.param & 0xF0) == 0xE0) m.command = CMD_MODCMDEX; break; case 0x4F: // set speed/tempo if(m.param < 0x20) { m.command = CMD_SPEED; speedFrac = 0; } else { m.command = CMD_TEMPO; } break; default: break; } // try to place/combine all remaining running effects. if(shouldDelay && m.command == CMD_NONE) { // insert a fine pattern delay here m.SetEffectCommand(CMD_S3MCMDEX, 0x61); shouldDelay = false; } } // TODO: create/use extra channels for delay if needed? } } // after we know how many channels there really are... m_nSamplePreAmp = 256 / GetNumChannels(); // Setup channel pan positions and volume SetupMODPanning(true); // Skip over scripts and drumpad info if(fileHeader.version > 0) { while(file.CanRead(2)) { uint16 scriptNum = file.ReadUint16BE(); if(scriptNum == 0xFFFF) break; file.Skip(2); uint32 length = file.ReadUint32BE(); file.Skip(length); } // Skip drumpad stuff file.Skip(17 * 2); } // Reading samples if(loadFlags & loadSampleData) { for(SAMPLEINDEX smp = 1; smp <= samplesInFile; smp++) if(Samples[smp].nLength) { SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(Samples[smp], file); if(smp > loopInfo.size()) continue; ConvertLoopSequence(Samples[smp], loopInfo[smp - 1]); // make a non-looping duplicate of this sample if needed if(nonLooped[smp - 1]) { ConvertLoopSlice(Samples[smp], Samples[nonLooped[smp - 1]], 0, Samples[smp].nLength, false); } for(const auto &info : loopInfo[smp - 1]) { // make duplicate samples for this individual section if needed if(info.looped) ConvertLoopSlice(Samples[smp], Samples[info.looped], info.loopStart, info.loopLength, true); if(info.nonLooped) ConvertLoopSlice(Samples[smp], Samples[info.nonLooped], info.loopStart, info.loopLength, false); } } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_dtm.cpp0000644000175000017500000003761414644610543020346 00000000000000/* * Load_dtm.cpp * ------------ * Purpose: Digital Tracker / Digital Home Studio module Loader (DTM) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN enum PatternFormats : uint32 { DTM_PT_PATTERN_FORMAT = 0, DTM_204_PATTERN_FORMAT = MagicBE("2.04"), DTM_206_PATTERN_FORMAT = MagicBE("2.06"), }; struct DTMFileHeader { char magic[4]; uint32be headerSize; uint16be type; // 0 = module uint8be stereoMode; // FF = panoramic stereo, 00 = old stereo uint8be bitDepth; // Typically 8, sometimes 16, but is not actually used anywhere? uint16be reserved; // Usually 0, but not in unknown title 1.dtm and unknown title 2.dtm uint16be speed; uint16be tempo; uint32be forcedSampleRate; // Seems to be ignored in newer files }; MPT_BINARY_STRUCT(DTMFileHeader, 22) // IFF-style Chunk struct DTMChunk { // 32-Bit chunk identifiers enum ChunkIdentifiers { idS_Q_ = MagicBE("S.Q."), idPATT = MagicBE("PATT"), idINST = MagicBE("INST"), idIENV = MagicBE("IENV"), idDAPT = MagicBE("DAPT"), idDAIT = MagicBE("DAIT"), idTEXT = MagicBE("TEXT"), idPATN = MagicBE("PATN"), idTRKN = MagicBE("TRKN"), idVERS = MagicBE("VERS"), idSV19 = MagicBE("SV19"), }; uint32be id; uint32be length; size_t GetLength() const { return length; } ChunkIdentifiers GetID() const { return static_cast(id.get()); } }; MPT_BINARY_STRUCT(DTMChunk, 8) struct DTMSample { uint32be reserved; // 0x204 for first sample, 0x208 for second, etc... uint32be length; // in bytes uint8be finetune; // -8....7 uint8be volume; // 0...64 uint32be loopStart; // in bytes uint32be loopLength; // ditto char name[22]; uint8be stereo; uint8be bitDepth; uint16be transpose; uint16be unknown; uint32be sampleRate; void ConvertToMPT(ModSample &mptSmp, uint32 forcedSampleRate, uint32 formatVersion) const { mptSmp.Initialize(MOD_TYPE_IT); mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = mptSmp.nLoopStart + loopLength; // In revolution to come.dtm, the file header says samples rate is 24512 Hz, but samples say it's 50000 Hz // Digital Home Studio ignores the header setting in 2.04-/2.06-style modules mptSmp.nC5Speed = (formatVersion == DTM_PT_PATTERN_FORMAT && forcedSampleRate > 0) ? forcedSampleRate : sampleRate; int32 transposeAmount = 0; #ifdef MODPLUG_TRACKER transposeAmount = MOD2XMFineTune(finetune); #else mptSmp.nFineTune = MOD2XMFineTune(finetune); #endif if(formatVersion == DTM_206_PATTERN_FORMAT && transpose > 0 && transpose != 48) { // Digital Home Studio applies this unconditionally, but some old songs sound wrong then (delirium.dtm). // Digital Tracker 2.03 ignores the setting. // Maybe this should not be applied for "real" Digital Tracker modules? transposeAmount += (48 - transpose) * 128; } mptSmp.Transpose(transposeAmount * (1.0 / (12.0 * 128.0))); mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4u; if(stereo & 1) { mptSmp.uFlags.set(CHN_STEREO); mptSmp.nLength /= 2u; mptSmp.nLoopStart /= 2u; mptSmp.nLoopEnd /= 2u; } if(bitDepth > 8) { mptSmp.uFlags.set(CHN_16BIT); mptSmp.nLength /= 2u; mptSmp.nLoopStart /= 2u; mptSmp.nLoopEnd /= 2u; } if(mptSmp.nLoopEnd > mptSmp.nLoopStart + 1) { mptSmp.uFlags.set(CHN_LOOP); } else { mptSmp.nLoopStart = mptSmp.nLoopEnd = 0; } } }; MPT_BINARY_STRUCT(DTMSample, 50) struct DTMInstrument { uint16be insNum; uint8be unknown1; uint8be envelope; // 0xFF = none uint8be sustain; // 0xFF = no sustain point uint16be fadeout; uint8be vibRate; uint8be vibDepth; uint8be modulationRate; uint8be modulationDepth; uint8be breathRate; uint8be breathDepth; uint8be volumeRate; uint8be volumeDepth; }; MPT_BINARY_STRUCT(DTMInstrument, 15) struct DTMEnvelope { struct DTMEnvPoint { uint8be value; uint8be tick; }; uint16be numPoints; DTMEnvPoint points[16]; }; MPT_BINARY_STRUCT(DTMEnvelope::DTMEnvPoint, 2) MPT_BINARY_STRUCT(DTMEnvelope, 34) struct DTMText { uint16be textType; // 0 = pattern, 1 = free, 2 = song uint32be textLength; uint16be tabWidth; uint16be reserved; uint16be oddLength; }; MPT_BINARY_STRUCT(DTMText, 12) static bool ValidateHeader(const DTMFileHeader &fileHeader) { if(std::memcmp(fileHeader.magic, "D.T.", 4) || fileHeader.headerSize < sizeof(fileHeader) - 8u || fileHeader.headerSize > 256 // Excessively long song title? || fileHeader.type != 0) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDTM(MemoryFileReader file, const uint64 *pfilesize) { DTMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadDTM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); DTMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } std::string songName; file.ReadString(songName, fileHeader.headerSize - (sizeof(fileHeader) - 8u)); auto chunks = ChunkReader(file).ReadChunks(1); // Read pattern properties uint32 patternFormat; if(FileReader chunk = chunks.GetChunk(DTMChunk::idPATT)) { const uint16 numChannels = chunk.ReadUint16BE(); if(numChannels < 1 || numChannels > 32) return false; InitializeGlobals(MOD_TYPE_DTM, numChannels); Patterns.ResizeArray(chunk.ReadUint16BE()); // Number of stored patterns, may be lower than highest pattern number patternFormat = chunk.ReadUint32BE(); if(patternFormat != DTM_PT_PATTERN_FORMAT && patternFormat != DTM_204_PATTERN_FORMAT && patternFormat != DTM_206_PATTERN_FORMAT) return false; } else { return false; } m_SongFlags.set(SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS | SONG_FASTPORTAS); m_playBehaviour.reset(kPeriodsAreHertz); m_playBehaviour.reset(kITVibratoTremoloPanbrello); // Various files have a default speed or tempo of 0 if(fileHeader.tempo) Order().SetDefaultTempoInt(fileHeader.tempo); if(fileHeader.speed) Order().SetDefaultSpeed(fileHeader.speed); if(fileHeader.stereoMode == 0) SetupMODPanning(true); m_songName = std::move(songName); // Read order list if(FileReader chunk = chunks.GetChunk(DTMChunk::idS_Q_)) { uint16 ordLen = chunk.ReadUint16BE(); uint16 restartPos = chunk.ReadUint16BE(); chunk.Skip(4); // Reserved ReadOrderFromFile(Order(), chunk, ordLen); Order().SetRestartPos(restartPos); } else { return false; } // Read global info if(FileReader chunk = chunks.GetChunk(DTMChunk::idSV19)) { chunk.Skip(2); // Ticks per quarter note, typically 24 uint32 fractionalTempo = chunk.ReadUint32BE(); Order().SetDefaultTempo(TEMPO(Order().GetDefaultTempo().GetInt() + fractionalTempo / 4294967296.0)); uint16be panning[32]; chunk.ReadArray(panning); for(CHANNELINDEX chn = 0; chn < 32 && chn < GetNumChannels(); chn++) { // Panning is in range 0...180, 90 = center ChnSettings[chn].nPan = static_cast(128 + Util::muldivr(std::min(static_cast(panning[chn]), int(180)) - 90, 128, 90)); } chunk.Skip(16); // Chunk ends here for old DTM modules if(chunk.CanRead(2)) { m_nDefaultGlobalVolume = std::min(chunk.ReadUint16BE(), static_cast(MAX_GLOBAL_VOLUME)); } chunk.Skip(128); uint16be volume[32]; if(chunk.ReadArray(volume)) { for(CHANNELINDEX chn = 0; chn < 32 && chn < GetNumChannels(); chn++) { // Volume is in range 0...128, 64 = normal ChnSettings[chn].nVolume = static_cast(std::min(static_cast(volume[chn]), int(128)) / 2); } m_nSamplePreAmp *= 2; // Compensate for channel volume range } } // Read song message if(FileReader chunk = chunks.GetChunk(DTMChunk::idTEXT)) { DTMText text; chunk.ReadStruct(text); if(text.oddLength == 0xFFFF) { chunk.Skip(1); } m_songMessage.Read(chunk, chunk.BytesLeft(), SongMessage::leCRLF); } // Read sample headers if(FileReader chunk = chunks.GetChunk(DTMChunk::idINST)) { uint16 numSamples = chunk.ReadUint16BE(); bool newSamples = (numSamples >= 0x8000); numSamples &= 0x7FFF; if(numSamples >= MAX_SAMPLES || !chunk.CanRead(numSamples * (sizeof(DTMSample) + (newSamples ? 2u : 0u)))) { return false; } m_nSamples = numSamples; for(SAMPLEINDEX smp = 1; smp <= numSamples; smp++) { SAMPLEINDEX realSample = newSamples ? (chunk.ReadUint16BE() + 1u) : smp; DTMSample dtmSample; chunk.ReadStruct(dtmSample); if(realSample < 1 || realSample >= MAX_SAMPLES) { continue; } m_nSamples = std::max(m_nSamples, realSample); ModSample &mptSmp = Samples[realSample]; dtmSample.ConvertToMPT(mptSmp, fileHeader.forcedSampleRate, patternFormat); m_szNames[realSample] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, dtmSample.name); } if(chunk.ReadUint16BE() == 0x0004) { // Digital Home Studio instruments m_nInstruments = std::min(static_cast(m_nSamples), static_cast(MAX_INSTRUMENTS - 1)); FileReader envChunk = chunks.GetChunk(DTMChunk::idIENV); while(chunk.CanRead(sizeof(DTMInstrument))) { DTMInstrument instr; chunk.ReadStruct(instr); if(instr.insNum < GetNumInstruments()) { ModSample &sample = Samples[instr.insNum + 1]; sample.nVibDepth = instr.vibDepth; sample.nVibRate = instr.vibRate; sample.nVibSweep = 255; ModInstrument *mptIns = AllocateInstrument(instr.insNum + 1, instr.insNum + 1); if(mptIns != nullptr) { InstrumentEnvelope &mptEnv = mptIns->VolEnv; mptIns->nFadeOut = std::min(static_cast(instr.fadeout), uint16(0xFFF)); if(instr.envelope != 0xFF && envChunk.Seek(2 + sizeof(DTMEnvelope) * instr.envelope)) { DTMEnvelope env; envChunk.ReadStruct(env); mptEnv.dwFlags.set(ENV_ENABLED); mptEnv.resize(std::min({ static_cast(env.numPoints), std::size(env.points), static_cast(MAX_ENVPOINTS) })); for(size_t i = 0; i < mptEnv.size(); i++) { mptEnv[i].value = std::min(uint8(64), static_cast(env.points[i].value)); mptEnv[i].tick = env.points[i].tick; } if(instr.sustain != 0xFF) { mptEnv.dwFlags.set(ENV_SUSTAIN); mptEnv.nSustainStart = mptEnv.nSustainEnd = instr.sustain; } if(!mptEnv.empty()) { mptEnv.dwFlags.set(ENV_LOOP); mptEnv.nLoopStart = mptEnv.nLoopEnd = static_cast(mptEnv.size() - 1); } } } } } } } // Read pattern data for(auto &chunk : chunks.GetAllChunks(DTMChunk::idDAPT)) { chunk.Skip(4); // FF FF FF FF PATTERNINDEX patNum = chunk.ReadUint16BE(); ROWINDEX numRows = chunk.ReadUint16BE(); if(patternFormat == DTM_206_PATTERN_FORMAT) { // The stored data is actually not row-based, but tick-based. numRows /= Order().GetDefaultSpeed(); } if(!(loadFlags & loadPatternData) || patNum > 255 || !Patterns.Insert(patNum, numRows)) { continue; } if(patternFormat == DTM_206_PATTERN_FORMAT) { chunk.Skip(4); for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { uint16 length = chunk.ReadUint16BE(); if(length % 2u) length++; FileReader rowChunk = chunk.ReadChunk(length); int tick = 0; std::div_t position = { 0, 0 }; while(rowChunk.CanRead(6) && static_cast(position.quot) < numRows) { ModCommand *m = Patterns[patNum].GetpModCommand(position.quot, chn); const auto [note, volume, instr, command, param, delay] = rowChunk.ReadArray(); if(note > 0 && note <= 96) { m->note = note + NOTE_MIN + 12; if(position.rem) m->SetEffectCommand(CMD_MODCMDEX, static_cast(0xD0 | std::min(position.rem, 15))); } else if(note & 0x80) { // Lower 7 bits contain note, probably intended for MIDI-like note-on/note-off events if(position.rem) m->SetEffectCommand(CMD_MODCMDEX, static_cast(0xC0 |std::min(position.rem, 15))); else m->note = NOTE_NOTECUT; } if(volume) { m->SetVolumeCommand(VOLCMD_VOLUME, std::min(volume, uint8(64))); // Volume can go up to 255, but we do not support over-amplification at the moment. } if(instr) { m->instr = instr; } if(command || param) { ConvertModCommand(*m, command, param); #ifdef MODPLUG_TRACKER m->Convert(MOD_TYPE_MOD, MOD_TYPE_IT, *this); #endif // G is 8-bit volume // P is tremor (need to disable oldfx) } if(delay & 0x80) tick += (delay & 0x7F) * 0x100 + rowChunk.ReadUint8(); else tick += delay; position = std::div(tick, Order().GetDefaultSpeed()); } } } else { for(ModCommand &m : Patterns[patNum]) { const auto data = chunk.ReadArray(); uint8 command = 0; if(patternFormat == DTM_204_PATTERN_FORMAT) { const auto [note, instrVol, instrCmd, param] = data; if(note > 0 && note < 0x80) { m.note = static_cast((note >> 4) * 12 + (note & 0x0F) + NOTE_MIN + 11); } uint8 vol = instrVol >> 2; if(vol) { m.SetVolumeCommand(VOLCMD_VOLUME, static_cast(vol - 1u)); } m.instr = ((instrVol & 0x03) << 4) | (instrCmd >> 4); command = instrCmd & 0x0F; m.param = param; } else { std::tie(command, m.param) = ReadMODPatternEntry(data, m); m.instr |= static_cast(data[0] & 0x30u); // Allow more than 31 instruments } ConvertModCommand(m, command, m.param); // Fix commands without memory and slide nibble precedence switch(m.command) { case CMD_PORTAMENTOUP: case CMD_PORTAMENTODOWN: if(!m.param) m.command = CMD_NONE; break; case CMD_VOLUMESLIDE: case CMD_TONEPORTAVOL: case CMD_VIBRATOVOL: if(m.param & 0xF0) m.param &= 0xF0; else if(!m.param) m.command = CMD_NONE; break; default: break; } #ifdef MODPLUG_TRACKER m.Convert(MOD_TYPE_MOD, MOD_TYPE_IT, *this); #endif } } } // Read pattern names if(FileReader chunk = chunks.GetChunk(DTMChunk::idPATN)) { PATTERNINDEX pat = 0; std::string name; while(chunk.CanRead(1) && pat < Patterns.Size()) { chunk.ReadNullString(name, 32); Patterns[pat].SetName(name); pat++; } } // Read channel names if(FileReader chunk = chunks.GetChunk(DTMChunk::idTRKN)) { CHANNELINDEX chn = 0; std::string name; while(chunk.CanRead(1) && chn < GetNumChannels()) { chunk.ReadNullString(name, 32); ChnSettings[chn].szName = name; chn++; } } // Read sample data for(auto &chunk : chunks.GetAllChunks(DTMChunk::idDAIT)) { SAMPLEINDEX smp = chunk.ReadUint16BE(); if(smp >= GetNumSamples() || !(loadFlags & loadSampleData)) { continue; } ModSample &mptSmp = Samples[smp + 1]; SampleIO( mptSmp.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, mptSmp.uFlags[CHN_STEREO] ? SampleIO::stereoInterleaved: SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM).ReadSample(mptSmp, chunk); } // Is this accurate? mpt::ustring tracker; if(patternFormat == DTM_206_PATTERN_FORMAT) { tracker = UL_("Digital Home Studio"); } else if(patternFormat == DTM_PT_PATTERN_FORMAT) { tracker = UL_("Digital Tracker 2.3"); } else if(FileReader chunk = chunks.GetChunk(DTMChunk::idVERS)) { uint32 version = chunk.ReadUint32BE(); tracker = MPT_UFORMAT("Digital Tracker {}.{}")(version >> 4, version & 0x0F); } else { tracker = UL_("Digital Tracker"); } m_modFormat.formatName = UL_("Digital Tracker"); m_modFormat.type = UL_("dtm"); m_modFormat.madeWithTracker = std::move(tracker); m_modFormat.charset = mpt::Charset::Amiga_no_C1; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ModSample.h0000644000175000017500000001764514731541123020145 00000000000000/* * ModSample.h * ----------- * Purpose: Module Sample header class and helpers * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" OPENMPT_NAMESPACE_BEGIN class CSoundFile; // Sample Struct struct ModSample { SmpLength nLength; // In frames SmpLength nLoopStart, nLoopEnd; // Ditto SmpLength nSustainStart, nSustainEnd; // Ditto union { void *pSample; // Pointer to sample data int8 *pSample8; // Pointer to 8-bit sample data int16 *pSample16; // Pointer to 16-bit sample data } pData; uint32 nC5Speed; // Frequency of middle-C, in Hz (for IT/S3M/MPTM) uint16 nPan; // Default sample panning (if pan flag is set), 0...256 uint16 nVolume; // Default volume, 0...256 (ignored if uFlags[SMP_NODEFAULTVOLUME] is set) uint16 nGlobalVol; // Global volume (sample volume is multiplied by this), 0...64 SampleFlags uFlags; // Sample flags (see ChannelFlags enum) int8 RelativeTone; // Relative note to middle c (for MOD/XM) int8 nFineTune; // Finetune period (for MOD/XM), -128...127, unit is 1/128th of a semitone VibratoType nVibType; // Auto vibrato type uint8 nVibSweep; // Auto vibrato sweep (i.e. how long it takes until the vibrato effect reaches its full depth) uint8 nVibDepth; // Auto vibrato depth uint8 nVibRate; // Auto vibrato rate (speed) uint8 rootNote; // For multisample import //char name[MAX_SAMPLENAME]; // Maybe it would be nicer to have sample names here, but that would require some refactoring. mpt::charbuf filename; std::string GetFilename() const { return filename; } union { std::array cues; OPLPatch adlib; }; ModSample(MODTYPE type = MOD_TYPE_NONE) { pData.pSample = nullptr; Initialize(type); } bool HasSampleData() const noexcept { MPT_ASSERT(!pData.pSample || (pData.pSample && nLength > 0)); // having sample pointer implies non-zero sample length return pData.pSample != nullptr && nLength != 0; } MPT_FORCEINLINE const void *samplev() const noexcept { return pData.pSample; } MPT_FORCEINLINE void *samplev() noexcept { return pData.pSample; } MPT_FORCEINLINE const std::byte *sampleb() const noexcept { return mpt::void_cast(pData.pSample); } MPT_FORCEINLINE std::byte *sampleb() noexcept { return mpt::void_cast(pData.pSample); } MPT_FORCEINLINE const int8 *sample8() const noexcept { MPT_ASSERT(GetElementarySampleSize() == sizeof(int8)); return pData.pSample8; } MPT_FORCEINLINE int8 *sample8() noexcept { MPT_ASSERT(GetElementarySampleSize() == sizeof(int8)); return pData.pSample8; } MPT_FORCEINLINE const int16 *sample16() const noexcept { MPT_ASSERT(GetElementarySampleSize() == sizeof(int16)); return pData.pSample16; } MPT_FORCEINLINE int16 *sample16() noexcept { MPT_ASSERT(GetElementarySampleSize() == sizeof(int16)); return pData.pSample16; } template MPT_FORCEINLINE const Tsample *sample() const noexcept = delete; template MPT_FORCEINLINE Tsample *sample() noexcept = delete; // Return the size of one (elementary) sample in bytes. uint8 GetElementarySampleSize() const noexcept { return (uFlags & CHN_16BIT) ? 2 : 1; } // Return the number of channels in the sample. uint8 GetNumChannels() const noexcept { return (uFlags & CHN_STEREO) ? 2 : 1; } // Return the number of bytes per frame (Channels * Elementary Sample Size) uint8 GetBytesPerSample() const noexcept { return GetElementarySampleSize() * GetNumChannels(); } // Return the size which pSample is at least. SmpLength GetSampleSizeInBytes() const noexcept { return nLength * GetBytesPerSample(); } // Returns sample rate of the sample. The argument is needed because // the sample rate is obtained differently for different module types. uint32 GetSampleRate(const MODTYPE type) const; // Translate sample properties between two given formats. void Convert(MODTYPE fromType, MODTYPE toType); // Initialize sample slot with default values. void Initialize(MODTYPE type = MOD_TYPE_NONE); // Copies sample data from another sample slot and ensures that the 16-bit/stereo flags are set accordingly. bool CopyWaveform(const ModSample &smpFrom); // Replace waveform with given data, keeping the currently chosen format of the sample slot. void ReplaceWaveform(void *newWaveform, const SmpLength newLength, CSoundFile &sndFile); // Allocate sample based on a ModSample's properties. // Returns number of bytes allocated, 0 on failure. size_t AllocateSample(); // Allocate sample memory. On sucess, a pointer to the silenced sample buffer is returned. On failure, nullptr is returned. static void *AllocateSample(SmpLength numFrames, size_t bytesPerSample); // Compute sample buffer size in bytes, including any overhead introduced by pre-computed loops and such. Returns 0 if sample is too big. static size_t GetRealSampleBufferSize(SmpLength numSamples, size_t bytesPerSample); void FreeSample(); static void FreeSample(void *samplePtr); // Set loop points and update loop wrap-around buffer void SetLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile); // Set sustain loop points and update loop wrap-around buffer void SetSustainLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile); // Retrieve the normal loop points std::pair GetLoop() const noexcept { return std::make_pair(nLoopStart, nLoopEnd); } // Retrieve the sustain loop points std::pair GetSustainLoop() const noexcept { return std::make_pair(nSustainStart, nSustainEnd); } // Update loop wrap-around buffer void PrecomputeLoops(CSoundFile &sndFile, bool updateChannels = true); // Propagate loop point changes to player bool UpdateLoopPointsInActiveChannels(CSoundFile &sndFile); constexpr bool HasLoop() const noexcept { return uFlags[CHN_LOOP] && nLoopEnd > nLoopStart; } constexpr bool HasSustainLoop() const noexcept { return uFlags[CHN_SUSTAINLOOP] && nSustainEnd > nSustainStart; } constexpr bool HasPingPongLoop() const noexcept { return uFlags.test_all(CHN_LOOP | CHN_PINGPONGLOOP) && nLoopEnd > nLoopStart; } constexpr bool HasPingPongSustainLoop() const noexcept { return uFlags.test_all(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN) && nSustainEnd > nSustainStart; } // Remove loop points if they're invalid. void SanitizeLoops(); // Transpose <-> Frequency conversions static uint32 TransposeToFrequency(int transpose, int finetune = 0); void TransposeToFrequency(); static std::pair FrequencyToTranspose(uint32 freq); void FrequencyToTranspose(); // Transpose the sample by amount specified in octaves (i.e. amount=1 transposes one octave up) void Transpose(double amount); // Check if the sample has any valid cue points bool HasAnyCuePoints() const; // Check if the sample's cue points are the default cue point set. bool HasCustomCuePoints() const; void SetDefaultCuePoints(); // Set cue points so that they are suitable for regular offset command extension void Set16BitCuePoints(); void RemoveAllCuePoints(); void SetAdlib(bool enable, OPLPatch patch = OPLPatch{{}}); }; template <> MPT_FORCEINLINE const int8 *ModSample::sample() const noexcept { MPT_ASSERT(GetElementarySampleSize() == sizeof(int8)); return pData.pSample8; } template <> MPT_FORCEINLINE int8 *ModSample::sample() noexcept { MPT_ASSERT(GetElementarySampleSize() == sizeof(int8)); return pData.pSample8; } template <> MPT_FORCEINLINE const int16 *ModSample::sample() const noexcept { MPT_ASSERT(GetElementarySampleSize() == sizeof(int16)); return pData.pSample16; } template <> MPT_FORCEINLINE int16 *ModSample::sample() noexcept { MPT_ASSERT(GetElementarySampleSize() == sizeof(int16)); return pData.pSample16; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MIDIEvents.cpp0000644000175000017500000001337014705226003020513 00000000000000/* * MIDIEvents.cpp * -------------- * Purpose: MIDI event handling, event lists, ... * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "MIDIEvents.h" OPENMPT_NAMESPACE_BEGIN namespace MIDIEvents { // Build a generic MIDI event uint32 Event(EventType eventType, uint8 midiChannel, uint8 dataByte1, uint8 dataByte2) { return (eventType << 4) | (midiChannel & 0x0F) | (dataByte1 << 8) | (dataByte2 << 16); } // Build a MIDI CC event uint32 CC(MidiCC midiCC, uint8 midiChannel, uint8 param) { return Event(evControllerChange, midiChannel, static_cast(midiCC), param); } // Build a MIDI Pitchbend event uint32 PitchBend(uint8 midiChannel, uint16 bendAmount) { return Event(evPitchBend, midiChannel, static_cast(bendAmount & 0x7F), static_cast(bendAmount >> 7)); } // Build a MIDI Program Change event uint32 ProgramChange(uint8 midiChannel, uint8 program) { return Event(evProgramChange, midiChannel, program, 0); } // Build a MIDI Note Off event uint32 NoteOff(uint8 midiChannel, uint8 note, uint8 velocity) { return Event(evNoteOff, midiChannel, note, velocity); } // Build a MIDI Note On event uint32 NoteOn(uint8 midiChannel, uint8 note, uint8 velocity) { return Event(evNoteOn, midiChannel, note, velocity); } // Build a MIDI System Event uint8 System(SystemEvent eventType) { return static_cast((evSystem << 4) | eventType); } // Build a MIDI Song Position Event uint32 SongPosition(uint16 quarterNotes) { return Event(evSystem, sysPositionPointer, static_cast(quarterNotes & 0x7F), static_cast((quarterNotes >> 7) & 0x7F)); } // Get MIDI channel from a MIDI event uint8 GetChannelFromEvent(uint32 midiMsg) { return static_cast((midiMsg & 0xF)); } // Get MIDI Event type from a MIDI event EventType GetTypeFromEvent(uint32 midiMsg) { return static_cast(((midiMsg >> 4) & 0xF)); } // Get first data byte from a MIDI event uint8 GetDataByte1FromEvent(uint32 midiMsg) { return static_cast(((midiMsg >> 8) & 0xFF)); } // Get second data byte from a MIDI event uint8 GetDataByte2FromEvent(uint32 midiMsg) { return static_cast(((midiMsg >> 16) & 0xFF)); } // Get the length of a MIDI event in bytes uint8 GetEventLength(uint8 firstByte) { uint8 msgSize = 3; switch(firstByte & 0xF0) { case 0xC0: case 0xD0: msgSize = 2; break; case 0xF0: switch(firstByte) { case 0xF1: case 0xF3: msgSize = 2; break; case 0xF2: msgSize = 3; break; default: msgSize = 1; break; } break; } return msgSize; } // MIDI CC Names const char* const MidiCCNames[MIDICC_end + 1] = { "BankSelect [Coarse]", //0 "ModulationWheel [Coarse]", //1 "Breathcontroller [Coarse]", //2 "", //3 "FootPedal [Coarse]", //4 "PortamentoTime [Coarse]", //5 "DataEntry [Coarse]", //6 "Volume [Coarse]", //7 "Balance [Coarse]", //8 "", //9 "Panposition [Coarse]", //10 "Expression [Coarse]", //11 "EffectControl1 [Coarse]", //12 "EffectControl2 [Coarse]", //13 "", //14 "", //15 "GeneralPurposeSlider1", //16 "GeneralPurposeSlider2", //17 "GeneralPurposeSlider3", //18 "GeneralPurposeSlider4", //19 "", //20 "", //21 "", //22 "", //23 "", //24 "", //25 "", //26 "", //27 "", //28 "", //29 "", //30 "", //31 "BankSelect [Fine]", //32 "ModulationWheel [Fine]", //33 "Breathcontroller [Fine]", //34 "", //35 "FootPedal [Fine]", //36 "PortamentoTime [Fine]", //37 "DataEntry [Fine]", //38 "Volume [Fine]", //39 "Balance [Fine]", //40 "", //41 "Panposition [Fine]", //42 "Expression [Fine]", //43 "EffectControl1 [Fine]", //44 "EffectControl2 [Fine]", //45 "", //46 "", //47 "", //48 "", //49 "", //50 "", //51 "", //52 "", //53 "", //54 "", //55 "", //56 "", //57 "", //58 "", //59 "", //60 "", //61 "", //62 "", //63 "HoldPedal [OnOff]", //64 "Portamento [OnOff]", //65 "SustenutoPedal [OnOff]", //66 "SoftPedal [OnOff]", //67 "LegatoPedal [OnOff]", //68 "Hold2Pedal [OnOff]", //69 "SoundVariation", //70 "SoundTimbre", //71 "SoundReleaseTime", //72 "SoundAttackTime", //73 "SoundBrightness", //74 "SoundControl6", //75 "SoundControl7", //76 "SoundControl8", //77 "SoundControl9", //78 "SoundControl10", //79 "GeneralPurposeButton1 [OnOff]",//80 "GeneralPurposeButton2 [OnOff]",//81 "GeneralPurposeButton3 [OnOff]",//82 "GeneralPurposeButton4 [OnOff]",//83 "", //84 "", //85 "", //86 "", //87 "", //88 "", //89 "", //90 "EffectsLevel", //91 "TremoloLevel", //92 "ChorusLevel", //93 "CelesteLevel", //94 "PhaserLevel", //95 "DataButtonIncrement", //96 "DataButtonDecrement", //97 "NonRegisteredParameter [Fine]",//98 "NonRegisteredParameter [Coarse]",//99 "RegisteredParameter [Fine]", //100 "RegisteredParameter [Coarse]", //101 "", //102 "", //103 "", //104 "", //105 "", //106 "", //107 "", //108 "", //109 "", //110 "", //111 "", //112 "", //113 "", //114 "", //115 "", //116 "", //117 "", //118 "", //119 "AllSoundOff", //120 "AllControllersOff", //121 "LocalKeyboard [OnOff]", //122 "AllNotesOff", //123 "OmniModeOff", //124 "OmniModeOn", //125 "MonoOperation", //126 "PolyOperation", //127 }; } // End namespace OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/TinyFFT.h0000644000175000017500000000224114052666041017534 00000000000000/* * TinyFFT.h * --------- * Purpose: A simple FFT implementation for power-of-two FFTs * Notes : This is a C++ adaption of Ryuhei Mori's BSD 2-clause licensed TinyFFT * available from https://github.com/ryuhei-mori/tinyfft * Authors: Ryuhei Mori * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include OPENMPT_NAMESPACE_BEGIN class TinyFFT { static constexpr std::complex I{0.0, 1.0}; std::vector> w; // Pre-computed twiddle factors const uint32 k; // log2 of FFT size void GenerateTwiddleFactors(uint32 i, uint32 b, std::complex z); public: TinyFFT(const uint32 fftSize); uint32 Size() const noexcept; // Computes in-place FFT of size 2^k of A, result is in bit-reversed order. void FFT(std::vector> &A) const; // Computes in-place IFFT of size 2^k of A, input is expected to be in bit-reversed order. void IFFT(std::vector> &A) const; static void Normalize(std::vector> &data); }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MODTools.h0000644000175000017500000001027414673105346017723 00000000000000/* * MODTools.h * ---------- * Purpose: Definition of MOD file structures (shared between several SoundTracker-/ProTracker-like formats) and helper functions * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/base/Endian.hpp" #include "SampleIO.h" #include "Snd_defs.h" OPENMPT_NAMESPACE_BEGIN class CSoundFile; struct ModSample; // File header following the sample headers struct MODFileHeader { uint8be numOrders; uint8be restartPos; // Tempo (early SoundTracker) or restart position (only PC trackers?) uint8be orderList[128]; }; MPT_BINARY_STRUCT(MODFileHeader, 130) // Sample Header struct MODSampleHeader { char name[22]; uint16be length; uint8be finetune; uint8be volume; uint16be loopStart; uint16be loopLength; // Convert an MOD sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp, bool is4Chn) const; // Convert OpenMPT's internal sample header to a MOD sample header. SmpLength ConvertToMOD(const ModSample &mptSmp); // Compute a "rating" of this sample header by counting invalid header data to ultimately reject garbage files. uint32 GetInvalidByteScore() const; bool HasDiskName() const; // Suggested threshold for rejecting invalid files based on cumulated score returned by GetInvalidByteScore static constexpr uint32 INVALID_BYTE_THRESHOLD = 40; // This threshold is used for files where the file magic only gives a // fragile result which alone would lead to too many false positives. // In particular, the files from Inconexia demo by Iguana // (https://www.pouet.net/prod.php?which=830) which have 3 \0 bytes in // the file magic tend to cause misdetection of random files. static constexpr uint32 INVALID_BYTE_FRAGILE_THRESHOLD = 1; // Retrieve the internal sample format flags for this sample. static SampleIO GetSampleFormat() { return SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM); } }; MPT_BINARY_STRUCT(MODSampleHeader, 30) // Pattern data of a 4-channel MOD file using MODPatternData = std::array, 4>, 64>; // Check if header magic equals a given string. inline bool IsMagic(const char *magic1, const char (&magic2)[5]) noexcept { return std::memcmp(magic1, magic2, 4) == 0; } // For .DTM files from Apocalypse Abyss, where the first 2108 bytes are swapped template inline T ReadAndSwap(TFileReader &file, const bool swapBytes) { T value{}; if(file.Read(value) && swapBytes) { static_assert(sizeof(value) % 2u == 0); auto byteView = mpt::as_raw_memory(value); for(size_t i = 0; i < sizeof(T); i += 2) { std::swap(byteView[i], byteView[i + 1]); } } return value; } // Convert MOD sample header and validate uint32 ReadMODSample(const MODSampleHeader &sampleHeader, ModSample &sample, mpt::charbuf &sampleName, bool is4Chn); // Check if a name string is valid (i.e. doesn't contain binary garbage data) uint32 CountInvalidChars(const mpt::span name) noexcept; enum class NameClassification { Empty, ValidASCII, Invalid, }; // Check if a name is a valid null-terminated ASCII string with no garbage after the null terminator, or if it's empty NameClassification ClassifyName(const mpt::span name) noexcept; // Count malformed bytes in MOD pattern data uint32 CountMalformedMODPatternData(const MODPatternData &patternData, const bool extendedFormat); // Check if number of malformed bytes in MOD pattern data exceeds some threshold template inline bool ValidateMODPatternData(TFileReader &file, const uint32 threshold, const bool extendedFormat) { MODPatternData patternData; if(!file.Read(patternData)) return false; return CountMalformedMODPatternData(patternData, extendedFormat) <= threshold; } // Parse the order list to determine how many patterns are used in the file. PATTERNINDEX GetNumPatterns(FileReader &file, CSoundFile &sndFile, ORDERINDEX numOrders, SmpLength totalSampleLen, SmpLength wowSampleLen, bool validateHiddenPatterns); OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MixerLoops.h0000644000175000017500000000245214320567132020355 00000000000000/* * MixerLoops.h * ------------ * Purpose: Utility inner loops for mixer-related functionality. * Notes : none. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Mixer.h" OPENMPT_NAMESPACE_BEGIN struct ModChannel; void StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, uint32 nCount, const float _i2fc); void FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *pOut, uint32 uint32, const float _f2ic); void InitMixBuffer(mixsample_t *pBuffer, uint32 nSamples); void InterleaveFrontRear(mixsample_t *pFrontBuf, mixsample_t *pRearBuf, uint32 nFrames); void MonoFromStereo(mixsample_t *pMixBuf, uint32 nSamples); #ifndef MPT_INTMIXER void InterleaveStereo(const mixsample_t * MPT_RESTRICT inputL, const mixsample_t * MPT_RESTRICT inputR, mixsample_t * MPT_RESTRICT output, size_t numSamples); void DeinterleaveStereo(const mixsample_t * MPT_RESTRICT input, mixsample_t * MPT_RESTRICT outputL, mixsample_t * MPT_RESTRICT outputR, size_t numSamples); #endif void EndChannelOfs(ModChannel &chn, mixsample_t *pBuffer, uint32 nSamples); void StereoFill(mixsample_t *pBuffer, uint32 nSamples, mixsample_t &rofs, mixsample_t &lofs); OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Paula.cpp0000644000175000017500000002234414405407751017657 00000000000000/* * Paula.cpp * --------- * Purpose: Emulating the Amiga's sound chip, Paula, by implementing resampling using band-limited steps (BLEPs) * Notes : The BLEP table generator code is a translation of Antti S. Lankila's original Python code. * Authors: OpenMPT Devs * Antti S. Lankila * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Paula.h" #include "TinyFFT.h" #include "Tables.h" #include "mpt/base/numbers.hpp" #include #include OPENMPT_NAMESPACE_BEGIN namespace Paula { namespace { MPT_NOINLINE std::vector KaiserFIR(int numTaps, double cutoff, double beta) { const double izeroBeta = Izero(beta); const double kPi = 4.0 * std::atan(1.0) * cutoff; const double xDiv = 1.0 / ((numTaps / 2) * (numTaps / 2)); const int numTapsDiv2 = numTaps / 2; std::vector result(numTaps); for(int i = 0; i < numTaps; i++) { double fsinc; if(i == numTapsDiv2) { fsinc = 1.0; } else { const double x = i - numTapsDiv2; const double xPi = x * kPi; // - sinc - - Kaiser window - -sinc- fsinc = std::sin(xPi) * Izero(beta * std::sqrt(1 - x * x * xDiv)) / (izeroBeta * xPi); } result[i] = fsinc * cutoff; } return result; } MPT_NOINLINE void FIR_MinPhase(std::vector &table, const TinyFFT &fft) { std::vector> cepstrum(fft.Size()); MPT_ASSERT(cepstrum.size() >= table.size()); for(size_t i = 0; i < table.size(); i++) cepstrum[i] = table[i]; // Compute the real cepstrum: fft -> abs + ln -> ifft -> real fft.FFT(cepstrum); for(auto &v : cepstrum) v = std::log(std::abs(v)); fft.IFFT(cepstrum); fft.Normalize(cepstrum); // Window the cepstrum in such a way that anticausal components become rejected for(size_t i = 1; i < cepstrum.size() / 2; i++) { cepstrum[i] *= 2; cepstrum[i + cepstrum.size() / 2] *= 0; } // Now cancel the previous steps: fft -> exp -> ifft -> real fft.FFT(cepstrum); for(auto &v : cepstrum) v = std::exp(v); fft.IFFT(cepstrum); fft.Normalize(cepstrum); for(size_t i = 0; i < table.size(); i++) table[i] = cepstrum[i].real(); } class BiquadFilter { const double b0, b1, b2, a1, a2; double x1 = 0.0, x2 = 0.0, y1 = 0.0, y2 = 0.0; double Filter(double x0) noexcept { double y0 = b0 * x0 + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2; x2 = x1; x1 = x0; y2 = y1; y1 = y0; return y0; } public: BiquadFilter(double b0_, double b1_, double b2_, double a1_, double a2_) : b0(b0_), b1(b1_), b2(b2_), a1(a1_), a2(a2_) { } std::vector Run(std::vector table) { x1 = 0.0; x2 = 0.0; y1 = 0.0; y2 = 0.0; // Initialize filter to stable state for(int i = 0; i < 10000; i++) Filter(table[0]); // Now run the filter for(auto &v : table) v = Filter(v); return table; } }; // Observe: a and b are reversed here. To be absolutely clear: // a is the nominator and b is the denominator. :-/ BiquadFilter ZTransform(double a0, double a1, double a2, double b0, double b1, double b2, double fc, double fs) { // Prewarp s - domain coefficients const double wp = 2.0 * fs * std::tan(mpt::numbers::pi * fc / fs); a2 /= wp * wp; a1 /= wp; b2 /= wp * wp; b1 /= wp; // Compute bilinear transform and return it const double bd = 4 * b2 * fs * fs + 2 * b1 * fs + b0; return BiquadFilter( (4 * a2 * fs * fs + 2 * a1 * fs + a0) / bd, (2 * a0 - 8 * a2 * fs * fs) / bd, (4 * a2 * fs * fs - 2 * a1 * fs + a0) / bd, (2 * b0 - 8 * b2 * fs * fs) / bd, (4 * b2 * fs * fs - 2 * b1 * fs + b0) / bd); } BiquadFilter MakeRCLowpass(double sampleRate, double freq) { const double omega = (2.0 * mpt::numbers::pi) * freq / sampleRate; const double term = 1 + 1 / omega; return BiquadFilter(1 / term, 0.0, 0.0, -1.0 + 1.0 / term, 0.0); } BiquadFilter MakeButterworth(double fs, double fc, double res_dB = 0) { // 2nd-order Butterworth s-domain coefficients are: // // b0 = 1.0 b1 = 0 b2 = 0 // a0 = 1 a1 = sqrt(2) a2 = 1 // // by tweaking the a1 parameter, some resonance can be produced. const double res = std::pow(10.0, (-res_dB / 10.0 / 2.0)); return ZTransform(1, 0, 0, 1, std::sqrt(2) * res, 1, fc, fs); } MPT_NOINLINE void Integrate(std::vector &table) { const double total = std::accumulate(table.begin(), table.end(), 0.0); double startVal = -total; for(auto &v : table) { startVal += v; v = startVal; } } MPT_NOINLINE void Quantize(const std::vector &in, Paula::BlepArray &quantized) { MPT_ASSERT(in.size() == Paula::BLEP_SIZE); constexpr int fact = 1 << Paula::BLEP_SCALE; const double cv = fact / (in.back() - in.front()); for(int i = 0; i < Paula::BLEP_SIZE; i++) { double val = in[i] * cv; #ifdef MPT_INTMIXER val = mpt::round(val); #endif quantized[i] = static_cast(-val); } } } // namespace void BlepTables::InitTables() { constexpr double sampleRate = Paula::PAULA_HZ; // Because Amiga only has 84 dB SNR, the noise floor is low enough with -90 dB. // A500 model uses slightly lower-quality kaiser window to obtain slightly // steeper stopband attenuation. The fixed filters attenuates the sidelobes by // 12 dB, compensating for the worse performance of the kaiser window. // 21 kHz stopband is not fully attenuated by 22 kHz. If the sampling frequency // is 44.1 kHz, all frequencies above 22 kHz will alias over 20 kHz, thus inaudible. // The output should be aliasingless for 48 kHz sampling frequency. auto unfilteredA500 = KaiserFIR(Paula::BLEP_SIZE, 21000.0 / sampleRate * 2.0, 8.0); auto unfilteredA1200 = KaiserFIR(Paula::BLEP_SIZE, 21000.0 / sampleRate * 2.0, 9.0); // Move filtering effects to start to allow IIRs more time to settle constexpr size_t padSize = 8; constexpr int fftSize = static_cast(mpt::bit_width(size_t(Paula::BLEP_SIZE)) + mpt::bit_width(padSize) - 2); const TinyFFT fft(fftSize); FIR_MinPhase(unfilteredA500, fft); FIR_MinPhase(unfilteredA1200, fft); // Make digital models for the filters on Amiga 500 and 1200. auto filterFixed5kHz = MakeRCLowpass(sampleRate, 4900.0); // The leakage filter seems to reduce treble in both models a bit // The A500 filter seems to be well modelled only with a 4.9 kHz // filter although the component values would suggest 5 kHz filter. auto filterLeakage = MakeRCLowpass(sampleRate, 32000.0); auto filterLED = MakeButterworth(sampleRate, 3275.0, -0.70); // Apply fixed filter to A500 auto amiga500Off = filterFixed5kHz.Run(unfilteredA500); // Produce the filtered outputs auto amiga1200Off = filterLeakage.Run(unfilteredA1200); // Produce LED filters auto amiga500On = filterLED.Run(amiga500Off); auto amiga1200On = filterLED.Run(amiga1200Off); // Integrate to produce blep Integrate(amiga500Off); Integrate(amiga500On); Integrate(amiga1200Off); Integrate(amiga1200On); Integrate(unfilteredA1200); // Quantize and scale Quantize(amiga500Off, WinSincIntegral[A500Off]); Quantize(amiga500On, WinSincIntegral[A500On]); Quantize(amiga1200Off, WinSincIntegral[A1200Off]); Quantize(amiga1200On, WinSincIntegral[A1200On]); Quantize(unfilteredA1200, WinSincIntegral[Unfiltered]); } const Paula::BlepArray &BlepTables::GetAmigaTable(Resampling::AmigaFilter amigaType, bool enableFilter) const { if(amigaType == Resampling::AmigaFilter::A500) return enableFilter ? WinSincIntegral[A500On] : WinSincIntegral[A500Off]; if(amigaType == Resampling::AmigaFilter::A1200) return enableFilter ? WinSincIntegral[A1200On] : WinSincIntegral[A1200Off]; return WinSincIntegral[Unfiltered]; } // we do not initialize blepState here // cppcheck-suppress uninitMemberVar State::State(uint32 sampleRate) { double amigaClocksPerSample = static_cast(PAULA_HZ) / sampleRate; numSteps = static_cast(amigaClocksPerSample / MINIMUM_INTERVAL); stepRemainder = SamplePosition::FromDouble(amigaClocksPerSample - numSteps * MINIMUM_INTERVAL); } void State::Reset() { remainder = SamplePosition(0); activeBleps = 0; firstBlep = MAX_BLEPS / 2u; globalOutputLevel = 0; } void State::InputSample(int16 sample) { if(sample != globalOutputLevel) { // Start a new blep: level is the difference, age (or phase) is 0 clocks. firstBlep = (firstBlep - 1u) % MAX_BLEPS; if(activeBleps < std::size(blepState)) activeBleps++; blepState[firstBlep].age = 0; blepState[firstBlep].level = sample - globalOutputLevel; globalOutputLevel = sample; } } // Return output simulated as series of bleps int State::OutputSample(const BlepArray &WinSincIntegral) { int output = globalOutputLevel * (1 << Paula::BLEP_SCALE); uint32 lastBlep = firstBlep + activeBleps; for(uint32 i = firstBlep; i != lastBlep; i++) { const auto &blep = blepState[i % MAX_BLEPS]; output -= WinSincIntegral[blep.age] * blep.level; } #ifdef MPT_INTMIXER output /= (1 << (Paula::BLEP_SCALE - 2)); // - 2 to compensate for the fact that we reduced the input sample bit depth #endif return output; } // Advance the simulation by given number of clock ticks void State::Clock(int cycles) { uint32 lastBlep = firstBlep + activeBleps; for(uint32 i = firstBlep; i != lastBlep; i++) { auto &blep = blepState[i % MAX_BLEPS]; blep.age += static_cast(cycles); if(blep.age >= Paula::BLEP_SIZE) { activeBleps = static_cast(i - firstBlep); return; } } } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_gmc.cpp0000644000175000017500000001401514721715306020315 00000000000000/* * Load_gmc.cpp * ------------ * Purpose: GMC (Game Music Creator) module loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN // Sample Header struct GMCSampleHeader { uint32be offset; uint16be length; uint8 zero; uint8 volume; uint32be address; uint16be loopLength; // Loop start is implicit uint16be dataStart; // Non-zero if sample was shortened in editor (amount of bytes trimmed from sample start) // Convert a GMC sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.nLength = length * 2u; mptSmp.nVolume = 4u * std::min(volume, uint8(64)); if(loopLength > 2) { mptSmp.nLoopStart = mptSmp.nLength - loopLength * 2u; mptSmp.nLoopEnd = mptSmp.nLength; mptSmp.uFlags.set(CHN_LOOP); } } bool IsValid() const { if(offset > 0x7F'FFFF || (offset & 1) || address > 0x7F'FFFF || (address & 1)) return false; if(length > 0x7FFF || dataStart > 0x7FFF || (dataStart & 1)) return false; if(loopLength > 2 && loopLength > length) return false; if(volume > 64) return false; if(zero != 0) return false; return true; } }; MPT_BINARY_STRUCT(GMCSampleHeader, 16) // File Header struct GMCFileHeader { GMCSampleHeader samples[15]; uint8 zero[3]; uint8 numOrders; uint16be orders[100]; bool IsValid() const noexcept { for(const auto &sample : samples) { if(!sample.IsValid()) return false; } if(zero[0] != 0 || zero[1] != 0 || zero[2] != 0) return false; if(!numOrders || numOrders > std::size(orders)) return false; for(uint16 ord : orders) { if(ord % 1024u) return false; } return true; } }; MPT_BINARY_STRUCT(GMCFileHeader, 444) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderGMC(MemoryFileReader file, const uint64 *pfilesize) { GMCFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadGMC(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); GMCFileHeader fileHeader; if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) return false; else if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_MOD, 4); m_nSamples = 15; m_nMinPeriod = 113 * 4; m_nMaxPeriod = 856 * 4; m_nSamplePreAmp = 64; m_SongFlags.set(SONG_FASTPORTAS | SONG_IMPORTED | SONG_FORMAT_NO_VOLCOL); Order().SetDefaultTempoInt(125); Order().SetDefaultSpeed(6); // Setup channel pan positions and volume SetupMODPanning(true); // Note: The Brides of Dracula modules contain a "hidden" pattern past fileHeader.numOrders. // This pattern would need to be read in order to align the samples correctly, however this would mean that the file size no longer matches // the expected size (the last sample would be missing 1024 samples at the end). // Looking at some gameplay footage, the playback is apparently broken ingame as well, and fixing it would break other modules (e.g. Jet Set Willy 2 Title). Order().resize(fileHeader.numOrders); PATTERNINDEX numPatterns = 0; for(ORDERINDEX ord = 0; ord < fileHeader.numOrders; ord++) { PATTERNINDEX pat = Order()[ord] = fileHeader.orders[ord] / 1024u; // Fix for Covert Action theme music (there appears to be a general bug in GMC export when pattern 63 is used) if(pat != 63) numPatterns = std::max(numPatterns, static_cast(pat + 1)); } for(SAMPLEINDEX smp = 1; smp <= 15; smp++) { fileHeader.samples[smp - 1].ConvertToMPT(Samples[smp]); } if(loadFlags & loadPatternData) Patterns.ResizeArray(numPatterns); for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { file.Skip(64 * 4 * 4); continue; } for(ROWINDEX row = 0; row < 64; row++) { auto rowBase = Patterns[pat].GetRow(row); for(CHANNELINDEX chn = 0; chn < 4; chn++) { ModCommand &m = rowBase[chn]; auto data = file.ReadArray(); // Probably bad conversion from SoundFX Import? (Stryx title music) const bool noteCut = (data[0] == 0xFF && data[1] == 0xFE); if(noteCut) data[0] = 0; else if(data[0] & 0xF0) return false; uint8 command = data[2] & 0x0F, param = data[3]; switch(command) { case 0x00: // Nothing param = 0; break; case 0x01: // Portamento up case 0x02: // Portamento down break; case 0x03: // Volume command = 0x0C; param &= 0x7F; break; case 0x04: // Pattern break if(param > 0x63) return false; command = 0x0D; break; case 0x05: // Position jump if(param > fileHeader.numOrders + 1) return false; command = 0x0B; break; case 0x06: // LED filter on case 0x07: // LED filter off param = command - 0x06; command = 0x0E; break; case 0x08: // Set speed command = 0x0F; break; default: command = param = 0; break; } ReadMODPatternEntry(data, m); ConvertModCommand(m, command, param); if(noteCut) m.note = NOTE_NOTECUT; if(m.command == CMD_PORTAMENTOUP) m.command = CMD_AUTO_PORTAUP; else if(m.command == CMD_PORTAMENTODOWN) m.command = CMD_AUTO_PORTADOWN; else if(m.command == CMD_TEMPO) m.command = CMD_SPEED; } } } if(loadFlags & loadSampleData) { for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { if(!Samples[smp].nLength) continue; SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(Samples[smp], file); } } m_modFormat.madeWithTracker = UL_("Game Music Creator"); m_modFormat.formatName = UL_("Game Music Creator"); m_modFormat.type = UL_("GMC"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; // No strings in this format... return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/WAVTools.cpp0000644000175000017500000003444214766102360020273 00000000000000/* * WAVTools.cpp * ------------ * Purpose: Definition of WAV file structures and helper functions * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "WAVTools.h" #include "Loaders.h" #include "Tagging.h" #include "../common/version.h" #ifndef MODPLUG_NO_FILESAVE #include "mpt/io/io.hpp" #include "mpt/io/io_virtual_wrapper.hpp" #include "../common/mptFileIO.h" #endif OPENMPT_NAMESPACE_BEGIN /////////////////////////////////////////////////////////// // WAV Reading WAVReader::WAVReader(FileReader &inputFile) : file(inputFile) { file.Rewind(); RIFFHeader fileHeader; codePage = 28591; // ISO 8859-1 isDLS = false; subFormat = 0; mayBeCoolEdit16_8 = false; if(!file.ReadStruct(fileHeader) || (fileHeader.magic != RIFFHeader::idRIFF && fileHeader.magic != RIFFHeader::idLIST) || (fileHeader.type != RIFFHeader::idWAVE && fileHeader.type != RIFFHeader::idwave)) { return; } isDLS = (fileHeader.magic == RIFFHeader::idLIST); auto chunks = file.ReadChunks(2); if(chunks.chunks.size() >= 4 && chunks.chunks[1].GetHeader().GetID() == RIFFChunk::iddata && chunks.chunks[1].GetHeader().GetLength() % 2u != 0 && chunks.chunks[2].GetHeader().GetLength() == 0 && chunks.chunks[3].GetHeader().GetID() == RIFFChunk::id____) { // Houston, we have a problem: Old versions of (Open)MPT didn't write RIFF padding bytes. -_- // Luckily, the only RIFF chunk with an odd size those versions would ever write would be the "data" chunk // (which contains the sample data), and its size is only odd iff the sample has an odd length and is in // 8-Bit mono format. In all other cases, the sample size (and thus the chunk size) is even. // And we're even more lucky: The versions of (Open)MPT in question will always write a relatively small // (smaller than 256 bytes) "smpl" chunk after the "data" chunk. This means that after an unpadded sample, // we will always read "mpl?" (? being the length of the "smpl" chunk) as the next chunk magic. The first two // 32-Bit members of the "smpl" chunk are always zero in our case, so we are going to read a chunk length of 0 // next and the next chunk magic, which will always consist of four zero bytes. Hooray! We just checked for those // four zero bytes and can be pretty confident that we should not have applied padding. file.Seek(sizeof(RIFFHeader)); chunks = file.ReadChunks(1); } // Read format chunk FileReader formatChunk = chunks.GetChunk(RIFFChunk::idfmt_); if(!formatChunk.ReadStruct(formatInfo)) { return; } if(formatInfo.format == WAVFormatChunk::fmtPCM && formatChunk.BytesLeft() == 4) { uint16 size = formatChunk.ReadIntLE(); uint16 value = formatChunk.ReadIntLE(); if(size == 2 && value == 1) { // May be Cool Edit 16.8 format. // See SampleFormats.cpp for details. mayBeCoolEdit16_8 = true; } } else if(formatInfo.format == WAVFormatChunk::fmtExtensible) { WAVFormatChunkExtension extFormat; if(!formatChunk.ReadStruct(extFormat)) { return; } subFormat = static_cast(mpt::UUID(extFormat.subFormat).GetData1()); } // Read sample data sampleData = chunks.GetChunk(RIFFChunk::iddata); if(!sampleData.IsValid()) { // The old IMA ADPCM loader code looked for the "pcm " chunk instead of the "data" chunk... // Dunno why (Windows XP's audio recorder saves IMA ADPCM files with a "data" chunk), but we will just look for both. sampleData = chunks.GetChunk(RIFFChunk::idpcm_); } // "fact" chunk should contain sample length of compressed samples. sampleLength = chunks.GetChunk(RIFFChunk::idfact).ReadUint32LE(); if((formatInfo.format != WAVFormatChunk::fmtIMA_ADPCM || sampleLength == 0) && GetSampleSize() != 0) { if((GetBlockAlign() == 0) || (GetBlockAlign() / GetNumChannels() >= 2 * GetSampleSize())) { // Some samples have an incorrect blockAlign / sample size set (e.g. it's 8 in SQUARE.WAV while it should be 1), so let's better not always trust this value. // The idea here is, if block align is off by twice or more, it is unlikely to be describing sample padding inside the block. // Ignore it in this case and calculate the length based on the single sample size and number of channels instead. sampleLength = sampleData.GetLength() / GetSampleSize(); } else { // Correct case (so that 20bit WAVEFORMATEX files work). sampleLength = sampleData.GetLength() / GetBlockAlign(); } } // Determine string encoding codePage = GetFileCodePage(chunks); // Check for loop points, texts, etc... FindMetadataChunks(chunks); // DLS bank chunk wsmpChunk = chunks.GetChunk(RIFFChunk::idwsmp); } void WAVReader::FindMetadataChunks(FileReader::ChunkList &chunks) { // Read sample loop points and other sampler information smplChunk = chunks.GetChunk(RIFFChunk::idsmpl); instChunk = chunks.GetChunk(RIFFChunk::idinst); // Read sample cues cueChunk = chunks.GetChunk(RIFFChunk::idcue_); // Read text chunks FileReader listChunk = chunks.GetChunk(RIFFChunk::idLIST); if(listChunk.ReadMagic("INFO")) { infoChunk = listChunk.ReadChunks(2); } // Read MPT sample information xtraChunk = chunks.GetChunk(RIFFChunk::idxtra); } uint16 WAVReader::GetFileCodePage(FileReader::ChunkList &chunks) { FileReader csetChunk = chunks.GetChunk(RIFFChunk::idCSET); if(!csetChunk.IsValid()) { FileReader iSFT = infoChunk.GetChunk(RIFFChunk::idISFT); if(iSFT.ReadMagic("OpenMPT")) { std::string versionString; iSFT.ReadString(versionString, mpt::saturate_cast(iSFT.BytesLeft())); versionString = mpt::trim(versionString); Version version = Version::Parse(mpt::ToUnicode(mpt::Charset::ISO8859_1, versionString)); if(version && version < MPT_V("1.28.00.02")) { return 1252; // mpt::Charset::Windows1252; // OpenMPT up to and including 1.28.00.01 wrote metadata in windows-1252 encoding } else { return 28591; // mpt::Charset::ISO8859_1; // as per spec } } else { return 28591; // mpt::Charset::ISO8859_1; // as per spec } } if(!csetChunk.CanRead(2)) { // chunk not parsable return 28591; // mpt::Charset::ISO8859_1; } uint16 codepage = csetChunk.ReadUint16LE(); return codepage; } void WAVReader::ApplySampleSettings(ModSample &sample, mpt::Charset sampleCharset, mpt::charbuf &sampleName) { // Read sample name FileReader textChunk = infoChunk.GetChunk(RIFFChunk::idINAM); if(textChunk.IsValid()) { std::string sampleNameEncoded; textChunk.ReadString(sampleNameEncoded, mpt::saturate_cast(textChunk.GetLength())); sampleName = mpt::ToCharset(sampleCharset, mpt::ToUnicode(codePage, mpt::Charset::Windows1252, sampleNameEncoded)); } if(isDLS) { // DLS sample -> sample filename sample.filename = sampleName; } // Read software name const bool isOldMPT = infoChunk.GetChunk(RIFFChunk::idISFT).ReadMagic("Modplug Tracker"); // Convert loops WAVSampleInfoChunk sampleInfo; smplChunk.Rewind(); if(smplChunk.ReadStruct(sampleInfo)) { WAVSampleLoop loopData; if(sampleInfo.numLoops > 1 && smplChunk.ReadStruct(loopData)) { // First loop: Sustain loop loopData.ApplyToSample(sample.nSustainStart, sample.nSustainEnd, sample.nLength, sample.uFlags, CHN_SUSTAINLOOP, CHN_PINGPONGSUSTAIN, isOldMPT); } // First loop (if only one loop is present) or second loop (if more than one loop is present): Normal sample loop if(smplChunk.ReadStruct(loopData)) { loopData.ApplyToSample(sample.nLoopStart, sample.nLoopEnd, sample.nLength, sample.uFlags, CHN_LOOP, CHN_PINGPONGLOOP, isOldMPT); } //sample.Transpose((60 - sampleInfo.baseNote) / 12.0); sample.rootNote = static_cast(sampleInfo.baseNote); if(sample.rootNote < 128) sample.rootNote += NOTE_MIN; else sample.rootNote = NOTE_NONE; sample.SanitizeLoops(); } if(sample.rootNote == NOTE_NONE && instChunk.LengthIsAtLeast(sizeof(WAVInstrumentChunk))) { WAVInstrumentChunk inst; instChunk.Rewind(); if(instChunk.ReadStruct(inst)) { sample.rootNote = inst.unshiftedNote; if(sample.rootNote < 128) sample.rootNote += NOTE_MIN; else sample.rootNote = NOTE_NONE; } } // Read cue points if(cueChunk.IsValid()) { uint32 numPoints = cueChunk.ReadUint32LE(); LimitMax(numPoints, mpt::saturate_cast(std::size(sample.cues))); for(uint32 i = 0; i < numPoints; i++) { WAVCuePoint cuePoint; cueChunk.ReadStruct(cuePoint); sample.cues[i] = cuePoint.position; } std::fill(std::begin(sample.cues) + numPoints, std::end(sample.cues), MAX_SAMPLE_LENGTH); } // Read MPT extra info WAVExtraChunk mptInfo; xtraChunk.Rewind(); if(xtraChunk.ReadStruct(mptInfo)) { if(mptInfo.flags & WAVExtraChunk::setPanning) sample.uFlags.set(CHN_PANNING); sample.nPan = std::min(static_cast(mptInfo.defaultPan), uint16(256)); sample.nVolume = std::min(static_cast(mptInfo.defaultVolume), uint16(256)); sample.nGlobalVol = std::min(static_cast(mptInfo.globalVolume), uint16(64)); sample.nVibType = static_cast(mptInfo.vibratoType.get()); sample.nVibSweep = mptInfo.vibratoSweep; sample.nVibDepth = mptInfo.vibratoDepth; sample.nVibRate = mptInfo.vibratoRate; if(xtraChunk.CanRead(MAX_SAMPLENAME)) { // Name present (clipboard only) // FIXME: When modules can have individual encoding in OpenMPT or when // internal metadata gets converted to Unicode, we must adjust this to // also specify encoding. xtraChunk.ReadString(sampleName, MAX_SAMPLENAME); xtraChunk.ReadString(sample.filename, mpt::saturate_cast(xtraChunk.BytesLeft())); } } } // Apply WAV loop information to a mod sample. void WAVSampleLoop::ApplyToSample(SmpLength &start, SmpLength &end, SmpLength sampleLength, SampleFlags &flags, ChannelFlags enableFlag, ChannelFlags bidiFlag, bool mptLoopFix) const { if(loopEnd == 0) { // Some WAV files seem to have loops going from 0 to 0... We should ignore those. return; } start = std::min(static_cast(loopStart), sampleLength); end = Clamp(static_cast(loopEnd), start, sampleLength); if(!mptLoopFix && end < sampleLength) { // RIFF loop end points are inclusive - old versions of MPT didn't consider this. end++; } flags.set(enableFlag); if(loopType == loopBidi) { flags.set(bidiFlag); } } // Convert internal loop information into a WAV loop. void WAVSampleLoop::ConvertToWAV(SmpLength start, SmpLength end, bool bidi) { identifier = 0; loopType = bidi ? loopBidi : loopForward; loopStart = mpt::saturate_cast(start); // Loop ends are *inclusive* in the RIFF standard, while they're *exclusive* in OpenMPT. if(end > start) { loopEnd = mpt::saturate_cast(end - 1); } else { loopEnd = loopStart; } fraction = 0; playCount = 0; } #ifndef MODPLUG_NO_FILESAVE WAVSampleWriter::WAVSampleWriter(mpt::IO::OFileBase &stream) : WAVWriter(stream) { return; } WAVSampleWriter::~WAVSampleWriter() { return; } // Write a sample loop information chunk to the file. void WAVSampleWriter::WriteLoopInformation(const ModSample &sample, SmpLength rangeStart, SmpLength rangeEnd) { if(!sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP] && !ModCommand::IsNote(sample.rootNote)) { return; } if(rangeEnd <= rangeStart) { rangeStart = 0; rangeEnd = sample.nLength; } StartChunk(RIFFChunk::idsmpl); WAVSampleInfoChunk info; uint32 sampleRate = sample.nC5Speed; if(sampleRate == 0) { sampleRate = ModSample::TransposeToFrequency(sample.RelativeTone, sample.nFineTune); } info.ConvertToWAV(sampleRate, sample.rootNote); // Set up loops std::array loops{{}}; const bool writeSustainLoop = sample.uFlags[CHN_SUSTAINLOOP] && sample.nSustainStart < rangeEnd && sample.nSustainEnd >= rangeStart; const bool writeNormalLoop = sample.uFlags[CHN_LOOP] && sample.nLoopStart < rangeEnd && sample.nLoopEnd >= rangeStart; if(writeSustainLoop) { loops[info.numLoops++].ConvertToWAV(std::max(sample.nSustainStart, rangeStart) - rangeStart, std::clamp(sample.nSustainEnd, rangeStart, rangeEnd) - rangeStart, sample.uFlags[CHN_PINGPONGSUSTAIN]); } if(writeNormalLoop) { loops[info.numLoops++].ConvertToWAV(std::max(sample.nLoopStart, rangeStart) - rangeStart, std::clamp(sample.nLoopEnd, rangeStart, rangeEnd) - rangeStart, sample.uFlags[CHN_PINGPONGLOOP]); } else if(writeSustainLoop) { // Since there are no "loop types" to distinguish between sustain and normal loops, OpenMPT assumes // that the first loop is a sustain loop if there are two loops. If we only want a sustain loop, // we will have to write a second bogus loop. loops[info.numLoops++].ConvertToWAV(0, 0, false); } mpt::IO::Write(s, info); for(uint32 i = 0; i < info.numLoops; i++) { mpt::IO::Write(s, loops[i]); } } // Write a sample's cue points to the file. void WAVSampleWriter::WriteCueInformation(const ModSample &sample, SmpLength rangeStart, SmpLength rangeEnd) { if(rangeEnd <= rangeStart) { rangeStart = 0; rangeEnd = sample.nLength; } uint32 numMarkers = 0; for(const auto cue : sample.cues) { if(mpt::is_in_range(cue, rangeStart, rangeEnd)) numMarkers++; } StartChunk(RIFFChunk::idcue_); mpt::IO::Write(s, mpt::as_le(numMarkers)); uint32 i = 0; for(const auto cue : sample.cues) { if(mpt::is_in_range(cue, rangeStart, rangeEnd)) { WAVCuePoint cuePoint = ConvertToWAVCuePoint(i++, cue - rangeStart); mpt::IO::Write(s, cuePoint); } } } // Write MPT's sample information chunk to the file. void WAVSampleWriter::WriteExtraInformation(const ModSample &sample, MODTYPE modType, const char *sampleName) { StartChunk(RIFFChunk::idxtra); WAVExtraChunk mptInfo; mptInfo.ConvertToWAV(sample, modType); mpt::IO::Write(s, mptInfo); if(sampleName != nullptr) { // Write sample name (clipboard only) // FIXME: When modules can have individual encoding in OpenMPT or when // internal metadata gets converted to Unicode, we must adjust this to // also specify encoding. char name[MAX_SAMPLENAME]; mpt::String::WriteBuf(mpt::String::nullTerminated, name) = sampleName; mpt::IO::Write(s, name); char filename[MAX_SAMPLEFILENAME]; mpt::String::WriteBuf(mpt::String::nullTerminated, filename) = sample.filename; mpt::IO::Write(s, filename); } } #endif // MODPLUG_NO_FILESAVE OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_plm.cpp0000644000175000017500000002530714704715777020362 00000000000000/* * Load_plm.cpp * ------------ * Purpose: PLM (Disorder Tracker 2) module loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct PLMFileHeader { char magic[4]; // "PLM\x1A" uint8le headerSize; // Number of bytes in header, including magic bytes uint8le version; // version code of file format (0x10) char songName[48]; uint8le numChannels; uint8le flags; // unused? uint8le maxVol; // Maximum volume for vol slides, normally 0x40 uint8le amplify; // SoundBlaster amplify, 0x40 = no amplify uint8le tempo; uint8le speed; uint8le panPos[32]; // 0...15 uint8le numSamples; uint8le numPatterns; uint16le numOrders; }; MPT_BINARY_STRUCT(PLMFileHeader, 96) struct PLMSampleHeader { enum SampleFlags { smp16Bit = 1, smpPingPong = 2, }; char magic[4]; // "PLS\x1A" uint8le headerSize; // Number of bytes in header, including magic bytes uint8le version; char name[32]; char filename[12]; uint8le panning; // 0...15, 255 = no pan uint8le volume; // 0...64 uint8le flags; // See SampleFlags uint16le sampleRate; char unused[4]; uint32le loopStart; uint32le loopEnd; uint32le length; }; MPT_BINARY_STRUCT(PLMSampleHeader, 71) struct PLMPatternHeader { uint32le size; uint8le numRows; uint8le numChannels; uint8le color; char name[25]; }; MPT_BINARY_STRUCT(PLMPatternHeader, 32) struct PLMOrderItem { uint16le x; // Starting position of pattern uint8le y; // Number of first channel uint8le pattern; }; MPT_BINARY_STRUCT(PLMOrderItem, 4) static bool ValidateHeader(const PLMFileHeader &fileHeader) { if(std::memcmp(fileHeader.magic, "PLM\x1A", 4) || fileHeader.version != 0x10 || fileHeader.numChannels == 0 || fileHeader.numChannels > 32 || fileHeader.headerSize < sizeof(PLMFileHeader) ) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const PLMFileHeader &fileHeader) { return fileHeader.headerSize - sizeof(PLMFileHeader) + 4 * (fileHeader.numOrders + fileHeader.numPatterns + fileHeader.numSamples); } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPLM(MemoryFileReader file, const uint64 *pfilesize) { PLMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); PLMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } if(!file.Seek(fileHeader.headerSize)) { return false; } InitializeGlobals(MOD_TYPE_PLM, fileHeader.numChannels + 1); // Additional channel for writing pattern breaks m_SongFlags = SONG_ITOLDEFFECTS; m_playBehaviour.set(kApplyOffsetWithoutNote); m_modFormat.formatName = UL_("Disorder Tracker 2"); m_modFormat.type = UL_("plm"); m_modFormat.charset = mpt::Charset::CP437; // Some PLMs use ASCIIZ, some space-padding strings...weird. Oh, and the file browser stops at 0 bytes in the name, the main GUI doesn't. m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songName); m_nSamplePreAmp = fileHeader.amplify; Order().SetDefaultTempoInt(fileHeader.tempo); Order().SetDefaultSpeed(fileHeader.speed); for(CHANNELINDEX chn = 0; chn < fileHeader.numChannels; chn++) { ChnSettings[chn].nPan = fileHeader.panPos[chn] * 0x11; } m_nSamples = fileHeader.numSamples; std::vector order(fileHeader.numOrders); file.ReadVector(order, fileHeader.numOrders); std::vector patternPos, samplePos; file.ReadVector(patternPos, fileHeader.numPatterns); file.ReadVector(samplePos, fileHeader.numSamples); for(SAMPLEINDEX smp = 0; smp < fileHeader.numSamples; smp++) { ModSample &sample = Samples[smp + 1]; sample.Initialize(); PLMSampleHeader sampleHeader; if(samplePos[smp] == 0 || !file.Seek(samplePos[smp]) || !file.ReadStruct(sampleHeader)) continue; m_szNames[smp + 1] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name); sample.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.filename); if(sampleHeader.panning <= 15) { sample.uFlags.set(CHN_PANNING); sample.nPan = sampleHeader.panning * 0x11; } sample.nGlobalVol = std::min(sampleHeader.volume.get(), uint8(64)); sample.nC5Speed = sampleHeader.sampleRate; sample.nLoopStart = sampleHeader.loopStart; sample.nLoopEnd = sampleHeader.loopEnd; sample.nLength = sampleHeader.length; if(sampleHeader.flags & PLMSampleHeader::smp16Bit) { sample.nLoopStart /= 2; sample.nLoopEnd /= 2; sample.nLength /= 2; } if(sample.nLoopEnd > sample.nLoopStart) { sample.uFlags.set(CHN_LOOP); if(sampleHeader.flags & PLMSampleHeader::smpPingPong) sample.uFlags.set(CHN_PINGPONGLOOP); } sample.SanitizeLoops(); if(loadFlags & loadSampleData) { file.Seek(samplePos[smp] + sampleHeader.headerSize); SampleIO( (sampleHeader.flags & PLMSampleHeader::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::unsignedPCM) .ReadSample(sample, file); } } if(!(loadFlags & loadPatternData)) { return true; } // PLM is basically one huge continuous pattern, so we split it up into smaller patterns. const ROWINDEX rowsPerPat = 64; uint32 maxPos = 0; static constexpr EffectCommand effTrans[] = { CMD_NONE, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VOLUMESLIDE, CMD_TREMOLO, CMD_VIBRATO, CMD_S3MCMDEX, // Tremolo Waveform CMD_S3MCMDEX, // Vibrato Waveform CMD_TEMPO, CMD_SPEED, CMD_POSITIONJUMP, // Jump to order CMD_POSITIONJUMP, // Break to end of this order CMD_OFFSET, CMD_S3MCMDEX, // GUS Panning CMD_RETRIG, CMD_S3MCMDEX, // Note Delay CMD_S3MCMDEX, // Note Cut CMD_S3MCMDEX, // Pattern Delay CMD_FINEVIBRATO, CMD_VIBRATOVOL, CMD_TONEPORTAVOL, CMD_OFFSETPERCENTAGE, }; Order().clear(); for(const auto &ord : order) { if(ord.pattern >= fileHeader.numPatterns || ord.y > fileHeader.numChannels || !file.Seek(patternPos[ord.pattern])) continue; PLMPatternHeader patHeader; file.ReadStruct(patHeader); if(!patHeader.numRows) continue; static_assert(ORDERINDEX_MAX >= (std::numeric_limits::max() + 255) / rowsPerPat); ORDERINDEX curOrd = static_cast(ord.x / rowsPerPat); ROWINDEX curRow = static_cast(ord.x % rowsPerPat); const CHANNELINDEX numChannels = std::min(patHeader.numChannels.get(), static_cast(fileHeader.numChannels - ord.y)); const uint32 patternEnd = ord.x + patHeader.numRows; maxPos = std::max(maxPos, patternEnd); std::array lastNote; lastNote.fill(NOTE_NONE); for(ROWINDEX r = 0; r < patHeader.numRows; r++, curRow++) { if(curRow >= rowsPerPat) { curRow = 0; curOrd++; } if(curOrd >= Order().size()) { Order().resize(curOrd + 1); Order()[curOrd] = Patterns.InsertAny(rowsPerPat); } PATTERNINDEX pat = Order()[curOrd]; if(!Patterns.IsValidPat(pat)) break; ModCommand *m = Patterns[pat].GetpModCommand(curRow, ord.y); for(CHANNELINDEX c = 0; c < numChannels; c++, m++) { const auto [note, instr, volume, command, param] = file.ReadArray(); if(note > 0 && note < 0x90) lastNote[c] = m->note = static_cast((note >> 4) * 12 + (note & 0x0F) + 12 + NOTE_MIN); else m->note = NOTE_NONE; m->instr = instr; m->volcmd = VOLCMD_VOLUME; if(volume != 0xFF) m->vol = volume; else m->volcmd = VOLCMD_NONE; if(command < std::size(effTrans)) { m->command = effTrans[command]; m->param = param; // Fix some commands switch(command) { case 0x07: // Tremolo waveform m->param = 0x40 | (m->param & 0x03); break; case 0x08: // Vibrato waveform m->param = 0x30 | (m->param & 0x03); break; case 0x0B: // Jump to order if(m->param < order.size()) { uint16 target = order[m->param].x; m->param = static_cast(target / rowsPerPat); ModCommand *mBreak = Patterns[pat].GetpModCommand(curRow, GetNumChannels() - 1); mBreak->command = CMD_PATTERNBREAK; mBreak->param = static_cast(target % rowsPerPat); } break; case 0x0C: // Jump to end of order { m->param = static_cast(patternEnd / rowsPerPat); ModCommand *mBreak = Patterns[pat].GetpModCommand(curRow, GetNumChannels() - 1); mBreak->command = CMD_PATTERNBREAK; mBreak->param = static_cast(patternEnd % rowsPerPat); } break; case 0x0E: // GUS Panning m->param = 0x80 | (m->param & 0x0F); break; case 0x10: // Delay Note m->param = 0xD0 | std::min(m->param, ModCommand::PARAM(0x0F)); break; case 0x11: // Cut Note m->param = 0xC0 | std::min(m->param, ModCommand::PARAM(0x0F)); break; case 0x12: // Pattern Delay m->param = 0xE0 | std::min(m->param, ModCommand::PARAM(0x0F)); break; case 0x04: // Volume Slide case 0x14: // Vibrato + Volume Slide case 0x15: // Tone Portamento + Volume Slide // If both nibbles of a volume slide are set, act as fine volume slide up if((m->param & 0xF0) && (m->param & 0x0F) && (m->param & 0xF0) != 0xF0) { m->param |= 0x0F; } break; case 0x0D: case 0x16: // Offset without note if(m->note == NOTE_NONE) { m->note = lastNote[c]; } break; } } } if(patHeader.numChannels > numChannels) { file.Skip(5 * (patHeader.numChannels - numChannels)); } } } // Module ends with the last row of the last order item ROWINDEX endPatSize = maxPos % rowsPerPat; ORDERINDEX endOrder = static_cast(maxPos / rowsPerPat); if(endPatSize > 0 && Order().IsValidPat(endOrder)) { Patterns[Order()[endOrder]].Resize(endPatSize, false); } // If there are still any non-existent patterns in our order list, insert some blank patterns. PATTERNINDEX blankPat = PATTERNINDEX_INVALID; for(auto &pat : Order()) { if(pat == PATTERNINDEX_INVALID) { if(blankPat == PATTERNINDEX_INVALID) { blankPat = Patterns.InsertAny(rowsPerPat); } pat = blankPat; } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ITTools.h0000644000175000017500000002674114500070502017606 00000000000000/* * ITTools.h * --------- * Purpose: Definition of IT file structures and helper functions * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/base/Endian.hpp" #include "Snd_defs.h" OPENMPT_NAMESPACE_BEGIN struct InstrumentEnvelope; struct ModInstrument; struct ModSample; class CSoundFile; class SampleIO; struct ITFileHeader { // Header Flags enum ITHeaderFlags { useStereoPlayback = 0x01, vol0Optimisations = 0x02, instrumentMode = 0x04, linearSlides = 0x08, itOldEffects = 0x10, itCompatGxx = 0x20, useMIDIPitchController = 0x40, reqEmbeddedMIDIConfig = 0x80, extendedFilterRange = 0x1000, }; // Special Flags enum ITHeaderSpecialFlags { embedSongMessage = 0x01, embedEditHistory = 0x02, embedPatternHighlights = 0x04, embedMIDIConfiguration = 0x08, }; char id[4]; // Magic Bytes (IMPM) char songname[26]; // Song Name, null-terminated (but may also contain nulls) uint8le highlight_minor; // Rows per Beat highlight uint8le highlight_major; // Rows per Measure highlight uint16le ordnum; // Number of Orders uint16le insnum; // Number of Instruments uint16le smpnum; // Number of Samples uint16le patnum; // Number of Patterns uint16le cwtv; // "Made With" Tracker uint16le cmwt; // "Compatible With" Tracker uint16le flags; // Header Flags uint16le special; // Special Flags, for embedding extra information uint8le globalvol; // Global Volume (0...128) uint8le mv; // Master Volume (0...128), referred to as Sample Volume in OpenMPT uint8le speed; // Initial Speed (1...255) uint8le tempo; // Initial Tempo (31...255) uint8le sep; // Pan Separation (0...128) uint8le pwd; // Pitch Wheel Depth uint16le msglength; // Length of Song Message uint32le msgoffset; // Offset of Song Message in File (IT crops message after first null) uint32le reserved; // Some IT versions save an edit timer here. ChibiTracker writes "CHBI" here. OpenMPT and Schism Tracker save extended version information here. uint8le chnpan[64]; // Initial Channel Panning uint8le chnvol[64]; // Initial Channel Volume }; MPT_BINARY_STRUCT(ITFileHeader, 192) struct ITEnvelope { // Envelope Flags enum ITEnvelopeFlags { envEnabled = 0x01, envLoop = 0x02, envSustain = 0x04, envCarry = 0x08, envFilter = 0x80, }; struct Node { int8le value; uint16le tick; }; uint8 flags; // Envelope Flags uint8 num; // Number of Envelope Nodes uint8 lpb; // Loop Start uint8 lpe; // Loop End uint8 slb; // Sustain Start uint8 sle; // Sustain End Node data[25]; // Envelope Node Positions / Values uint8 reserved; // Reserved // Convert OpenMPT's internal envelope format to an IT/MPTM envelope. void ConvertToIT(const InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 envDefault); // Convert IT/MPTM envelope data into OpenMPT's internal envelope format - To be used by ITInstrToMPT() void ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 maxNodes) const; }; MPT_BINARY_STRUCT(ITEnvelope::Node, 3) MPT_BINARY_STRUCT(ITEnvelope, 82) // Old Impulse Instrument Format (cmwt < 0x200) struct ITOldInstrument { enum ITOldInstrFlags { envEnabled = 0x01, envLoop = 0x02, envSustain = 0x04, }; char id[4]; // Magic Bytes (IMPI) char filename[13]; // DOS Filename, null-terminated uint8le flags; // Volume Envelope Flags uint8le vls; // Envelope Loop Start uint8le vle; // Envelope Loop End uint8le sls; // Envelope Sustain Start uint8le sle; // Envelope Sustain End char reserved1[2]; // Reserved uint16le fadeout; // Instrument Fadeout (0...128) uint8le nna; // New Note Action uint8le dnc; // Duplicate Note Check Type uint16le trkvers; // Tracker ID uint8le nos; // Number of embedded samples char reserved2; // Reserved char name[26]; // Instrument Name, null-terminated (but may also contain nulls) char reserved3[6]; // Even more reserved bytes uint8le keyboard[240]; // Sample / Transpose map uint8le volenv[200]; // This appears to be a pre-computed (interpolated) version of the volume envelope data found below. uint8le nodes[25 * 2]; // Volume Envelope Node Positions / Values // Convert an ITOldInstrument to OpenMPT's internal instrument representation. void ConvertToMPT(ModInstrument &mptIns) const; }; MPT_BINARY_STRUCT(ITOldInstrument, 554) // Impulse Instrument Format struct ITInstrument { enum ITInstrumentFlags : uint8 { ignorePanning = 0x80, enableCutoff = 0x80, enableResonance = 0x80, }; char id[4]; // Magic Bytes (IMPI) char filename[13]; // DOS Filename, null-terminated uint8le nna; // New Note Action uint8le dct; // Duplicate Note Check Type uint8le dca; // Duplicate Note Check Action uint16le fadeout; // Instrument Fadeout (0...256, although values up to 1024 would be sensible. Up to IT2.07, the limit was 0...128) int8le pps; // Pitch/Pan Separatation uint8le ppc; // Pitch/Pan Centre uint8le gbv; // Global Volume uint8le dfp; // Panning uint8le rv; // Vol Swing uint8le rp; // Pan Swing uint16le trkvers; // Tracker ID uint8le nos; // Number of embedded samples char reserved1; // Reserved char name[26]; // Instrument Name, null-terminated (but may also contain nulls) uint8le ifc; // Filter Cutoff uint8le ifr; // Filter Resonance uint8le mch; // MIDI Channel uint8le mpr; // MIDI Program uint8le mbank[2]; // MIDI Bank uint8le keyboard[240]; // Sample / Transpose map ITEnvelope volenv; // Volume Envelope ITEnvelope panenv; // Pan Envelope ITEnvelope pitchenv; // Pitch / Filter Envelope char dummy[4]; // IT saves some additional padding bytes to match the size of the old instrument format for simplified loading. We use them for some hacks. // Convert OpenMPT's internal instrument representation to an ITInstrument. Returns amount of bytes that need to be written. uint32 ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile); // Convert an ITInstrument to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read. uint32 ConvertToMPT(ModInstrument &mptIns, MODTYPE fromType) const; }; MPT_BINARY_STRUCT(ITInstrument, 554) // MPT IT Instrument Extension struct ITInstrumentEx { ITInstrument iti; // Normal IT Instrument uint8 keyboardhi[120]; // High Byte of Sample map // Convert OpenMPT's internal instrument representation to an ITInstrumentEx. Returns amount of bytes that need to be written. uint32 ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile); // Convert an ITInstrumentEx to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read. uint32 ConvertToMPT(ModInstrument &mptIns, MODTYPE fromType) const; }; MPT_BINARY_STRUCT(ITInstrumentEx, sizeof(ITInstrument) + 120) // IT Sample Format struct ITSample { enum ITSampleFlags : uint8 { sampleDataPresent = 0x01, sample16Bit = 0x02, sampleStereo = 0x04, sampleCompressed = 0x08, sampleLoop = 0x10, sampleSustain = 0x20, sampleBidiLoop = 0x40, sampleBidiSustain = 0x80, enablePanning = 0x80, cvtSignedSample = 0x01, cvtOPLInstrument = 0x40, // FM instrument in MPTM cvtExternalSample = 0x80, // Keep MPTM sample on disk cvtADPCMSample = 0xFF, // MODPlugin :( // ITTECH.TXT says these convert flags are "safe to ignore". IT doesn't ignore them, though, so why should we? :) cvtBigEndian = 0x02, cvtDelta = 0x04, cvtPTM8to16 = 0x08, }; char id[4]; // Magic Bytes (IMPS) char filename[13]; // DOS Filename, null-terminated uint8le gvl; // Global Volume uint8le flags; // Sample Flags uint8le vol; // Default Volume char name[26]; // Sample Name, null-terminated (but may also contain nulls) uint8le cvt; // Sample Import Format uint8le dfp; // Sample Panning uint32le length; // Sample Length (in samples) uint32le loopbegin; // Sample Loop Begin (in samples) uint32le loopend; // Sample Loop End (in samples) uint32le C5Speed; // C-5 frequency uint32le susloopbegin; // Sample Sustain Begin (in samples) uint32le susloopend; // Sample Sustain End (in samples) uint32le samplepointer; // Pointer to sample data uint8le vis; // Auto-Vibrato Rate (called Sweep in IT) uint8le vid; // Auto-Vibrato Depth uint8le vir; // Auto-Vibrato Sweep (called Rate in IT) uint8le vit; // Auto-Vibrato Type // Convert OpenMPT's internal sample representation to an ITSample. void ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compress, bool compressIT215, bool allowExternal); // Convert an ITSample to OpenMPT's internal sample representation. uint32 ConvertToMPT(ModSample &mptSmp) const; // Retrieve the internal sample format flags for this instrument. SampleIO GetSampleFormat(uint16 cwtv = 0x214) const; }; MPT_BINARY_STRUCT(ITSample, 80) struct FileHistory; // IT Header extension: Save history struct ITHistoryStruct { uint16le fatdate; // DOS / FAT date when the file was opened / created in the editor. For details, read https://docs.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-dosdatetimetofiletime uint16le fattime; // DOS / FAT time when the file was opened / created in the editor. uint32le runtime; // The time how long the file was open in the editor, in 1/18.2th seconds. (= ticks of the DOS timer) // Convert an ITHistoryStruct to OpenMPT's internal edit history representation void ConvertToMPT(FileHistory &mptHistory) const; // Convert OpenMPT's internal edit history representation to an ITHistoryStruct void ConvertToIT(const FileHistory &mptHistory); }; MPT_BINARY_STRUCT(ITHistoryStruct, 8) enum IT_ReaderBitMasks { // pattern row parsing, the channel data is read to obtain // number of channels active in the pattern. These bit masks are // to blank out sections of the byte of data being read. IT_bitmask_patternChanField_c = 0x7f, IT_bitmask_patternChanMask_c = 0x3f, IT_bitmask_patternChanEnabled_c = 0x80, IT_bitmask_patternChanUsed_c = 0x0f }; // Calculate Schism Tracker version field for IT / S3M header based on specified release date // Date calculation derived from https://alcor.concordia.ca/~gpkatch/gdate-algorithm.html template struct SchismVersionFromDate { private: static constexpr int32 mm = (m + 9) % 12; static constexpr int32 yy = y - mm / 10; public: static constexpr int32 date = yy * 365 + yy / 4 - yy / 100 + yy / 400 + (mm * 306 + 5) / 10 + (d - 1); }; inline constexpr int32 SchismTrackerEpoch = SchismVersionFromDate<2009, 10, 31>::date; uint32 DecodeITEditTimer(uint16 cwtv, uint32 editTime); OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ModSample.cpp0000644000175000017500000004231314717445260020477 00000000000000/* * ModSample.h * ----------- * Purpose: Module Sample header class and helpers * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "ModSample.h" #include "AudioCriticalSection.h" #include "modsmp_ctrl.h" #include "Sndfile.h" #include "mpt/base/numbers.hpp" #include OPENMPT_NAMESPACE_BEGIN // Translate sample properties between two given formats. void ModSample::Convert(MODTYPE fromType, MODTYPE toType) { uFlags.reset(CHN_REVERSE); // Not supported by any native formats yet // Convert between frequency and transpose values if necessary. if((!(toType & (MOD_TYPE_MOD | MOD_TYPE_XM))) && (fromType & (MOD_TYPE_MOD | MOD_TYPE_XM))) { TransposeToFrequency(); RelativeTone = 0; nFineTune = 0; // TransposeToFrequency assumes NTSC middle-C frequency like FT2, but we play MODs with PAL middle-C! if(fromType == MOD_TYPE_MOD) nC5Speed = Util::muldivr_unsigned(nC5Speed, 8287, 8363); } else if((toType & (MOD_TYPE_MOD | MOD_TYPE_XM)) && (!(fromType & (MOD_TYPE_MOD | MOD_TYPE_XM)))) { // FrequencyToTranspose assumes NTSC middle-C frequency like FT2, but we play MODs with PAL middle-C! if(toType == MOD_TYPE_MOD) nC5Speed = Util::muldivr_unsigned(nC5Speed, 8363, 8287); FrequencyToTranspose(); } if(toType == MOD_TYPE_MOD) { if(RelativeTone == -1 && nFineTune == 0) nFineTune = -128; RelativeTone = 0; nFineTune &= ~0x0F; } // No ping-pong loop, panning and auto-vibrato for MOD / S3M samples if(toType & (MOD_TYPE_MOD | MOD_TYPE_S3M)) { uFlags.reset(CHN_PINGPONGLOOP | CHN_PANNING); nVibDepth = 0; nVibRate = 0; nVibSweep = 0; nVibType = VIB_SINE; } // No global volume / sustain loops for MOD/S3M/XM if(toType & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_S3M)) { nGlobalVol = 64; // Sustain loops - convert to normal loops if(uFlags[CHN_SUSTAINLOOP]) { // We probably overwrite a normal loop here, but since sustain loops are evaluated before normal loops, this is just correct. nLoopStart = nSustainStart; nLoopEnd = nSustainEnd; uFlags.set(CHN_LOOP); uFlags.set(CHN_PINGPONGLOOP, uFlags[CHN_PINGPONGSUSTAIN]); } nSustainStart = nSustainEnd = 0; uFlags.reset(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN); } // All XM samples have default panning, and XM's autovibrato settings are rather limited. if(toType & MOD_TYPE_XM) { if(!uFlags[CHN_PANNING]) { uFlags.set(CHN_PANNING); nPan = 128; } LimitMax(nVibDepth, uint8(15)); LimitMax(nVibRate, uint8(63)); } // Autovibrato sweep setting is inverse in XM (0 = "no sweep") and IT (0 = "no vibrato") if(((fromType & MOD_TYPE_XM) && (toType & (MOD_TYPE_IT | MOD_TYPE_MPT))) || ((toType & MOD_TYPE_XM) && (fromType & (MOD_TYPE_IT | MOD_TYPE_MPT)))) { if(nVibRate != 0 && nVibDepth != 0) { if(nVibSweep != 0) nVibSweep = mpt::saturate_cast(Util::muldivr_unsigned(nVibDepth, 256, nVibSweep)); else nVibSweep = 255; } } // Convert incompatible autovibrato types if(toType == MOD_TYPE_IT && nVibType == VIB_RAMP_UP) { nVibType = VIB_RAMP_DOWN; } else if(toType == MOD_TYPE_XM && nVibType == VIB_RANDOM) { nVibType = VIB_SINE; } // No external samples in formats other than MPTM. if(toType != MOD_TYPE_MPT) { uFlags.reset(SMP_KEEPONDISK); } // No Adlib instruments in formats that can't handle it. if(!CSoundFile::SupportsOPL(toType) && uFlags[CHN_ADLIB]) { SetAdlib(false); } else if(toType == MOD_TYPE_S3M && uFlags[CHN_ADLIB]) { // No support for OPL3 waveforms in S3M adlib[8] &= 0x03; adlib[9] &= 0x03; } } // Initialize sample slot with default values. void ModSample::Initialize(MODTYPE type) { FreeSample(); nLength = 0; nLoopStart = nLoopEnd = 0; nSustainStart = nSustainEnd = 0; nC5Speed = 8363; nPan = 128; nVolume = 256; nGlobalVol = 64; uFlags.reset(CHN_PANNING | CHN_SUSTAINLOOP | CHN_LOOP | CHN_PINGPONGLOOP | CHN_PINGPONGSUSTAIN | CHN_REVERSE | CHN_ADLIB | SMP_MODIFIED | SMP_KEEPONDISK); if(type == MOD_TYPE_XM) { uFlags.set(CHN_PANNING); } RelativeTone = 0; nFineTune = 0; nVibType = VIB_SINE; nVibSweep = 0; nVibDepth = 0; nVibRate = 0; rootNote = 0; filename = ""; if(type & (MOD_TYPE_DBM | MOD_TYPE_IMF | MOD_TYPE_MED)) { for(SmpLength i = 1; i < 10; i++) { cues[i - 1] = Util::muldiv_unsigned(i, 255 * 256, 9); } } else { RemoveAllCuePoints(); } } // Returns sample rate of the sample. uint32 ModSample::GetSampleRate(const MODTYPE type) const { uint32 rate; if(CSoundFile::UseFinetuneAndTranspose(type)) rate = TransposeToFrequency(RelativeTone, nFineTune); else rate = nC5Speed; // TransposeToFrequency assumes NTSC middle-C frequency like FT2, but we play MODs with PAL middle-C! if(type == MOD_TYPE_MOD) rate = Util::muldivr_unsigned(rate, 8287, 8363); return (rate > 0) ? rate : 8363; } // Copies sample data from another sample slot and ensures that the 16-bit/stereo flags are set accordingly. bool ModSample::CopyWaveform(const ModSample &smpFrom) { if(!smpFrom.HasSampleData()) return false; // If we duplicate a sample slot, avoid deleting the sample we just copy from if(smpFrom.sampleb() == sampleb()) pData.pSample = nullptr; LimitMax(nLength, smpFrom.nLength); uFlags.set(CHN_16BIT, smpFrom.uFlags[CHN_16BIT]); uFlags.set(CHN_STEREO, smpFrom.uFlags[CHN_STEREO]); if(AllocateSample()) { memcpy(sampleb(), smpFrom.sampleb(), GetSampleSizeInBytes()); return true; } return false; } // Replace waveform with given data, keeping the currently chosen format of the sample slot. void ModSample::ReplaceWaveform(void *newWaveform, const SmpLength newLength, CSoundFile &sndFile) { auto oldWaveform = samplev(); FlagSet setFlags, resetFlags; setFlags.set(CHN_16BIT, uFlags[CHN_16BIT]); resetFlags.set(CHN_16BIT, !uFlags[CHN_16BIT]); setFlags.set(CHN_STEREO, uFlags[CHN_STEREO]); resetFlags.set(CHN_STEREO, !uFlags[CHN_STEREO]); CriticalSection cs; ctrlChn::ReplaceSample(sndFile, *this, newWaveform, newLength, setFlags, resetFlags); pData.pSample = newWaveform; nLength = newLength; FreeSample(oldWaveform); } // Allocate sample based on a ModSample's properties. // Returns number of bytes allocated, 0 on failure. size_t ModSample::AllocateSample() { FreeSample(); if((pData.pSample = AllocateSample(nLength, GetBytesPerSample())) == nullptr) { return 0; } else { return GetSampleSizeInBytes(); } } // Allocate sample memory. On success, a pointer to the silenced sample buffer is returned. On failure, nullptr is returned. // numFrames must contain the sample length, bytesPerSample the size of a sampling point multiplied with the number of channels. void *ModSample::AllocateSample(SmpLength numFrames, size_t bytesPerSample) { const size_t allocSize = GetRealSampleBufferSize(numFrames, bytesPerSample); if(allocSize != 0) { char *p = new(std::nothrow) char[allocSize]; if(p != nullptr) { memset(p, 0, allocSize); return p + (InterpolationLookaheadBufferSize * MaxSamplingPointSize); } } return nullptr; } // Compute sample buffer size in bytes, including any overhead introduced by pre-computed loops and such. Returns 0 if sample is too big. size_t ModSample::GetRealSampleBufferSize(SmpLength numSamples, size_t bytesPerSample) { // Number of required lookahead samples: // * 1x InterpolationMaxLookahead samples before the actual sample start. This is set to MaxSamplingPointSize due to the way AllocateSample/FreeSample currently work. // * 1x InterpolationMaxLookahead samples of silence after the sample end (if normal loop end == sample end, this can be optimized out). // * 2x InterpolationMaxLookahead before the loop point (because we start at InterpolationMaxLookahead before the loop point and will look backwards from there as well) // * 2x InterpolationMaxLookahead after the loop point (for wrap-around) // * 4x InterpolationMaxLookahead for the sustain loop (same as the two points above) const SmpLength maxSize = Util::MaxValueOfType(numSamples); const SmpLength lookaheadBufferSize = (MaxSamplingPointSize + 1 + 4 + 4) * InterpolationLookaheadBufferSize; if(numSamples == 0 || numSamples > MAX_SAMPLE_LENGTH || lookaheadBufferSize > maxSize - numSamples) { return 0; } numSamples += lookaheadBufferSize; if(maxSize / bytesPerSample < numSamples) { return 0; } return numSamples * bytesPerSample; } void ModSample::FreeSample() { FreeSample(pData.pSample); pData.pSample = nullptr; } void ModSample::FreeSample(void *samplePtr) { if(samplePtr) { delete[](((char *)samplePtr) - (InterpolationLookaheadBufferSize * MaxSamplingPointSize)); } } // Set loop points and update loop wrap-around buffer void ModSample::SetLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile) { nLoopStart = start; nLoopEnd = end; LimitMax(nLoopEnd, nLength); if(nLoopStart < nLoopEnd) { uFlags.set(CHN_LOOP, enable); uFlags.set(CHN_PINGPONGLOOP, pingpong && enable); } else { nLoopStart = nLoopEnd = 0; uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP); } PrecomputeLoops(sndFile, true); } // Set sustain loop points and update loop wrap-around buffer void ModSample::SetSustainLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile) { nSustainStart = start; nSustainEnd = end; LimitMax(nLoopEnd, nLength); if(nSustainStart < nSustainEnd) { uFlags.set(CHN_SUSTAINLOOP, enable); uFlags.set(CHN_PINGPONGSUSTAIN, pingpong && enable); } else { nSustainStart = nSustainEnd = 0; uFlags.reset(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN); } PrecomputeLoops(sndFile, true); } namespace // Unnamed namespace for local implementation functions. { template class PrecomputeLoop { protected: T *target; const T *sampleData; SmpLength loopEnd; int numChannels; bool pingpong; bool ITPingPongMode; public: PrecomputeLoop(T *target, const T *sampleData, SmpLength loopEnd, int numChannels, bool pingpong, bool ITPingPongMode) : target(target), sampleData(sampleData), loopEnd(loopEnd), numChannels(numChannels), pingpong(pingpong), ITPingPongMode(ITPingPongMode) { if(loopEnd > 0) { CopyLoop(true); CopyLoop(false); } } void CopyLoop(bool direction) const { // Direction: true = start reading and writing forward, false = start reading and writing backward (write direction never changes) const int numSamples = 2 * InterpolationLookaheadBufferSize + (direction ? 1 : 0); // Loop point is included in forward loop expansion T *dest = target + numChannels * (2 * InterpolationLookaheadBufferSize - 1); // Write buffer offset SmpLength readPosition = loopEnd - 1; const int writeIncrement = direction ? 1 : -1; int readIncrement = writeIncrement; for(int i = 0; i < numSamples; i++) { // Copy sample over to lookahead buffer for(int c = 0; c < numChannels; c++) { dest[c] = sampleData[readPosition * numChannels + c]; } dest += writeIncrement * numChannels; if(readPosition == loopEnd - 1 && readIncrement > 0) { // Reached end of loop while going forward if(pingpong) { readIncrement = -1; if(ITPingPongMode && readPosition > 0) { readPosition--; } } else { readPosition = 0; } } else if(readPosition == 0 && readIncrement < 0) { // Reached start of loop while going backward if(pingpong) { readIncrement = 1; } else { readPosition = loopEnd - 1; } } else { readPosition += readIncrement; } } } }; template void PrecomputeLoopsImpl(ModSample &smp, const CSoundFile &sndFile) { const int numChannels = smp.GetNumChannels(); const int copySamples = numChannels * InterpolationLookaheadBufferSize; T *sampleData = static_cast(smp.samplev()); T *afterSampleStart = sampleData + smp.nLength * numChannels; T *loopLookAheadStart = afterSampleStart + copySamples; T *sustainLookAheadStart = loopLookAheadStart + 4 * copySamples; // Hold sample on the same level as the last sampling point at the end to prevent extra pops with interpolation. // Do the same at the sample start, too. for(int i = 0; i < (int)InterpolationLookaheadBufferSize; i++) { for(int c = 0; c < numChannels; c++) { afterSampleStart[i * numChannels + c] = afterSampleStart[-numChannels + c]; sampleData[-(i + 1) * numChannels + c] = sampleData[c]; } } if(smp.uFlags[CHN_LOOP]) { PrecomputeLoop(loopLookAheadStart, sampleData + smp.nLoopStart * numChannels, smp.nLoopEnd - smp.nLoopStart, numChannels, smp.uFlags[CHN_PINGPONGLOOP], sndFile.m_playBehaviour[kITPingPongMode]); } if(smp.uFlags[CHN_SUSTAINLOOP]) { PrecomputeLoop(sustainLookAheadStart, sampleData + smp.nSustainStart * numChannels, smp.nSustainEnd - smp.nSustainStart, numChannels, smp.uFlags[CHN_PINGPONGSUSTAIN], sndFile.m_playBehaviour[kITPingPongMode]); } } } // unnamed namespace void ModSample::PrecomputeLoops(CSoundFile &sndFile, bool updateChannels) { if(!HasSampleData()) return; SanitizeLoops(); // Update channels with possibly changed loop values if(updateChannels) { UpdateLoopPointsInActiveChannels(sndFile); } if(GetElementarySampleSize() == 2) PrecomputeLoopsImpl(*this, sndFile); else if(GetElementarySampleSize() == 1) PrecomputeLoopsImpl(*this, sndFile); } // Propagate loop point changes to player bool ModSample::UpdateLoopPointsInActiveChannels(CSoundFile &sndFile) { if(!HasSampleData()) return false; CriticalSection cs; // Update channels with new loop values for(auto &chn : sndFile.m_PlayState.Chn) { if(chn.pModSample != this || chn.nLength == 0) continue; bool looped = false, bidi = false; if(nSustainStart < nSustainEnd && nSustainEnd <= nLength && uFlags[CHN_SUSTAINLOOP] && !chn.dwFlags[CHN_KEYOFF]) { // Sustain loop is active chn.nLoopStart = nSustainStart; chn.nLoopEnd = nSustainEnd; chn.nLength = nSustainEnd; looped = true; bidi = uFlags[CHN_PINGPONGSUSTAIN]; } else if(nLoopStart < nLoopEnd && nLoopEnd <= nLength && uFlags[CHN_LOOP]) { // Normal loop is active chn.nLoopStart = nLoopStart; chn.nLoopEnd = nLoopEnd; chn.nLength = nLoopEnd; looped = true; bidi = uFlags[CHN_PINGPONGLOOP]; } chn.dwFlags.set(CHN_LOOP, looped); chn.dwFlags.set(CHN_PINGPONGLOOP, looped && bidi); if(chn.position.GetUInt() > chn.nLength) { chn.position.Set(chn.nLoopStart); chn.dwFlags.reset(CHN_PINGPONGFLAG); } if(!bidi) { chn.dwFlags.reset(CHN_PINGPONGFLAG); } if(!looped) { chn.nLength = nLength; } } return true; } // Remove loop points if they're invalid. void ModSample::SanitizeLoops() { LimitMax(nSustainEnd, nLength); LimitMax(nLoopEnd, nLength); if(nSustainStart >= nSustainEnd) { nSustainStart = nSustainEnd = 0; uFlags.reset(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN); } if(nLoopStart >= nLoopEnd) { nLoopStart = nLoopEnd = 0; uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP); } } ///////////////////////////////////////////////////////////// // Transpose <-> Frequency conversions uint32 ModSample::TransposeToFrequency(int transpose, int finetune) { return mpt::saturate_round(std::pow(2.0, (transpose * 128.0 + finetune) * (1.0 / (12.0 * 128.0))) * 8363.0); } void ModSample::TransposeToFrequency() { nC5Speed = TransposeToFrequency(RelativeTone, nFineTune); } // Return a pair of {transpose, finetune} std::pair ModSample::FrequencyToTranspose(uint32 freq) { if(!freq) return {}; const auto f2t = mpt::saturate_round(std::log(freq * (1.0 / 8363.0)) * (12.0 * 128.0 * (1.0 / mpt::numbers::ln2))); const auto fine = std::div(Clamp(f2t, -16384, 16383), int32(128)); return {static_cast(fine.quot), static_cast(fine.rem)}; } void ModSample::FrequencyToTranspose() { std::tie(RelativeTone, nFineTune) = FrequencyToTranspose(nC5Speed); } // Transpose the sample by amount specified in octaves (i.e. amount=1 transposes one octave up) void ModSample::Transpose(double amount) { nC5Speed = mpt::saturate_round(nC5Speed * std::pow(2.0, amount)); } // Check if the sample has any valid cue points bool ModSample::HasAnyCuePoints() const { if(uFlags[CHN_ADLIB]) return false; for(auto pt : cues) { if(pt < nLength) return true; } return false; } // Check if the sample's cue points are the default cue point set. bool ModSample::HasCustomCuePoints() const { if(uFlags[CHN_ADLIB]) return false; for(SmpLength i = 0; i < std::size(cues); i++) { const SmpLength defaultValue = (i + 1) << 11; if(cues[i] != defaultValue && (cues[i] < nLength || defaultValue < nLength)) return true; } return false; } void ModSample::SetDefaultCuePoints() { // Default cues compatible with old-style volume column offset for(int i = 0; i < 9; i++) { cues[i] = (i + 1) << 11; } } void ModSample::Set16BitCuePoints() { // Cue points that are useful for extending regular offset command for(int i = 0; i < 9; i++) { cues[i] = (i + 1) << 16; } } void ModSample::RemoveAllCuePoints() { if(!uFlags[CHN_ADLIB]) cues.fill(MAX_SAMPLE_LENGTH); } void ModSample::SetAdlib(bool enable, OPLPatch patch) { if(!enable && uFlags[CHN_ADLIB]) { SetDefaultCuePoints(); } uFlags.set(CHN_ADLIB, enable); if(enable) { // Bogus sample to make playback work uFlags.reset(CHN_16BIT | CHN_STEREO); nLength = 4; AllocateSample(); adlib = patch; } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/OggStream.h0000644000175000017500000000346514353564245020161 00000000000000/* * OggStream.h * ----------- * Purpose: Basic Ogg stream parsing functionality * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/base/Endian.hpp" #include "mpt/io/io.hpp" #include "../common/FileReaderFwd.h" OPENMPT_NAMESPACE_BEGIN namespace Ogg { struct PageHeader { char capture_pattern[4]; // "OggS" uint8le version; uint8le header_type; uint64le granule_position; uint32le bitstream_serial_number; uint32le page_sequence_number; uint32le CRC_checksum; uint8le page_segments; }; MPT_BINARY_STRUCT(PageHeader, 27) struct PageInfo { PageHeader header; uint8 segment_table[255]; PageInfo() { MemsetZero(header); MemsetZero(segment_table); } uint16 GetPagePhysicalSize() const; uint16 GetPageHeaderSize() const; uint16 GetPageDataSize() const; }; // returns false on EOF bool AdvanceToPageMagic(FileCursor &file); bool ReadPage(FileCursor &file, PageInfo &pageInfo, std::vector *pageData = nullptr); bool ReadPage(FileCursor &file, PageInfo &pageInfo, std::vector &pageData); bool ReadPage(FileCursor &file); bool ReadPageAndSkipJunk(FileCursor &file, PageInfo &pageInfo, std::vector &pageData); bool UpdatePageCRC(PageInfo &pageInfo, const std::vector &pageData); template bool WritePage(Tfile & f, const PageInfo &pageInfo, const std::vector &pageData) { if(!mpt::IO::Write(f, pageInfo.header)) { return false; } if(!mpt::IO::WriteRaw(f, pageInfo.segment_table, pageInfo.header.page_segments)) { return false; } if(!mpt::IO::WriteRaw(f, pageData.data(), pageData.size())) { return false; } return true; } } // namespace Ogg OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_mdl.cpp0000644000175000017500000005324614644610543020335 00000000000000/* * Load_mdl.cpp * ------------ * Purpose: Digitrakker (MDL) module loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN // MDL file header struct MDLFileHeader { char id[4]; // "DMDL" uint8 version; }; MPT_BINARY_STRUCT(MDLFileHeader, 5) // RIFF-style Chunk struct MDLChunk { // 16-Bit chunk identifiers enum ChunkIdentifiers { idInfo = MagicLE("IN"), idMessage = MagicLE("ME"), idPats = MagicLE("PA"), idPatNames = MagicLE("PN"), idTracks = MagicLE("TR"), idInstrs = MagicLE("II"), idVolEnvs = MagicLE("VE"), idPanEnvs = MagicLE("PE"), idFreqEnvs = MagicLE("FE"), idSampleInfo = MagicLE("IS"), ifSampleData = MagicLE("SA"), }; uint16le id; uint32le length; size_t GetLength() const { return length; } ChunkIdentifiers GetID() const { return static_cast(id.get()); } }; MPT_BINARY_STRUCT(MDLChunk, 6) struct MDLInfoBlock { char title[32]; char composer[20]; uint16le numOrders; uint16le restartPos; uint8le globalVol; // 1...255 uint8le speed; // 1...255 uint8le tempo; // 4...255 uint8le chnSetup[32]; uint8 GetNumChannels() const { uint8 numChannels = 0; for(uint8 c = 0; c < 32; c++) { if(!(chnSetup[c] & 0x80)) numChannels = c + 1; } return numChannels; } }; MPT_BINARY_STRUCT(MDLInfoBlock, 91) // Sample header in II block struct MDLSampleHeader { uint8le smpNum; uint8le lastNote; uint8le volume; uint8le volEnvFlags; // 6 bits env #, 2 bits flags uint8le panning; uint8le panEnvFlags; uint16le fadeout; uint8le vibSpeed; uint8le vibDepth; uint8le vibSweep; uint8le vibType; uint8le reserved; // zero uint8le freqEnvFlags; }; MPT_BINARY_STRUCT(MDLSampleHeader, 14) struct MDLEnvelope { uint8 envNum; struct { uint8 x; // Delta value from last point, 0 means no more points defined uint8 y; // 0...63 } nodes[15]; uint8 flags; uint8 loop; // Lower 4 bits = start, upper 4 bits = end void ConvertToMPT(InstrumentEnvelope &mptEnv) const { mptEnv.dwFlags.reset(); mptEnv.clear(); mptEnv.reserve(15); int16 tick = -nodes[0].x; for(uint8 n = 0; n < 15; n++) { if(!nodes[n].x) break; tick += nodes[n].x; mptEnv.push_back(EnvelopeNode(tick, std::min(nodes[n].y, uint8(64)))); // actually 0-63 } mptEnv.nLoopStart = (loop & 0x0F); mptEnv.nLoopEnd = (loop >> 4); mptEnv.nSustainStart = mptEnv.nSustainEnd = (flags & 0x0F); if(flags & 0x10) mptEnv.dwFlags.set(ENV_SUSTAIN); if(flags & 0x20) mptEnv.dwFlags.set(ENV_LOOP); } }; MPT_BINARY_STRUCT(MDLEnvelope, 33) struct MDLPatternHeader { uint8le channels; uint8le lastRow; char name[16]; }; MPT_BINARY_STRUCT(MDLPatternHeader, 18) enum { MDLNOTE_NOTE = 1 << 0, MDLNOTE_SAMPLE = 1 << 1, MDLNOTE_VOLUME = 1 << 2, MDLNOTE_EFFECTS = 1 << 3, MDLNOTE_PARAM1 = 1 << 4, MDLNOTE_PARAM2 = 1 << 5, }; static constexpr VibratoType MDLVibratoType[] = { VIB_SINE, VIB_RAMP_DOWN, VIB_SQUARE, VIB_SINE }; static constexpr EffectCommand MDLEffTrans[] = { /* 0 */ CMD_NONE, /* 1st column only */ /* 1 */ CMD_PORTAMENTOUP, /* 2 */ CMD_PORTAMENTODOWN, /* 3 */ CMD_TONEPORTAMENTO, /* 4 */ CMD_VIBRATO, /* 5 */ CMD_ARPEGGIO, /* 6 */ CMD_NONE, /* Either column */ /* 7 */ CMD_TEMPO, /* 8 */ CMD_PANNING8, /* 9 */ CMD_S3MCMDEX, /* A */ CMD_NONE, /* B */ CMD_POSITIONJUMP, /* C */ CMD_GLOBALVOLUME, /* D */ CMD_PATTERNBREAK, /* E */ CMD_S3MCMDEX, /* F */ CMD_SPEED, /* 2nd column only */ /* G */ CMD_VOLUMESLIDE, // up /* H */ CMD_VOLUMESLIDE, // down /* I */ CMD_RETRIG, /* J */ CMD_TREMOLO, /* K */ CMD_TREMOR, /* L */ CMD_NONE, }; // receive an MDL effect, give back a 'normal' one. static std::pair ConvertMDLCommand(const uint8 command, uint8 param) { if(command >= std::size(MDLEffTrans)) return {CMD_NONE, uint8(0)}; EffectCommand cmd = MDLEffTrans[command]; switch(command) { #ifdef MODPLUG_TRACKER case 0x07: // Tempo // MDL supports any nonzero tempo value, but OpenMPT doesn't param = std::max(param, uint8(0x20)); break; #endif // MODPLUG_TRACKER case 0x08: // Panning param = (param & 0x7F) * 2u; break; case 0x09: // Set Envelope (we can only have one envelope per type...) if(param < 0x40) param = 0x78; // Enable the one volume envelope we have else if (param < 0x80) param = 0x7A; // Enable the one panning envelope we have else if(param < 0xC0) param = 0x7C; // Enable the one pitch envelope we have else cmd = CMD_NONE; break; case 0x0C: // Global volume param = static_cast((param + 1) / 2u); break; case 0x0D: // Pattern Break // Convert from BCD param = static_cast(10 * (param >> 4) + (param & 0x0F)); break; case 0x0E: // Special switch(param >> 4) { case 0x0: // unused case 0x3: // unused case 0x8: // Set Samplestatus (loop type) cmd = CMD_NONE; break; case 0x1: // Pan Slide Left cmd = CMD_PANNINGSLIDE; param = (std::min(static_cast(param & 0x0F), uint8(0x0E)) << 4) | 0x0F; break; case 0x2: // Pan Slide Right cmd = CMD_PANNINGSLIDE; param = 0xF0 | std::min(static_cast(param & 0x0F), uint8(0x0E)); break; case 0x4: // Vibrato Waveform param = 0x30 | (param & 0x0F); break; case 0x5: // Set Finetune cmd = CMD_FINETUNE; param = (param << 4) ^ 0x80; break; case 0x6: // Pattern Loop param = 0xB0 | (param & 0x0F); break; case 0x7: // Tremolo Waveform param = 0x40 | (param & 0x0F); break; case 0x9: // Retrig cmd = CMD_RETRIG; param &= 0x0F; break; case 0xA: // Global vol slide up cmd = CMD_GLOBALVOLSLIDE; param = static_cast(0xF0 & (((param & 0x0F) + 1) << 3)); break; case 0xB: // Global vol slide down cmd = CMD_GLOBALVOLSLIDE; param = static_cast(((param & 0x0F) + 1) >> 1); break; case 0xC: // Note cut case 0xD: // Note delay case 0xE: // Pattern delay // Nothing to change here break; case 0xF: // Offset -- further mangled later. cmd = CMD_OFFSET; break; } break; case 0x10: // Volslide up if(param < 0xE0) { // 00...DF regular slide - four times more precise than in XM param >>= 2; if(param > 0x0F) param = 0x0F; param <<= 4; } else if(param < 0xF0) { // E0...EF extra fine slide (on first tick, 4 times finer) param = (((param & 0x0F) << 2) | 0x0F); } else { // F0...FF regular fine slide (on first tick) - like in XM param = ((param << 4) | 0x0F); } break; case 0x11: // Volslide down if(param < 0xE0) { // 00...DF regular slide - four times more precise than in XM param >>= 2; if(param > 0x0F) param = 0x0F; } else if(param < 0xF0) { // E0...EF extra fine slide (on first tick, 4 times finer) param = (((param & 0x0F) >> 2) | 0xF0); } else { // F0...FF regular fine slide (on first tick) - like in XM } break; } return {cmd, param}; } // Returns true if command was lost static bool ImportMDLCommands(ModCommand &m, uint8 vol, uint8 cmd1, uint8 cmd2, uint8 param1, uint8 param2) { // Map second effect values 1-6 to effects G-L if(cmd2 >= 1 && cmd2 <= 6) cmd2 += 15; auto [e1, p1] = ConvertMDLCommand(cmd1, param1); auto [e2, p2] = ConvertMDLCommand(cmd2, param2); /* From the Digitrakker documentation: * EFx -xx - Set Sample Offset This is a double-command. It starts the sample at adress xxx*256. Example: C-5 01 -- EF1 -23 ->starts sample 01 at address 12300 (in hex). Kind of screwy, but I guess it's better than the mess required to do it with IT (which effectively requires 3 rows in order to set the offset past 0xff00). If we had access to the entire track, we *might* be able to shove the high offset SAy into surrounding rows (or 2x MPTM #xx), but it wouldn't always be possible, it'd make the loader a lot uglier, and generally would be more trouble than it'd be worth to implement. What's more is, if there's another effect in the second column, it's ALSO processed in addition to the offset, and the second data byte is shared between the two effects. */ uint32 offset = uint32_max; EffectCommand otherCmd = CMD_NONE; if(e1 == CMD_OFFSET) { // EFy -xx => offset yxx00 offset = ((p1 & 0x0F) << 8) | p2; p1 = (p1 & 0x0F) ? 0xFF : p2; if(e2 == CMD_OFFSET) e2 = CMD_NONE; else otherCmd = e2; } else if (e2 == CMD_OFFSET) { // --- EFy => offset y0000 offset = (p2 & 0x0F) << 8; p2 = (p2 & 0x0F) ? 0xFF : 0; otherCmd = e1; } if(offset != uint32_max && offset > 0xFF && ModCommand::GetEffectWeight(otherCmd) < ModCommand::GetEffectWeight(CMD_OFFSET)) { m.SetEffectCommand(CMD_OFFSET, static_cast(offset & 0xFF)); m.SetVolumeCommand(VOLCMD_OFFSET, static_cast(offset >> 8)); return otherCmd != CMD_NONE || vol != 0; } if(vol) { m.SetVolumeCommand(VOLCMD_VOLUME, static_cast((vol + 2) / 4u)); } // If we have Dxx + G00, or Dxx + H00, combine them into Lxx/Kxx. ModCommand::CombineEffects(e1, p1, e2, p2); // Try to preserve the "best" effect. if(e1 == CMD_NONE || (e1 == e2 && e1 != CMD_S3MCMDEX)) { // Digitrakker processes the effects left-to-right, so if both effects are the same, the // second essentially overrides the first. m.SetEffectCommand(e2, p2); return false; } else if(e2 == CMD_NONE) { m.SetEffectCommand(e1, p1); return false; } else if(!vol) { return m.FillInTwoCommands(e1, p1, e2, p2).first != CMD_NONE; } else { if(ModCommand::GetEffectWeight(e1) > ModCommand::GetEffectWeight(e2)) m.SetEffectCommand(e1, p1); else m.SetEffectCommand(e2, p2); return true; } } static void MDLReadEnvelopes(FileReader file, std::vector &envelopes) { if(!file.CanRead(1)) return; envelopes.resize(64); uint8 numEnvs = file.ReadUint8(); while(numEnvs--) { MDLEnvelope mdlEnv; if(!file.ReadStruct(mdlEnv) || mdlEnv.envNum > 63) continue; envelopes[mdlEnv.envNum] = mdlEnv; } } static void CopyEnvelope(InstrumentEnvelope &mptEnv, uint8 flags, std::vector &envelopes) { uint8 envNum = flags & 0x3F; if(envNum < envelopes.size()) envelopes[envNum].ConvertToMPT(mptEnv); mptEnv.dwFlags.set(ENV_ENABLED, (flags & 0x80) && !mptEnv.empty()); } static uint8 GetMDLPatternChannelCount(FileReader chunk, uint8 numChannels, const uint8 fileVersion) { const uint8 numPats = chunk.ReadUint8(); for(uint8 pat = 0; pat < numPats && numChannels < 32; pat++) { uint8 readChans = 32; if(fileVersion >= 0x10) { MDLPatternHeader patHead; chunk.ReadStruct(patHead); readChans = patHead.channels; } for(uint8 chn = 0; chn < readChans; chn++) { if(chunk.ReadUint16LE() > 0 && chn >= numChannels && chn < 32) numChannels = chn + 1; } } return numChannels; } static bool ValidateHeader(const MDLFileHeader &fileHeader) { if(std::memcmp(fileHeader.id, "DMDL", 4) || fileHeader.version >= 0x20) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize) { MDLFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); MDLFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } ChunkReader chunkFile(file); ChunkReader::ChunkList chunks = chunkFile.ReadChunks(0); // Read global info FileReader chunk = chunks.GetChunk(MDLChunk::idInfo); MDLInfoBlock info; if(!chunk.IsValid() || !chunk.ReadStruct(info)) { return false; } // In case any muted channels contain data, be sure that we import them as well. const uint8 numChannels = std::max(GetMDLPatternChannelCount(chunks.GetChunk(MDLChunk::idPats), info.GetNumChannels(), fileHeader.version), uint8(1)); InitializeGlobals(MOD_TYPE_MDL, numChannels); m_SongFlags = SONG_ITCOMPATGXX; m_playBehaviour.set(kPerChannelGlobalVolSlide); m_playBehaviour.set(kApplyOffsetWithoutNote); m_playBehaviour.reset(kPeriodsAreHertz); m_playBehaviour.reset(kITVibratoTremoloPanbrello); m_playBehaviour.reset(kITSCxStopsSample); // Gate effect in underbeat.mdl m_modFormat.formatName = UL_("Digitrakker"); m_modFormat.type = UL_("mdl"); m_modFormat.madeWithTracker = U_("Digitrakker ") + ( (fileHeader.version == 0x11) ? UL_("3") // really could be 2.99b - close enough : (fileHeader.version == 0x10) ? UL_("2.3") : (fileHeader.version == 0x00) ? UL_("2.0 - 2.2b") // there was no 1.x release : UL_("")); m_modFormat.charset = mpt::Charset::CP437; m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, info.title); m_songArtist = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::spacePadded, info.composer)); m_nDefaultGlobalVolume = info.globalVol + 1; Order().SetDefaultSpeed(Clamp(info.speed, 1, 255)); Order().SetDefaultTempoInt(Clamp(info.tempo, 4, 255)); ReadOrderFromFile(Order(), chunk, info.numOrders); Order().SetRestartPos(info.restartPos); for(CHANNELINDEX c = 0; c < GetNumChannels(); c++) { ChnSettings[c].nPan = (info.chnSetup[c] & 0x7F) * 2u; if(ChnSettings[c].nPan == 254) ChnSettings[c].nPan = 256; if(info.chnSetup[c] & 0x80) ChnSettings[c].dwFlags.set(CHN_MUTE); chunk.ReadString(ChnSettings[c].szName, 8); } // Read song message chunk = chunks.GetChunk(MDLChunk::idMessage); m_songMessage.Read(chunk, chunk.GetLength(), SongMessage::leCR); // Read sample info and data chunk = chunks.GetChunk(MDLChunk::idSampleInfo); if(chunk.IsValid()) { FileReader dataChunk = chunks.GetChunk(MDLChunk::ifSampleData); uint8 numSamples = chunk.ReadUint8(); for(uint8 smp = 0; smp < numSamples; smp++) { const SAMPLEINDEX sampleIndex = chunk.ReadUint8(); if(sampleIndex == 0 || sampleIndex >= MAX_SAMPLES || !chunk.CanRead(32 + 8 + 2 + 12 + 2)) break; if(sampleIndex > GetNumSamples()) m_nSamples = sampleIndex; ModSample &sample = Samples[sampleIndex]; sample.Initialize(); sample.Set16BitCuePoints(); chunk.ReadString(m_szNames[sampleIndex], 32); chunk.ReadString(sample.filename, 8); uint32 c4speed; if(fileHeader.version < 0x10) c4speed = chunk.ReadUint16LE(); else c4speed = chunk.ReadUint32LE(); sample.nC5Speed = c4speed * 2u; sample.nLength = chunk.ReadUint32LE(); sample.nLoopStart = chunk.ReadUint32LE(); sample.nLoopEnd = chunk.ReadUint32LE(); if(sample.nLoopEnd != 0) { sample.uFlags.set(CHN_LOOP); sample.nLoopEnd += sample.nLoopStart; } uint8 volume = chunk.ReadUint8(); if(fileHeader.version < 0x10) sample.nVolume = volume; uint8 flags = chunk.ReadUint8(); if(flags & 0x01) { sample.uFlags.set(CHN_16BIT); sample.nLength /= 2u; sample.nLoopStart /= 2u; sample.nLoopEnd /= 2u; } sample.uFlags.set(CHN_PINGPONGLOOP, (flags & 0x02) != 0); SampleIO sampleIO( (flags & 0x01) ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, (flags & 0x0C) ? SampleIO::MDL : SampleIO::signedPCM); if(loadFlags & loadSampleData) { sampleIO.ReadSample(sample, dataChunk); } } } chunk = chunks.GetChunk(MDLChunk::idInstrs); if(chunk.IsValid()) { std::vector volEnvs, panEnvs, pitchEnvs; MDLReadEnvelopes(chunks.GetChunk(MDLChunk::idVolEnvs), volEnvs); MDLReadEnvelopes(chunks.GetChunk(MDLChunk::idPanEnvs), panEnvs); MDLReadEnvelopes(chunks.GetChunk(MDLChunk::idFreqEnvs), pitchEnvs); uint8 numInstruments = chunk.ReadUint8(); for(uint8 i = 0; i < numInstruments; i++) { const auto [ins, numSamples] = chunk.ReadArray(); uint8 firstNote = 0; ModInstrument *mptIns = nullptr; if(ins == 0 || !chunk.CanRead(32 + sizeof(MDLSampleHeader) * numSamples) || (mptIns = AllocateInstrument(ins)) == nullptr) { chunk.Skip(32 + sizeof(MDLSampleHeader) * numSamples); continue; } chunk.ReadString(mptIns->name, 32); for(uint8 smp = 0; smp < numSamples; smp++) { MDLSampleHeader sampleHeader; chunk.ReadStruct(sampleHeader); if(sampleHeader.smpNum == 0 || sampleHeader.smpNum > GetNumSamples()) continue; LimitMax(sampleHeader.lastNote, static_cast(std::size(mptIns->Keyboard))); for(uint8 n = firstNote; n <= sampleHeader.lastNote; n++) { mptIns->Keyboard[n] = sampleHeader.smpNum; } firstNote = sampleHeader.lastNote + 1; CopyEnvelope(mptIns->VolEnv, sampleHeader.volEnvFlags, volEnvs); CopyEnvelope(mptIns->PanEnv, sampleHeader.panEnvFlags, panEnvs); CopyEnvelope(mptIns->PitchEnv, sampleHeader.freqEnvFlags, pitchEnvs); mptIns->nFadeOut = (sampleHeader.fadeout + 1u) / 2u; #ifdef MODPLUG_TRACKER if((mptIns->VolEnv.dwFlags & (ENV_ENABLED | ENV_LOOP)) == ENV_ENABLED) { // Fade-out is only supposed to happen on key-off, not at the end of a volume envelope. // Fake it by putting a loop at the end. mptIns->VolEnv.nLoopStart = mptIns->VolEnv.nLoopEnd = static_cast(mptIns->VolEnv.size() - 1); mptIns->VolEnv.dwFlags.set(ENV_LOOP); } for(auto &p : mptIns->PitchEnv) { // Scale pitch envelope p.value = (p.value * 6u) / 16u; } #endif // MODPLUG_TRACKER // Samples were already initialized above. Let's hope they are not going to be re-used with different volume / panning / vibrato... ModSample &mptSmp = Samples[sampleHeader.smpNum]; // This flag literally enables and disables the default volume of a sample. If you disable this flag, // the sample volume of a previously sample is re-used, even if you put an instrument number next to the note. if(sampleHeader.volEnvFlags & 0x40) mptSmp.nVolume = sampleHeader.volume; else mptSmp.uFlags.set(SMP_NODEFAULTVOLUME); mptSmp.nPan = std::min(static_cast(sampleHeader.panning * 2), uint16(254)); mptSmp.nVibType = MDLVibratoType[sampleHeader.vibType & 3]; mptSmp.nVibSweep = sampleHeader.vibSweep; mptSmp.nVibDepth = static_cast((sampleHeader.vibDepth + 3u) / 4u); mptSmp.nVibRate = sampleHeader.vibSpeed; // Convert to IT-like vibrato sweep if(mptSmp.nVibSweep != 0) mptSmp.nVibSweep = mpt::saturate_cast(Util::muldivr_unsigned(mptSmp.nVibDepth, 256, mptSmp.nVibSweep)); else mptSmp.nVibSweep = 255; if(sampleHeader.panEnvFlags & 0x40) mptSmp.uFlags.set(CHN_PANNING); } } } // Read pattern tracks std::vector tracks; if((loadFlags & loadPatternData) && (chunk = chunks.GetChunk(MDLChunk::idTracks)).IsValid()) { uint32 numTracks = chunk.ReadUint16LE(); tracks.resize(numTracks + 1); for(uint32 i = 1; i <= numTracks; i++) { tracks[i] = chunk.ReadChunk(chunk.ReadUint16LE()); } } // Read actual patterns if((loadFlags & loadPatternData) && (chunk = chunks.GetChunk(MDLChunk::idPats)).IsValid()) { PATTERNINDEX numPats = chunk.ReadUint8(); Patterns.ResizeArray(numPats); for(PATTERNINDEX pat = 0; pat < numPats; pat++) { CHANNELINDEX numChans = 32; ROWINDEX numRows = 64; std::string name; if(fileHeader.version >= 0x10) { MDLPatternHeader patHead; chunk.ReadStruct(patHead); numChans = patHead.channels; numRows = patHead.lastRow + 1; name = mpt::String::ReadBuf(mpt::String::spacePadded, patHead.name); } if(!Patterns.Insert(pat, numRows)) { chunk.Skip(2 * numChans); continue; } Patterns[pat].SetName(name); for(CHANNELINDEX chn = 0; chn < numChans; chn++) { uint16 trkNum = chunk.ReadUint16LE(); if(!trkNum || trkNum >= tracks.size() || chn >= GetNumChannels()) continue; FileReader &track = tracks[trkNum]; track.Rewind(); ROWINDEX row = 0; while(row < numRows && track.CanRead(1)) { ModCommand *m = Patterns[pat].GetpModCommand(row, chn); uint8 b = track.ReadUint8(); uint8 x = (b >> 2), y = (b & 3); switch(y) { case 0: // (x + 1) empty notes follow row += x + 1; break; case 1: // Repeat previous note (x + 1) times if(row > 0) { ModCommand &orig = *Patterns[pat].GetpModCommand(row - 1, chn); do { *m = orig; m += GetNumChannels(); row++; } while (row < numRows && x--); } break; case 2: // Copy note from row x if(row > x) { *m = *Patterns[pat].GetpModCommand(x, chn); } row++; break; case 3: // New note data if(x & MDLNOTE_NOTE) { b = track.ReadUint8(); m->note = (b > 120) ? static_cast(NOTE_KEYOFF) : static_cast(b); } if(x & MDLNOTE_SAMPLE) { m->instr = track.ReadUint8(); } { uint8 vol = 0, e1 = 0, e2 = 0, p1 = 0, p2 = 0; if(x & MDLNOTE_VOLUME) { vol = track.ReadUint8(); } if(x & MDLNOTE_EFFECTS) { b = track.ReadUint8(); e1 = (b & 0x0F); e2 = (b >> 4); } if(x & MDLNOTE_PARAM1) p1 = track.ReadUint8(); if(x & MDLNOTE_PARAM2) p2 = track.ReadUint8(); ImportMDLCommands(*m, vol, e1, e2, p1, p2); } row++; break; } } } } } if((loadFlags & loadPatternData) && (chunk = chunks.GetChunk(MDLChunk::idPatNames)).IsValid()) { PATTERNINDEX i = 0; while(i < Patterns.Size() && chunk.CanRead(16)) { char name[17]; chunk.ReadString(name, 16); Patterns[i].SetName(name); } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/TinyFFT.cpp0000644000175000017500000000640013575445376020107 00000000000000/* * TinyFFT.cpp * ----------- * Purpose: A simple FFT implementation for power-of-two FFTs * Notes : This is a C++ adaption of Ryuhei Mori's BSD 2-clause licensed TinyFFT * available from https://github.com/ryuhei-mori/tinyfft * Authors: Ryuhei Mori * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "TinyFFT.h" OPENMPT_NAMESPACE_BEGIN void TinyFFT::GenerateTwiddleFactors(uint32 i, uint32 b, std::complex z) { if(b == 0) w[i] = z; else { GenerateTwiddleFactors(i, b >> 1, z); GenerateTwiddleFactors(i | b, b >> 1, z * w[b]); } } TinyFFT::TinyFFT(const uint32 fftSize) : w(std::size_t(1) << (fftSize - 1)) , k(fftSize) { const uint32 m = 1 << k; constexpr double PI2_ = 6.28318530717958647692; const double arg = -PI2_ / m; for(uint32 i = 1, j = m / 4; j; i <<= 1, j >>= 1) { w[i] = std::exp(I * (arg * j)); } GenerateTwiddleFactors(0, m / 4, 1); } uint32 TinyFFT::Size() const noexcept { return 1 << k; } // Computes in-place FFT of size 2^k of A, result is in bit-reversed order. void TinyFFT::FFT(std::vector> &A) const { MPT_ASSERT(A.size() == (std::size_t(1) << k)); const uint32 m = 1 << k; uint32 u = 1; uint32 v = m / 4; if(k & 1) { for(uint32 j = 0; j < m / 2; j++) { auto Ajv = A[j + (m / 2)]; A[j + (m / 2)] = A[j] - Ajv; A[j] += Ajv; } u <<= 1; v >>= 1; } for(uint32 i = k & ~1; i > 0; i -= 2) { for(uint32 jh = 0; jh < u; jh++) { auto wj = w[jh << 1]; auto wj2 = w[jh]; auto wj3 = wj2 * wj; for(uint32 j = jh << i, je = j + v; j < je; j++) { auto tmp0 = A[j]; auto tmp1 = wj * A[j + v]; auto tmp2 = wj2 * A[j + 2 * v]; auto tmp3 = wj3 * A[j + 3 * v]; auto ttmp0 = tmp0 + tmp2; auto ttmp2 = tmp0 - tmp2; auto ttmp1 = tmp1 + tmp3; auto ttmp3 = -I * (tmp1 - tmp3); A[j] = ttmp0 + ttmp1; A[j + v] = ttmp0 - ttmp1; A[j + 2 * v] = ttmp2 + ttmp3; A[j + 3 * v] = ttmp2 - ttmp3; } } u <<= 2; v >>= 2; } } // Computes in-place IFFT of size 2^k of A, input is expected to be in bit-reversed order. void TinyFFT::IFFT(std::vector> &A) const { MPT_ASSERT(A.size() == (std::size_t(1) << k)); const uint32 m = 1 << k; uint32 u = m / 4; uint32 v = 1; for(uint32 i = 2; i <= k; i += 2) { for(uint32 jh = 0; jh < u; jh++) { auto wj = std::conj(w[jh << 1]); auto wj2 = std::conj(w[jh]); auto wj3 = wj2 * wj; for(uint32 j = jh << i, je = j + v; j < je; j++) { auto tmp0 = A[j]; auto tmp1 = A[j + v]; auto tmp2 = A[j + 2 * v]; auto tmp3 = A[j + 3 * v]; auto ttmp0 = tmp0 + tmp1; auto ttmp1 = tmp0 - tmp1; auto ttmp2 = tmp2 + tmp3; auto ttmp3 = I * (tmp2 - tmp3); A[j] = ttmp0 + ttmp2; A[j + v] = wj * (ttmp1 + ttmp3); A[j + 2 * v] = wj2 * (ttmp0 - ttmp2); A[j + 3 * v] = wj3 * (ttmp1 - ttmp3); } } u >>= 2; v <<= 2; } if(k & 1) { for(uint32 j = 0; j < m / 2; j++) { auto Ajv = A[j + (m / 2)]; A[j + (m / 2)] = A[j] - Ajv; A[j] += Ajv; } } } void TinyFFT::Normalize(std::vector> &data) { const double s = static_cast(data.size()); for(auto &v : data) v /= s; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/modsmp_ctrl.cpp0000644000175000017500000002423314731541123021131 00000000000000/* * modsmp_ctrl.cpp * --------------- * Purpose: Basic sample editing code. * Notes : This is a legacy namespace. Some of this stuff is not required in libopenmpt (but stuff in soundlib/ still depends on it). The rest could be merged into struct ModSample. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "modsmp_ctrl.h" #include "AudioCriticalSection.h" #include "Sndfile.h" OPENMPT_NAMESPACE_BEGIN namespace ctrlSmp { template static void ReverseSampleImpl(T *pStart, const SmpLength length) { for(SmpLength i = 0; i < length / 2; i++) { std::swap(pStart[i], pStart[length - 1 - i]); } } // Reverse sample data bool ReverseSample(ModSample &smp, SmpLength start, SmpLength end, CSoundFile &sndFile) { if(!smp.HasSampleData()) return false; if(end == 0 || start > smp.nLength || end > smp.nLength) { start = 0; end = smp.nLength; } if(end - start < 2) return false; static_assert(MaxSamplingPointSize <= 4); if(smp.GetBytesPerSample() == 4) // 16 bit stereo ReverseSampleImpl(static_cast(smp.samplev()) + start, end - start); else if(smp.GetBytesPerSample() == 2) // 16 bit mono / 8 bit stereo ReverseSampleImpl(static_cast(smp.samplev()) + start, end - start); else if(smp.GetBytesPerSample() == 1) // 8 bit mono ReverseSampleImpl(static_cast(smp.samplev()) + start, end - start); else return false; smp.PrecomputeLoops(sndFile, false); return true; } template static void InvertSampleImpl(T *pStart, const SmpLength length) { for(SmpLength i = 0; i < length; i++) { pStart[i] = ~pStart[i]; } } // Invert sample data (flip by 180 degrees) bool InvertSample(ModSample &smp, SmpLength start, SmpLength end, CSoundFile &sndFile) { if(!smp.HasSampleData()) return false; if(end == 0 || start > smp.nLength || end > smp.nLength) { start = 0; end = smp.nLength; } start *= smp.GetNumChannels(); end *= smp.GetNumChannels(); if(smp.GetElementarySampleSize() == 2) InvertSampleImpl(smp.sample16() + start, end - start); else if(smp.GetElementarySampleSize() == 1) InvertSampleImpl(smp.sample8() + start, end - start); else return false; smp.PrecomputeLoops(sndFile, false); return true; } template static void XFadeSampleImpl(const T *srcIn, const T *srcOut, T *output, const SmpLength fadeLength, double e) { const double length = 1.0 / static_cast(fadeLength); for(SmpLength i = 0; i < fadeLength; i++, srcIn++, srcOut++, output++) { double fact1 = std::pow(i * length, e); double fact2 = std::pow((fadeLength - i) * length, e); int32 val = static_cast( static_cast(*srcIn) * fact1 + static_cast(*srcOut) * fact2); *output = mpt::saturate_cast(val); } } // X-Fade sample data to create smooth loop transitions bool XFadeSample(ModSample &smp, SmpLength fadeLength, int fadeLaw, bool afterloopFade, bool useSustainLoop, CSoundFile &sndFile) { if(!smp.HasSampleData()) return false; const auto [loopStart, loopEnd] = useSustainLoop ? smp.GetSustainLoop() : smp.GetLoop(); if(loopEnd <= loopStart || loopEnd > smp.nLength) return false; if(loopStart < fadeLength) return false; const SmpLength start = (loopStart - fadeLength) * smp.GetNumChannels(); const SmpLength end = (loopEnd - fadeLength) * smp.GetNumChannels(); const SmpLength afterloopStart = loopStart * smp.GetNumChannels(); const SmpLength afterloopEnd = loopEnd * smp.GetNumChannels(); const SmpLength afterLoopLength = std::min(smp.nLength - loopEnd, fadeLength) * smp.GetNumChannels(); fadeLength *= smp.GetNumChannels(); // e=0.5: constant power crossfade (for uncorrelated samples), e=1.0: constant volume crossfade (for perfectly correlated samples) const double e = 1.0 - fadeLaw / 200000.0; if(smp.GetElementarySampleSize() == 2) { XFadeSampleImpl(smp.sample16() + start, smp.sample16() + end, smp.sample16() + end, fadeLength, e); if(afterloopFade) XFadeSampleImpl(smp.sample16() + afterloopEnd, smp.sample16() + afterloopStart, smp.sample16() + afterloopEnd, afterLoopLength, e); } else if(smp.GetElementarySampleSize() == 1) { XFadeSampleImpl(smp.sample8() + start, smp.sample8() + end, smp.sample8() + end, fadeLength, e); if(afterloopFade) XFadeSampleImpl(smp.sample8() + afterloopEnd, smp.sample8() + afterloopStart, smp.sample8() + afterloopEnd, afterLoopLength, e); } else return false; smp.PrecomputeLoops(sndFile, true); return true; } template static void ConvertStereoToMonoMixImpl(T *pDest, const SmpLength length) { const T *pEnd = pDest + length; for(T *pSource = pDest; pDest != pEnd; pDest++, pSource += 2) { *pDest = static_cast(mpt::rshift_signed(pSource[0] + pSource[1] + 1, 1)); } } template static void ConvertStereoToMonoOneChannelImpl(T *pDest, const T *pSource, const SmpLength length) { for(const T *pEnd = pDest + length; pDest != pEnd; pDest++, pSource += 2) { *pDest = *pSource; } } // Convert a multichannel sample to mono (currently only implemented for stereo) bool ConvertToMono(ModSample &smp, CSoundFile &sndFile, StereoToMonoMode conversionMode) { if(!smp.HasSampleData() || smp.GetNumChannels() != 2) return false; // Note: Sample is overwritten in-place! Unused data is not deallocated! if(conversionMode == mixChannels) { if(smp.GetElementarySampleSize() == 2) ConvertStereoToMonoMixImpl(smp.sample16(), smp.nLength); else if(smp.GetElementarySampleSize() == 1) ConvertStereoToMonoMixImpl(smp.sample8(), smp.nLength); else return false; } else { if(conversionMode == splitSample) { conversionMode = onlyLeft; } if(smp.GetElementarySampleSize() == 2) ConvertStereoToMonoOneChannelImpl(smp.sample16(), smp.sample16() + (conversionMode == onlyLeft ? 0 : 1), smp.nLength); else if(smp.GetElementarySampleSize() == 1) ConvertStereoToMonoOneChannelImpl(smp.sample8(), smp.sample8() + (conversionMode == onlyLeft ? 0 : 1), smp.nLength); else return false; } CriticalSection cs; smp.uFlags.reset(CHN_STEREO); for(auto &chn : sndFile.m_PlayState.Chn) { if(chn.pModSample == &smp) { chn.dwFlags.reset(CHN_STEREO); } } smp.PrecomputeLoops(sndFile, false); return true; } template static void SplitStereoImpl(void *destL, void *destR, const T *source, SmpLength length) { T *l = static_cast(destL), *r = static_cast(destR); while(length--) { *(l++) = source[0]; *(r++) = source[1]; source += 2; } } // Converts a stereo sample into two mono samples. Source sample will not be deleted. bool SplitStereo(const ModSample &source, ModSample &left, ModSample &right, CSoundFile &sndFile) { if(!source.HasSampleData() || source.GetNumChannels() != 2 || &left == &right) return false; const bool sourceIsLeft = &left == &source, sourceIsRight = &right == &source; if(left.HasSampleData() && !sourceIsLeft) return false; if(right.HasSampleData() && !sourceIsRight) return false; void *leftData = sourceIsLeft ? left.samplev() : ModSample::AllocateSample(source.nLength, source.GetElementarySampleSize()); void *rightData = sourceIsRight ? right.samplev() : ModSample::AllocateSample(source.nLength, source.GetElementarySampleSize()); if(!leftData || !rightData) { if(!sourceIsLeft) ModSample::FreeSample(leftData); if(!sourceIsRight) ModSample::FreeSample(rightData); return false; } if(source.GetElementarySampleSize() == 2) SplitStereoImpl(leftData, rightData, source.sample16(), source.nLength); else if(source.GetElementarySampleSize() == 1) SplitStereoImpl(leftData, rightData, source.sample8(), source.nLength); else MPT_ASSERT_NOTREACHED(); CriticalSection cs; left = source; left.uFlags.reset(CHN_STEREO); left.pData.pSample = leftData; right = source; right.uFlags.reset(CHN_STEREO); right.pData.pSample = rightData; for(auto &chn : sndFile.m_PlayState.Chn) { if(chn.pModSample == &left || chn.pModSample == &right) chn.dwFlags.reset(CHN_STEREO); } left.PrecomputeLoops(sndFile, false); right.PrecomputeLoops(sndFile, false); return true; } template static void ConvertMonoToStereoImpl(const T *MPT_RESTRICT src, T *MPT_RESTRICT dst, SmpLength length) { while(length--) { dst[0] = *src; dst[1] = *src; dst += 2; src++; } } // Convert a multichannel sample to mono (currently only implemented for stereo) bool ConvertToStereo(ModSample &smp, CSoundFile &sndFile) { if(!smp.HasSampleData() || smp.GetNumChannels() != 1) return false; void *newSample = ModSample::AllocateSample(smp.nLength, smp.GetBytesPerSample() * 2); if(newSample == nullptr) { return 0; } if(smp.GetElementarySampleSize() == 2) ConvertMonoToStereoImpl(smp.sample16(), (int16 *)newSample, smp.nLength); else if(smp.GetElementarySampleSize() == 1) ConvertMonoToStereoImpl(smp.sample8(), (int8 *)newSample, smp.nLength); else return false; CriticalSection cs; smp.uFlags.set(CHN_STEREO); smp.ReplaceWaveform(newSample, smp.nLength, sndFile); smp.PrecomputeLoops(sndFile, false); return true; } } // namespace ctrlSmp namespace ctrlChn { void ReplaceSample( CSoundFile &sndFile, const ModSample &sample, const void * const pNewSample, const SmpLength newLength, FlagSet setFlags, FlagSet resetFlags) { const bool periodIsFreq = sndFile.PeriodsAreFrequencies(); for(auto &chn : sndFile.m_PlayState.Chn) { if(chn.pModSample == &sample) { if(chn.pCurrentSample != nullptr) chn.pCurrentSample = pNewSample; if(chn.position.GetUInt() > newLength) chn.position.Set(0); if(chn.nLength > 0) LimitMax(chn.nLength, newLength); if(chn.InSustainLoop()) { chn.nLoopStart = sample.nSustainStart; chn.nLoopEnd = sample.nSustainEnd; } else { chn.nLoopStart = sample.nLoopStart; chn.nLoopEnd = sample.nLoopEnd; } chn.dwFlags.set(setFlags); chn.dwFlags.reset(resetFlags); if(chn.nC5Speed && sample.nC5Speed && !sndFile.UseFinetuneAndTranspose()) { if(periodIsFreq) chn.nPeriod = Util::muldivr_unsigned(chn.nPeriod, sample.nC5Speed, chn.nC5Speed); else chn.nPeriod = Util::muldivr_unsigned(chn.nPeriod, chn.nC5Speed, sample.nC5Speed); } chn.nC5Speed = sample.nC5Speed; } } } } // namespace ctrlChn OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_stm.cpp0000644000175000017500000004267114716466733020376 00000000000000/* * Load_stm.cpp * ------------ * Purpose: STM (Scream Tracker 2) and STX (Scream Tracker Music Interface Kit - a mixture of STM and S3M) module loaders * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "S3MTools.h" OPENMPT_NAMESPACE_BEGIN // STM sample header struct struct STMSampleHeader { char filename[12]; // Can't have long comments - just filename comments :) uint8le zero; uint8le disk; // A blast from the past uint16le offset; // 20-bit offset in file (lower 4 bits are zero) uint16le length; // Sample length uint16le loopStart; // Loop start point uint16le loopEnd; // Loop end point uint8le volume; // Volume uint8le reserved2; uint16le sampleRate; uint8le reserved3[6]; // Convert an STM sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, filename); mptSmp.nC5Speed = sampleRate; mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4; mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; if(mptSmp.nLength < 2) mptSmp.nLength = 0; if(mptSmp.nLoopStart < mptSmp.nLength && mptSmp.nLoopEnd > mptSmp.nLoopStart && mptSmp.nLoopEnd != 0xFFFF) { mptSmp.uFlags = CHN_LOOP; mptSmp.nLength = std::max(mptSmp.nLoopEnd, mptSmp.nLength); // ST2 does not sanitize loop end, allow it to overflow into the next sample's data } } }; MPT_BINARY_STRUCT(STMSampleHeader, 32) // STM file header struct STMFileHeader { char songname[20]; char trackerName[8]; // !Scream! for ST 2.xx uint8 dosEof; // 0x1A uint8 filetype; // 1=song, 2=module (only 2 is supported, of course) :) uint8 verMajor; uint8 verMinor; uint8 initTempo; uint8 numPatterns; uint8 globalVolume; uint8 reserved[13]; bool Validate() const { if(filetype != 2 || (dosEof != 0x1A && dosEof != 2) // ST2 ignores this, ST3 doesn't. Broken versions of putup10.stm / putup11.stm have dosEof = 2. || verMajor != 2 || (verMinor != 0 && verMinor != 10 && verMinor != 20 && verMinor != 21) || numPatterns > 64 || (globalVolume > 64 && globalVolume != 0x58)) // 0x58 may be a placeholder value in earlier ST2 versions. { return false; } return ValidateTrackerName(trackerName); } static bool ValidateTrackerName(const char (&trackerName)[8]) { // Tracker string can be anything really (ST2 and ST3 won't check it), // but we do not want to generate too many false positives here, as // STM already has very few magic bytes anyway. // Magic bytes that have been found in the wild are !Scream!, BMOD2STM, WUZAMOD! and SWavePro. for(uint8 c : trackerName) { if(c < 0x20 || c >= 0x7F) return false; } return true; } uint64 GetHeaderMinimumAdditionalSize() const { return 31 * sizeof(STMSampleHeader) + (verMinor == 0 ? 64 : 128) + numPatterns * 64 * 4; } }; MPT_BINARY_STRUCT(STMFileHeader, 48) static bool ValidateSTMOrderList(ModSequence &order) { for(auto &pat : order) { if(pat == 99 || pat == 255) // 99 is regular, sometimes a single 255 entry can be found too pat = PATTERNINDEX_INVALID; else if(pat > 63) return false; } return true; } static void ConvertSTMCommand(ModCommand &m, const uint8 command, const ROWINDEX row, const uint8 fileVerMinor, uint8 &newTempo, ORDERINDEX &breakPos, ROWINDEX &breakRow) { static constexpr EffectCommand stmEffects[] = { CMD_NONE, CMD_SPEED, CMD_POSITIONJUMP, CMD_PATTERNBREAK, // .ABC CMD_VOLUMESLIDE, CMD_PORTAMENTODOWN, CMD_PORTAMENTOUP, CMD_TONEPORTAMENTO, // DEFG CMD_VIBRATO, CMD_TREMOR, CMD_ARPEGGIO, CMD_NONE, // HIJK CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, // LMNO // KLMNO can be entered in the editor but don't do anything }; m.command = stmEffects[command & 0x0F]; switch(m.command) { case CMD_VOLUMESLIDE: // Lower nibble always has precedence, and there are no fine slides. if(m.param & 0x0F) m.param &= 0x0F; else m.param &= 0xF0; break; case CMD_PATTERNBREAK: m.param = static_cast((m.param & 0xF0) * 10 + (m.param & 0x0F)); if(breakPos != ORDERINDEX_INVALID && m.param == 0) { // Merge Bxx + C00 into just Bxx m.command = CMD_POSITIONJUMP; m.param = static_cast(breakPos); breakPos = ORDERINDEX_INVALID; } LimitMax(breakRow, row); break; case CMD_POSITIONJUMP: // This effect is also very weird. // Bxx doesn't appear to cause an immediate break -- it merely // sets the next order for when the pattern ends (either by // playing it all the way through, or via Cxx effect) breakPos = m.param; breakRow = 63; m.command = CMD_NONE; break; case CMD_TREMOR: // this actually does something with zero values, and has no // effect memory. which makes SENSE for old-effects tremor, // but ST3 went and screwed it all up by adding an effect // memory and IT followed that, and those are much more popular // than STM so we kind of have to live with this effect being // broken... oh well. not a big loss. break; case CMD_SPEED: if(fileVerMinor < 21) m.param = static_cast(((m.param / 10u) << 4u) + m.param % 10u); if(!m.param) { m.command = CMD_NONE; break; } #ifdef MODPLUG_TRACKER // ST2 has a very weird tempo mode where the length of a tick depends both // on the ticks per row and a scaling factor. Try to write the tempo into a separate command. newTempo = m.param; m.param >>= 4; #else MPT_UNREFERENCED_PARAMETER(newTempo); #endif // MODPLUG_TRACKER break; default: // Anything not listed above is a no-op if there's no value, as ST2 doesn't have effect memory. if(!m.param) m.command = CMD_NONE; break; } } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTM(MemoryFileReader file, const uint64 *pfilesize) { STMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.Validate()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); STMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return false; if(!fileHeader.Validate()) return false; if(!file.CanRead(mpt::saturate_cast(fileHeader.GetHeaderMinimumAdditionalSize()))) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_STM, 4); m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songname); m_modFormat.formatName = UL_("Scream Tracker 2"); m_modFormat.type = UL_("stm"); m_modFormat.charset = mpt::Charset::CP437; if(!std::memcmp(fileHeader.trackerName, "!Scream!", 8)) { if(fileHeader.verMinor >= 21) m_modFormat.madeWithTracker = UL_("Scream Tracker 2.2 - 2.3 or compatible"); else m_modFormat.madeWithTracker = MPT_UFORMAT("Scream Tracker {}.{} or compatible")(fileHeader.verMajor, mpt::ufmt::dec0<2>(fileHeader.verMinor)); } else if(!std::memcmp(fileHeader.trackerName, "BMOD2STM", 8)) m_modFormat.madeWithTracker = UL_("BMOD2STM"); else if(!std::memcmp(fileHeader.trackerName, "WUZAMOD!", 8)) m_modFormat.madeWithTracker = UL_("Wuzamod"); else if(!std::memcmp(fileHeader.trackerName, "SWavePro", 8)) m_modFormat.madeWithTracker = UL_("SoundWave Pro"); else m_modFormat.madeWithTracker = UL_("Unknown"); m_playBehaviour.set(kST3SampleSwap); m_nSamples = 31; m_nMinPeriod = 64; m_nMaxPeriod = 0x7FFF; m_playBehaviour.set(kST3SampleSwap); uint8 initTempo = fileHeader.initTempo; if(fileHeader.verMinor < 21) initTempo = static_cast(((initTempo / 10u) << 4u) + initTempo % 10u); if(initTempo == 0) initTempo = 0x60; Order().SetDefaultTempo(ConvertST2Tempo(initTempo)); Order().SetDefaultSpeed(initTempo >> 4); if(fileHeader.verMinor > 10) m_nDefaultGlobalVolume = std::min(fileHeader.globalVolume, uint8(64)) * 4u; // Read samples uint16 sampleOffsets[31]; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { STMSampleHeader sampleHeader; file.ReadStruct(sampleHeader); if(sampleHeader.zero != 0 && sampleHeader.zero != 46) // putup10.stm has zero = 46 return false; sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.filename); sampleOffsets[smp - 1] = sampleHeader.offset; } // Read order list ReadOrderFromFile(Order(), file, fileHeader.verMinor == 0 ? 64 : 128); if(!ValidateSTMOrderList(Order())) return false; if(loadFlags & loadPatternData) Patterns.ResizeArray(fileHeader.numPatterns); for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { for(int i = 0; i < 64 * 4; i++) { uint8 note = file.ReadUint8(); if(note < 0xFB || note > 0xFD) file.Skip(3); } continue; } auto m = Patterns[pat].begin(); ORDERINDEX breakPos = ORDERINDEX_INVALID; ROWINDEX breakRow = 63; // Candidate row for inserting pattern break for(ROWINDEX row = 0; row < 64; row++) { uint8 newTempo = 0; for(CHANNELINDEX chn = 0; chn < 4; chn++, m++) { uint8 note = file.ReadUint8(), insVol, volCmd, cmdInf; switch(note) { case 0xFB: note = insVol = volCmd = cmdInf = 0x00; break; case 0xFC: continue; case 0xFD: m->note = NOTE_NOTECUT; continue; default: { const auto patData = file.ReadArray(); insVol = patData[0]; volCmd = patData[1]; cmdInf = patData[2]; } break; } if(note == 0xFE) m->note = NOTE_NOTECUT; else if(note < 0x60) m->note = static_cast((note >> 4) * 12 + (note & 0x0F) + 36 + NOTE_MIN); m->instr = insVol >> 3; if(m->instr > 31) { m->instr = 0; } uint8 vol = (insVol & 0x07) | ((volCmd & 0xF0) >> 1); if(vol <= 64) { m->volcmd = VOLCMD_VOLUME; m->vol = vol; } m->param = cmdInf; ConvertSTMCommand(*m, volCmd & 0x0F, row, fileHeader.verMinor, newTempo, breakPos, breakRow); } if(newTempo != 0) { Patterns[pat].WriteEffect(EffectWriter(CMD_TEMPO, mpt::saturate_round(ConvertST2Tempo(newTempo).ToDouble())).Row(row).RetryPreviousRow()); } } if(breakPos != ORDERINDEX_INVALID) { Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast(breakPos)).Row(breakRow).RetryPreviousRow()); } } // Reading Samples if(loadFlags & loadSampleData) { const SampleIO sampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM); for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { ModSample &sample = Samples[smp]; // ST2 just plays random noise for samples with a default volume of 0 if(sample.nLength && sample.nVolume > 0) { FileReader::pos_type sampleOffset = sampleOffsets[smp - 1] << 4; // acidlamb.stm has some bogus samples with sample offsets past EOF if(sampleOffset > sizeof(STMFileHeader) && file.Seek(sampleOffset)) { sampleIO.ReadSample(sample, file); } } } } return true; } // STX file header struct STXFileHeader { char songName[20]; char trackerName[8]; // Typically !Scream! but mustn't be relied upon, like for STM uint16le patternSize; // or EOF in newer file version (except for future brain.stx?!) uint16le unknown1; uint16le patTableOffset; uint16le smpTableOffset; uint16le chnTableOffset; uint32le unknown2; uint8 globalVolume; uint8 initTempo; uint32le unknown3; uint16le numPatterns; uint16le numSamples; uint16le numOrders; char unknown4[6]; char magic[4]; bool Validate() const { if(std::memcmp(magic, "SCRM", 4) || (patternSize < 64 && patternSize != 0x1A) || patternSize > 0x840 || (globalVolume > 64 && globalVolume != 0x58) // 0x58 may be a placeholder value in earlier ST2 versions. || numPatterns > 64 || numSamples > 96 // Some STX files have more sample slots than their STM counterpart for mysterious reasons || (numOrders > 0x81 && numOrders != 0x101) || unknown1 != 0 || unknown2 != 0 || unknown3 != 1) { return false; } return STMFileHeader::ValidateTrackerName(trackerName); } uint64 GetHeaderMinimumAdditionalSize() const { return std::max({(patTableOffset << 4) + numPatterns * 2, (smpTableOffset << 4) + numSamples * 2, (chnTableOffset << 4) + 32 + numOrders * 5 }); } }; MPT_BINARY_STRUCT(STXFileHeader, 64) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTX(MemoryFileReader file, const uint64 *pfilesize) { STXFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.Validate()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadSTX(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); STXFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return false; if(!fileHeader.Validate()) return false; if (!file.CanRead(mpt::saturate_cast(fileHeader.GetHeaderMinimumAdditionalSize()))) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_STM, 4); m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songName); m_nSamples = fileHeader.numSamples; m_nMinPeriod = 64; m_nMaxPeriod = 0x7FFF; m_playBehaviour.set(kST3SampleSwap); uint8 initTempo = fileHeader.initTempo; if(initTempo == 0) initTempo = 0x60; Order().SetDefaultTempo(ConvertST2Tempo(initTempo)); Order().SetDefaultSpeed(initTempo >> 4); m_nDefaultGlobalVolume = std::min(fileHeader.globalVolume, uint8(64)) * 4u; std::vector patternOffsets, sampleOffsets; file.Seek(fileHeader.patTableOffset << 4); file.ReadVector(patternOffsets, fileHeader.numPatterns); file.Seek(fileHeader.smpTableOffset << 4); file.ReadVector(sampleOffsets, fileHeader.numSamples); // Read order list file.Seek((fileHeader.chnTableOffset << 4) + 32); Order().resize(fileHeader.numOrders); for(auto &pat : Order()) { pat = file.ReadUint8(); file.Skip(4); } if(!ValidateSTMOrderList(Order())) return false; // Read samples for(SAMPLEINDEX smp = 1; smp <= fileHeader.numSamples; smp++) { if(!file.Seek(sampleOffsets[smp - 1] << 4)) return false; S3MSampleHeader sampleHeader; file.ReadStruct(sampleHeader); sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.filename); const uint32 sampleOffset = sampleHeader.GetSampleOffset(); if((loadFlags & loadSampleData) && sampleHeader.length != 0 && file.Seek(sampleOffset)) { sampleHeader.GetSampleFormat(true).ReadSample(Samples[smp], file); } } // Read patterns uint8 formatVersion = 1; if(!patternOffsets.empty() && fileHeader.patternSize != 0x1A) { if(!file.Seek(patternOffsets.front() << 4)) return false; // First two bytes describe pattern size, like in S3M if(file.ReadUint16LE() == fileHeader.patternSize) formatVersion = 0; } if(loadFlags & loadPatternData) Patterns.ResizeArray(fileHeader.numPatterns); for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) break; if(!file.Seek(patternOffsets[pat] << 4)) return false; if(formatVersion == 0 && file.ReadUint16LE() > 0x840) return false; ORDERINDEX breakPos = ORDERINDEX_INVALID; ROWINDEX breakRow = 63; // Candidate row for inserting pattern break auto rowBase = Patterns[pat].GetRow(0); ROWINDEX row = 0; uint8 newTempo = 0; while(row < 64) { uint8 info = file.ReadUint8(); if(info == s3mEndOfRow) { // End of row if(newTempo != 0) { Patterns[pat].WriteEffect(EffectWriter(CMD_TEMPO, mpt::saturate_round(ConvertST2Tempo(newTempo).ToDouble())).Row(row).RetryPreviousRow()); newTempo = 0; } if(++row < 64) { rowBase = Patterns[pat].GetRow(row); } continue; } CHANNELINDEX channel = (info & s3mChannelMask); ModCommand dummy; ModCommand &m = (channel < GetNumChannels()) ? rowBase[channel] : dummy; if(info & s3mNotePresent) { const auto [note, instr] = file.ReadArray(); if(note < 0xF0) m.note = static_cast(Clamp((note & 0x0F) + 12 * (note >> 4) + 36 + NOTE_MIN, NOTE_MIN, NOTE_MAX)); else if(note == s3mNoteOff) m.note = NOTE_NOTECUT; else if(note == s3mNoteNone) m.note = NOTE_NONE; m.instr = instr; } if(info & s3mVolumePresent) { uint8 volume = file.ReadUint8(); m.volcmd = VOLCMD_VOLUME; m.vol = std::min(volume, uint8(64)); } if(info & s3mEffectPresent) { const auto [command, param] = file.ReadArray(); m.param = param; ConvertSTMCommand(m, command, row, 0xFF, newTempo, breakPos, breakRow); } } if(breakPos != ORDERINDEX_INVALID) { Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast(breakPos)).Row(breakRow).RetryPreviousRow()); } } m_modFormat.formatName = UL_("Scream Tracker Music Interface Kit"); m_modFormat.type = UL_("stx"); m_modFormat.charset = mpt::Charset::CP437; m_modFormat.madeWithTracker = MPT_UFORMAT("STM2STX 1.{}")(formatVersion); return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_it.cpp0000644000175000017500000027152214741767413020203 00000000000000/* * Load_it.cpp * ----------- * Purpose: IT (Impulse Tracker) module loader / saver * Notes : Also handles MPTM loading / saving, as the formats are almost identical. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "tuningcollection.h" #include "mod_specifications.h" #ifdef MODPLUG_TRACKER #include "../mptrack/Moddoc.h" #include "../mptrack/TrackerSettings.h" #endif // MODPLUG_TRACKER #ifdef MPT_EXTERNAL_SAMPLES #include "../common/mptPathString.h" #endif // MPT_EXTERNAL_SAMPLES #include "../common/serialization_utils.h" #ifndef MODPLUG_NO_FILESAVE #include "../common/mptFileIO.h" #endif // MODPLUG_NO_FILESAVE #include "plugins/PlugInterface.h" #include #include "../common/version.h" #include "ITTools.h" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" OPENMPT_NAMESPACE_BEGIN const uint16 verMptFileVer = 0x891; const uint16 verMptFileVerLoadLimit = 0x1000; // If cwtv-field is greater or equal to this value, // the MPTM file will not be loaded. /* MPTM version history for cwtv-field in "IT" header (only for MPTM files!): 0x890(1.18.02.00) -> 0x891(1.19.00.00): Pattern-specific time signatures Fixed behaviour of Pattern Loop command for rows > 255 (r617) 0x88F(1.18.01.00) -> 0x890(1.18.02.00): Removed volume command velocity :xy, added delay-cut command :xy. 0x88E(1.17.02.50) -> 0x88F(1.18.01.00): Numerous changes 0x88D(1.17.02.49) -> 0x88E(1.17.02.50): Changed ID to that of IT and undone the orderlist change done in 0x88A->0x88B. Now extended orderlist is saved as extension. 0x88C(1.17.02.48) -> 0x88D(1.17.02.49): Some tuning related changes - that part fails to read on older versions. 0x88B -> 0x88C: Changed type in which tuning number is printed to file: size_t -> uint16. 0x88A -> 0x88B: Changed order-to-pattern-index table type from uint8-array to vector. */ #ifndef MODPLUG_NO_FILESAVE static bool AreNonDefaultTuningsUsed(const CSoundFile& sf) { const INSTRUMENTINDEX numIns = sf.GetNumInstruments(); for(INSTRUMENTINDEX i = 1; i <= numIns; i++) { if(sf.Instruments[i] != nullptr && sf.Instruments[i]->pTuning != nullptr) return true; } return false; } static void WriteTuningCollection(std::ostream& oStrm, const CTuningCollection& tc) { tc.Serialize(oStrm, U_("Tune specific tunings")); } static void WriteTuningMap(std::ostream& oStrm, const CSoundFile& sf) { if(sf.GetNumInstruments() > 0) { //Writing instrument tuning data: first creating //tuning name <-> tuning id number map, //and then writing the tuning id for every instrument. //For example if there are 6 instruments and //first half use tuning 'T1', and the other half //tuning 'T2', the output would be something like //T1 1 T2 2 1 1 1 2 2 2 //Creating the tuning address <-> tuning id number map. std::map tNameToShort_Map; unsigned short figMap = 0; for(INSTRUMENTINDEX i = 1; i <= sf.GetNumInstruments(); i++) { CTuning *pTuning = nullptr; if(sf.Instruments[i] != nullptr) { pTuning = sf.Instruments[i]->pTuning; } auto iter = tNameToShort_Map.find(pTuning); if(iter != tNameToShort_Map.end()) continue; //Tuning already mapped. tNameToShort_Map[pTuning] = figMap; figMap++; } //...and write the map with tuning names replacing //the addresses. const uint16 tuningMapSize = static_cast(tNameToShort_Map.size()); mpt::IO::WriteIntLE(oStrm, tuningMapSize); for(auto &iter : tNameToShort_Map) { if(iter.first) mpt::IO::WriteSizedStringLE(oStrm, mpt::ToCharset(mpt::Charset::UTF8, iter.first->GetName())); else //Case: Using original IT tuning. mpt::IO::WriteSizedStringLE(oStrm, "->MPT_ORIGINAL_IT<-"); mpt::IO::WriteIntLE(oStrm, iter.second); } //Writing tuning data for instruments. for(INSTRUMENTINDEX i = 1; i <= sf.GetNumInstruments(); i++) { CTuning *pTuning = nullptr; if(sf.Instruments[i] != nullptr) { pTuning = sf.Instruments[i]->pTuning; } auto iter = tNameToShort_Map.find(pTuning); if(iter == tNameToShort_Map.end()) //Should never happen { sf.AddToLog(LogError, U_("Error: 210807_1")); return; } mpt::IO::WriteIntLE(oStrm, iter->second); } } } #endif // MODPLUG_NO_FILESAVE static void ReadTuningCollection(std::istream &iStrm, CTuningCollection &tc, const std::size_t dummy, mpt::Charset defaultCharset) { MPT_UNREFERENCED_PARAMETER(dummy); mpt::ustring name; tc.Deserialize(iStrm, name, defaultCharset); } template static bool ReadTuningMapTemplate(std::istream& iStrm, std::map &shortToTNameMap, mpt::Charset charset, const size_t maxNum = 500) { TUNNUMTYPE numTuning = 0; mpt::IO::ReadIntLE(iStrm, numTuning); if(numTuning > maxNum) return true; for(size_t i = 0; i < numTuning; i++) { std::string temp; uint16 ui = 0; if(!mpt::IO::ReadSizedStringLE(iStrm, temp, 255)) return true; mpt::IO::ReadIntLE(iStrm, ui); shortToTNameMap[ui] = mpt::ToUnicode(charset, temp); } if(iStrm.good()) return false; else return true; } static void ReadTuningMapImpl(std::istream& iStrm, CSoundFile& csf, mpt::Charset charset, const size_t = 0, bool old = false) { std::map shortToTNameMap; if(old) { ReadTuningMapTemplate(iStrm, shortToTNameMap, charset); } else { ReadTuningMapTemplate(iStrm, shortToTNameMap, charset); } // Read & set tunings for instruments std::vector notFoundTunings; for(INSTRUMENTINDEX i = 1; i<=csf.GetNumInstruments(); i++) { uint16 ui = 0; mpt::IO::ReadIntLE(iStrm, ui); auto iter = shortToTNameMap.find(ui); if(csf.Instruments[i] && iter != shortToTNameMap.end()) { const mpt::ustring str = iter->second; if(str == U_("->MPT_ORIGINAL_IT<-")) { csf.Instruments[i]->pTuning = nullptr; continue; } csf.Instruments[i]->pTuning = csf.GetTuneSpecificTunings().GetTuning(str); if(csf.Instruments[i]->pTuning) continue; #ifdef MODPLUG_TRACKER CTuning *localTuning = TrackerSettings::Instance().oldLocalTunings->GetTuning(str); if(localTuning) { std::unique_ptr pNewTuning = std::make_unique(*localTuning); CTuning *pT = csf.GetTuneSpecificTunings().AddTuning(std::move(pNewTuning)); if(pT) { csf.AddToLog(LogInformation, U_("Local tunings are deprecated and no longer supported. Tuning '") + str + U_("' found in Local tunings has been copied to Tune-specific tunings and will be saved in the module file.")); csf.Instruments[i]->pTuning = pT; if(csf.GetpModDoc() != nullptr) { csf.GetpModDoc()->SetModified(); } continue; } else { csf.AddToLog(LogError, U_("Copying Local tuning '") + str + U_("' to Tune-specific tunings failed.")); } } #endif if(str == U_("12TET [[fs15 1.17.02.49]]") || str == U_("12TET")) { std::unique_ptr pNewTuning = csf.CreateTuning12TET(str); CTuning *pT = csf.GetTuneSpecificTunings().AddTuning(std::move(pNewTuning)); if(pT) { #ifdef MODPLUG_TRACKER csf.AddToLog(LogInformation, U_("Built-in tunings will no longer be used. Tuning '") + str + U_("' has been copied to Tune-specific tunings and will be saved in the module file.")); csf.Instruments[i]->pTuning = pT; if(csf.GetpModDoc() != nullptr) { csf.GetpModDoc()->SetModified(); } #endif continue; } else { #ifdef MODPLUG_TRACKER csf.AddToLog(LogError, U_("Copying Built-in tuning '") + str + U_("' to Tune-specific tunings failed.")); #endif } } // Checking if not found tuning already noticed. if(!mpt::contains(notFoundTunings, str)) { notFoundTunings.push_back(str); csf.AddToLog(LogWarning, U_("Tuning '") + str + U_("' used by the module was not found.")); #ifdef MODPLUG_TRACKER if(csf.GetpModDoc() != nullptr) { csf.GetpModDoc()->SetModified(); // The tuning is changed so the modified flag is set. } #endif // MODPLUG_TRACKER } csf.Instruments[i]->pTuning = nullptr; } else { //This 'else' happens probably only in case of corrupted file. if(csf.Instruments[i]) csf.Instruments[i]->pTuning = nullptr; } } //End read&set instrument tunings } static void ReadTuningMap(std::istream& iStrm, CSoundFile& csf, const size_t dummy, mpt::Charset charset) { ReadTuningMapImpl(iStrm, csf, charset, dummy, false); } ////////////////////////////////////////////////////////// // Impulse Tracker IT file support size_t CSoundFile::ITInstrToMPT(FileReader &file, ModInstrument &ins, uint16 trkvers) { if(trkvers < 0x0200) { // Load old format (IT 1.xx) instrument (early IT 2.xx modules may have cmwt set to 1.00 for backwards compatibility) ITOldInstrument instrumentHeader; if(!file.ReadStruct(instrumentHeader)) { return 0; } else { instrumentHeader.ConvertToMPT(ins); return sizeof(ITOldInstrument); } } else { const FileReader::pos_type offset = file.GetPosition(); // Try loading extended instrument... instSize will differ between normal and extended instruments. ITInstrumentEx instrumentHeader; file.ReadStructPartial(instrumentHeader); size_t instSize = instrumentHeader.ConvertToMPT(ins, GetType()); file.Seek(offset + instSize); // Try reading modular instrument data. // Yes, it is completely idiotic that we have both this and LoadExtendedInstrumentProperties. // This is only required for files saved with *really* old OpenMPT versions (pre-1.17-RC1). // This chunk was also written in later versions (probably to maintain compatibility with // those ancient versions), but this also means that redundant information is stored in the file. // Starting from OpenMPT 1.25.02.07, this chunk is no longer written. if(file.ReadMagic("MSNI")) { //...the next piece of data must be the total size of the modular data FileReader modularData = file.ReadChunk(file.ReadUint32LE()); instSize += 8 + modularData.GetLength(); if(modularData.ReadMagic("GULP")) { ins.nMixPlug = modularData.ReadUint8(); if(ins.nMixPlug > MAX_MIXPLUGINS) ins.nMixPlug = 0; } } return instSize; } } static void CopyPatternName(CPattern &pattern, FileReader &file) { char name[MAX_PATTERNNAME] = ""; file.ReadString(name, MAX_PATTERNNAME); pattern.SetName(name); } // Get version of Impulse Tracker that was used to create an IT/S3M file. mpt::ustring CSoundFile::GetImpulseTrackerVersion(uint16 cwtv, uint16 cmwt) { mpt::ustring version; cwtv &= 0xFFF; if(cmwt > 0x0214) { version = UL_("Impulse Tracker 2.15"); } else if(cwtv >= 0x0215 && cwtv <= 0x0217) { const mpt::uchar *versions[] = {UL_("1-2"), UL_("3"), UL_("4-5")}; version = MPT_UFORMAT("Impulse Tracker 2.14p{}")(mpt::ustring_view(versions[cwtv - 0x0215])); } else { version = MPT_UFORMAT("Impulse Tracker {}.{}")((cwtv & 0x0F00) >> 8, mpt::ufmt::hex0<2>((cwtv & 0xFF))); } return version; } // Get version of Schism Tracker that was used to create an IT/S3M file. mpt::ustring CSoundFile::GetSchismTrackerVersion(uint16 cwtv, uint32 reserved) { // Schism Tracker version information in a nutshell: // < 0x020: a proper version (files saved by such versions are likely very rare) // = 0x020: any version between the 0.2a release (2005-04-29?) and 2007-04-17 // = 0x050: anywhere from 2007-04-17 to 2009-10-31 // > 0x050: the number of days since 2009-10-31 // = 0xFFF: any version starting from 2020-10-28 (exact version stored in reserved value) cwtv &= 0xFFF; if(cwtv > 0x050) { int32 date = SchismTrackerEpoch + (cwtv < 0xFFF ? cwtv - 0x050 : reserved); int32 y = static_cast((Util::mul32to64(10000, date) + 14780) / 3652425); int32 ddd = date - (365 * y + y / 4 - y / 100 + y / 400); if(ddd < 0) { y--; ddd = date - (365 * y + y / 4 - y / 100 + y / 400); } int32 mi = (100 * ddd + 52) / 3060; return MPT_UFORMAT("Schism Tracker {}-{}-{}")( mpt::ufmt::dec0<4>(y + (mi + 2) / 12), mpt::ufmt::dec0<2>((mi + 2) % 12 + 1), mpt::ufmt::dec0<2>(ddd - (mi * 306 + 5) / 10 + 1)); } else { return MPT_UFORMAT("Schism Tracker 0.{}")(mpt::ufmt::hex0<2>(cwtv)); } } static bool ValidateHeader(const ITFileHeader &fileHeader) { if((std::memcmp(fileHeader.id, "IMPM", 4) && std::memcmp(fileHeader.id, "tpm.", 4)) || fileHeader.insnum > 0xFF || fileHeader.smpnum >= MAX_SAMPLES ) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const ITFileHeader &fileHeader) { return fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize) { ITFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); ITFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_IT, 0); bool interpretModPlugMade = false; mpt::ustring madeWithTracker; // OpenMPT crap at the end of file size_t mptStartPos = 0; if(!memcmp(fileHeader.id, "tpm.", 4)) { // Legacy MPTM files (old 1.17.02.4x releases) SetType(MOD_TYPE_MPT); file.Seek(file.GetLength() - 4); mptStartPos = file.ReadUint32LE(); } else { if(fileHeader.cwtv > 0x888 && fileHeader.cwtv <= 0xFFF) { file.Seek(file.GetLength() - 4); mptStartPos = file.ReadUint32LE(); if(mptStartPos >= 0x100 && mptStartPos < file.GetLength()) { if(file.Seek(mptStartPos) && file.ReadMagic("228")) { SetType(MOD_TYPE_MPT); if(fileHeader.cwtv >= verMptFileVerLoadLimit) { AddToLog(LogError, U_("The file informed that it is incompatible with this version of OpenMPT. Loading was terminated.")); return false; } else if(fileHeader.cwtv > verMptFileVer) { AddToLog(LogInformation, U_("The loaded file was made with a more recent OpenMPT version and this version may not be able to load all the features or play the file correctly.")); } } } } if(GetType() == MOD_TYPE_IT) { // Which tracker was used to make this? if((fileHeader.cwtv & 0xF000) == 0x5000) { // OpenMPT Version number (Major.Minor) // This will only be interpreted as "made with ModPlug" (i.e. disable compatible playback etc) if the "reserved" field is set to "OMPT" - else, compatibility was used. uint32 mptVersion = (fileHeader.cwtv & 0x0FFF) << 16; if(!memcmp(&fileHeader.reserved, "OMPT", 4)) interpretModPlugMade = true; else if(mptVersion >= 0x01'29'00'00) mptVersion |= fileHeader.reserved & 0xFFFF; m_dwLastSavedWithVersion = Version(mptVersion); } else if(fileHeader.cmwt == 0x888 || fileHeader.cwtv == 0x888) { // OpenMPT 1.17.02.26 (r122) to 1.18 // Exact version number will be determined later. interpretModPlugMade = true; m_dwLastSavedWithVersion = MPT_V("1.17.00.00"); } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0202 && fileHeader.reserved == 0) { // ModPlug Tracker b3.2 - 1.09, instruments 557 bytes apart m_dwLastSavedWithVersion = MPT_V("1.09.00.00"); madeWithTracker = UL_("ModPlug Tracker b3.2 - 1.09"); interpretModPlugMade = true; } else if(fileHeader.cwtv == 0x0300 && fileHeader.cmwt == 0x0300 && fileHeader.reserved == 0 && fileHeader.ordnum == 256 && fileHeader.sep == 128 && fileHeader.pwd == 0) { // A rare variant used from OpenMPT 1.17.02.20 (r113) to 1.17.02.25 (r121), found e.g. in xTr1m-SD.it m_dwLastSavedWithVersion = MPT_V("1.17.02.20"); interpretModPlugMade = true; } } } m_SongFlags.set(SONG_LINEARSLIDES, (fileHeader.flags & ITFileHeader::linearSlides) != 0); m_SongFlags.set(SONG_ITOLDEFFECTS, (fileHeader.flags & ITFileHeader::itOldEffects) != 0); m_SongFlags.set(SONG_ITCOMPATGXX, (fileHeader.flags & ITFileHeader::itCompatGxx) != 0); m_SongFlags.set(SONG_EXFILTERRANGE, (fileHeader.flags & ITFileHeader::extendedFilterRange) != 0); m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songname); // Read row highlights if((fileHeader.special & ITFileHeader::embedPatternHighlights)) { // MPT 1.09 and older (and maybe also newer) versions leave this blank (0/0), but have the "special" flag set. // Newer versions of MPT and OpenMPT 1.17 *always* write 4/16 here. // Thus, we will just ignore those old versions. // Note: OpenMPT 1.17.03.02 was the first version to properly make use of the time signature in the IT header. // This poses a small unsolvable problem: // - In compatible mode, we cannot distinguish this version from earlier 1.17 releases. // Thus we cannot know when to read this field or not (m_dwLastSavedWithVersion will always be 1.17.00.00). // Luckily OpenMPT 1.17.03.02 should not be very wide-spread. // - In normal mode the time signature is always present in the song extensions anyway. So it's okay if we read // the signature here and maybe overwrite it later when parsing the song extensions. if(!m_dwLastSavedWithVersion || m_dwLastSavedWithVersion >= MPT_V("1.17.03.02")) { m_nDefaultRowsPerBeat = fileHeader.highlight_minor; m_nDefaultRowsPerMeasure = fileHeader.highlight_major; } } // Global Volume m_nDefaultGlobalVolume = fileHeader.globalvol << 1; if(m_nDefaultGlobalVolume > MAX_GLOBAL_VOLUME) m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; if(fileHeader.speed) Order().SetDefaultSpeed(fileHeader.speed); Order().SetDefaultTempoInt(std::max(uint8(31), static_cast(fileHeader.tempo))); m_nSamplePreAmp = std::min(static_cast(fileHeader.mv), uint8(128)); // Reading orders file.Seek(sizeof(ITFileHeader)); if(GetType() == MOD_TYPE_MPT && fileHeader.cwtv > 0x88A && fileHeader.cwtv <= 0x88D) { // Deprecated format used for MPTm files created with OpenMPT 1.17.02.46 - 1.17.02.48. uint16 version = file.ReadUint16LE(); if(version != 0) return false; uint32 numOrd = file.ReadUint32LE(); if(numOrd > ModSpecs::mptm.ordersMax || !ReadOrderFromFile(Order(), file, numOrd)) return false; } else { ReadOrderFromFile(Order(), file, fileHeader.ordnum, 0xFF, 0xFE); } // Reading instrument, sample and pattern offsets std::vector insPos, smpPos, patPos; if(!file.ReadVector(insPos, fileHeader.insnum) || !file.ReadVector(smpPos, fileHeader.smpnum) || !file.ReadVector(patPos, fileHeader.patnum)) { return false; } // Find the first parapointer. // This is used for finding out whether the edit history is actually stored in the file or not, // as some early versions of Schism Tracker set the history flag, but didn't save anything. // We will consider the history invalid if it ends after the first parapointer. uint32 minPtr = std::numeric_limits::max(); for(uint32 pos : insPos) { if(pos > 0 && pos < minPtr) minPtr = pos; } for(uint32 pos : smpPos) { if(pos > 0 && pos < minPtr) minPtr = pos; } for(uint32 pos : patPos) { if(pos > 0 && pos < minPtr) minPtr = pos; } if(fileHeader.special & ITFileHeader::embedSongMessage) { minPtr = std::min(minPtr, fileHeader.msgoffset.get()); } const bool possiblyUNMO3 = fileHeader.cmwt == 0x0214 && (fileHeader.cwtv == 0x0214 || fileHeader.cwtv == 0) && fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0 && fileHeader.pwd == 0 && fileHeader.reserved == 0 && (fileHeader.flags & (ITFileHeader::useMIDIPitchController | ITFileHeader::reqEmbeddedMIDIConfig)) == 0; if(possiblyUNMO3 && fileHeader.insnum == 0 && fileHeader.smpnum > 0 && file.GetPosition() + 4 * smpPos.size() + 2 <= minPtr) { // UNMO3 < v2.4.0.1 reserves some space for instrument parapointers even in sample mode. // This makes reading MIDI macros and plugin information impossible. // Note: While UNMO3 and CheeseTracker header fingerprints are almost identical, we cannot mis-detect CheeseTracker here, // as it always sets the instrument mode flag and writes non-zero row highlights. bool oldUNMO3 = true; for(uint16 i = 0; i < fileHeader.smpnum; i++) { if(file.ReadUint32LE() != 0) { oldUNMO3 = false; file.SkipBack(4 + i * 4); break; } } if(oldUNMO3) { madeWithTracker = UL_("UNMO3 <= 2.4"); } } if(possiblyUNMO3 && fileHeader.cwtv == 0) { madeWithTracker = UL_("UNMO3 v0/1"); } // Reading IT Edit History Info // This is only supposed to be present if bit 1 of the special flags is set. // However, old versions of Schism and probably other trackers always set this bit // even if they don't write the edit history count. So we have to filter this out... // This is done by looking at the parapointers. If the history data ends after // the first parapointer, we assume that it's actually no history data. if(fileHeader.special & ITFileHeader::embedEditHistory) { const uint16 nflt = file.ReadUint16LE(); if(file.CanRead(nflt * sizeof(ITHistoryStruct)) && file.GetPosition() + nflt * sizeof(ITHistoryStruct) <= minPtr) { m_FileHistory.resize(nflt); for(auto &mptHistory : m_FileHistory) { ITHistoryStruct itHistory; file.ReadStruct(itHistory); itHistory.ConvertToMPT(mptHistory); } if(possiblyUNMO3 && nflt == 0) { if(fileHeader.special & ITFileHeader::embedPatternHighlights) madeWithTracker = UL_("UNMO3 <= 2.4.0.1"); // Set together with MIDI macro embed flag else madeWithTracker = UL_("UNMO3"); // Either 2.4.0.2+ or no MIDI macros embedded } } else { // Oops, we were not supposed to read this. file.SkipBack(2); } } else if(possiblyUNMO3 && fileHeader.special <= 1) { // UNMO3 < v2.4.0.1 will set the edit history special bit iff the MIDI macro embed bit is also set, // but it always writes the two extra bytes for the edit history length (zeros). // If MIDI macros are embedded, we are fine and end up in the first case of the if statement (read edit history). // Otherwise we end up here and might have to read the edit history length. if(file.ReadUint16LE() == 0) { madeWithTracker = UL_("UNMO3 <= 2.4"); } else { // These were not zero bytes, but potentially belong to the upcoming MIDI config - need to skip back. // I think the only application that could end up here is CheeseTracker, if it allows to write 0 for both row highlight values. // IT 2.14 itself will always write the edit history. file.SkipBack(2); } } // Reading MIDI Output & Macros bool hasMidiConfig = (fileHeader.flags & ITFileHeader::reqEmbeddedMIDIConfig) || (fileHeader.special & ITFileHeader::embedMIDIConfiguration); if(hasMidiConfig && file.ReadStruct(m_MidiCfg)) { m_MidiCfg.Sanitize(); } bool hasModPlugExtensions = false; // Read pattern names: "PNAM" FileReader patNames; if(file.ReadMagic("PNAM")) { patNames = file.ReadChunk(file.ReadUint32LE()); hasModPlugExtensions = true; } // Read channel names: "CNAM" if(file.ReadMagic("CNAM")) { FileReader chnNames = file.ReadChunk(file.ReadUint32LE()); ChnSettings.resize(std::min(MAX_BASECHANNELS, static_cast(chnNames.GetLength() / MAX_CHANNELNAME))); hasModPlugExtensions = true; for(auto &chn : ChnSettings) { chnNames.ReadString(chn.szName, MAX_CHANNELNAME); } } // Read mix plugins information FileReader pluginChunk = file.ReadChunk((minPtr >= file.GetPosition()) ? minPtr - file.GetPosition() : file.BytesLeft()); const auto [hasPluginChunks, isBeRoTracker] = LoadMixPlugins(pluginChunk, false); if(hasPluginChunks) hasModPlugExtensions = true; if(fileHeader.cwtv == 0x0217 && fileHeader.cmwt == 0x0200 && fileHeader.reserved == 0 && !isBeRoTracker) { if(hasModPlugExtensions || (!Order().empty() && Order().back() == PATTERNINDEX_INVALID) || memchr(fileHeader.chnpan, 0xFF, sizeof(fileHeader.chnpan)) != nullptr) { m_dwLastSavedWithVersion = MPT_V("1.16"); madeWithTracker = UL_("ModPlug Tracker 1.09 - 1.16"); } else { // OpenMPT 1.17 disguised as this in compatible mode, // but never writes 0xFF in the pan map for unused channels (which is an invalid value). // It also doesn't write a final "---" pattern in the order list. // Could also be original ModPlug Tracker though if all 64 channels and no ModPlug extensions are used. m_dwLastSavedWithVersion = MPT_V("1.17"); madeWithTracker = UL_("OpenMPT 1.17 (compatibility export)"); } interpretModPlugMade = true; } // Read Song Message if((fileHeader.special & ITFileHeader::embedSongMessage) && fileHeader.msglength > 0 && file.Seek(fileHeader.msgoffset)) { // Generally, IT files should use CR for line endings. However, ChibiTracker uses LF. One could do... // if(itHeader.cwtv == 0x0214 && itHeader.cmwt == 0x0214 && itHeader.reserved == ITFileHeader::chibiMagic) --> Chibi detected. // But we'll just use autodetection here: m_songMessage.Read(file, fileHeader.msglength, SongMessage::leAutodetect); } // Reading Instruments m_nInstruments = 0; if(fileHeader.flags & ITFileHeader::instrumentMode) { m_nInstruments = std::min(static_cast(fileHeader.insnum), static_cast(MAX_INSTRUMENTS - 1)); } for(INSTRUMENTINDEX i = 0; i < GetNumInstruments(); i++) { if(insPos[i] > 0 && file.Seek(insPos[i]) && file.CanRead(fileHeader.cmwt < 0x200 ? sizeof(ITOldInstrument) : sizeof(ITInstrument))) { ModInstrument *instrument = AllocateInstrument(i + 1); if(instrument != nullptr) { ITInstrToMPT(file, *instrument, fileHeader.cmwt); // MIDI Pitch Wheel Depth is a global setting in IT. Apply it to all instruments. instrument->midiPWD = fileHeader.pwd; } } } // In order to properly compute the position, in file, of eventual extended settings // such as "attack" we need to keep the "real" size of the last sample as those extra // setting will follow this sample in the file FileReader::pos_type lastSampleOffset = 0; if(fileHeader.smpnum > 0) { lastSampleOffset = smpPos[fileHeader.smpnum - 1] + sizeof(ITSample); } bool possibleXMconversion = false; // There's a bug in IT somewhere that resets the "sample data present" flag in sample headers, but keeps the sample length // of a previously deleted sample (presumably). // As old ModPlug versions didn't set this flag under some circumstances (if a sample wasn't referenced by any instruments in instrument mode), // and because there appear to be some external tools that forget to set this flag at all, we only respect the flag if the file // vaguely looks like it was saved with IT. Some files that play garbage data if we don't do this: // astral projection.it by Lord Jon Ray // classic illusions.it by Blackstar // deep in dance.it by Simply DJ // There are many more such files but they don't reference the broken samples in their pattern data, or the sample data pointer // points right to the end of the file, so in both cases no audible problem can be observed. const bool muteBuggySamples = !interpretModPlugMade && fileHeader.cwtv >= 0x0100 && fileHeader.cwtv <= 0x0217 && (fileHeader.cwtv < 0x0207 || fileHeader.reserved != 0); // Reading Samples m_nSamples = std::min(static_cast(fileHeader.smpnum), static_cast(MAX_SAMPLES - 1)); bool lastSampleCompressed = false, anyADPCM = false; for(SAMPLEINDEX i = 0; i < GetNumSamples(); i++) { ITSample sampleHeader; if(smpPos[i] > 0 && file.Seek(smpPos[i]) && file.ReadStruct(sampleHeader)) { ModSample &sample = Samples[i + 1]; size_t sampleOffset = sampleHeader.ConvertToMPT(sample); if(muteBuggySamples && !(sampleHeader.flags & ITSample::sampleDataPresent)) sample.nLength = 0; m_szNames[i + 1] = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); if(!file.Seek(sampleOffset)) continue; lastSampleCompressed = false; if(sample.uFlags[CHN_ADLIB]) { // FM instrument in MPTM OPLPatch patch; if(file.ReadArray(patch)) { sample.SetAdlib(true, patch); } } else if(!sample.uFlags[SMP_KEEPONDISK]) { SampleIO sampleIO = sampleHeader.GetSampleFormat(fileHeader.cwtv); if(loadFlags & loadSampleData) { sampleIO.ReadSample(sample, file); } else { if(sampleIO.IsVariableLengthEncoded()) lastSampleCompressed = true; else file.Skip(sampleIO.CalculateEncodedSize(sample.nLength)); } if(sampleIO.GetEncoding() == SampleIO::unsignedPCM && sample.nLength != 0) { // There is some XM to IT converter (don't know which one) and it identifies as IT 2.04. // The only safe way to distinguish it from an IT-saved file are the unsigned samples. possibleXMconversion = true; } else if(sampleIO.GetEncoding() == SampleIO::ADPCM) { anyADPCM = true; } } else { // External sample in MPTM file size_t strLen; file.ReadVarInt(strLen); if((loadFlags & loadSampleData) && strLen) { std::string filenameU8; file.ReadString(filenameU8, strLen); #if defined(MPT_EXTERNAL_SAMPLES) SetSamplePath(i + 1, mpt::PathString::FromUTF8(filenameU8)); #elif !defined(LIBOPENMPT_BUILD_TEST) AddToLog(LogWarning, MPT_UFORMAT("Loading external sample {} ('{}') failed: External samples are not supported.")(i + 1, mpt::ToUnicode(mpt::Charset::UTF8, filenameU8))); #endif // MPT_EXTERNAL_SAMPLES } else { file.Skip(strLen); } } lastSampleOffset = std::max(lastSampleOffset, file.GetPosition()); } } m_nSamples = std::max(SAMPLEINDEX(1), GetNumSamples()); if(possibleXMconversion && fileHeader.cwtv == 0x0204 && fileHeader.cmwt == 0x0200 && fileHeader.special == 0 && fileHeader.reserved == 0 && (fileHeader.flags & ~ITFileHeader::linearSlides) == (ITFileHeader::useStereoPlayback | ITFileHeader::instrumentMode | ITFileHeader::itOldEffects) && fileHeader.globalvol == 128 && fileHeader.mv == 48 && fileHeader.sep == 128 && fileHeader.pwd == 0 && fileHeader.msglength == 0) { for(uint8 pan : fileHeader.chnpan) { if(pan != 0x20 && pan != 0xA0) possibleXMconversion = false; } for(uint8 vol : fileHeader.chnvol) { if(vol != 0x40) possibleXMconversion = false; } for(size_t i = 20; i < std::size(fileHeader.songname); i++) { if(fileHeader.songname[i] != 0) possibleXMconversion = false; } if(possibleXMconversion) madeWithTracker = UL_("XM Conversion"); } m_nMinPeriod = 0; m_nMaxPeriod = int32_max; PATTERNINDEX numPats = std::min(static_cast(patPos.size()), GetModSpecifications().patternsMax); if(numPats != patPos.size()) { // Hack: Notify user here if file contains more patterns than what can be read. AddToLog(LogWarning, MPT_UFORMAT("The module contains {} patterns but only {} patterns can be loaded in this OpenMPT version.")(patPos.size(), numPats)); } if(!(loadFlags & loadPatternData)) { numPats = 0; } // Checking for number of used channels, which is not explicitly specified in the file. CHANNELINDEX numChannels = std::max(GetNumChannels(), CHANNELINDEX(1)); for(PATTERNINDEX pat = 0; pat < numPats; pat++) { if(patPos[pat] == 0 || !file.Seek(patPos[pat])) continue; uint16 len = file.ReadUint16LE(); ROWINDEX numRows = file.ReadUint16LE(); if(numRows < 1 || numRows > MAX_PATTERN_ROWS || !file.Skip(4)) continue; FileReader patternData = file.ReadChunk(len); ROWINDEX row = 0; std::vector chnMask(numChannels); while(row < numRows && patternData.CanRead(1)) { uint8 b = patternData.ReadUint8(); if(!b) { row++; continue; } CHANNELINDEX ch = (b & IT_bitmask_patternChanField_c); // 0x7f We have some data grab a byte keeping only 7 bits if(ch) { ch = (ch - 1);// & IT_bitmask_patternChanMask_c; // 0x3f mask of the byte again, keeping only 6 bits } if(ch >= chnMask.size()) { chnMask.resize(ch + 1, 0); } if(b & IT_bitmask_patternChanEnabled_c) // 0x80 check if the upper bit is enabled. { chnMask[ch] = patternData.ReadUint8(); // set the channel mask for this channel. } // Channel used if(chnMask[ch] & 0x0F) // if this channel is used set m_nChannels { if(ch >= numChannels && ch < MAX_BASECHANNELS) { numChannels = ch + 1; } // Skip a number of bytes depending on note, instrument, volume, effect being present. static constexpr uint8 maskToSkips[] = {0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5}; patternData.Skip(maskToSkips[chnMask[ch] & 0x0F]); } } lastSampleOffset = std::max(lastSampleOffset, file.GetPosition()); } ChnSettings.resize(numChannels); // Compute extra instruments settings position if(lastSampleOffset > 0) { file.Seek(lastSampleOffset); if(lastSampleCompressed) { // If the last sample was compressed, we do not know where it ends. // Hence, in case we decided not to decode the sample data, we now // have to emulate this until we reach EOF or some instrument / song properties. while(file.CanRead(4)) { if(file.ReadMagic("XTPM") || file.ReadMagic("STPM")) { uint32 id = file.ReadUint32LE(); file.SkipBack(8); // Our chunk IDs should only contain ASCII characters if(!(id & 0x80808080) && (id & 0x60606060)) { break; } } file.Skip(file.ReadUint16LE()); } } } // Load instrument and song extensions. const bool hasExtendedInstrumentProperties = LoadExtendedInstrumentProperties(file); interpretModPlugMade |= hasExtendedInstrumentProperties; if(interpretModPlugMade && !isBeRoTracker) { m_playBehaviour.reset(); m_nMixLevels = MixLevels::Original; } // Need to do this before reading the patterns because m_nChannels might be modified by LoadExtendedSongProperties. *sigh* const bool hasExtendedSongProperties = LoadExtendedSongProperties(file, false, &interpretModPlugMade); // Reading Channels Pan Positions const CHANNELINDEX headerChannels = std::min(GetNumChannels(), CHANNELINDEX(64)); for(CHANNELINDEX i = 0; i < headerChannels; i++) { if(fileHeader.chnpan[i] == 0xFF) continue; ChnSettings[i].nVolume = Clamp(fileHeader.chnvol[i], 0, 64); if(fileHeader.chnpan[i] & 0x80) ChnSettings[i].dwFlags.set(CHN_MUTE); uint8 n = fileHeader.chnpan[i] & 0x7F; if(n <= 64) ChnSettings[i].nPan = n * 4; if(n == 100) ChnSettings[i].dwFlags.set(CHN_SURROUND); } // Reading Patterns Patterns.ResizeArray(numPats); bool hasVolColOffset = false; for(PATTERNINDEX pat = 0; pat < numPats; pat++) { if(patPos[pat] == 0 || !file.Seek(patPos[pat])) { // Empty 64-row pattern if(!Patterns.Insert(pat, 64)) { AddToLog(LogWarning, MPT_UFORMAT("Allocating patterns failed starting from pattern {}")(pat)); break; } // Now (after the Insert() call), we can read the pattern name. CopyPatternName(Patterns[pat], patNames); continue; } uint16 len = file.ReadUint16LE(); ROWINDEX numRows = file.ReadUint16LE(); if(!file.Skip(4) || !Patterns.Insert(pat, numRows)) continue; FileReader patternData = file.ReadChunk(len); // Now (after the Insert() call), we can read the pattern name. CopyPatternName(Patterns[pat], patNames); std::vector chnMask(GetNumChannels()); std::vector lastValue(GetNumChannels(), ModCommand{}); auto patData = Patterns[pat].begin(); ROWINDEX row = 0; ModCommand dummy{}; while(row < numRows && patternData.CanRead(1)) { uint8 b = patternData.ReadUint8(); if(!b) { row++; patData += GetNumChannels(); continue; } CHANNELINDEX ch = b & IT_bitmask_patternChanField_c; // 0x7f if(ch) { ch = (ch - 1); //& IT_bitmask_patternChanMask_c; // 0x3f } if(ch >= chnMask.size()) { chnMask.resize(ch + 1, 0); lastValue.resize(ch + 1, ModCommand{}); MPT_ASSERT(chnMask.size() <= GetNumChannels()); } if(b & IT_bitmask_patternChanEnabled_c) // 0x80 { chnMask[ch] = patternData.ReadUint8(); } // Now we grab the data for this particular row/channel. ModCommand &m = ch < GetNumChannels() ? patData[ch] : dummy; if(chnMask[ch] & 0x10) { m.note = lastValue[ch].note; } if(chnMask[ch] & 0x20) { m.instr = lastValue[ch].instr; } if(chnMask[ch] & 0x40) { m.volcmd = lastValue[ch].volcmd; m.vol = lastValue[ch].vol; } if(chnMask[ch] & 0x80) { m.command = lastValue[ch].command; m.param = lastValue[ch].param; } if(chnMask[ch] & 1) // Note { uint8 note = patternData.ReadUint8(); if(note < 0x80) note += NOTE_MIN; else if(note == 0xFF) note = NOTE_KEYOFF; else if(note == 0xFE) note = NOTE_NOTECUT; else if(note == 0xFD && GetType() != MOD_TYPE_MPT) note = NOTE_NONE; // Note: in MPTM format, NOTE_FADE is written as 0xFD to preserve compatibility with older OpenMPT versions. else note = NOTE_FADE; m.note = lastValue[ch].note = note; } if(chnMask[ch] & 2) { m.instr = lastValue[ch].instr = patternData.ReadUint8(); } if(chnMask[ch] & 4) { uint8 vol = patternData.ReadUint8(); // 0-64: Set Volume if(vol <= 64) { m.volcmd = VOLCMD_VOLUME; m.vol = vol; } else // 128-192: Set Panning if(vol >= 128 && vol <= 192) { m.volcmd = VOLCMD_PANNING; m.vol = vol - 128; } else // 65-74: Fine Volume Up if(vol < 75) { m.volcmd = VOLCMD_FINEVOLUP; m.vol = vol - 65; } else // 75-84: Fine Volume Down if(vol < 85) { m.volcmd = VOLCMD_FINEVOLDOWN; m.vol = vol - 75; } else // 85-94: Volume Slide Up if(vol < 95) { m.volcmd = VOLCMD_VOLSLIDEUP; m.vol = vol - 85; } else // 95-104: Volume Slide Down if(vol < 105) { m.volcmd = VOLCMD_VOLSLIDEDOWN; m.vol = vol - 95; } else // 105-114: Pitch Slide Up if(vol < 115) { m.volcmd = VOLCMD_PORTADOWN; m.vol = vol - 105; } else // 115-124: Pitch Slide Down if(vol < 125) { m.volcmd = VOLCMD_PORTAUP; m.vol = vol - 115; } else // 193-202: Portamento To if(vol >= 193 && vol <= 202) { m.volcmd = VOLCMD_TONEPORTAMENTO; m.vol = vol - 193; } else // 203-212: Vibrato depth if(vol >= 203 && vol <= 212) { m.volcmd = VOLCMD_VIBRATODEPTH; m.vol = vol - 203; // Old versions of ModPlug saved this as vibrato speed instead, so let's fix that. if(m.vol && m_dwLastSavedWithVersion && m_dwLastSavedWithVersion <= MPT_V("1.17.02.54")) m.volcmd = VOLCMD_VIBRATOSPEED; } else // 213-222: Unused (was velocity) // 223-232: Offset if(vol >= 223 && vol <= 232) { m.volcmd = VOLCMD_OFFSET; m.vol = vol - 223; hasVolColOffset = true; } lastValue[ch].volcmd = m.volcmd; lastValue[ch].vol = m.vol; } // Reading command/param if(chnMask[ch] & 8) { const auto [command, param] = patternData.ReadArray(); S3MConvert(m, command, param, true); // IT 1.xx does not support high offset command if(m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0xA0 && fileHeader.cwtv < 0x0200) m.command = CMD_DUMMY; // Fix handling of commands V81-VFF in ITs made with old Schism Tracker versions // (fixed in https://github.com/schismtracker/schismtracker/commit/ab5517d4730d4c717f7ebffb401445679bd30888 - one of the last versions to identify as v0.50) else if(m.command == CMD_GLOBALVOLUME && m.param > 0x80 && fileHeader.cwtv >= 0x1000 && fileHeader.cwtv <= 0x1050) m.param = 0x80; // In some IT-compatible trackers, it is possible to input a parameter without a command. // In this case, we still need to update the last value memory (so that we don't reuse a previous non-empty effect). // OpenMPT didn't do this until v1.25.01.07. // Example: ckbounce.it lastValue[ch].command = m.command; lastValue[ch].param = m.param; } } } // Remove (default) cue points if no volume column offset is found (unless it's a new enough MPTM file, which could contain intentionally-placed custom cue points that we don't want to lose) if(!hasVolColOffset && (GetType() != MOD_TYPE_MPT || m_dwLastSavedWithVersion < MPT_V("1.24.02.06"))) { for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { Samples[smp].RemoveAllCuePoints(); } } if(!m_dwLastSavedWithVersion && fileHeader.cwtv == 0x0888) { // Up to OpenMPT 1.17.02.45 (r165), it was possible that the "last saved with" field was 0 // when saving a file in OpenMPT for the first time. m_dwLastSavedWithVersion = MPT_V("1.17.00.00"); } if(m_dwLastSavedWithVersion && madeWithTracker.empty()) { madeWithTracker = UL_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion); bool isCompatExport = memcmp(&fileHeader.reserved, "OMPT", 4) && (fileHeader.cwtv & 0xF000) == 0x5000; if(m_dwLastSavedWithVersion == MPT_V("1.17.00.00")) isCompatExport = !hasExtendedInstrumentProperties && !hasExtendedSongProperties && !hasModPlugExtensions; if(isCompatExport) { madeWithTracker += UL_(" (compatibility export)"); } else if(m_dwLastSavedWithVersion.IsTestVersion()) { madeWithTracker += UL_(" (test build)"); } } else { const int32 schismDateVersion = SchismTrackerEpoch + ((fileHeader.cwtv == 0x1FFF) ? fileHeader.reserved : (fileHeader.cwtv - 0x1050)); switch(fileHeader.cwtv >> 12) { case 0: if(isBeRoTracker) { // Old versions madeWithTracker = UL_("BeRoTracker"); } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0200 && fileHeader.flags == 9 && fileHeader.special == 0 && fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0 && fileHeader.insnum == 0 && fileHeader.patnum + 1 == fileHeader.ordnum && fileHeader.globalvol == 128 && fileHeader.mv == 100 && fileHeader.speed == 1 && fileHeader.sep == 128 && fileHeader.pwd == 0 && fileHeader.msglength == 0 && fileHeader.msgoffset == 0 && fileHeader.reserved == 0) { madeWithTracker = UL_("OpenSPC conversion"); } else if(fileHeader.cwtv == 0x0202 && fileHeader.cmwt == 0x0200 && fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0 && fileHeader.reserved == 0 && !patPos.empty() && !smpPos.empty() && patPos[0] != 0 && patPos[0] < smpPos[0]) { // ModPlug Tracker 1.0 pre-alpha up to alpha 4, patterns located before instruments / samples m_dwLastSavedWithVersion = MPT_V("1.00.00.A0"); madeWithTracker = UL_("ModPlug Tracker 1.0 pre-alpha / alpha"); interpretModPlugMade = true; } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0200 && fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0 && fileHeader.reserved == 0) { if(fileHeader.special & (ITFileHeader::embedPatternHighlights | ITFileHeader::embedEditHistory)) { // ModPlug Tracker 1.0a6/b1/b2 // Instruments are 557 bytes apart in beta 2.3, in beta 1 still 560 bytes like in earlier versions if(insPos.size() >= 2 && insPos[1] - insPos[0] == 557) { m_dwLastSavedWithVersion = MPT_V("1.00.00.B2"); madeWithTracker = UL_("ModPlug Tracker 1.0b2"); } else { m_dwLastSavedWithVersion = MPT_V("1.00.00.B1"); madeWithTracker = UL_("ModPlug Tracker 1.0 alpha / beta"); } } else { // ModPlug Tracker 1.0a5, instruments 560 bytes apart m_dwLastSavedWithVersion = MPT_V("1.00.00.A5"); madeWithTracker = UL_("ModPlug Tracker 1.0a5"); } interpretModPlugMade = true; } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && !memcmp(&fileHeader.reserved, "CHBI", 4)) { madeWithTracker = UL_("ChibiTracker"); m_playBehaviour.reset(kITShortSampleRetrig); m_nSamplePreAmp /= 2; } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && fileHeader.special <= 1 && fileHeader.pwd == 0 && fileHeader.reserved == 0 && (fileHeader.flags & (ITFileHeader::vol0Optimisations | ITFileHeader::instrumentMode | ITFileHeader::useMIDIPitchController | ITFileHeader::reqEmbeddedMIDIConfig | ITFileHeader::extendedFilterRange)) == ITFileHeader::instrumentMode && m_nSamples > 1 && (Samples[1].filename == "XXXXXXXX.YYY")) { madeWithTracker = UL_("CheeseTracker"); } else if(fileHeader.cwtv == 0 && madeWithTracker.empty()) { madeWithTracker = UL_("Unknown"); } else if(fileHeader.cwtv >= 0x0208 && fileHeader.cwtv <= 0x0214 && !fileHeader.reserved && m_FileHistory.empty() && madeWithTracker.empty()) { // Any file made with IT starting from v2.07 onwards should have an edit history madeWithTracker = UL_("Unknown"); } else if(fileHeader.cmwt < 0x0300 && madeWithTracker.empty()) { madeWithTracker = GetImpulseTrackerVersion(fileHeader.cwtv, fileHeader.cmwt); if(m_FileHistory.empty() && fileHeader.reserved != 0) { // Starting from version 2.07, IT stores the total edit time of a module in the "reserved" field uint32 editTime = DecodeITEditTimer(fileHeader.cwtv, fileHeader.reserved); FileHistory hist; hist.openTime = static_cast(editTime * (HISTORY_TIMER_PRECISION / 18.2)); m_FileHistory.push_back(hist); } } break; case 1: madeWithTracker = GetSchismTrackerVersion(fileHeader.cwtv, fileHeader.reserved); { static constexpr std::pair SchismQuirks[] = { {SchismVersionFromDate<2015, 1, 29>::date, kPeriodsAreHertz }, // https://github.com/schismtracker/schismtracker/commit/671b30311082a0e7df041fca25f989b5d2478f69 {SchismVersionFromDate<2016, 5, 13>::date, kITShortSampleRetrig }, // https://github.com/schismtracker/schismtracker/commit/e7b1461fe751554309fd403713c2a1ef322105ca {SchismVersionFromDate<2021, 5, 2>::date, kITDoNotOverrideChannelPan }, // https://github.com/schismtracker/schismtracker/commit/a34ec86dc819915debc9e06f4727b77bf2dd29ee {SchismVersionFromDate<2021, 5, 2>::date, kITPanningReset }, // https://github.com/schismtracker/schismtracker/commit/648f5116f984815c69e11d018b32dfec53c6b97a {SchismVersionFromDate<2021, 11, 1>::date, kITPitchPanSeparation }, // https://github.com/schismtracker/schismtracker/commit/6e9f1207015cae0fe1b829fff7bb867e02ec6dea {SchismVersionFromDate<2022, 4, 30>::date, kITEmptyNoteMapSlot }, // https://github.com/schismtracker/schismtracker/commit/1b2f7d5522fcb971f134a6664182ca569f7c8008 {SchismVersionFromDate<2022, 4, 30>::date, kITPortamentoSwapResetsPos }, // https://github.com/schismtracker/schismtracker/commit/1b2f7d5522fcb971f134a6664182ca569f7c8008 {SchismVersionFromDate<2022, 4, 30>::date, kITMultiSampleInstrumentNumber}, // https://github.com/schismtracker/schismtracker/commit/1b2f7d5522fcb971f134a6664182ca569f7c8008 {SchismVersionFromDate<2023, 3, 9>::date, kITInitialNoteMemory }, // https://github.com/schismtracker/schismtracker/commit/73e9d60676c2b48c8e94e582373e29517105b2b1 {SchismVersionFromDate<2023, 10, 17>::date, kITDCTBehaviour }, // https://github.com/schismtracker/schismtracker/commit/31d36dc00013fc5ab0efa20c782af18e8b006e07 {SchismVersionFromDate<2023, 10, 19>::date, kITSampleAndHoldPanbrello }, // https://github.com/schismtracker/schismtracker/commit/411ec16b190ba1a486d8b0907ad8d74f8fdc2840 {SchismVersionFromDate<2023, 10, 19>::date, kITPortaNoNote }, // https://github.com/schismtracker/schismtracker/commit/8ff0a86a715efb50c89770fb9095d4c4089ff187 {SchismVersionFromDate<2023, 10, 22>::date, kITFirstTickHandling }, // https://github.com/schismtracker/schismtracker/commit/b9609e4f827e1b6ce9ebe6573b85e69388ca0ea0 {SchismVersionFromDate<2023, 10, 22>::date, kITMultiSampleInstrumentNumber}, // https://github.com/schismtracker/schismtracker/commit/a9e5df533ab52c35190fcc1cbfed4f0347b660bb {SchismVersionFromDate<2024, 3, 9>::date, kITPanbrelloHold }, // https://github.com/schismtracker/schismtracker/commit/ebdebaa8c8a735a7bf49df55debded1b7aac3605 {SchismVersionFromDate<2024, 5, 12>::date, kITNoSustainOnPortamento }, // https://github.com/schismtracker/schismtracker/commit/6f68f2855a7e5e4ffe825869244e631e15741037 {SchismVersionFromDate<2024, 5, 12>::date, kITEmptyNoteMapSlotIgnoreCell }, // https://github.com/schismtracker/schismtracker/commit/aa84148e019a65f3d52ecd33fd84bfecfdb87bf4 {SchismVersionFromDate<2024, 5, 27>::date, kITOffsetWithInstrNumber }, // https://github.com/schismtracker/schismtracker/commit/9237960d45079a54ad73f87bacfe5dd8ae82e273 {SchismVersionFromDate<2024, 10, 13>::date, kITDoublePortamentoSlides }, // https://github.com/schismtracker/schismtracker/commit/223e327d9448561931b8cac8a55180286b17276c {SchismVersionFromDate<2025, 1, 8>::date, kITCarryAfterNoteOff }, // https://github.com/schismtracker/schismtracker/commit/ff7a817df327c8f13d97b8c6546a9329f59edff8 }; for(const auto &quirk : SchismQuirks) { if(schismDateVersion < quirk.first) m_playBehaviour.reset(quirk.second); } } // Hertz in Amiga mode: Added 2021-05-02, https://github.com/schismtracker/schismtracker/commit/c656a6cbd5aaf81198a7580faf81cb7960cb6afa if(schismDateVersion < SchismVersionFromDate<2021, 05, 02>::date && !m_SongFlags[SONG_LINEARSLIDES]) m_playBehaviour.reset(kPeriodsAreHertz); // Imprecise calculation of ping-pong loop wraparound: Added 2021-11-01, https://github.com/schismtracker/schismtracker/commit/22cbb9b676e9c2c9feb7a6a17deca7a17ac138cc if(schismDateVersion < SchismVersionFromDate<2021, 11, 01>::date) m_playBehaviour.set(kImprecisePingPongLoops); break; case 4: madeWithTracker = MPT_UFORMAT("pyIT {}.{}")((fileHeader.cwtv & 0x0F00) >> 8, mpt::ufmt::hex0<2>(fileHeader.cwtv & 0xFF)); break; case 6: madeWithTracker = UL_("BeRoTracker"); break; case 7: if(fileHeader.cwtv == 0x7FFF && fileHeader.cmwt == 0x0215) madeWithTracker = UL_("munch.py"); else madeWithTracker = MPT_UFORMAT("ITMCK {}.{}.{}")((fileHeader.cwtv >> 8) & 0x0F, (fileHeader.cwtv >> 4) & 0x0F, fileHeader.cwtv & 0x0F); break; case 0xD: if(fileHeader.cwtv == 0xDAEB) madeWithTracker = UL_("spc2it"); else if(fileHeader.cwtv == 0xD1CE) madeWithTracker = UL_("itwriter"); else madeWithTracker = UL_("Unknown"); break; } } if(anyADPCM) madeWithTracker += UL_(" (ADPCM packed)"); // Ignore MIDI data. Fixes some files like denonde.it that were made with old versions of Impulse Tracker (which didn't support Zxx filters) and have Zxx effects in the patterns. // Example: denonde.it by Mystical // Note: Only checking the cwtv "made with" version is not enough: spx-visionsofthepast.it has the strange combination of cwtv=2.00, cmwt=2.16 // Hence to be sure, we check that both values are below 2.14. // Note that all ModPlug Tracker alpha versions do not support filters yet. Earlier alphas identify as cwtv=2.02, cmwt=2.00, but later alpha versions identify as IT 2.14. // Apart from that, there's an unknown XM conversion tool declaring a lower comaptible version, which naturally also does not support filters, so it's okay that it is caught here. if((fileHeader.cwtv < 0x0214 && fileHeader.cmwt < 0x0214) || (m_dwLastSavedWithVersion && m_dwLastSavedWithVersion <= MPT_V("1.00.00.A6"))) { m_MidiCfg.ClearZxxMacros(); } if(GetType() == MOD_TYPE_MPT) { // START - mpt specific: if(fileHeader.cwtv > 0x0889 && file.Seek(mptStartPos)) { LoadMPTMProperties(file, fileHeader.cwtv); } } m_modFormat.formatName = (GetType() == MOD_TYPE_MPT) ? U_("OpenMPT MPTM") : MPT_UFORMAT("Impulse Tracker {}.{}")(fileHeader.cmwt >> 8, mpt::ufmt::hex0<2>(fileHeader.cmwt & 0xFF)); m_modFormat.type = (GetType() == MOD_TYPE_MPT) ? U_("mptm") : U_("it"); m_modFormat.madeWithTracker = std::move(madeWithTracker); m_modFormat.charset = m_dwLastSavedWithVersion ? mpt::Charset::Windows1252 : mpt::Charset::CP437; #if MPT_TIME_UTC_ON_DISK #ifdef MODPLUG_TRACKER m_modFormat.timezone = (m_dwLastSavedWithVersion && (m_dwLastSavedWithVersion >= MPT_TIME_UTC_ON_DISK_VERSION)) ? mpt::Date::LogicalTimezone::UTC : mpt::Date::LogicalTimezone::Local; #else m_modFormat.timezone = (m_dwLastSavedWithVersion && (m_dwLastSavedWithVersion >= MPT_TIME_UTC_ON_DISK_VERSION)) ? mpt::Date::LogicalTimezone::UTC : mpt::Date::LogicalTimezone::Unspecified; #endif #else #ifdef MODPLUG_TRACKER m_modFormat.timezone = mpt::Date::LogicalTimezone::Local; #else m_modFormat.timezone = mpt::Date::LogicalTimezone::Unspecified; #endif #endif return true; } void CSoundFile::LoadMPTMProperties(FileReader &file, uint16 cwtv) { std::istringstream iStrm(mpt::buffer_cast(file.GetRawDataAsByteVector())); if(cwtv >= 0x88D) { srlztn::SsbRead ssb(iStrm); ssb.BeginRead("mptm", Version::Current().GetRawVersion()); int8 useUTF8Tuning = 0; ssb.ReadItem(useUTF8Tuning, "UTF8Tuning"); mpt::Charset TuningCharset = useUTF8Tuning ? mpt::Charset::UTF8 : GetCharsetInternal(); ssb.ReadItem(GetTuneSpecificTunings(), "0", [TuningCharset](std::istream &iStrm, CTuningCollection &tc, const std::size_t dummy){ return ReadTuningCollection(iStrm, tc, dummy, TuningCharset); }); ssb.ReadItem(*this, "1", [TuningCharset](std::istream& iStrm, CSoundFile& csf, const std::size_t dummy){ return ReadTuningMap(iStrm, csf, dummy, TuningCharset); }); ssb.ReadItem(Order, "2", &ReadModSequenceOld); ssb.ReadItem(Patterns, FileIdPatterns, &ReadModPatterns); mpt::Charset sequenceDefaultCharset = GetCharsetInternal(); ssb.ReadItem(Order, FileIdSequences, [sequenceDefaultCharset](std::istream &iStrm, ModSequenceSet &seq, std::size_t nSize){ return ReadModSequences(iStrm, seq, nSize, sequenceDefaultCharset); }); if(ssb.HasFailed()) { AddToLog(LogError, U_("Unknown error occurred while deserializing file.")); } } else { // Loading for older files. mpt::ustring name; if(GetTuneSpecificTunings().Deserialize(iStrm, name, GetCharsetInternal()) != Tuning::SerializationResult::Success) { AddToLog(LogError, U_("Loading tune specific tunings failed.")); } else { ReadTuningMapImpl(iStrm, *this, GetCharsetInternal(), 0, cwtv < 0x88C); } } } #ifndef MODPLUG_NO_FILESAVE // Save edit history. Pass a null pointer for *f to retrieve the number of bytes that would be written. static uint32 SaveITEditHistory(const CSoundFile &sndFile, std::ostream *file) { size_t num = sndFile.GetFileHistory().size(); #ifdef MODPLUG_TRACKER const CModDoc *pModDoc = sndFile.GetpModDoc(); num += (pModDoc != nullptr) ? 1 : 0; // + 1 for this session #endif // MODPLUG_TRACKER uint16 fnum = mpt::saturate_cast(num); // Number of entries that are actually going to be written const uint32 bytesWritten = 2 + fnum * 8; // Number of bytes that are actually going to be written if(!file) { return bytesWritten; } std::ostream & f = *file; // Write number of history entries mpt::IO::WriteIntLE(f, fnum); // Write history data const size_t start = (num > uint16_max) ? num - uint16_max : 0; for(size_t n = start; n < num; n++) { FileHistory mptHistory; #ifdef MODPLUG_TRACKER if(n < sndFile.GetFileHistory().size()) #endif // MODPLUG_TRACKER { // Previous timestamps mptHistory = sndFile.GetFileHistory()[n]; #ifdef MODPLUG_TRACKER } else if(pModDoc != nullptr) { // Current ("new") timestamp const mpt::Date::Unix creationTime = pModDoc->GetCreationTime(); if(sndFile.GetTimezoneInternal() == mpt::Date::LogicalTimezone::UTC) { mptHistory.loadDate = mpt::Date::forget_timezone(mpt::Date::UnixAsUTC(creationTime)); } else if(sndFile.GetTimezoneInternal() == mpt::Date::LogicalTimezone::Local) { mptHistory.loadDate = mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(creationTime)); } else { // assume UTC mptHistory.loadDate = mpt::Date::forget_timezone(mpt::Date::UnixAsUTC(creationTime)); } mptHistory.openTime = static_cast(mpt::round((mpt::Date::UnixAsSeconds(mpt::Date::UnixNow()) - mpt::Date::UnixAsSeconds(creationTime)) * HISTORY_TIMER_PRECISION)); #endif // MODPLUG_TRACKER } ITHistoryStruct itHistory; itHistory.ConvertToIT(mptHistory); mpt::IO::Write(f, itHistory); } return bytesWritten; } bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool compatibilityExport) { const CModSpecifications &specs = (GetType() == MOD_TYPE_MPT ? ModSpecs::mptm : (compatibilityExport ? ModSpecs::it : ModSpecs::itEx)); uint32 dwChnNamLen; ITFileHeader itHeader; uint64 dwPos = 0; uint32 dwHdrPos = 0, dwExtra = 0; // Writing Header MemsetZero(itHeader); dwChnNamLen = 0; memcpy(itHeader.id, "IMPM", 4); mpt::String::WriteBuf(mpt::String::nullTerminated, itHeader.songname) = m_songName; itHeader.highlight_minor = mpt::saturate_cast(m_nDefaultRowsPerBeat); itHeader.highlight_major = mpt::saturate_cast(m_nDefaultRowsPerMeasure); if(GetType() == MOD_TYPE_MPT) { itHeader.ordnum = Order().GetLengthTailTrimmed(); if(Order().NeedsExtraDatafield() && itHeader.ordnum > 256) { // If there are more order items, write them elsewhere. itHeader.ordnum = 256; } } else { // An additional "---" pattern is appended so Impulse Tracker won't ignore the last order item. // Interestingly, this can exceed IT's 256 order limit. Also, IT will always save at least two orders. itHeader.ordnum = std::min(Order().GetLengthTailTrimmed(), specs.ordersMax) + 1; if(itHeader.ordnum < 2) itHeader.ordnum = 2; } itHeader.insnum = std::min(m_nInstruments, specs.instrumentsMax); itHeader.smpnum = std::min(m_nSamples, specs.samplesMax); itHeader.patnum = std::min(Patterns.GetNumPatterns(), specs.patternsMax); // Parapointers std::vector patpos(itHeader.patnum); std::vector smppos(itHeader.smpnum); std::vector inspos(itHeader.insnum); //VERSION if(GetType() == MOD_TYPE_MPT) { // MPTM itHeader.cwtv = verMptFileVer; // Used in OMPT-hack versioning. itHeader.cmwt = 0x888; } else { // IT const uint32 mptVersion = Version::Current().GetRawVersion(); itHeader.cwtv = 0x5000 | static_cast((mptVersion >> 16) & 0x0FFF); // format: txyy (t = tracker ID, x = version major, yy = version minor), e.g. 0x5117 (OpenMPT = 5, 117 = v1.17) itHeader.cmwt = 0x0214; // Common compatible tracker :) // Hack from schism tracker: for(INSTRUMENTINDEX nIns = 1; nIns <= GetNumInstruments(); nIns++) { if(Instruments[nIns] && Instruments[nIns]->PitchEnv.dwFlags[ENV_FILTER]) { itHeader.cmwt = 0x0216; break; } } if(compatibilityExport) itHeader.reserved = mptVersion & 0xFFFF; else memcpy(&itHeader.reserved, "OMPT", 4); } itHeader.flags = ITFileHeader::useStereoPlayback | ITFileHeader::useMIDIPitchController; itHeader.special = ITFileHeader::embedEditHistory | ITFileHeader::embedPatternHighlights; if(m_nInstruments) itHeader.flags |= ITFileHeader::instrumentMode; if(m_SongFlags[SONG_LINEARSLIDES]) itHeader.flags |= ITFileHeader::linearSlides; if(m_SongFlags[SONG_ITOLDEFFECTS]) itHeader.flags |= ITFileHeader::itOldEffects; if(m_SongFlags[SONG_ITCOMPATGXX]) itHeader.flags |= ITFileHeader::itCompatGxx; if(m_SongFlags[SONG_EXFILTERRANGE] && !compatibilityExport) itHeader.flags |= ITFileHeader::extendedFilterRange; itHeader.globalvol = static_cast(m_nDefaultGlobalVolume / 2u); itHeader.mv = static_cast(std::min(m_nSamplePreAmp, uint32(128))); itHeader.speed = mpt::saturate_cast(Order().GetDefaultSpeed()); itHeader.tempo = mpt::saturate_cast(Order().GetDefaultTempo().GetInt()); // We save the real tempo in an extension below if it exceeds 255. itHeader.sep = 128; // pan separation // IT doesn't have a per-instrument Pitch Wheel Depth setting, so we just store the first non-zero PWD setting in the header. for(INSTRUMENTINDEX ins = 1; ins <= GetNumInstruments(); ins++) { if(Instruments[ins] != nullptr && Instruments[ins]->midiPWD != 0) { itHeader.pwd = static_cast(std::abs(Instruments[ins]->midiPWD)); break; } } dwHdrPos = sizeof(itHeader) + itHeader.ordnum; // Channel Pan and Volume memset(itHeader.chnpan, 0xA0, 64); memset(itHeader.chnvol, 64, 64); for(CHANNELINDEX ich = 0; ich < std::min(GetNumChannels(), CHANNELINDEX(64)); ich++) // Header only has room for settings for 64 chans... { itHeader.chnpan[ich] = (uint8)(ChnSettings[ich].nPan >> 2); if (ChnSettings[ich].dwFlags[CHN_SURROUND]) itHeader.chnpan[ich] = 100; itHeader.chnvol[ich] = (uint8)(ChnSettings[ich].nVolume); #ifdef MODPLUG_TRACKER if(TrackerSettings::Instance().MiscSaveChannelMuteStatus) #endif if (ChnSettings[ich].dwFlags[CHN_MUTE]) itHeader.chnpan[ich] |= 0x80; } // Channel names if(!compatibilityExport) { for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { if(ChnSettings[i].szName[0]) { dwChnNamLen = (i + 1) * MAX_CHANNELNAME; } } if(dwChnNamLen) dwExtra += dwChnNamLen + 8; } if(!m_MidiCfg.IsMacroDefaultSetupUsed()) { itHeader.flags |= ITFileHeader::reqEmbeddedMIDIConfig; itHeader.special |= ITFileHeader::embedMIDIConfiguration; dwExtra += sizeof(MIDIMacroConfigData); } // Pattern Names const PATTERNINDEX numNamedPats = compatibilityExport ? 0 : Patterns.GetNumNamedPatterns(); if(numNamedPats > 0) { dwExtra += (numNamedPats * MAX_PATTERNNAME) + 8; } // Mix Plugins. Just calculate the size of this extra block for now. if(!compatibilityExport) { dwExtra += SaveMixPlugins(nullptr, true); } // Edit History. Just calculate the size of this extra block for now. dwExtra += SaveITEditHistory(*this, nullptr); // Comments uint16 msglength = 0; if(!m_songMessage.empty()) { itHeader.special |= ITFileHeader::embedSongMessage; itHeader.msglength = msglength = mpt::saturate_cast(m_songMessage.length() + 1u); itHeader.msgoffset = dwHdrPos + dwExtra + (itHeader.insnum + itHeader.smpnum + itHeader.patnum) * 4; } // Write file header mpt::IO::Write(f, itHeader); Order().WriteAsByte(f, itHeader.ordnum); mpt::IO::Write(f, inspos); mpt::IO::Write(f, smppos); mpt::IO::Write(f, patpos); // Writing edit history information SaveITEditHistory(*this, &f); // Writing midi cfg if(itHeader.flags & ITFileHeader::reqEmbeddedMIDIConfig) { mpt::IO::Write(f, static_cast(m_MidiCfg)); } // Writing pattern names if(numNamedPats) { mpt::IO::WriteRaw(f, "PNAM", 4); mpt::IO::WriteIntLE(f, numNamedPats * MAX_PATTERNNAME); for(PATTERNINDEX pat = 0; pat < numNamedPats; pat++) { char name[MAX_PATTERNNAME]; mpt::String::WriteBuf(mpt::String::maybeNullTerminated, name) = Patterns[pat].GetName(); mpt::IO::Write(f, name); } } // Writing channel names if(dwChnNamLen && !compatibilityExport) { mpt::IO::WriteRaw(f, "CNAM", 4); mpt::IO::WriteIntLE(f, dwChnNamLen); uint32 nChnNames = dwChnNamLen / MAX_CHANNELNAME; for(uint32 inam = 0; inam < nChnNames; inam++) { char name[MAX_CHANNELNAME]; mpt::String::WriteBuf(mpt::String::maybeNullTerminated, name) = ChnSettings[inam].szName; mpt::IO::Write(f, name); } } // Writing mix plugins info if(!compatibilityExport) { SaveMixPlugins(&f, false); } // Writing song message dwPos = dwHdrPos + dwExtra + (itHeader.insnum + itHeader.smpnum + itHeader.patnum) * 4; if(itHeader.special & ITFileHeader::embedSongMessage) { dwPos += msglength; mpt::IO::WriteRaw(f, m_songMessage.c_str(), msglength); } // Writing instruments const ModInstrument dummyInstr; for(INSTRUMENTINDEX nins = 1; nins <= itHeader.insnum; nins++) { ITInstrumentEx iti; uint32 instSize; const ModInstrument &instr = (Instruments[nins] != nullptr) ? *Instruments[nins] : dummyInstr; instSize = iti.ConvertToIT(instr, compatibilityExport, *this); // Writing instrument inspos[nins - 1] = static_cast(dwPos); dwPos += instSize; mpt::IO::WritePartial(f, iti, instSize); } // Writing dummy sample headers (until we know the correct sample data offset) ITSample itss; MemsetZero(itss); for(SAMPLEINDEX smp = 0; smp < itHeader.smpnum; smp++) { smppos[smp] = static_cast(dwPos); dwPos += sizeof(ITSample); mpt::IO::Write(f, itss); } // Writing Patterns bool needsMptPatSave = false; for(PATTERNINDEX pat = 0; pat < itHeader.patnum; pat++) { uint32 dwPatPos = static_cast(dwPos); if (!Patterns.IsValidPat(pat)) continue; if(Patterns[pat].GetOverrideSignature()) needsMptPatSave = true; // Check for empty pattern if(Patterns[pat].GetNumRows() == 64 && Patterns.IsPatternEmpty(pat)) { patpos[pat] = 0; continue; } patpos[pat] = static_cast(dwPos); // Write pattern header ROWINDEX writeRows = mpt::saturate_cast(Patterns[pat].GetNumRows()); if(compatibilityExport) writeRows = std::clamp(writeRows, ROWINDEX(32), ROWINDEX(200)); if(writeRows != Patterns[pat].GetNumRows()) AddToLog(LogWarning, MPT_UFORMAT("Warning: Pattern {} was resized from {} to {} rows.")(pat, Patterns[pat].GetNumRows(), writeRows)); uint16 writeSize = 0; uint16le patinfo[4]; patinfo[0] = 0; patinfo[1] = static_cast(writeRows); patinfo[2] = 0; patinfo[3] = 0; mpt::IO::Write(f, patinfo); dwPos += 8; struct ChnState { uint8 note = 0, instr = 0, vol = 0, command = 0, param = 0, valid = 0, mask = 0xFF; }; const CHANNELINDEX maxChannels = std::min(specs.channelsMax, GetNumChannels()); std::vector chnStates(maxChannels); // Maximum 7 bytes per cell, plus end of row marker, so this buffer is always large enough to cover one row. std::vector buf(7 * maxChannels + 1); const ROWINDEX readRows = std::min(writeRows, Patterns[pat].GetNumRows()); for(ROWINDEX row = 0; row < readRows; row++) { uint32 len = 0; const ModCommand *m = Patterns[pat].GetpModCommand(row, 0); bool writePatternBreak = (readRows < writeRows && row + 1 == readRows && !Patterns[pat].RowHasJump(row)); for(CHANNELINDEX ch = 0; ch < maxChannels; ch++, m++) { // Skip mptm-specific notes. if(m->IsPcNote()) { needsMptPatSave = true; continue; } auto &chnState = chnStates[ch]; uint8 b = 1; uint8 vol = 0xFF; uint8 note = m->note; if(note >= NOTE_MIN && note <= NOTE_MIN + 119) note = m->note - NOTE_MIN; else if(note == NOTE_FADE) note = (GetType() == MOD_TYPE_MPT) ? 0xFD : 0xF6; else if(note == NOTE_NOTECUT) note = 0xFE; else if(note == NOTE_KEYOFF) note = 0xFF; else b = 0; if(m->instr) b |= 2; if(m->volcmd != VOLCMD_NONE) { vol = std::min(m->vol, uint8(9)); switch(m->volcmd) { case VOLCMD_VOLUME: vol = std::min(m->vol, uint8(64)); break; case VOLCMD_PANNING: vol = std::min(m->vol, uint8(64)) + 128; break; case VOLCMD_VOLSLIDEUP: vol += 85; break; case VOLCMD_VOLSLIDEDOWN: vol += 95; break; case VOLCMD_FINEVOLUP: vol += 65; break; case VOLCMD_FINEVOLDOWN: vol += 75; break; case VOLCMD_VIBRATODEPTH: vol += 203; break; case VOLCMD_TONEPORTAMENTO: vol += 193; break; case VOLCMD_PORTADOWN: vol += 105; break; case VOLCMD_PORTAUP: vol += 115; break; case VOLCMD_VIBRATOSPEED: vol = 203; break; case VOLCMD_OFFSET: if(!compatibilityExport) vol += 223; else vol = 0xFF; break; default: vol = 0xFF; } } if(vol != 0xFF) b |= 4; uint8 command = 0, param = 0; if(m->command == CMD_VOLUME && vol == 0xFF) { vol = std::min(m->param, ModCommand::PARAM(64)); b |= 4; } else if(m->command != CMD_NONE) { S3MSaveConvert(*m, command, param, true, compatibilityExport); if (command) b |= 8; } if(writePatternBreak && !(b & 8)) { b |= 8; command = 'C' ^ 0x40; writePatternBreak = false; } // Packing information if (b) { // Same note ? if (b & 1) { if ((note == chnState.note) && (chnState.valid & 1)) { b &= ~1; b |= 0x10; } else { chnState.note = note; chnState.valid |= 1; } } // Same instrument ? if (b & 2) { if ((m->instr == chnState.instr) && (chnState.valid & 2)) { b &= ~2; b |= 0x20; } else { chnState.instr = m->instr; chnState.valid |= 2; } } // Same volume column byte ? if (b & 4) { if ((vol == chnState.vol) && (chnState.valid & 4)) { b &= ~4; b |= 0x40; } else { chnState.vol = vol; chnState.valid |= 4; } } // Same command / param ? if (b & 8) { if ((command == chnState.command) && (param == chnState.param) && (chnState.valid & 8)) { b &= ~8; b |= 0x80; } else { chnState.command = command; chnState.param = param; chnState.valid |= 8; } } if (b != chnState.mask) { chnState.mask = b; buf[len++] = static_cast((ch + 1) | IT_bitmask_patternChanEnabled_c); buf[len++] = b; } else { buf[len++] = static_cast(ch + 1); } if (b & 1) buf[len++] = note; if (b & 2) buf[len++] = m->instr; if (b & 4) buf[len++] = vol; if (b & 8) { buf[len++] = command; buf[len++] = param; } } } buf[len++] = 0; if(writeSize > uint16_max - len) { AddToLog(LogWarning, MPT_UFORMAT("Warning: File format limit was reached. Some pattern data may not get written to file. (pattern {})")(pat)); break; } else { writeSize += static_cast(len); mpt::IO::WriteRaw(f, buf.data(), len); } if(writePatternBreak) { // Didn't manage to put a pattern break, so put it on the next row instead. const uint8 patternBreak[] = {1 | IT_bitmask_patternChanEnabled_c, 8, 'C' ^ 0x40, 0}; mpt::IO::Write(f, patternBreak); writeSize += sizeof(patternBreak); } } if(readRows < writeRows) { // Invent empty rows at end (if we end up here, the pattern is very short and we don't have to care about writeSize overflowing the 16-bit limit) writeSize += static_cast(writeRows - readRows); buf.assign(writeRows - readRows, 0); mpt::IO::Write(f, buf); } dwPos += writeSize; mpt::IO::SeekAbsolute(f, dwPatPos); patinfo[0] = writeSize; mpt::IO::Write(f, patinfo); mpt::IO::SeekAbsolute(f, dwPos); } // Writing Sample Data for(SAMPLEINDEX smp = 1; smp <= itHeader.smpnum; smp++) { const ModSample &sample = Samples[smp]; #ifdef MODPLUG_TRACKER uint32 type = GetType() == MOD_TYPE_IT ? 1 : 4; if(compatibilityExport) type = 2; bool compress = ((((sample.GetNumChannels() > 1) ? TrackerSettings::Instance().MiscITCompressionStereo : TrackerSettings::Instance().MiscITCompressionMono) & type) != 0); #else bool compress = false; #endif // MODPLUG_TRACKER // Old MPT, DUMB and probably other libraries will only consider the IT2.15 compression flag if the header version also indicates IT2.15. // MilkyTracker <= 0.90.85 assumes IT2.15 compression with cmwt == 0x215, ignoring the delta flag completely. itss.ConvertToIT(sample, GetType(), compress, itHeader.cmwt >= 0x215, GetType() == MOD_TYPE_MPT); const bool isExternal = itss.cvt == ITSample::cvtExternalSample; mpt::String::WriteBuf(mpt::String::nullTerminated, itss.name) = m_szNames[smp]; itss.samplepointer = static_cast(dwPos); if(dwPos > uint32_max) { // Sample position does not fit into sample pointer! AddToLog(LogWarning, MPT_UFORMAT("Cannot save sample {}: File size exceeds 4 GB.")(smp)); itss.samplepointer = 0; itss.length = 0; } SmpLength smpLength = itss.length; // Possibly truncated to 2^32 samples mpt::IO::SeekAbsolute(f, smppos[smp - 1]); mpt::IO::Write(f, itss); if(dwPos > uint32_max) { continue; } // TODO this actually wraps around at 2 GB, so we either need to use the 64-bit seek API or warn earlier! mpt::IO::SeekAbsolute(f, dwPos); if(!isExternal) { if(sample.nLength > smpLength && smpLength != 0) { // Sample length does not fit into IT header! AddToLog(LogWarning, MPT_UFORMAT("Truncating sample {}: Length exceeds exceeds 4 gigasamples.")(smp)); } dwPos += itss.GetSampleFormat().WriteSample(f, sample, smpLength); } else { #ifdef MPT_EXTERNAL_SAMPLES const std::string filenameU8 = mpt::AbsolutePathToRelative(GetSamplePath(smp), filename.GetDirectoryWithDrive()).ToUTF8(); const size_t strSize = filenameU8.size(); size_t intBytes = 0; if(mpt::IO::WriteVarInt(f, strSize, &intBytes)) { dwPos += intBytes + strSize; mpt::IO::WriteRaw(f, filenameU8.data(), strSize); } #else MPT_UNREFERENCED_PARAMETER(filename); #endif // MPT_EXTERNAL_SAMPLES } } //Save hacked-on extra info if(!compatibilityExport) { if(GetNumInstruments()) { SaveExtendedInstrumentProperties(0, GetType(), f); } SaveExtendedSongProperties(f); } // Updating offsets mpt::IO::SeekAbsolute(f, dwHdrPos); mpt::IO::Write(f, inspos); mpt::IO::Write(f, smppos); mpt::IO::Write(f, patpos); if(GetType() == MOD_TYPE_IT) { return true; } //hack //BEGIN: MPT SPECIFIC: bool success = true; mpt::IO::SeekEnd(f); const mpt::IO::Offset MPTStartPos = mpt::IO::TellWrite(f); srlztn::SsbWrite ssb(f); ssb.BeginWrite("mptm", Version::Current().GetRawVersion()); if(GetTuneSpecificTunings().GetNumTunings() > 0 || AreNonDefaultTuningsUsed(*this)) ssb.WriteItem(int8(1), "UTF8Tuning"); if(GetTuneSpecificTunings().GetNumTunings() > 0) ssb.WriteItem(GetTuneSpecificTunings(), "0", &WriteTuningCollection); if(AreNonDefaultTuningsUsed(*this)) ssb.WriteItem(*this, "1", &WriteTuningMap); if(Order().NeedsExtraDatafield()) ssb.WriteItem(Order, "2", &WriteModSequenceOld); if(needsMptPatSave) ssb.WriteItem(Patterns, FileIdPatterns, &WriteModPatterns); ssb.WriteItem(Order, FileIdSequences, &WriteModSequences); ssb.FinishWrite(); if(ssb.HasFailed()) { AddToLog(LogError, U_("Error occurred in writing MPTM extensions.")); } //Last 4 bytes should tell where the hack mpt things begin. if(!f.good()) { f.clear(); success = false; } mpt::IO::WriteIntLE(f, static_cast(MPTStartPos)); mpt::IO::SeekEnd(f); //END : MPT SPECIFIC //NO WRITING HERE ANYMORE. return success; } #endif // MODPLUG_NO_FILESAVE #ifndef MODPLUG_NO_FILESAVE uint32 CSoundFile::SaveMixPlugins(std::ostream *file, bool updatePlugData) { #ifndef NO_PLUGINS uint32 totalSize = 0; for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++) { const SNDMIXPLUGIN &plugin = m_MixPlugins[i]; if(plugin.IsValidPlugin()) { uint32 chunkSize = sizeof(SNDMIXPLUGININFO) + 4; // plugininfo+4 (datalen) if(plugin.pMixPlugin && updatePlugData) { plugin.pMixPlugin->SaveAllParameters(); } const uint32 extraDataSize = 4 + sizeof(IEEE754binary32LE) + // 4 for ID and size of dryRatio 4 + sizeof(int32); // Default Program // For each extra entity, add 4 for ID, plus 4 for size of entity, plus size of entity chunkSize += extraDataSize + 4; // +4 is for size field itself const uint32 plugDataSize = std::min(mpt::saturate_cast(plugin.pluginData.size()), uint32_max - chunkSize); chunkSize += plugDataSize; if(file) { std::ostream &f = *file; // Chunk ID (= plugin ID) char id[4] = { 'F', 'X', '0', '0' }; if(i >= 100) id[1] = static_cast(static_cast('0') + (i / 100u)); id[2] = static_cast(static_cast('0') + ((i / 10u) % 10u)); id[3] = static_cast(static_cast('0') + (i % 10u)); mpt::IO::WriteRaw(f, id, 4); // Write chunk size, plugin info and plugin data chunk mpt::IO::WriteIntLE(f, chunkSize); mpt::IO::Write(f, m_MixPlugins[i].Info); mpt::IO::WriteIntLE(f, plugDataSize); if(plugDataSize) { mpt::IO::WriteRaw(f, m_MixPlugins[i].pluginData.data(), plugDataSize); } mpt::IO::WriteIntLE(f, extraDataSize); // Dry/Wet ratio mpt::IO::WriteRaw(f, "DWRT", 4); // DWRT chunk does not include a size, so better make sure we always write 4 bytes here. static_assert(sizeof(IEEE754binary32LE) == 4); mpt::IO::Write(f, IEEE754binary32LE(m_MixPlugins[i].fDryRatio)); // Default program mpt::IO::WriteRaw(f, "PROG", 4); // PROG chunk does not include a size, so better make sure we always write 4 bytes here. static_assert(sizeof(m_MixPlugins[i].defaultProgram) == sizeof(int32)); mpt::IO::WriteIntLE(f, m_MixPlugins[i].defaultProgram); // Please, if you add any more chunks here, don't repeat history (see above) and *do* add a size field for your chunk, mmmkay? } totalSize += chunkSize + 8; } } std::vector chinfo(GetNumChannels()); uint32 numChInfo = 0; for(CHANNELINDEX j = 0; j < GetNumChannels(); j++) { if((chinfo[j] = ChnSettings[j].nMixPlugin) != 0) { numChInfo = j + 1; } } if(numChInfo) { if(file) { std::ostream &f = *file; mpt::IO::WriteRaw(f, "CHFX", 4); mpt::IO::WriteIntLE(f, numChInfo * 4); chinfo.resize(numChInfo); mpt::IO::Write(f, chinfo); } totalSize += numChInfo * 4 + 8; } return totalSize; #else MPT_UNREFERENCED_PARAMETER(file); MPT_UNREFERENCED_PARAMETER(updatePlugData); return 0; #endif // NO_PLUGINS } #endif // MODPLUG_NO_FILESAVE std::pair CSoundFile::LoadMixPlugins(FileReader &file, bool ignoreChannelCount) { bool hasPluginChunks = false, isBeRoTracker = false; while(file.CanRead(9)) { char code[4]; file.ReadArray(code); const uint32 chunkSize = file.ReadUint32LE(); if(!memcmp(code, "IMPI", 4) // IT instrument, we definitely read too far || !memcmp(code, "IMPS", 4) // IT sample, ditto || !memcmp(code, "XTPM", 4) // Instrument extensions, ditto || !memcmp(code, "STPM", 4) // Song extensions, ditto || !file.CanRead(chunkSize)) { file.SkipBack(8); return std::make_pair(hasPluginChunks, isBeRoTracker); } FileReader chunk = file.ReadChunk(chunkSize); // Channel FX if(!memcmp(code, "CHFX", 4)) { if(!ignoreChannelCount) { ChnSettings.resize(std::clamp(static_cast(chunkSize / 4), GetNumChannels(), MAX_BASECHANNELS)); } for(auto &chn : ChnSettings) { chn.nMixPlugin = static_cast(chunk.ReadUint32LE()); } hasPluginChunks = true; #ifndef NO_PLUGINS } // Plugin Data FX00, ... FX99, F100, ... F255 #define MPT_ISDIGIT(x) (code[(x)] >= '0' && code[(x)] <= '9') else if(code[0] == 'F' && (code[1] == 'X' || MPT_ISDIGIT(1)) && MPT_ISDIGIT(2) && MPT_ISDIGIT(3)) #undef MPT_ISDIGIT { uint16 fxplug = static_cast((code[2] - '0') * 10 + (code[3] - '0')); //calculate plug-in number. if(code[1] != 'X') fxplug += static_cast((code[1] - '0') * 100); if(fxplug < MAX_MIXPLUGINS) { PLUGINDEX plug = static_cast(fxplug); ReadMixPluginChunk(chunk, m_MixPlugins[plug]); } hasPluginChunks = true; #endif // NO_PLUGINS } else if(!memcmp(code, "MODU", 4)) { isBeRoTracker = true; m_dwLastSavedWithVersion = Version(); // Reset MPT detection for old files that have a similar fingerprint } } return std::make_pair(hasPluginChunks, isBeRoTracker); } #ifndef NO_PLUGINS void CSoundFile::ReadMixPluginChunk(FileReader &file, SNDMIXPLUGIN &plugin) { // MPT's standard plugin data. Size not specified in file.. grrr.. file.ReadStruct(plugin.Info); mpt::String::SetNullTerminator(plugin.Info.szName.buf); mpt::String::SetNullTerminator(plugin.Info.szLibraryName.buf); plugin.editorX = plugin.editorY = int32_min; // Plugin user data FileReader pluginDataChunk = file.ReadChunk(file.ReadUint32LE()); plugin.pluginData.resize(mpt::saturate_cast(pluginDataChunk.BytesLeft())); pluginDataChunk.ReadRaw(mpt::as_span(plugin.pluginData)); if(FileReader modularData = file.ReadChunk(file.ReadUint32LE()); modularData.IsValid()) { while(modularData.CanRead(5)) { // do we recognize this chunk? char code[4]; modularData.ReadArray(code); uint32 dataSize = 0; if(!memcmp(code, "DWRT", 4) || !memcmp(code, "PROG", 4)) { // Legacy system with fixed size chunks dataSize = 4; } else { dataSize = modularData.ReadUint32LE(); } FileReader dataChunk = modularData.ReadChunk(dataSize); if(!memcmp(code, "DWRT", 4)) { plugin.fDryRatio = mpt::safe_clamp(dataChunk.ReadFloatLE(), 0.0f, 1.0f); } else if(!memcmp(code, "PROG", 4)) { plugin.defaultProgram = dataChunk.ReadUint32LE(); } else if(!memcmp(code, "MCRO", 4)) { // Read plugin-specific macros //dataChunk.ReadStructPartial(plugin.macros, dataChunk.GetLength()); } } } } #endif // NO_PLUGINS #ifndef MODPLUG_NO_FILESAVE void CSoundFile::SaveExtendedSongProperties(std::ostream &f) const { const CModSpecifications &specs = GetModSpecifications(); // Extra song data - Yet Another Hack. mpt::IO::WriteIntLE(f, MagicBE("MPTS")); const auto WriteModularHeader = [](std::ostream &f, uint32 code, size_t fsize) { mpt::IO::WriteIntLE(f, code); MPT_ASSERT(mpt::in_range(fsize)); mpt::IO::WriteIntLE(f, static_cast(fsize)); }; const auto WriteModular = [&WriteModularHeader](std::ostream &f, uint32 code, auto field) { WriteModularHeader(f, code, sizeof(field)); mpt::IO::WriteIntLE(f, field); }; if(Order().GetDefaultTempo().GetInt() > 255) { uint32 tempo = Order().GetDefaultTempo().GetInt(); WriteModular(f, MagicBE("DT.."), tempo); } if(Order().GetDefaultTempo().GetFract() != 0 && specs.hasFractionalTempo) { uint32 tempo = Order().GetDefaultTempo().GetFract(); WriteModular(f, MagicLE("DTFR"), tempo); } if(m_nDefaultRowsPerBeat > 255 || m_nDefaultRowsPerMeasure > 255 || GetType() == MOD_TYPE_XM) { WriteModular(f, MagicBE("RPB."), m_nDefaultRowsPerBeat); WriteModular(f, MagicBE("RPM."), m_nDefaultRowsPerMeasure); } if(GetType() != MOD_TYPE_XM) { WriteModular(f, MagicBE("C..."), GetNumChannels()); } if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && GetNumChannels() > 64) { // IT header has only room for 64 channels. Save the settings that do not fit to the header here as an extension. WriteModularHeader(f, MagicBE("ChnS"), (GetNumChannels() - 64) * 2); for(CHANNELINDEX chn = 64; chn < GetNumChannels(); chn++) { uint8 panvol[2]; panvol[0] = (uint8)(ChnSettings[chn].nPan >> 2); if (ChnSettings[chn].dwFlags[CHN_SURROUND]) panvol[0] = 100; if (ChnSettings[chn].dwFlags[CHN_MUTE]) panvol[0] |= 0x80; panvol[1] = (uint8)ChnSettings[chn].nVolume; mpt::IO::Write(f, panvol); } } if(m_nTempoMode != TempoMode::Classic) { WriteModularHeader(f, MagicBE("TM.."), 1); uint8 mode = static_cast(m_nTempoMode); mpt::IO::WriteIntLE(f, mode); } const int32 tmpMixLevels = static_cast(m_nMixLevels); WriteModular(f, MagicBE("PMM."), tmpMixLevels); if(m_dwCreatedWithVersion) { WriteModular(f, MagicBE("CWV."), m_dwCreatedWithVersion.GetRawVersion()); } WriteModular(f, MagicBE("LSWV"), Version::Current().GetRawVersion()); if(GetType() == MOD_TYPE_XM || m_nSamplePreAmp > 128) { WriteModular(f, MagicBE("SPA."), m_nSamplePreAmp); } WriteModular(f, MagicBE("VSTV"), m_nVSTiVolume); if(GetType() == MOD_TYPE_XM && m_nDefaultGlobalVolume != MAX_GLOBAL_VOLUME) { WriteModular(f, MagicBE("DGV."), m_nDefaultGlobalVolume); } if(GetType() != MOD_TYPE_XM && Order().GetRestartPos() != 0) { WriteModular(f, MagicBE("RP.."), Order().GetRestartPos()); } if(m_nResampling != SRCMODE_DEFAULT && specs.hasDefaultResampling) { WriteModular(f, MagicLE("RSMP"), static_cast(m_nResampling)); } // Sample cues if(GetType() == MOD_TYPE_MPT) { for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { const ModSample &sample = Samples[smp]; if(sample.nLength && sample.HasCustomCuePoints()) { // Write one chunk for every sample. // Rationale: chunks are limited to 65536 bytes, which can easily be reached // with the amount of samples that OpenMPT supports. WriteModularHeader(f, MagicLE("CUES"), 2 + std::size(sample.cues) * 4); mpt::IO::WriteIntLE(f, smp); for(auto cue : sample.cues) { mpt::IO::WriteIntLE(f, cue); } } } } // Tempo Swing Factors if(!m_tempoSwing.empty()) { std::ostringstream oStrm; TempoSwing::Serialize(oStrm, m_tempoSwing); std::string data = oStrm.str(); uint16 length = mpt::saturate_cast(data.size()); WriteModularHeader(f, MagicLE("SWNG"), length); mpt::IO::WriteRaw(f, data.data(), length); } // Playback compatibility flags { const auto supportedBehaviours = GetSupportedPlaybackBehaviour(GetBestSaveFormat()); std::array bits; bits.fill(0); size_t maxBit = 0; for(size_t i = 0; i < kMaxPlayBehaviours; i++) { if(m_playBehaviour[i] && supportedBehaviours[i]) { bits[i >> 3] |= 1 << (i & 0x07); maxBit = i + 8; } } uint16 numBytes = static_cast(maxBit / 8u); WriteModularHeader(f, MagicBE("MSF."), numBytes); mpt::IO::WriteRaw(f, bits.data(), numBytes); } if(!m_songArtist.empty() && specs.hasArtistName) { std::string songArtistU8 = mpt::ToCharset(mpt::Charset::UTF8, m_songArtist); uint16 length = mpt::saturate_cast(songArtistU8.length()); WriteModularHeader(f, MagicLE("AUTH"), length); mpt::IO::WriteRaw(f, songArtistU8.c_str(), length); } #ifdef MODPLUG_TRACKER // MIDI mapping directives if(GetMIDIMapper().GetCount() > 0) { const size_t objectsize = GetMIDIMapper().Serialize(); if(!mpt::in_range(objectsize)) { AddToLog(LogWarning, U_("Too many MIDI Mapping directives to save; data won't be written.")); } else { WriteModularHeader(f, MagicBE("MIMA"), objectsize); GetMIDIMapper().Serialize(&f); } } // Channel colors { CHANNELINDEX numChannels = 0; for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { if(ChnSettings[i].color != ModChannelSettings::INVALID_COLOR) { numChannels = i + 1; } } if(numChannels > 0) { WriteModularHeader(f, MagicLE("CCOL"), numChannels * 4); for(CHANNELINDEX i = 0; i < numChannels; i++) { uint32 color = ChnSettings[i].color; if(color != ModChannelSettings::INVALID_COLOR) color &= 0x00FFFFFF; std::array rgb{static_cast(color), static_cast(color >> 8), static_cast(color >> 16), static_cast(color >> 24)}; mpt::IO::Write(f, rgb); } } } #endif } #endif // MODPLUG_NO_FILESAVE /* The following song properties can be read and written: AUTH [all] Song artist C... [IT / MPTM] Number of channels (for IT / MPTM where there is no explicit channel count and we want to keep the properties of channels beyond the last channel that contains any pattern data) CCOL [all] Channel colors ChnS [IT / MPTM] Channel settings for channels 65-127 if needed (doesn't fit to IT header). CUES [MPTM] Sample cue points CWV. [all] Created With Version DGV. [XM] Default Global Volume DT.. [all] Default Tempo, if it doesn't fit in the header value DTFR [MPTM] Fractional part of default tempo LSWV [all] Last Saved With Version MIMA [all] MIdi MApping directives MSF. [all] Mod(Specific)Flags PMM. [all] Mix Mode RP.. [IT / MPTM] Legacy Restart Position RPB. [all] Rows Per Beat (if not supported / value doesn't fit in header) RPM. [all] Per Measure (if not supported / value doesn't fit in header) RSMP [MPTM] Default resampling SPA. [all] Sample Pre-Amp (if not supported / value doesn't fit in header) SWNG [MPTM] Tempo swing factors TM.. [all] Tempo Mode VSTV [all] Synth volume */ template void ReadField(FileReader &chunk, std::size_t size, T &field) { field = chunk.ReadSizedIntLE(size); } template void ReadFieldCast(FileReader &chunk, std::size_t size, T &field) { static_assert(sizeof(T) <= sizeof(int32)); field = static_cast(chunk.ReadSizedIntLE(size)); } bool CSoundFile::LoadExtendedSongProperties(FileReader &file, bool ignoreChannelCount, bool *pInterpretMptMade) { if(!file.ReadMagic("STPM")) // 'MPTS' { return false; } // Found MPTS, interpret the file MPT made. if(pInterpretMptMade != nullptr) *pInterpretMptMade = true; // HACK: Reset mod flags to default values here, as they are not always written. m_playBehaviour.reset(); while(file.CanRead(7)) { const uint32 code = file.ReadUint32LE(); const uint16 size = file.ReadUint16LE(); // Start of MPTM extensions, non-ASCII ID or truncated field if(code == MagicLE("228\x04")) { file.SkipBack(6); break; } else if((code & 0x80808080) || !(code & 0x60606060) || !file.CanRead(size)) { break; } FileReader chunk = file.ReadChunk(size); switch (code) // interpret field code { case MagicBE("DT.."): { uint32 tempo; ReadField(chunk, size, tempo); Order().SetDefaultTempo(TEMPO(tempo, Order().GetDefaultTempo().GetFract())); break; } case MagicLE("DTFR"): { uint32 tempoFract; ReadField(chunk, size, tempoFract); Order().SetDefaultTempo(TEMPO(Order().GetDefaultTempo().GetInt(), tempoFract)); break; } case MagicBE("RPB."): ReadField(chunk, size, m_nDefaultRowsPerBeat); break; case MagicBE("RPM."): ReadField(chunk, size, m_nDefaultRowsPerMeasure); break; // FIXME: If there are only PC events on the last few channels in an MPTM MO3, they won't be imported! case MagicBE("C..."): if(!ignoreChannelCount) { CHANNELINDEX chn = 0; ReadField(chunk, size, chn); ChnSettings.resize(Clamp(chn, GetNumChannels(), MAX_BASECHANNELS)); } break; case MagicBE("TM.."): ReadFieldCast(chunk, size, m_nTempoMode); break; case MagicBE("PMM."): ReadFieldCast(chunk, size, m_nMixLevels); break; case MagicBE("CWV."): { uint32 ver = 0; ReadField(chunk, size, ver); m_dwCreatedWithVersion = Version(ver); break; } case MagicBE("LSWV"): { uint32 ver = 0; ReadField(chunk, size, ver); if(ver != 0) { m_dwLastSavedWithVersion = Version(ver); } break; } case MagicBE("SPA."): ReadField(chunk, size, m_nSamplePreAmp); break; case MagicBE("VSTV"): ReadField(chunk, size, m_nVSTiVolume); break; case MagicBE("DGV."): ReadField(chunk, size, m_nDefaultGlobalVolume); break; case MagicBE("RP.."): if(GetType() != MOD_TYPE_XM) { ORDERINDEX restartPos; ReadField(chunk, size, restartPos); Order().SetRestartPos(restartPos); } break; case MagicLE("RSMP"): ReadFieldCast(chunk, size, m_nResampling); if(!Resampling::IsKnownMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT; break; #ifdef MODPLUG_TRACKER case MagicBE("MIMA"): GetMIDIMapper().Deserialize(chunk); break; case MagicLE("CCOL"): // Channel colors { const CHANNELINDEX channelsInFile = static_cast(size / 4u); if(!ignoreChannelCount) ChnSettings.resize(std::clamp(GetNumChannels(), channelsInFile, MAX_BASECHANNELS)); const CHANNELINDEX numChannels = std::min(channelsInFile, GetNumChannels()); for(CHANNELINDEX i = 0; i < numChannels; i++) { auto rgb = chunk.ReadArray(); if(rgb[3]) ChnSettings[i].color = ModChannelSettings::INVALID_COLOR; else ChnSettings[i].color = rgb[0] | (rgb[1] << 8) | (rgb[2] << 16); } } break; #endif case MagicLE("AUTH"): { std::string artist; chunk.ReadString(artist, chunk.GetLength()); m_songArtist = mpt::ToUnicode(mpt::Charset::UTF8, artist); } break; case MagicBE("ChnS"): // Channel settings for channels 65+ static_assert(MAX_BASECHANNELS >= 64); if(size <= (MAX_BASECHANNELS - 64) * 2 && (size % 2u) == 0 && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) { const CHANNELINDEX channelsInFile = mpt::saturate_cast(64 + size / 2); if(!ignoreChannelCount) ChnSettings.resize(std::clamp(GetNumChannels(), channelsInFile, MAX_BASECHANNELS)); const CHANNELINDEX numChannels = std::min(channelsInFile, GetNumChannels()); for(CHANNELINDEX chn = 64; chn < numChannels; chn++) { auto [pan, vol] = chunk.ReadArray(); if(pan != 0xFF) { ChnSettings[chn].nVolume = vol; ChnSettings[chn].nPan = 128; ChnSettings[chn].dwFlags.reset(); if(pan & 0x80) ChnSettings[chn].dwFlags.set(CHN_MUTE); pan &= 0x7F; if(pan <= 64) ChnSettings[chn].nPan = pan << 2; if(pan == 100) ChnSettings[chn].dwFlags.set(CHN_SURROUND); } } } break; case MagicLE("CUES"): // Sample cues if(size > 2) { SAMPLEINDEX smp = chunk.ReadUint16LE(); if(smp > 0 && smp <= GetNumSamples()) { ModSample &sample = Samples[smp]; for(auto &cue : sample.cues) { if(chunk.CanRead(4)) cue = chunk.ReadUint32LE(); else cue = MAX_SAMPLE_LENGTH; } } } break; case MagicLE("SWNG"): // Tempo Swing Factors if(size > 2) { std::istringstream iStrm(mpt::buffer_cast(chunk.ReadRawDataAsByteVector())); TempoSwing::Deserialize(iStrm, m_tempoSwing, chunk.GetLength()); } break; case MagicBE("MSF."): // Playback compatibility flags { size_t bit = 0; m_playBehaviour.reset(); while(chunk.CanRead(1) && bit < m_playBehaviour.size()) { uint8 b = chunk.ReadUint8(); for(uint8 i = 0; i < 8; i++, bit++) { if((b & (1 << i)) && bit < m_playBehaviour.size()) { m_playBehaviour.set(bit); } } } } break; } } // Validate read values. Order().SetDefaultTempo(Clamp(Order().GetDefaultTempo(), GetModSpecifications().GetTempoMin(), GetModSpecifications().GetTempoMax())); if(m_nTempoMode >= TempoMode::NumModes) m_nTempoMode = TempoMode::Classic; if(m_nMixLevels >= MixLevels::NumMixLevels) m_nMixLevels = MixLevels::Original; //m_dwCreatedWithVersion //m_dwLastSavedWithVersion return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_tcb.cpp0000644000175000017500000001405115017401256020312 00000000000000/* * Load_tcb.cpp * ------------ * Purpose: TCB Tracker module loader * Notes : Based on the manual scan available at https://files.scene.org/view/resources/gotpapers/manuals/tcb_tracker_1.0_manual_1990.pdf * and a bit of messing about in TCB Tracker 1.0 and 1.1. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "MODTools.h" OPENMPT_NAMESPACE_BEGIN struct TCBFileHeader { char magic[8]; // "AN COOL." (new) or "AN COOL!" (early TCB Tracker beta versions; not even TCB Tracker 1.0 can read these files) uint32be numPatterns; uint8 tempo; uint8 unused1; uint8 order[128]; uint8 numOrders; uint8 unused2; // Supposed to be part of lastOrder but then it would have to be a little-endian word bool IsNewFormat() const { return magic[7] == '.'; } bool IsValid() const { if(memcmp(magic, "AN COOL.", 8) && memcmp(magic, "AN COOL!", 8)) return false; if(tempo > 15 || unused1 || numOrders > 127 || unused2 || numPatterns > 128) return false; for(uint8 ord : order) { if(ord >= 128) return false; } return true; } uint32 GetHeaderMinimumAdditionalSize() const { uint32 size = 16 * 8; // Instrument names if(IsNewFormat()) size += 2 + 32; // Amiga flag + special values size += numPatterns * 512; return size; } }; MPT_BINARY_STRUCT(TCBFileHeader, 144) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderTCB(MemoryFileReader file, const uint64 *pfilesize) { TCBFileHeader fileHeader; file.Rewind(); if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadTCB(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); TCBFileHeader fileHeader; if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) return false; if(!file.CanRead(fileHeader.GetHeaderMinimumAdditionalSize())) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_MOD, 4); SetupMODPanning(true); Order().SetDefaultSpeed(16 - fileHeader.tempo); Order().SetDefaultTempoInt(125); ReadOrderFromArray(Order(), fileHeader.order, std::max(uint8(1), fileHeader.numOrders)); m_nSamplePreAmp = 64; m_SongFlags.set(SONG_IMPORTED); m_playBehaviour.set(kApplyUpperPeriodLimit); const bool newFormat = fileHeader.IsNewFormat(); bool useAmigaFreqs = false; if(newFormat) { uint16 amigaFreqs = file.ReadUint16BE(); if(amigaFreqs > 1) return false; useAmigaFreqs = amigaFreqs != 0; } const auto instrNames = file.ReadArray(); std::array specialValues{}; if(newFormat) file.ReadStruct(specialValues); m_nMinPeriod = useAmigaFreqs ? 113 * 4 : 92 * 4; m_nMaxPeriod = useAmigaFreqs ? 856 * 4 : 694 * 4; const PATTERNINDEX numPatterns = static_cast(fileHeader.numPatterns); if(loadFlags & loadPatternData) Patterns.ResizeArray(numPatterns); const uint8 noteOffset = useAmigaFreqs ? 0 : 3; for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { file.Skip(512); continue; } for(ModCommand &m : Patterns[pat]) { const auto [note, instrEffect] = file.ReadArray(); if(note >= 0x10 && note <= 0x3B) { m.note = static_cast(NOTE_MIDDLEC - 24 + (note >> 4) * 12 + (note & 0x0F) + noteOffset); m.instr = static_cast((instrEffect >> 4) + 1); } else if(note) { return false; } switch(instrEffect & 0x0F) { case 0x00: // Nothing case 0x0E: // Reserved case 0x0F: // Reserved break; case 0x0B: // Interrupt sample case 0x0C: // Continue sample after interrupt m.SetVolumeCommand(VOLCMD_PLAYCONTROL, static_cast(((specialValues[0x0B] == 2) ? 5 : 0) + ((instrEffect & 0x0F) - 0x0B))); break; case 0x0D: // End Pattern m.SetEffectCommand(CMD_PATTERNBREAK, 0); break; default: // Pitch Bend if(int value = specialValues[(instrEffect & 0x0F)]; value > 0) m.SetEffectCommand(CMD_PORTAMENTODOWN, mpt::saturate_cast((value + 16) / 32)); else if(value < 0) m.SetEffectCommand(CMD_PORTAMENTOUP, mpt::saturate_cast((- value + 16) / 32)); } } } const auto sampleStart = file.GetPosition(); file.Skip(4); // Size of remaining data FileReader sampleHeaders1 = file.ReadChunk(16 * 4); FileReader sampleHeaders2 = file.ReadChunk(16 * 8); SampleIO sampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::unsignedPCM); m_nSamples = 16; for(SAMPLEINDEX smp = 1; smp <= 16; smp++) { ModSample &mptSmp = Samples[smp]; mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.nVolume = std::min(sampleHeaders1.ReadUint8(), uint8(127)) * 2; sampleHeaders1.Skip(1); // Empty value according to docs mptSmp.nLoopStart = sampleHeaders1.ReadUint16BE(); uint32 offset = sampleHeaders2.ReadUint32BE(); mptSmp.nLength = sampleHeaders2.ReadUint32BE(); if(mptSmp.nLoopStart && mptSmp.nLoopStart < mptSmp.nLength) { mptSmp.nLoopEnd = mptSmp.nLength; mptSmp.nLoopStart = mptSmp.nLength - mptSmp.nLoopStart; mptSmp.uFlags.set(CHN_LOOP); } if(!useAmigaFreqs) mptSmp.nFineTune = 5 * 16; if((loadFlags & loadSampleData) && mptSmp.nLength > 1 && file.Seek(sampleStart + offset)) sampleIO.ReadSample(mptSmp, file); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::spacePadded, instrNames[smp - 1]); } m_modFormat.formatName = newFormat ? UL_("TCB Tracker") : UL_("TCB Tracker (Beta Format)"); m_modFormat.type = UL_("tcb"); // Official file extension is MOD (which is the only extension TCB Tracker accepts), but both ModLand and Fujiology use TCB instead, and this makes it easier to differentiate the format for library users... m_modFormat.madeWithTracker = newFormat ? UL_("TCB Tracker 1.0 - 2.0") : UL_("TCB Tracker Beta"); m_modFormat.charset = mpt::Charset::AtariST; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_ims.cpp0000644000175000017500000000760014721715306020341 00000000000000/* * Load_ims.cpp * ------------ * Purpose: Images Music System (IMS) module loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "MODTools.h" OPENMPT_NAMESPACE_BEGIN struct IMSFileHeader { std::array songName; std::array sampleHeaders; MODFileHeader order; uint32be sampleDataOffset; bool IsValid() const { if(CountInvalidChars(songName)) return false; uint16 hasSampleLength = 0; for(const auto &sampleHeader : sampleHeaders) { if(sampleHeader.length > 0x8000 || sampleHeader.finetune || sampleHeader.GetInvalidByteScore()) return false; hasSampleLength |= sampleHeader.length; } if(!hasSampleLength) return false; if(!order.numOrders || order.numOrders > 128 || order.restartPos > order.numOrders) return false; if(sampleDataOffset <= 1084) return false; const auto patternDiv = std::div(sampleDataOffset - 1084, 768); if(patternDiv.rem) return false; const uint8 numPatterns = mpt::saturate_cast(patternDiv.quot); if(numPatterns > 128) return false; for(const auto pat : order.orderList) { if(pat >= numPatterns) return false; } return true; } }; MPT_BINARY_STRUCT(IMSFileHeader, 1084) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIMS(MemoryFileReader file, const uint64 *pfilesize) { IMSFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(pfilesize && *pfilesize < fileHeader.sampleDataOffset) return ProbeFailure; if(!fileHeader.IsValid()) return ProbeFailure; return ProbeSuccess; } bool CSoundFile::ReadIMS(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); IMSFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return false; if(!fileHeader.IsValid()) return false; if(!file.LengthIsAtLeast(fileHeader.sampleDataOffset)) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_MOD, 4); m_SongFlags.set(SONG_IMPORTED | SONG_FORMAT_NO_VOLCOL); Order().SetDefaultTempoInt(125); Order().SetDefaultSpeed(6); Order().SetRestartPos(fileHeader.order.restartPos); m_nMinPeriod = 113 * 4; m_nMaxPeriod = 1712 * 4; m_nSamples = 31; m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songName); ReadOrderFromArray(Order(), fileHeader.order.orderList, fileHeader.order.numOrders); file.Seek(20); for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { const auto &sampleHeader = fileHeader.sampleHeaders[smp - 1]; sampleHeader.ConvertToMPT(Samples[smp], true); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name); } if(loadFlags & loadPatternData) { file.Seek(1084); const PATTERNINDEX numPatterns = static_cast((fileHeader.sampleDataOffset - 1084u) / 768u); for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { if(!Patterns.Insert(pat, 64)) return false; for(ModCommand &m : Patterns[pat]) { const auto data = file.ReadArray(); if(const uint8 note = (data[0] & 0x3F); note < 48) m.note = NOTE_MIDDLEC - 24 + note; else if(note != 63) return false; m.instr = ((data[0] & 0xC0) >> 2) | (data[1] >> 4); if(m.instr > 31) return false; ConvertModCommand(m, data[1] & 0x0F, data[2]); } } } if(loadFlags & loadSampleData) { file.Seek(fileHeader.sampleDataOffset); for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { if(!Samples[smp].nLength) continue; SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(Samples[smp], file); } } m_modFormat.formatName = UL_("Images Music System"); m_modFormat.type = UL_("ims"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/PlayState.h0000644000175000017500000000774614722674176020212 00000000000000/* * PlayState.h * ----------- * Purpose: This class represents all of the playback state of a module. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "ModChannel.h" #include "Snd_defs.h" #include #include #include OPENMPT_NAMESPACE_BEGIN struct PlayState { friend class CSoundFile; public: samplecount_t m_lTotalSampleCount = 0; // Total number of rendered samples protected: samplecount_t m_nBufferCount = 0; // Remaining number samples to render for this tick double m_dBufferDiff = 0.0; // Modern tempo rounding error compensation public: double m_ppqPosFract = 0.0; // Fractional PPQ position within current measure uint32 m_ppqPosBeat = 0; // PPQ position of the last start of measure uint32 m_nTickCount = 0; // Current tick being processed protected: uint32 m_nPatternDelay = 0; // Pattern delay (rows) uint32 m_nFrameDelay = 0; // Fine pattern delay (ticks) public: uint32 m_nSamplesPerTick = 0; ROWINDEX m_nCurrentRowsPerBeat = 0; // Current time signature ROWINDEX m_nCurrentRowsPerMeasure = 0; // Current time signature uint32 m_nMusicSpeed = 0; // Current speed TEMPO m_nMusicTempo; // Current tempo // Playback position ROWINDEX m_nRow = 0; // Current row being processed ROWINDEX m_nNextRow = 0; // Next row to process protected: ROWINDEX m_nextPatStartRow = 0; // For FT2's E60 bug ROWINDEX m_breakRow = 0; // Candidate target row for pattern break ROWINDEX m_patLoopRow = 0; // Candidate target row for pattern loop ORDERINDEX m_posJump = 0; // Candidate target order for position jump public: PATTERNINDEX m_nPattern = 0; // Current pattern being processed ORDERINDEX m_nCurrentOrder = 0; // Current order being processed ORDERINDEX m_nNextOrder = 0; // Next order to process ORDERINDEX m_nSeqOverride = ORDERINDEX_INVALID; // Queued order to be processed next, regardless of what order would normally follow OrderTransitionMode m_seqOverrideMode = OrderTransitionMode::AtPatternEnd; // Global volume public: int32 m_nGlobalVolume = MAX_GLOBAL_VOLUME; // Current global volume (0...MAX_GLOBAL_VOLUME) protected: // Global volume ramping int32 m_nSamplesToGlobalVolRampDest = 0, m_nGlobalVolumeRampAmount = 0; int32 m_nGlobalVolumeDestination = 0, m_lHighResRampingGlobalVolume = 0; public: FlagSet m_flags = SONG_POSITIONCHANGED; std::array ChnMix; // Index of channels in Chn to be actually mixed std::array Chn; // Mixing channels... First m_nChannels channels are directly mapped to pattern channels (i.e. they are never NNA channels)! GlobalScriptState m_globalScriptState; struct MIDIMacroEvaluationResults { std::map pluginDryWetRatio; std::map, PlugParamValue> pluginParameter; }; std::vector m_midiMacroScratchSpace; std::optional m_midiMacroEvaluationResults; public: PlayState(); void ResetGlobalVolumeRamping() noexcept; void UpdateTimeSignature(const CSoundFile &sndFile) noexcept; void UpdatePPQ(bool patternTransition) noexcept; constexpr uint32 TicksOnRow() const noexcept { return (m_nMusicSpeed + m_nFrameDelay) * std::max(m_nPatternDelay, uint32(1)); } mpt::span PatternChannels(const CSoundFile &sndFile) noexcept; mpt::span PatternChannels(const CSoundFile &sndFile) const noexcept { return const_cast(this)->PatternChannels(sndFile); } mpt::span BackgroundChannels(const CSoundFile &sndFile) noexcept; mpt::span BackgroundChannels(const CSoundFile &sndFile) const noexcept { return const_cast(this)->PatternChannels(sndFile); } }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/BitReader.h0000644000175000017500000000353214502511125020106 00000000000000/* * BitReader.h * ----------- * Purpose: An extended FileReader to read bit-oriented rather than byte-oriented streams. * Notes : The current implementation can only read bit widths up to 32 bits, and it always * reads bits starting from the least significant bit, as this is all that is * required by the class users at the moment. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "../common/FileReader.h" #include #include "mpt/io/base.hpp" OPENMPT_NAMESPACE_BEGIN class BitReader : private FileReader { protected: pos_type m_bufPos = 0; pos_type m_bufSize = 0; uint32 bitBuf = 0; // Current bit buffer int m_bitNum = 0; // Currently available number of bits std::byte buffer[mpt::IO::BUFFERSIZE_TINY]{}; public: class eof : public std::range_error { public: eof() : std::range_error("Truncated bit buffer") { } }; BitReader() : FileReader() { } BitReader(mpt::span bytedata) : FileReader(bytedata) { } BitReader(const FileCursor &other) : FileReader(other) { } BitReader(FileCursor &&other) : FileReader(std::move(other)) { } pos_type GetLength() const { return FileReader::GetLength(); } pos_type GetPosition() const { return FileReader::GetPosition() - m_bufSize + m_bufPos; } uint32 ReadBits(int numBits) { while(m_bitNum < numBits) { // Fetch more bits if(m_bufPos >= m_bufSize) { m_bufSize = ReadRaw(mpt::as_span(buffer)).size(); m_bufPos = 0; if(!m_bufSize) { throw eof(); } } bitBuf |= (static_cast(buffer[m_bufPos++]) << m_bitNum); m_bitNum += 8; } uint32 v = bitBuf & ((1 << numBits) - 1); bitBuf >>= numBits; m_bitNum -= numBits; return v; } }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Message.cpp0000644000175000017500000001364514502511125020172 00000000000000/* * Message.cpp * ----------- * Purpose: Various functions for processing song messages (allocating, reading from file...) * Notes : Those functions should offer a rather high level of abstraction compared to * previous ways of reading the song messages. There are still many things to do, * though. Future versions of ReadMessage() could e.g. offer charset conversion * and the code is not yet ready for unicode. * Some functions for preparing the message text to be written to a file would * also be handy. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Message.h" #include "../common/FileReader.h" #include "mpt/string/utility.hpp" OPENMPT_NAMESPACE_BEGIN // Read song message from a mapped file. // [in] data: pointer to the data in memory that is going to be read // [in] length: number of characters that should be read. Trailing null characters are automatically removed. // [in] lineEnding: line ending formatting of the text in memory. // [out] returns true on success. bool SongMessage::Read(const std::byte *data, size_t length, LineEnding lineEnding) { const char *str = mpt::byte_cast(data); while(length != 0 && str[length - 1] == '\0') { // Ignore trailing null character. length--; } // Simple line-ending detection algorithm. VERY simple. if(lineEnding == leAutodetect) { size_t nCR = 0, nLF = 0, nCRLF = 0; // find CRs, LFs and CRLFs for(size_t i = 0; i < length; i++) { char c = str[i]; if(c == '\r') nCR++; else if(c == '\n') nLF++; if(i && str[i - 1] == '\r' && c == '\n') nCRLF++; } // evaluate findings if(nCR == nLF && nCR == nCRLF) lineEnding = leCRLF; else if(nCR && !nLF) lineEnding = leCR; else if(!nCR && nLF) lineEnding = leLF; else lineEnding = leMixed; } size_t finalLength = 0; // calculate the final amount of characters to be allocated. for(size_t i = 0; i < length; i++) { finalLength++; if(str[i] == '\r' && lineEnding == leCRLF) i++; // skip the LF } clear(); reserve(finalLength); for(size_t i = 0; i < length; i++) { char c = str[i]; switch(c) { case '\r': if(lineEnding != leLF) c = InternalLineEnding; else c = ' '; if(lineEnding == leCRLF) i++; // skip the LF break; case '\n': if(lineEnding != leCR && lineEnding != leCRLF) c = InternalLineEnding; else c = ' '; break; case '\0': c = ' '; break; default: break; } push_back(c); } return true; } bool SongMessage::Read(FileReader &file, const size_t length, LineEnding lineEnding) { FileReader::pos_type readLength = std::min(static_cast(length), file.BytesLeft()); FileReader::PinnedView fileView = file.ReadPinnedView(readLength); bool success = Read(fileView.data(), fileView.size(), lineEnding); return success; } // Read comments with fixed line length from a mapped file. // [in] data: pointer to the data in memory that is going to be read // [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended). // [in] lineLength: The fixed length of a line. // [in] lineEndingLength: The padding space between two fixed lines. (there could for example be a null char after every line) // [out] returns true on success. bool SongMessage::ReadFixedLineLength(const std::byte *data, const size_t length, const size_t lineLength, const size_t lineEndingLength) { if(lineLength == 0) return false; clear(); reserve(length); size_t readPos = 0, writePos = 0; while(readPos < length) { size_t thisLineLength = std::min(lineLength, length - readPos); append(mpt::byte_cast(data) + readPos, thisLineLength); append(1, InternalLineEnding); // Fix weird chars for(size_t pos = writePos; pos < writePos + thisLineLength; pos++) { switch(operator[](pos)) { case '\0': case '\n': case '\r': operator[](pos) = ' '; break; } } readPos += thisLineLength + std::min(lineEndingLength, length - readPos - thisLineLength); writePos += thisLineLength + 1; } return true; } bool SongMessage::ReadFixedLineLength(FileReader &file, const size_t length, const size_t lineLength, const size_t lineEndingLength) { FileReader::pos_type readLength = std::min(static_cast(length), file.BytesLeft()); FileReader::PinnedView fileView = file.ReadPinnedView(readLength); bool success = ReadFixedLineLength(fileView.data(), fileView.size(), lineLength, lineEndingLength); return success; } // Retrieve song message. // [in] lineEnding: line ending formatting of the text in memory. // [out] returns formatted song message. std::string SongMessage::GetFormatted(const LineEnding lineEnding) const { std::string comments; comments.reserve(length()); for(auto c : *this) { if(c == InternalLineEnding) { switch(lineEnding) { case leCR: comments.push_back('\r'); break; case leCRLF: comments.push_back('\r'); comments.push_back('\n'); break; case leLF: comments.push_back('\n'); break; default: comments.push_back('\r'); break; } } else { comments.push_back(c); } } return comments; } bool SongMessage::SetFormatted(std::string message, LineEnding lineEnding) { MPT_ASSERT(lineEnding == leLF || lineEnding == leCR || lineEnding == leCRLF); switch(lineEnding) { case leLF: message = mpt::replace(message, std::string("\n"), std::string(1, InternalLineEnding)); break; case leCR: message = mpt::replace(message, std::string("\r"), std::string(1, InternalLineEnding)); break; case leCRLF: message = mpt::replace(message, std::string("\r\n"), std::string(1, InternalLineEnding)); break; default: MPT_ASSERT_NOTREACHED(); break; } if(message == *this) { return false; } assign(std::move(message)); return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleFormats.cpp0000644000175000017500000024077615020413412021366 00000000000000/* * SampleFormats.cpp * ----------------- * Purpose: Code for loading various more or less common sample and instrument formats. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "ITTools.h" #include "Loaders.h" #include "mod_specifications.h" #include "S3MTools.h" #include "Sndfile.h" #include "Tagging.h" #include "tuningcollection.h" #include "WAVTools.h" #include "XMTools.h" #include "../common/FileReader.h" #include "../common/misc_util.h" #include "../common/version.h" #include "../soundlib/AudioCriticalSection.h" #include "../soundlib/ModSampleCopy.h" #include "mpt/format/join.hpp" #include "mpt/string/utility.hpp" #include "openmpt/base/Endian.hpp" #ifdef MODPLUG_TRACKER #include "../mptrack/Moddoc.h" #include "Dlsbank.h" #endif // MODPLUG_TRACKER #ifndef MODPLUG_NO_FILESAVE #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "../common/mptFileIO.h" #endif // !MODPLUG_NO_FILESAVE #include #include OPENMPT_NAMESPACE_BEGIN using namespace mpt::uuid_literals; bool CSoundFile::ReadSampleFromFile(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize, bool includeInstrumentFormats) { if(!nSample || nSample >= MAX_SAMPLES) return false; if(!ReadWAVSample(nSample, file, mayNormalize) && !(includeInstrumentFormats && ReadXISample(nSample, file)) && !(includeInstrumentFormats && ReadITISample(nSample, file)) && !ReadW64Sample(nSample, file) && !ReadCAFSample(nSample, file) && !ReadAIFFSample(nSample, file, mayNormalize) && !ReadITSSample(nSample, file) && !(includeInstrumentFormats && ReadPATSample(nSample, file)) && !ReadIFFSample(nSample, file) && !ReadS3ISample(nSample, file) && !ReadSBISample(nSample, file) && !ReadAUSample(nSample, file, mayNormalize) && !ReadBRRSample(nSample, file) && !ReadFLACSample(nSample, file) && !ReadOpusSample(nSample, file) && !ReadVorbisSample(nSample, file) && !ReadMP3Sample(nSample, file, false) && !ReadMediaFoundationSample(nSample, file) ) { return false; } if(nSample > GetNumSamples()) { m_nSamples = nSample; } if(Samples[nSample].uFlags[CHN_ADLIB]) { InitOPL(); } return true; } bool CSoundFile::ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize) { if ((!nInstr) || (nInstr >= MAX_INSTRUMENTS)) return false; if(!ReadITIInstrument(nInstr, file) && !ReadXIInstrument(nInstr, file) && !ReadPATInstrument(nInstr, file) && !ReadSFZInstrument(nInstr, file) // Generic read && !ReadSampleAsInstrument(nInstr, file, mayNormalize)) { bool ok = false; #ifdef MODPLUG_TRACKER CDLSBank bank; if(bank.Open(file)) { ok = bank.ExtractInstrument(*this, nInstr, 0, 0); } #endif // MODPLUG_TRACKER if(!ok) return false; } if(nInstr > GetNumInstruments()) m_nInstruments = nInstr; return true; } bool CSoundFile::ReadSampleAsInstrument(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize) { // Scanning free sample SAMPLEINDEX nSample = GetNextFreeSample(nInstr); // may also return samples which are only referenced by the current instrument if(nSample == SAMPLEINDEX_INVALID) { return false; } // Loading Instrument ModInstrument *pIns = new (std::nothrow) ModInstrument(nSample); if(pIns == nullptr) { return false; } if(!ReadSampleFromFile(nSample, file, mayNormalize, false)) { delete pIns; return false; } // Remove all samples which are only referenced by the old instrument, except for the one we just loaded our new sample into. RemoveInstrumentSamples(nInstr, nSample); // Replace the instrument DestroyInstrument(nInstr, doNoDeleteAssociatedSamples); Instruments[nInstr] = pIns; #if defined(MPT_EXTERNAL_SAMPLES) SetSamplePath(nSample, file.GetOptionalFileName().value_or(P_(""))); #endif return true; } bool CSoundFile::DestroyInstrument(INSTRUMENTINDEX nInstr, deleteInstrumentSamples removeSamples) { if(nInstr == 0 || nInstr >= MAX_INSTRUMENTS || !Instruments[nInstr]) return true; if(removeSamples == deleteAssociatedSamples) { RemoveInstrumentSamples(nInstr); } CriticalSection cs; ModInstrument *pIns = Instruments[nInstr]; Instruments[nInstr] = nullptr; for(auto &chn : m_PlayState.Chn) { if(chn.pModInstrument == pIns) chn.pModInstrument = nullptr; } delete pIns; return true; } // Remove all unused samples from the given nInstr and keep keepSample if provided bool CSoundFile::RemoveInstrumentSamples(INSTRUMENTINDEX nInstr, SAMPLEINDEX keepSample) { if(Instruments[nInstr] == nullptr) { return false; } std::vector keepSamples(GetNumSamples() + 1, true); // Check which samples are used by the instrument we are going to nuke. auto referencedSamples = Instruments[nInstr]->GetSamples(); for(auto sample : referencedSamples) { if(sample <= GetNumSamples()) { keepSamples[sample] = false; } } // If we want to keep a specific sample, do so. if(keepSample != SAMPLEINDEX_INVALID) { if(keepSample <= GetNumSamples()) { keepSamples[keepSample] = true; } } // Check if any of those samples are referenced by other instruments as well, in which case we want to keep them of course. for(INSTRUMENTINDEX nIns = 1; nIns <= GetNumInstruments(); nIns++) if (Instruments[nIns] != nullptr && nIns != nInstr) { Instruments[nIns]->GetSamples(keepSamples); } // Now nuke the selected samples. RemoveSelectedSamples(keepSamples); return true; } //////////////////////////////////////////////////////////////////////////////// // // I/O From another song // bool CSoundFile::ReadInstrumentFromSong(INSTRUMENTINDEX targetInstr, const CSoundFile &srcSong, INSTRUMENTINDEX sourceInstr) { if ((!sourceInstr) || (sourceInstr > srcSong.GetNumInstruments()) || (targetInstr >= MAX_INSTRUMENTS) || (!srcSong.Instruments[sourceInstr])) { return false; } if (m_nInstruments < targetInstr) m_nInstruments = targetInstr; ModInstrument *pIns = new (std::nothrow) ModInstrument(); if(pIns == nullptr) { return false; } DestroyInstrument(targetInstr, deleteAssociatedSamples); Instruments[targetInstr] = pIns; *pIns = *srcSong.Instruments[sourceInstr]; std::vector sourceSample; // Sample index in source song std::vector targetSample; // Sample index in target song SAMPLEINDEX targetIndex = 0; // Next index for inserting sample for(auto &sample : pIns->Keyboard) { const SAMPLEINDEX sourceIndex = sample; if(sourceIndex > 0 && sourceIndex <= srcSong.GetNumSamples()) { const auto entry = std::find(sourceSample.cbegin(), sourceSample.cend(), sourceIndex); if(entry == sourceSample.end()) { // Didn't consider this sample yet, so add it to our map. targetIndex = GetNextFreeSample(targetInstr, targetIndex + 1); if(targetIndex <= GetModSpecifications().samplesMax) { sourceSample.push_back(sourceIndex); targetSample.push_back(targetIndex); sample = targetIndex; } else { sample = 0; } } else { // Sample reference has already been created, so only need to update the sample map. sample = *(entry - sourceSample.begin() + targetSample.begin()); } } else { // Invalid or no source sample sample = 0; } } #ifdef MODPLUG_TRACKER if(pIns->filename.empty() && srcSong.GetpModDoc() != nullptr && &srcSong != this) { pIns->filename = srcSong.GetpModDoc()->GetPathNameMpt().GetFilename().ToLocale(); } #endif pIns->Convert(srcSong.GetType(), GetType()); if(pIns->pTuning && this != &srcSong) { CTuning *existingTuning = m_pTuningsTuneSpecific->FindIdenticalTuning(*pIns->pTuning); if(existingTuning) pIns->pTuning = existingTuning; else pIns->pTuning = m_pTuningsTuneSpecific->AddTuning(std::make_unique(*pIns->pTuning)); } // Copy all referenced samples over for(size_t i = 0; i < targetSample.size(); i++) { ReadSampleFromSong(targetSample[i], srcSong, sourceSample[i]); } return true; } bool CSoundFile::ReadSampleFromSong(SAMPLEINDEX targetSample, const CSoundFile &srcSong, SAMPLEINDEX sourceSample) { if(!sourceSample || sourceSample > srcSong.GetNumSamples() || (targetSample >= GetModSpecifications().samplesMax && targetSample > GetNumSamples())) { return false; } if(GetNumSamples() < targetSample) m_nSamples = targetSample; DestroySampleThreadsafe(targetSample); const ModSample &sourceSmp = srcSong.GetSample(sourceSample); ModSample &targetSmp = GetSample(targetSample); targetSmp = sourceSmp; m_szNames[targetSample] = srcSong.m_szNames[sourceSample]; if(sourceSmp.HasSampleData()) { if(targetSmp.CopyWaveform(sourceSmp)) targetSmp.PrecomputeLoops(*this, false); // Remember on-disk path (for MPTM files), but don't implicitely enable on-disk storage // (we really don't want this for e.g. duplicating samples or splitting stereo samples) #ifdef MPT_EXTERNAL_SAMPLES SetSamplePath(targetSample, srcSong.GetSamplePath(sourceSample)); #endif targetSmp.uFlags.reset(SMP_KEEPONDISK); } #ifdef MODPLUG_TRACKER if((targetSmp.filename.empty()) && srcSong.GetpModDoc() != nullptr && &srcSong != this) { targetSmp.filename = mpt::ToCharset(GetCharsetInternal(), srcSong.GetpModDoc()->GetTitle()); } #endif if(targetSmp.uFlags[CHN_ADLIB] && !SupportsOPL()) { AddToLog(LogInformation, U_("OPL instruments are not supported by this format.")); } targetSmp.Convert(srcSong.GetType(), GetType()); if(targetSmp.uFlags[CHN_ADLIB]) { InitOPL(); } return true; } //////////////////////////////////////////////////////////////////////// // IMA ADPCM Support for WAV files static bool IMAADPCMUnpack16(int16 *target, SmpLength sampleLen, FileReader file, uint16 blockAlign, uint32 numChannels) { static constexpr int8 IMAIndexTab[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; static constexpr int16 IMAUnpackTable[90] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767, 0 }; if(target == nullptr || blockAlign < 4u * numChannels) return false; SmpLength samplePos = 0; sampleLen *= numChannels; while(file.CanRead(4u * numChannels) && samplePos < sampleLen) { FileReader block = file.ReadChunk(blockAlign); FileReader::PinnedView blockView = block.GetPinnedView(); const std::byte *data = blockView.data(); const uint32 blockSize = static_cast(blockView.size()); for(uint32 chn = 0; chn < numChannels; chn++) { // Block header int32 value = block.ReadInt16LE(); int32 nIndex = block.ReadUint8(); Limit(nIndex, 0, 89); block.Skip(1); SmpLength smpPos = samplePos + chn; uint32 dataPos = (numChannels + chn) * 4; // Block data while(smpPos <= (sampleLen - 8) && dataPos <= (blockSize - 4)) { for(uint32 i = 0; i < 8; i++) { uint8 delta = mpt::byte_cast(data[dataPos]); if(i & 1) { delta >>= 4; dataPos++; } else { delta &= 0x0F; } int32 v = IMAUnpackTable[nIndex] >> 3; if (delta & 1) v += IMAUnpackTable[nIndex] >> 2; if (delta & 2) v += IMAUnpackTable[nIndex] >> 1; if (delta & 4) v += IMAUnpackTable[nIndex]; if (delta & 8) value -= v; else value += v; nIndex += IMAIndexTab[delta & 7]; Limit(nIndex, 0, 88); Limit(value, -32768, 32767); target[smpPos] = static_cast(value); smpPos += numChannels; } dataPos += (numChannels - 1) * 4u; } } samplePos += ((blockSize - (numChannels * 4u)) * 2u); } return true; } //////////////////////////////////////////////////////////////////////////////// // WAV Open bool CSoundFile::ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize, FileReader *wsmpChunk) { WAVReader wavFile(file); static constexpr WAVFormatChunk::SampleFormats SupportedFormats[] = {WAVFormatChunk::fmtPCM, WAVFormatChunk::fmtFloat, WAVFormatChunk::fmtIMA_ADPCM, WAVFormatChunk::fmtMP3, WAVFormatChunk::fmtALaw, WAVFormatChunk::fmtULaw}; if(!wavFile.IsValid() || wavFile.GetNumChannels() == 0 || wavFile.GetNumChannels() > 2 || (wavFile.GetBitsPerSample() == 0 && wavFile.GetSampleFormat() != WAVFormatChunk::fmtMP3) || (wavFile.GetBitsPerSample() < 32 && wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat) || (wavFile.GetBitsPerSample() > 64) || !mpt::contains(SupportedFormats, wavFile.GetSampleFormat())) { return false; } DestroySampleThreadsafe(nSample); m_szNames[nSample] = ""; ModSample &sample = Samples[nSample]; sample.Initialize(); sample.nLength = wavFile.GetSampleLength(); sample.nC5Speed = wavFile.GetSampleRate(); wavFile.ApplySampleSettings(sample, GetCharsetInternal(), m_szNames[nSample]); FileReader sampleChunk = wavFile.GetSampleData(); SampleIO sampleIO( SampleIO::_8bit, (wavFile.GetNumChannels() > 1) ? SampleIO::stereoInterleaved : SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM); if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtIMA_ADPCM && wavFile.GetNumChannels() <= 2) { // IMA ADPCM 4:1 LimitMax(sample.nLength, MAX_SAMPLE_LENGTH); sample.uFlags.set(CHN_16BIT); sample.uFlags.set(CHN_STEREO, wavFile.GetNumChannels() == 2); if(!sample.AllocateSample()) { return false; } IMAADPCMUnpack16(sample.sample16(), sample.nLength, sampleChunk, wavFile.GetBlockAlign(), wavFile.GetNumChannels()); sample.PrecomputeLoops(*this, false); } else if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtMP3) { // MP3 in WAV bool loadedMP3 = ReadMP3Sample(nSample, sampleChunk, false, true) || ReadMediaFoundationSample(nSample, sampleChunk, true); if(!loadedMP3) { return false; } } else if(!wavFile.IsExtensibleFormat() && wavFile.MayBeCoolEdit16_8() && wavFile.GetSampleFormat() == WAVFormatChunk::fmtPCM && wavFile.GetBitsPerSample() == 32 && wavFile.GetBlockAlign() == wavFile.GetNumChannels() * 4) { // Syntrillium Cool Edit hack to store IEEE 32bit floating point // Format is described as 32bit integer PCM contained in 32bit blocks and an WAVEFORMATEX extension size of 2 which contains a single 16 bit little endian value of 1. // (This is parsed in WAVTools.cpp and returned via MayBeCoolEdit16_8()). // The data actually stored in this case is little endian 32bit floating point PCM with 2**15 full scale. // Cool Edit calls this format "16.8 float". sampleIO |= SampleIO::_32bit; sampleIO |= SampleIO::floatPCM15; sampleIO.ReadSample(sample, sampleChunk); } else if(!wavFile.IsExtensibleFormat() && wavFile.GetSampleFormat() == WAVFormatChunk::fmtPCM && wavFile.GetBitsPerSample() == 24 && wavFile.GetBlockAlign() == wavFile.GetNumChannels() * 4) { // Syntrillium Cool Edit hack to store IEEE 32bit floating point // Format is described as 24bit integer PCM contained in 32bit blocks. // The data actually stored in this case is little endian 32bit floating point PCM with 2**23 full scale. // Cool Edit calls this format "24.0 float". sampleIO |= SampleIO::_32bit; sampleIO |= SampleIO::floatPCM23; sampleIO.ReadSample(sample, sampleChunk); } else if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtALaw || wavFile.GetSampleFormat() == WAVFormatChunk::fmtULaw) { // a-law / u-law sampleIO |= SampleIO::_16bit; sampleIO |= wavFile.GetSampleFormat() == WAVFormatChunk::fmtALaw ? SampleIO::aLaw : SampleIO::uLaw; sampleIO.ReadSample(sample, sampleChunk); } else { // PCM / Float SampleIO::Bitdepth bitDepth; switch((wavFile.GetBitsPerSample() - 1) / 8u) { default: case 0: bitDepth = SampleIO::_8bit; break; case 1: bitDepth = SampleIO::_16bit; break; case 2: bitDepth = SampleIO::_24bit; break; case 3: bitDepth = SampleIO::_32bit; break; case 7: bitDepth = SampleIO::_64bit; break; } sampleIO |= bitDepth; if(wavFile.GetBitsPerSample() <= 8) sampleIO |= SampleIO::unsignedPCM; if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat) sampleIO |= SampleIO::floatPCM; if(mayNormalize) sampleIO.MayNormalize(); sampleIO.ReadSample(sample, sampleChunk); } if(wsmpChunk != nullptr) { // DLS WSMP chunk *wsmpChunk = wavFile.GetWsmpChunk(); } sample.Convert(MOD_TYPE_IT, GetType()); sample.PrecomputeLoops(*this, false); return true; } /////////////////////////////////////////////////////////////// // Save WAV #ifndef MODPLUG_NO_FILESAVE bool CSoundFile::SaveWAVSample(SAMPLEINDEX nSample, std::ostream &f) const { const ModSample &sample = Samples[nSample]; if(sample.uFlags[CHN_ADLIB] || !sample.HasSampleData()) return false; mpt::IO::OFile ff(f); WAVSampleWriter file(ff); file.WriteFormat(sample.GetSampleRate(GetType()), sample.GetElementarySampleSize() * 8, sample.GetNumChannels(), WAVFormatChunk::fmtPCM); // Write sample data file.StartChunk(RIFFChunk::iddata); SampleIO( sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, sample.uFlags[CHN_STEREO] ? SampleIO::stereoInterleaved : SampleIO::mono, SampleIO::littleEndian, sample.uFlags[CHN_16BIT] ? SampleIO::signedPCM : SampleIO::unsignedPCM) .WriteSample(f, sample); file.WriteLoopInformation(sample); file.WriteExtraInformation(sample, GetType()); if(sample.HasCustomCuePoints()) { file.WriteCueInformation(sample); } FileTags tags; tags.encoder = Version::Current().GetOpenMPTVersionString(); tags.title = mpt::ToUnicode(GetCharsetInternal(), m_szNames[nSample]); file.WriteMetatags(tags); file.Finalize(); return true; } #endif // MODPLUG_NO_FILESAVE ///////////////// // Sony Wave64 // struct Wave64FileHeader { mpt::GUIDms GuidRIFF; uint64le FileSize; mpt::GUIDms GuidWAVE; }; MPT_BINARY_STRUCT(Wave64FileHeader, 40) struct Wave64ChunkHeader { mpt::GUIDms GuidChunk; uint64le Size; }; MPT_BINARY_STRUCT(Wave64ChunkHeader, 24) struct Wave64Chunk { Wave64ChunkHeader header; FileReader::pos_type GetLength() const { uint64 length = header.Size; if(length < sizeof(Wave64ChunkHeader)) { length = 0; } else { length -= sizeof(Wave64ChunkHeader); } return mpt::saturate_cast(length); } mpt::UUID GetID() const { return mpt::UUID(header.GuidChunk); } }; MPT_BINARY_STRUCT(Wave64Chunk, 24) static void Wave64TagFromLISTINFO(mpt::ustring & dst, uint16 codePage, const FileReader::ChunkList & infoChunk, RIFFChunk::ChunkIdentifiers id) { if(!infoChunk.ChunkExists(id)) { return; } FileReader textChunk = infoChunk.GetChunk(id); if(!textChunk.IsValid()) { return; } std::string str; textChunk.ReadString(str, mpt::saturate_cast(textChunk.GetLength())); str = mpt::replace(str, std::string("\r\n"), std::string("\n")); str = mpt::replace(str, std::string("\r"), std::string("\n")); dst = mpt::ToUnicode(codePage, mpt::Charset::Windows1252, str); } bool CSoundFile::ReadW64Sample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize) { file.Rewind(); constexpr mpt::UUID guidRIFF = "66666972-912E-11CF-A5D6-28DB04C10000"_uuid; constexpr mpt::UUID guidWAVE = "65766177-ACF3-11D3-8CD1-00C04F8EDB8A"_uuid; constexpr mpt::UUID guidLIST = "7473696C-912F-11CF-A5D6-28DB04C10000"_uuid; constexpr mpt::UUID guidFMT = "20746D66-ACF3-11D3-8CD1-00C04F8EDB8A"_uuid; //constexpr mpt::UUID guidFACT = "74636166-ACF3-11D3-8CD1-00C04F8EDB8A"_uuid; constexpr mpt::UUID guidDATA = "61746164-ACF3-11D3-8CD1-00C04F8EDB8A"_uuid; //constexpr mpt::UUID guidLEVL = "6C76656C-ACF3-11D3-8CD1-00C04F8EDB8A"_uuid; //constexpr mpt::UUID guidJUNK = "6b6E756A-ACF3-11D3-8CD1-00C04f8EDB8A"_uuid; //constexpr mpt::UUID guidBEXT = "74786562-ACF3-11D3-8CD1-00C04F8EDB8A"_uuid; //constexpr mpt::UUID guiMARKER = "ABF76256-392D-11D2-86C7-00C04F8EDB8A"_uuid; //constexpr mpt::UUID guiSUMMARYLIST = "925F94BC-525A-11D2-86DC-00C04F8EDB8A"_uuid; constexpr mpt::UUID guidCSET = "54455343-ACF3-11D3-8CD1-00C04F8EDB8A"_uuid; Wave64FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(mpt::UUID(fileHeader.GuidRIFF) != guidRIFF) { return false; } if(mpt::UUID(fileHeader.GuidWAVE) != guidWAVE) { return false; } if(fileHeader.FileSize != file.GetLength()) { return false; } FileReader chunkFile = file; auto chunkList = chunkFile.ReadChunks(8); if(!chunkList.ChunkExists(guidFMT)) { return false; } FileReader formatChunk = chunkList.GetChunk(guidFMT); WAVFormatChunk format; if(!formatChunk.ReadStruct(format)) { return false; } uint16 sampleFormat = format.format; if(format.format == WAVFormatChunk::fmtExtensible) { WAVFormatChunkExtension formatExt; if(!formatChunk.ReadStruct(formatExt)) { return false; } sampleFormat = static_cast(mpt::UUID(formatExt.subFormat).GetData1()); } if(format.sampleRate == 0) { return false; } if(format.numChannels == 0) { return false; } if(format.numChannels > 2) { return false; } if(sampleFormat != WAVFormatChunk::fmtPCM && sampleFormat != WAVFormatChunk::fmtFloat) { return false; } if(sampleFormat == WAVFormatChunk::fmtFloat && format.bitsPerSample != 32 && format.bitsPerSample != 64) { return false; } if(sampleFormat == WAVFormatChunk::fmtPCM && format.bitsPerSample > 64) { return false; } SampleIO::Bitdepth bitDepth; switch((format.bitsPerSample - 1) / 8u) { default: case 0: bitDepth = SampleIO::_8bit ; break; case 1: bitDepth = SampleIO::_16bit; break; case 2: bitDepth = SampleIO::_24bit; break; case 3: bitDepth = SampleIO::_32bit; break; case 7: bitDepth = SampleIO::_64bit; break; } SampleIO sampleIO( bitDepth, (format.numChannels > 1) ? SampleIO::stereoInterleaved : SampleIO::mono, SampleIO::littleEndian, (sampleFormat == WAVFormatChunk::fmtFloat) ? SampleIO::floatPCM : SampleIO::signedPCM); if(format.bitsPerSample <= 8) { sampleIO |= SampleIO::unsignedPCM; } if(mayNormalize) { sampleIO.MayNormalize(); } FileTags tags; uint16 codePage = 28591; // mpt::Charset::ISO8859_1 FileReader csetChunk = chunkList.GetChunk(guidCSET); if(csetChunk.IsValid()) { if(csetChunk.CanRead(2)) { codePage = csetChunk.ReadUint16LE(); } } if(chunkList.ChunkExists(guidLIST)) { FileReader listChunk = chunkList.GetChunk(guidLIST); if(listChunk.ReadMagic("INFO")) { auto infoChunk = listChunk.ReadChunks(2); Wave64TagFromLISTINFO(tags.title, codePage, infoChunk, RIFFChunk::idINAM); Wave64TagFromLISTINFO(tags.encoder, codePage, infoChunk, RIFFChunk::idISFT); //Wave64TagFromLISTINFO(void, codePage, infoChunk, RIFFChunk::idICOP); Wave64TagFromLISTINFO(tags.artist, codePage, infoChunk, RIFFChunk::idIART); Wave64TagFromLISTINFO(tags.album, codePage, infoChunk, RIFFChunk::idIPRD); Wave64TagFromLISTINFO(tags.comments, codePage, infoChunk, RIFFChunk::idICMT); //Wave64TagFromLISTINFO(void, codePage, infoChunk, RIFFChunk::idIENG); //Wave64TagFromLISTINFO(void, codePage, infoChunk, RIFFChunk::idISBJ); Wave64TagFromLISTINFO(tags.genre, codePage, infoChunk, RIFFChunk::idIGNR); //Wave64TagFromLISTINFO(void, codePage, infoChunk, RIFFChunk::idICRD); Wave64TagFromLISTINFO(tags.year, codePage, infoChunk, RIFFChunk::idYEAR); Wave64TagFromLISTINFO(tags.trackno, codePage, infoChunk, RIFFChunk::idTRCK); Wave64TagFromLISTINFO(tags.url, codePage, infoChunk, RIFFChunk::idTURL); //Wave64TagFromLISTINFO(tags.bpm, codePage, infoChunk, void); } } if(!chunkList.ChunkExists(guidDATA)) { return false; } FileReader audioData = chunkList.GetChunk(guidDATA); SmpLength length = mpt::saturate_cast(audioData.GetLength() / (sampleIO.GetEncodedBitsPerSample()/8)); ModSample &mptSample = Samples[nSample]; DestroySampleThreadsafe(nSample); mptSample.Initialize(); mptSample.nLength = length; mptSample.nC5Speed = format.sampleRate; sampleIO.ReadSample(mptSample, audioData); m_szNames[nSample] = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(tags)); mptSample.Convert(MOD_TYPE_IT, GetType()); mptSample.PrecomputeLoops(*this, false); return true; } #ifndef MODPLUG_NO_FILESAVE /////////////////////////////////////////////////////////////// // Save RAW bool CSoundFile::SaveRAWSample(SAMPLEINDEX nSample, std::ostream &f) const { const ModSample &sample = Samples[nSample]; if(!sample.HasSampleData()) return false; SampleIO( sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, sample.uFlags[CHN_STEREO] ? SampleIO::stereoInterleaved : SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .WriteSample(f, sample); return true; } #endif // MODPLUG_NO_FILESAVE ///////////////////////////////////////////////////////////// // GUS Patches struct GF1PatchFileHeader { char magic[8]; // "GF1PATCH" char version[4]; // "100", or "110" char id[10]; // "ID#000002" char copyright[60]; // Copyright uint8le numInstr; // Number of instruments in patch uint8le voices; // Number of voices, usually 14 uint8le channels; // Number of wav channels that can be played concurently to the patch uint16le numSamples; // Total number of waveforms for all the .PAT uint16le volume; // Master volume uint32le dataSize; char reserved2[36]; }; MPT_BINARY_STRUCT(GF1PatchFileHeader, 129) struct GF1Instrument { uint16le id; // Instrument id: 0-65535 char name[16]; // Name of instrument. Gravis doesn't seem to use it uint32le size; // Number of bytes for the instrument with header. (To skip to next instrument) uint8 layers; // Number of layers in instrument: 1-4 char reserved[40]; }; MPT_BINARY_STRUCT(GF1Instrument, 63) struct GF1SampleHeader { char name[7]; // null terminated string. name of the wave. uint8le fractions; // Start loop point fraction in 4 bits + End loop point fraction in the 4 other bits. uint32le length; // total size of wavesample. limited to 65535 now by the drivers, not the card. uint32le loopstart; // start loop position in the wavesample uint32le loopend; // end loop position in the wavesample uint16le freq; // Rate at which the wavesample has been sampled uint32le low_freq; // check note.h for the correspondance. uint32le high_freq; // check note.h for the correspondance. uint32le root_freq; // check note.h for the correspondance. int16le finetune; // fine tune. -512 to +512, EXCLUDING 0 cause it is a multiplier. 512 is one octave off, and 1 is a neutral value uint8le balance; // Balance: 0-15. 0=full left, 15 = full right uint8le env_rate[6]; // attack rates uint8le env_volume[6]; // attack volumes uint8le tremolo_sweep, tremolo_rate, tremolo_depth; uint8le vibrato_sweep, vibrato_rate, vibrato_depth; uint8le flags; int16le scale_frequency; // Note uint16le scale_factor; // 0...2048 (1024 is normal) or 0...2 char reserved[36]; }; MPT_BINARY_STRUCT(GF1SampleHeader, 96) // -- GF1 Envelopes -- // // It can be represented like this (the envelope is totally bogus, it is // just to show the concept): // // | // | /----` | | // | /------/ `\ | | | | | // | / \ | | | | | // | / \ | | | | | // |/ \ | | | | | // ---------------------------- | | | | | | // <---> attack rate 0 0 1 2 3 4 5 amplitudes // <----> attack rate 1 // <> attack rate 2 // <--> attack rate 3 // <> attack rate 4 // <-----> attack rate 5 // // -- GF1 Flags -- // // bit 0: 8/16 bit // bit 1: Signed/Unsigned // bit 2: off/on looping // bit 3: off/on bidirectionnal looping // bit 4: off/on backward looping // bit 5: off/on sustaining (3rd point in env.) // bit 6: off/on envelopes // bit 7: off/on clamped release (6th point, env) struct GF1Layer { uint8le previous; // If !=0 the wavesample to use is from the previous layer. The waveheader is still needed uint8le id; // Layer id: 0-3 uint32le size; // data size in bytes in the layer, without the header. to skip to next layer for example: uint8le samples; // number of wavesamples char reserved[40]; }; MPT_BINARY_STRUCT(GF1Layer, 47) static double PatchFreqToNote(uint32 nFreq) { return std::log(nFreq / 2044.0) * (12.0 * 1.44269504088896340736); // 1.0/std::log(2.0) } static int32 PatchFreqToNoteInt(uint32 nFreq) { return mpt::saturate_round(PatchFreqToNote(nFreq)); } static void PatchToSample(CSoundFile *that, SAMPLEINDEX nSample, GF1SampleHeader &sampleHeader, FileReader &file) { ModSample &sample = that->GetSample(nSample); file.ReadStruct(sampleHeader); sample.Initialize(); if(sampleHeader.flags & 4) sample.uFlags.set(CHN_LOOP); if(sampleHeader.flags & 8) sample.uFlags.set(CHN_PINGPONGLOOP); if(sampleHeader.flags & 16) sample.uFlags.set(CHN_REVERSE); sample.nLength = sampleHeader.length; sample.nLoopStart = sampleHeader.loopstart; sample.nLoopEnd = sampleHeader.loopend; sample.nC5Speed = sampleHeader.freq; sample.nPan = static_cast((sampleHeader.balance * 256 + 8) / 15); if(sample.nPan > 256) sample.nPan = 128; else sample.uFlags.set(CHN_PANNING); sample.nVibType = VIB_SINE; sample.nVibSweep = sampleHeader.vibrato_sweep; sample.nVibDepth = sampleHeader.vibrato_depth; sample.nVibRate = sampleHeader.vibrato_rate / 4; if(sampleHeader.scale_factor) { sample.Transpose((84.0 - PatchFreqToNote(sampleHeader.root_freq)) / 12.0); } SampleIO sampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, (sampleHeader.flags & 2) ? SampleIO::unsignedPCM : SampleIO::signedPCM); if(sampleHeader.flags & 1) { sampleIO |= SampleIO::_16bit; sample.nLength /= 2; sample.nLoopStart /= 2; sample.nLoopEnd /= 2; } sampleIO.ReadSample(sample, file); sample.Convert(MOD_TYPE_IT, that->GetType()); sample.PrecomputeLoops(*that, false); that->m_szNames[nSample] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name); } bool CSoundFile::ReadPATSample(SAMPLEINDEX nSample, FileReader &file) { file.Rewind(); GF1PatchFileHeader fileHeader; GF1Instrument instrHeader; // We only support one instrument GF1Layer layerHeader; if(!file.ReadStruct(fileHeader) || memcmp(fileHeader.magic, "GF1PATCH", 8) || (memcmp(fileHeader.version, "110\0", 4) && memcmp(fileHeader.version, "100\0", 4)) || memcmp(fileHeader.id, "ID#000002\0", 10) || !fileHeader.numInstr || !fileHeader.numSamples || !file.ReadStruct(instrHeader) //|| !instrHeader.layers // DOO.PAT has 0 layers || !file.ReadStruct(layerHeader) || !layerHeader.samples) { return false; } DestroySampleThreadsafe(nSample); GF1SampleHeader sampleHeader; PatchToSample(this, nSample, sampleHeader, file); if(instrHeader.name[0] > ' ') { m_szNames[nSample] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, instrHeader.name); } return true; } // PAT Instrument bool CSoundFile::ReadPATInstrument(INSTRUMENTINDEX nInstr, FileReader &file) { file.Rewind(); GF1PatchFileHeader fileHeader; GF1Instrument instrHeader; // We only support one instrument GF1Layer layerHeader; if(!file.ReadStruct(fileHeader) || memcmp(fileHeader.magic, "GF1PATCH", 8) || (memcmp(fileHeader.version, "110\0", 4) && memcmp(fileHeader.version, "100\0", 4)) || memcmp(fileHeader.id, "ID#000002\0", 10) || !fileHeader.numInstr || !fileHeader.numSamples || !file.ReadStruct(instrHeader) //|| !instrHeader.layers // DOO.PAT has 0 layers || !file.ReadStruct(layerHeader) || !layerHeader.samples) { return false; } ModInstrument *pIns = new (std::nothrow) ModInstrument(); if(pIns == nullptr) { return false; } DestroyInstrument(nInstr, deleteAssociatedSamples); if (nInstr > m_nInstruments) m_nInstruments = nInstr; Instruments[nInstr] = pIns; pIns->name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, instrHeader.name); pIns->nFadeOut = 2048; if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) { pIns->nNNA = NewNoteAction::NoteOff; pIns->nDNA = DuplicateNoteAction::NoteFade; } SAMPLEINDEX nextSample = 0; int32 nMinSmpNote = 0xFF; SAMPLEINDEX nMinSmp = 0; for(uint8 smp = 0; smp < layerHeader.samples; smp++) { // Find a free sample nextSample = GetNextFreeSample(nInstr, nextSample + 1); if(nextSample == SAMPLEINDEX_INVALID) break; if(m_nSamples < nextSample) m_nSamples = nextSample; if(!nMinSmp) nMinSmp = nextSample; // Load it GF1SampleHeader sampleHeader; PatchToSample(this, nextSample, sampleHeader, file); int32 nMinNote = (sampleHeader.low_freq > 100) ? PatchFreqToNoteInt(sampleHeader.low_freq) : 0; int32 nMaxNote = (sampleHeader.high_freq > 100) ? PatchFreqToNoteInt(sampleHeader.high_freq) : static_cast(NOTE_MAX); int32 nBaseNote = (sampleHeader.root_freq > 100) ? PatchFreqToNoteInt(sampleHeader.root_freq) : -1; if(!sampleHeader.scale_factor && layerHeader.samples == 1) { nMinNote = 0; nMaxNote = NOTE_MAX; } // Fill Note Map for(int32 k = 0; k < NOTE_MAX; k++) { if(k == nBaseNote || (!pIns->Keyboard[k] && k >= nMinNote && k <= nMaxNote)) { if(!sampleHeader.scale_factor) pIns->NoteMap[k] = NOTE_MIDDLEC; pIns->Keyboard[k] = nextSample; if(k < nMinSmpNote) { nMinSmpNote = k; nMinSmp = nextSample; } } } } if(nMinSmp) { // Fill note map and missing samples for(uint8 k = 0; k < NOTE_MAX; k++) { if(!pIns->NoteMap[k]) pIns->NoteMap[k] = k + 1; if(!pIns->Keyboard[k]) { pIns->Keyboard[k] = nMinSmp; } else { nMinSmp = pIns->Keyboard[k]; } } } pIns->Sanitize(MOD_TYPE_IT); pIns->Convert(MOD_TYPE_IT, GetType()); return true; } ///////////////////////////////////////////////////////////// // S3I Samples bool CSoundFile::ReadS3ISample(SAMPLEINDEX nSample, FileReader &file) { file.Rewind(); S3MSampleHeader sampleHeader; if(!file.ReadStruct(sampleHeader) || (sampleHeader.sampleType != S3MSampleHeader::typePCM && sampleHeader.sampleType != S3MSampleHeader::typeAdMel) || (memcmp(sampleHeader.magic, "SCRS", 4) && memcmp(sampleHeader.magic, "SCRI", 4)) || !file.Seek(sampleHeader.GetSampleOffset())) { return false; } if(sampleHeader.sampleType >= S3MSampleHeader::typeAdMel) { if(SupportsOPL()) { InitOPL(); } else { AddToLog(LogInformation, U_("OPL instruments are not supported by this format.")); return true; } } DestroySampleThreadsafe(nSample); ModSample &sample = Samples[nSample]; sampleHeader.ConvertToMPT(sample); m_szNames[nSample] = mpt::String::ReadBuf(mpt::String::nullTerminated, sampleHeader.name); if(sampleHeader.sampleType < S3MSampleHeader::typeAdMel) sampleHeader.GetSampleFormat(false).ReadSample(sample, file); sample.Convert(MOD_TYPE_S3M, GetType()); sample.PrecomputeLoops(*this, false); return true; } #ifndef MODPLUG_NO_FILESAVE bool CSoundFile::SaveS3ISample(SAMPLEINDEX smp, std::ostream &f) const { const ModSample &sample = Samples[smp]; if(!sample.uFlags[CHN_ADLIB] && !sample.HasSampleData()) return false; S3MSampleHeader sampleHeader{}; SmpLength length = sampleHeader.ConvertToS3M(sample); mpt::String::WriteBuf(mpt::String::nullTerminated, sampleHeader.name) = m_szNames[smp]; mpt::String::WriteBuf(mpt::String::maybeNullTerminated, sampleHeader.reserved2) = mpt::ToCharset(mpt::Charset::UTF8, Version::Current().GetOpenMPTVersionString()); if(length) sampleHeader.dataPointer[1] = sizeof(S3MSampleHeader) >> 4; mpt::IO::Write(f, sampleHeader); if(length) sampleHeader.GetSampleFormat(false).WriteSample(f, sample, length); return true; } #endif // MODPLUG_NO_FILESAVE ///////////////////////////////////////////////////////////// // SBI OPL patch files bool CSoundFile::ReadSBISample(SAMPLEINDEX sample, FileReader &file) { file.Rewind(); const auto magic = file.ReadArray(); if((memcmp(magic.data(), "SBI\x1A", 4) && memcmp(magic.data(), "SBI\x1D", 4)) // 1D = broken JuceOPLVSTi files || !file.CanRead(32 + sizeof(OPLPatch)) || file.CanRead(64)) // Arbitrary threshold to reject files that are unlikely to be SBI files return false; if(!SupportsOPL()) { AddToLog(LogInformation, U_("OPL instruments are not supported by this format.")); return true; } DestroySampleThreadsafe(sample); InitOPL(); ModSample &mptSmp = Samples[sample]; mptSmp.Initialize(MOD_TYPE_S3M); file.ReadString(m_szNames[sample], 32); OPLPatch patch; file.ReadArray(patch); mptSmp.SetAdlib(true, patch); mptSmp.Convert(MOD_TYPE_S3M, GetType()); return true; } ///////////////////////////////////////////////////////////// // XI Instruments bool CSoundFile::ReadXIInstrument(INSTRUMENTINDEX nInstr, FileReader &file) { file.Rewind(); XIInstrumentHeader fileHeader; if(!file.ReadStruct(fileHeader) || memcmp(fileHeader.signature, "Extended Instrument: ", 21) || fileHeader.version != XIInstrumentHeader::fileVersion || fileHeader.eof != 0x1A) { return false; } ModInstrument *pIns = new (std::nothrow) ModInstrument(); if(pIns == nullptr) { return false; } DestroyInstrument(nInstr, deleteAssociatedSamples); if(nInstr > m_nInstruments) { m_nInstruments = nInstr; } Instruments[nInstr] = pIns; fileHeader.ConvertToMPT(*pIns); // Translate sample map and find available sample slots std::vector sampleMap(fileHeader.numSamples); SAMPLEINDEX maxSmp = 0; for(size_t i = 0 + 12; i < 96 + 12; i++) { if(pIns->Keyboard[i] >= fileHeader.numSamples) { continue; } if(sampleMap[pIns->Keyboard[i]] == 0) { // Find slot for this sample maxSmp = GetNextFreeSample(nInstr, maxSmp + 1); if(maxSmp != SAMPLEINDEX_INVALID) { sampleMap[pIns->Keyboard[i]] = maxSmp; } } pIns->Keyboard[i] = sampleMap[pIns->Keyboard[i]]; } if(m_nSamples < maxSmp) { m_nSamples = maxSmp; } std::vector sampleFlags(fileHeader.numSamples); // Read sample headers for(SAMPLEINDEX i = 0; i < fileHeader.numSamples; i++) { XMSample sampleHeader; if(!file.ReadStruct(sampleHeader) || !sampleMap[i]) { continue; } ModSample &mptSample = Samples[sampleMap[i]]; sampleHeader.ConvertToMPT(mptSample); fileHeader.instrument.ApplyAutoVibratoToMPT(mptSample); mptSample.Convert(MOD_TYPE_XM, GetType()); if(GetType() != MOD_TYPE_XM && fileHeader.numSamples == 1) { // No need to pan that single sample, thank you... mptSample.uFlags &= ~CHN_PANNING; } mptSample.filename = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); m_szNames[sampleMap[i]] = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); sampleFlags[i] = sampleHeader.GetSampleFormat(); } // Read sample data for(SAMPLEINDEX i = 0; i < fileHeader.numSamples; i++) { if(sampleMap[i]) { sampleFlags[i].ReadSample(Samples[sampleMap[i]], file); Samples[sampleMap[i]].PrecomputeLoops(*this, false); } } // Read MPT crap LoadExtendedInstrumentProperties(mpt::as_span(&Instruments[nInstr], 1), file); pIns->Convert(MOD_TYPE_XM, GetType()); pIns->Sanitize(GetType()); return true; } #ifndef MODPLUG_NO_FILESAVE bool CSoundFile::SaveXIInstrument(INSTRUMENTINDEX nInstr, std::ostream &f) const { ModInstrument *pIns = Instruments[nInstr]; if(pIns == nullptr) { return false; } // Create file header XIInstrumentHeader header; const auto sampleList = header.ConvertToXM(*pIns, false); const auto &samples = sampleList.samples; if(sampleList.tooManySamples) AddToLog(LogInformation, MPT_UFORMAT("This instrument references too many samples, only the first {} will be exported.")(samples.size())); if(samples.size() > 0 && samples[0] <= GetNumSamples()) { // Copy over auto-vibrato settings of first sample header.instrument.ApplyAutoVibratoToXM(Samples[samples[0]], GetType()); } mpt::IO::Write(f, header); std::vector sampleFlags(samples.size()); // XI Sample Headers for(SAMPLEINDEX i = 0; i < samples.size(); i++) { XMSample xmSample; if(samples[i] <= GetNumSamples()) { xmSample.ConvertToXM(Samples[samples[i]], GetType(), false); } else { MemsetZero(xmSample); } sampleFlags[i] = xmSample.GetSampleFormat(); mpt::String::WriteBuf(mpt::String::spacePadded, xmSample.name) = m_szNames[samples[i]]; mpt::IO::Write(f, xmSample); } // XI Sample Data for(SAMPLEINDEX i = 0; i < samples.size(); i++) { if(samples[i] <= GetNumSamples()) { sampleFlags[i].WriteSample(f, Samples[samples[i]]); } } SaveExtendedInstrumentProperties(nInstr, MOD_TYPE_XM, f); return true; } #endif // MODPLUG_NO_FILESAVE // Read first sample from XI file into a sample slot bool CSoundFile::ReadXISample(SAMPLEINDEX nSample, FileReader &file) { file.Rewind(); XIInstrumentHeader fileHeader; if(!file.ReadStruct(fileHeader) || !file.CanRead(sizeof(XMSample)) || memcmp(fileHeader.signature, "Extended Instrument: ", 21) || fileHeader.version != XIInstrumentHeader::fileVersion || fileHeader.eof != 0x1A || fileHeader.numSamples == 0) { return false; } if(m_nSamples < nSample) { m_nSamples = nSample; } uint16 numSamples = fileHeader.numSamples; FileReader::pos_type samplePos = sizeof(XIInstrumentHeader) + numSamples * sizeof(XMSample); // Preferably read the middle-C sample auto sample = fileHeader.instrument.sampleMap[48]; if(sample >= fileHeader.numSamples) sample = 0; XMSample sampleHeader; while(sample--) { file.ReadStruct(sampleHeader); samplePos += sampleHeader.length; } file.ReadStruct(sampleHeader); // Gotta skip 'em all! file.Seek(samplePos); DestroySampleThreadsafe(nSample); ModSample &mptSample = Samples[nSample]; sampleHeader.ConvertToMPT(mptSample); if(GetType() != MOD_TYPE_XM) { // No need to pan that single sample, thank you... mptSample.uFlags.reset(CHN_PANNING); } fileHeader.instrument.ApplyAutoVibratoToMPT(mptSample); mptSample.Convert(MOD_TYPE_XM, GetType()); mptSample.filename = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); m_szNames[nSample] = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); // Read sample data sampleHeader.GetSampleFormat().ReadSample(Samples[nSample], file); Samples[nSample].PrecomputeLoops(*this, false); return true; } /////////////// // Apple CAF // struct CAFFileHeader { uint32be mFileType; uint16be mFileVersion; uint16be mFileFlags; }; MPT_BINARY_STRUCT(CAFFileHeader, 8) struct CAFChunkHeader { uint32be mChunkType; int64be mChunkSize; }; MPT_BINARY_STRUCT(CAFChunkHeader, 12) struct CAFChunk { enum ChunkIdentifiers { iddesc = MagicBE("desc"), iddata = MagicBE("data"), idstrg = MagicBE("strg"), idinfo = MagicBE("info") }; CAFChunkHeader header; FileReader::pos_type GetLength() const { int64 length = header.mChunkSize; if(length == -1) { length = std::numeric_limits::max(); // spec } if(length < 0) { length = std::numeric_limits::max(); // heuristic } return mpt::saturate_cast(length); } ChunkIdentifiers GetID() const { return static_cast(header.mChunkType.get()); } }; MPT_BINARY_STRUCT(CAFChunk, 12) enum { CAFkAudioFormatLinearPCM = MagicBE("lpcm"), CAFkAudioFormatAppleIMA4 = MagicBE("ima4"), CAFkAudioFormatMPEG4AAC = MagicBE("aac "), CAFkAudioFormatMACE3 = MagicBE("MAC3"), CAFkAudioFormatMACE6 = MagicBE("MAC6"), CAFkAudioFormatULaw = MagicBE("ulaw"), CAFkAudioFormatALaw = MagicBE("alaw"), CAFkAudioFormatMPEGLayer1 = MagicBE(".mp1"), CAFkAudioFormatMPEGLayer2 = MagicBE(".mp2"), CAFkAudioFormatMPEGLayer3 = MagicBE(".mp3"), CAFkAudioFormatAppleLossless = MagicBE("alac") }; enum { CAFkCAFLinearPCMFormatFlagIsFloat = (1L << 0), CAFkCAFLinearPCMFormatFlagIsLittleEndian = (1L << 1) }; struct CAFAudioFormat { float64be mSampleRate; uint32be mFormatID; uint32be mFormatFlags; uint32be mBytesPerPacket; uint32be mFramesPerPacket; uint32be mChannelsPerFrame; uint32be mBitsPerChannel; }; MPT_BINARY_STRUCT(CAFAudioFormat, 32) static void CAFSetTagFromInfoKey(mpt::ustring & dst, const std::map & infoMap, const std::string & key) { auto item = infoMap.find(key); if(item == infoMap.end()) { return; } if(item->second.empty()) { return; } dst = mpt::ToUnicode(mpt::Charset::UTF8, item->second); } bool CSoundFile::ReadCAFSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize) { file.Rewind(); CAFFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(fileHeader.mFileType != MagicBE("caff")) { return false; } if(fileHeader.mFileVersion != 1) { return false; } auto chunkList = file.ReadChunks(0); CAFAudioFormat audioFormat; if(!chunkList.GetChunk(CAFChunk::iddesc).ReadStruct(audioFormat)) { return false; } if(audioFormat.mSampleRate <= 0.0) { return false; } if(audioFormat.mChannelsPerFrame == 0) { return false; } if(audioFormat.mChannelsPerFrame > 2) { return false; } if(!mpt::in_range(mpt::saturate_round(audioFormat.mSampleRate.get()))) { return false; } uint32 sampleRate = static_cast(mpt::saturate_round(audioFormat.mSampleRate.get())); if(sampleRate <= 0) { return false; } SampleIO sampleIO; if(audioFormat.mFormatID == CAFkAudioFormatLinearPCM) { if(audioFormat.mFramesPerPacket != 1) { return false; } if(audioFormat.mBytesPerPacket == 0) { return false; } if(audioFormat.mBitsPerChannel == 0) { return false; } if(audioFormat.mFormatFlags & CAFkCAFLinearPCMFormatFlagIsFloat) { if(audioFormat.mBitsPerChannel != 32 && audioFormat.mBitsPerChannel != 64) { return false; } if(audioFormat.mBytesPerPacket != audioFormat.mChannelsPerFrame * audioFormat.mBitsPerChannel/8) { return false; } } if(audioFormat.mBytesPerPacket % audioFormat.mChannelsPerFrame != 0) { return false; } if(audioFormat.mBytesPerPacket / audioFormat.mChannelsPerFrame != 1 && audioFormat.mBytesPerPacket / audioFormat.mChannelsPerFrame != 2 && audioFormat.mBytesPerPacket / audioFormat.mChannelsPerFrame != 3 && audioFormat.mBytesPerPacket / audioFormat.mChannelsPerFrame != 4 && audioFormat.mBytesPerPacket / audioFormat.mChannelsPerFrame != 8 ) { return false; } SampleIO::Channels channels = (audioFormat.mChannelsPerFrame == 2) ? SampleIO::stereoInterleaved : SampleIO::mono; SampleIO::Endianness endianness = (audioFormat.mFormatFlags & CAFkCAFLinearPCMFormatFlagIsLittleEndian) ? SampleIO::littleEndian : SampleIO::bigEndian; SampleIO::Encoding encoding = (audioFormat.mFormatFlags & CAFkCAFLinearPCMFormatFlagIsFloat) ? SampleIO::floatPCM : SampleIO::signedPCM; SampleIO::Bitdepth bitdepth = static_cast((audioFormat.mBytesPerPacket / audioFormat.mChannelsPerFrame) * 8); sampleIO = SampleIO(bitdepth, channels, endianness, encoding); } else { return false; } if(mayNormalize) { sampleIO.MayNormalize(); } /* std::map stringMap; // UTF-8 if(chunkList.ChunkExists(CAFChunk::idstrg)) { FileReader stringsChunk = chunkList.GetChunk(CAFChunk::idstrg); uint32 numEntries = stringsChunk.ReadUint32BE(); if(stringsChunk.Skip(12 * numEntries)) { FileReader stringData = stringsChunk.ReadChunk(stringsChunk.BytesLeft()); stringsChunk.Seek(4); for(uint32 entry = 0; entry < numEntries && stringsChunk.CanRead(12); entry++) { uint32 stringID = stringsChunk.ReadUint32BE(); int64 offset = stringsChunk.ReadIntBE(); if(offset >= 0 && mpt::in_range(offset)) { stringData.Seek(mpt::saturate_cast(offset)); std::string str; if(stringData.ReadNullString(str)) { stringMap[stringID] = str; } } } } } */ std::map infoMap; // UTF-8 if(chunkList.ChunkExists(CAFChunk::idinfo)) { FileReader informationChunk = chunkList.GetChunk(CAFChunk::idinfo); uint32 numEntries = informationChunk.ReadUint32BE(); for(uint32 entry = 0; entry < numEntries && informationChunk.CanRead(2); entry++) { std::string key; std::string value; if(!informationChunk.ReadNullString(key)) { break; } if(!informationChunk.ReadNullString(value)) { break; } if(!key.empty() && !value.empty()) { infoMap[key] = value; } } } FileTags tags; CAFSetTagFromInfoKey(tags.bpm, infoMap, "tempo"); //CAFSetTagFromInfoKey(void, infoMap, "key signature"); //CAFSetTagFromInfoKey(void, infoMap, "time signature"); CAFSetTagFromInfoKey(tags.artist, infoMap, "artist"); CAFSetTagFromInfoKey(tags.album, infoMap, "album"); CAFSetTagFromInfoKey(tags.trackno, infoMap, "track number"); CAFSetTagFromInfoKey(tags.year, infoMap, "year"); //CAFSetTagFromInfoKey(void, infoMap, "composer"); //CAFSetTagFromInfoKey(void, infoMap, "lyricist"); CAFSetTagFromInfoKey(tags.genre, infoMap, "genre"); CAFSetTagFromInfoKey(tags.title, infoMap, "title"); //CAFSetTagFromInfoKey(void, infoMap, "recorded date"); CAFSetTagFromInfoKey(tags.comments, infoMap, "comments"); //CAFSetTagFromInfoKey(void, infoMap, "copyright"); //CAFSetTagFromInfoKey(void, infoMap, "source encoder"); CAFSetTagFromInfoKey(tags.encoder, infoMap, "encoding application"); //CAFSetTagFromInfoKey(void, infoMap, "nominal bit rate"); //CAFSetTagFromInfoKey(void, infoMap, "channel layout"); //CAFSetTagFromInfoKey(tags.url, infoMap, void); if(!chunkList.ChunkExists(CAFChunk::iddata)) { return false; } FileReader dataChunk = chunkList.GetChunk(CAFChunk::iddata); dataChunk.Skip(4); // edit count FileReader audioData = dataChunk.ReadChunk(dataChunk.BytesLeft()); SmpLength length = mpt::saturate_cast((audioData.GetLength() / audioFormat.mBytesPerPacket) * audioFormat.mFramesPerPacket); ModSample &mptSample = Samples[nSample]; DestroySampleThreadsafe(nSample); mptSample.Initialize(); mptSample.nLength = length; mptSample.nC5Speed = sampleRate; sampleIO.ReadSample(mptSample, audioData); m_szNames[nSample] = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(tags)); mptSample.Convert(MOD_TYPE_IT, GetType()); mptSample.PrecomputeLoops(*this, false); return true; } ///////////////////////////////////////////////////////////////////////////////////////// // AIFF File I/O // AIFF header struct AIFFHeader { char magic[4]; // FORM uint32be length; // Size of the file, not including magic and length char type[4]; // AIFF or AIFC }; MPT_BINARY_STRUCT(AIFFHeader, 12) // General IFF Chunk header struct AIFFChunk { // 32-Bit chunk identifiers enum ChunkIdentifiers { idCOMM = MagicBE("COMM"), idSSND = MagicBE("SSND"), idINST = MagicBE("INST"), idMARK = MagicBE("MARK"), idNAME = MagicBE("NAME"), }; uint32be id; // See ChunkIdentifiers uint32be length; // Chunk size without header size_t GetLength() const { return length; } ChunkIdentifiers GetID() const { return static_cast(id.get()); } }; MPT_BINARY_STRUCT(AIFFChunk, 8) // "Common" chunk (in AIFC, a compression ID and compression name follows this header, but apart from that it's identical) struct AIFFCommonChunk { uint16be numChannels; uint32be numSampleFrames; uint16be sampleSize; uint8be sampleRate[10]; // Sample rate in 80-Bit floating point // Convert sample rate to integer uint32 GetSampleRate() const { uint32 mantissa = (sampleRate[2] << 24) | (sampleRate[3] << 16) | (sampleRate[4] << 8) | (sampleRate[5] << 0); uint32 last = 0; uint8 exp = 30 - sampleRate[1]; while(exp--) { last = mantissa; mantissa >>= 1; } if(last & 1) mantissa++; return mantissa; } }; MPT_BINARY_STRUCT(AIFFCommonChunk, 18) // Sound chunk struct AIFFSoundChunk { uint32be offset; uint32be blockSize; }; MPT_BINARY_STRUCT(AIFFSoundChunk, 8) // Marker struct AIFFMarker { uint16be id; uint32be position; // Position in sample uint8be nameLength; // Not counting eventually existing padding byte in name string }; MPT_BINARY_STRUCT(AIFFMarker, 7) // Instrument loop struct AIFFInstrumentLoop { enum PlayModes { noLoop = 0, loopNormal = 1, loopBidi = 2, }; uint16be playMode; uint16be beginLoop; // Marker index uint16be endLoop; // Marker index }; MPT_BINARY_STRUCT(AIFFInstrumentLoop, 6) struct AIFFInstrumentChunk { uint8be baseNote; uint8be detune; uint8be lowNote; uint8be highNote; uint8be lowVelocity; uint8be highVelocity; uint16be gain; AIFFInstrumentLoop sustainLoop; AIFFInstrumentLoop releaseLoop; }; MPT_BINARY_STRUCT(AIFFInstrumentChunk, 20) bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize) { file.Rewind(); // Verify header AIFFHeader fileHeader; if(!file.ReadStruct(fileHeader) || memcmp(fileHeader.magic, "FORM", 4) || (memcmp(fileHeader.type, "AIFF", 4) && memcmp(fileHeader.type, "AIFC", 4))) { return false; } auto chunks = file.ReadChunks(2); // Read COMM chunk FileReader commChunk(chunks.GetChunk(AIFFChunk::idCOMM)); AIFFCommonChunk sampleInfo; if(!commChunk.ReadStruct(sampleInfo)) { return false; } // Is this a proper sample? if(sampleInfo.numSampleFrames == 0 || sampleInfo.numChannels < 1 || sampleInfo.numChannels > 2 || sampleInfo.sampleSize < 1 || sampleInfo.sampleSize > 64) { return false; } // Read compression type in AIFF-C files. uint8 compression[4] = { 'N', 'O', 'N', 'E' }; SampleIO::Endianness endian = SampleIO::bigEndian; if(!memcmp(fileHeader.type, "AIFC", 4)) { if(!commChunk.ReadArray(compression)) { return false; } if(!memcmp(compression, "twos", 4)) { endian = SampleIO::littleEndian; } } // Read SSND chunk FileReader soundChunk(chunks.GetChunk(AIFFChunk::idSSND)); AIFFSoundChunk sampleHeader; if(!soundChunk.ReadStruct(sampleHeader)) { return false; } SampleIO::Bitdepth bitDepth; switch((sampleInfo.sampleSize - 1) / 8) { default: case 0: bitDepth = SampleIO::_8bit; break; case 1: bitDepth = SampleIO::_16bit; break; case 2: bitDepth = SampleIO::_24bit; break; case 3: bitDepth = SampleIO::_32bit; break; case 7: bitDepth = SampleIO::_64bit; break; } SampleIO sampleIO(bitDepth, (sampleInfo.numChannels == 2) ? SampleIO::stereoInterleaved : SampleIO::mono, endian, SampleIO::signedPCM); if(!memcmp(compression, "fl32", 4) || !memcmp(compression, "FL32", 4) || !memcmp(compression, "fl64", 4) || !memcmp(compression, "FL64", 4)) { sampleIO |= SampleIO::floatPCM; } else if(!memcmp(compression, "alaw", 4) || !memcmp(compression, "ALAW", 4)) { sampleIO |= SampleIO::aLaw; sampleIO |= SampleIO::_16bit; } else if(!memcmp(compression, "ulaw", 4) || !memcmp(compression, "ULAW", 4)) { sampleIO |= SampleIO::uLaw; sampleIO |= SampleIO::_16bit; } else if(!memcmp(compression, "raw ", 4)) { sampleIO |= SampleIO::unsignedPCM; } if(mayNormalize) { sampleIO.MayNormalize(); } if(soundChunk.CanRead(sampleHeader.offset)) { soundChunk.Skip(sampleHeader.offset); } ModSample &mptSample = Samples[nSample]; DestroySampleThreadsafe(nSample); mptSample.Initialize(); mptSample.nLength = sampleInfo.numSampleFrames; mptSample.nC5Speed = sampleInfo.GetSampleRate(); sampleIO.ReadSample(mptSample, soundChunk); // Read MARK and INST chunk to extract sample loops FileReader markerChunk(chunks.GetChunk(AIFFChunk::idMARK)); AIFFInstrumentChunk instrHeader; if(markerChunk.IsValid() && chunks.GetChunk(AIFFChunk::idINST).ReadStruct(instrHeader)) { uint16 numMarkers = markerChunk.ReadUint16BE(); std::vector markers; markers.reserve(numMarkers); for(size_t i = 0; i < numMarkers; i++) { AIFFMarker marker; if(!markerChunk.ReadStruct(marker)) { break; } markers.push_back(marker); markerChunk.Skip(marker.nameLength + ((marker.nameLength % 2u) == 0 ? 1 : 0)); } if(instrHeader.sustainLoop.playMode != AIFFInstrumentLoop::noLoop) { mptSample.uFlags.set(CHN_SUSTAINLOOP); mptSample.uFlags.set(CHN_PINGPONGSUSTAIN, instrHeader.sustainLoop.playMode == AIFFInstrumentLoop::loopBidi); } if(instrHeader.releaseLoop.playMode != AIFFInstrumentLoop::noLoop) { mptSample.uFlags.set(CHN_LOOP); mptSample.uFlags.set(CHN_PINGPONGLOOP, instrHeader.releaseLoop.playMode == AIFFInstrumentLoop::loopBidi); } // Read markers for(const auto &m : markers) { if(m.id == instrHeader.sustainLoop.beginLoop) mptSample.nSustainStart = m.position; if(m.id == instrHeader.sustainLoop.endLoop) mptSample.nSustainEnd = m.position; if(m.id == instrHeader.releaseLoop.beginLoop) mptSample.nLoopStart = m.position; if(m.id == instrHeader.releaseLoop.endLoop) mptSample.nLoopEnd = m.position; } mptSample.SanitizeLoops(); } // Extract sample name FileReader nameChunk(chunks.GetChunk(AIFFChunk::idNAME)); if(nameChunk.IsValid()) { nameChunk.ReadString(m_szNames[nSample], mpt::saturate_cast(nameChunk.GetLength())); } else { m_szNames[nSample] = ""; } mptSample.Convert(MOD_TYPE_IT, GetType()); mptSample.PrecomputeLoops(*this, false); return true; } static bool AUIsAnnotationLineWithField(const std::string &line) { std::size_t pos = line.find('='); if(pos == std::string::npos) { return false; } if(pos == 0) { return false; } const auto field = std::string_view(line).substr(0, pos); // Scan for invalid chars for(auto c : field) { if(!mpt::is_in_range(c, 'a', 'z') && !mpt::is_in_range(c, 'A', 'Z') && !mpt::is_in_range(c, '0', '9') && c != '-' && c != '_') { return false; } } return true; } static std::string AUTrimFieldFromAnnotationLine(const std::string &line) { if(!AUIsAnnotationLineWithField(line)) { return line; } std::size_t pos = line.find('='); return line.substr(pos + 1); } static std::string AUGetAnnotationFieldFromLine(const std::string &line) { if(!AUIsAnnotationLineWithField(line)) { return std::string(); } std::size_t pos = line.find('='); return line.substr(0, pos); } bool CSoundFile::ReadAUSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize) { file.Rewind(); // Verify header const auto magic = file.ReadArray(); const bool bigEndian = !std::memcmp(magic.data(), ".snd", 4); const bool littleEndian = !std::memcmp(magic.data(), "dns.", 4); if(!bigEndian && !littleEndian) return false; auto readUint32 = std::bind(bigEndian ? &FileReader::ReadUint32BE : &FileReader::ReadUint32LE, file); uint32 dataOffset = readUint32(); // must be divisible by 8 according to spec, however, there are files that ignore this requirement uint32 dataSize = readUint32(); uint32 encoding = readUint32(); uint32 sampleRate = readUint32(); uint32 channels = readUint32(); // According to spec, a minimum 8 byte annotation field after the header fields is required, // however, there are files in the wild that violate this requirement. // Thus, check for 24 instead of 32 here. if(dataOffset < 24) // data offset points inside header { return false; } if(channels < 1 || channels > 2) return false; SampleIO sampleIO(SampleIO::_8bit, channels == 1 ? SampleIO::mono : SampleIO::stereoInterleaved, bigEndian ? SampleIO::bigEndian : SampleIO::littleEndian, SampleIO::signedPCM); switch(encoding) { case 1: sampleIO |= SampleIO::_16bit; // u-law sampleIO |= SampleIO::uLaw; break; case 2: break; // 8-bit linear PCM case 3: sampleIO |= SampleIO::_16bit; break; // 16-bit linear PCM case 4: sampleIO |= SampleIO::_24bit; break; // 24-bit linear PCM case 5: sampleIO |= SampleIO::_32bit; break; // 32-bit linear PCM case 6: sampleIO |= SampleIO::_32bit; // 32-bit IEEE floating point sampleIO |= SampleIO::floatPCM; break; case 7: sampleIO |= SampleIO::_64bit; // 64-bit IEEE floating point sampleIO |= SampleIO::floatPCM; break; case 27: sampleIO |= SampleIO::_16bit; // a-law sampleIO |= SampleIO::aLaw; break; default: return false; } if(!file.LengthIsAtLeast(dataOffset)) { return false; } FileTags tags; // This reads annotation metadata as written by OpenMPT, sox, ffmpeg. // Additionally, we fall back to just reading the whole field as a single comment. // We only read up to the first \0 byte. file.Seek(24); std::string annotation; file.ReadString(annotation, dataOffset - 24); annotation = mpt::replace(annotation, std::string("\r\n"), std::string("\n")); annotation = mpt::replace(annotation, std::string("\r"), std::string("\n")); mpt::Charset charset = mpt::IsUTF8(annotation) ? mpt::Charset::UTF8 : mpt::Charset::ISO8859_1; const auto lines = mpt::split(annotation, std::string("\n")); bool hasFields = false; for(const auto &line : lines) { if(AUIsAnnotationLineWithField(line)) { hasFields = true; break; } } if(hasFields) { std::map> linesPerField; std::string lastField = "comment"; for(const auto &line : lines) { if(AUIsAnnotationLineWithField(line)) { lastField = mpt::ToLowerCaseAscii(mpt::trim(AUGetAnnotationFieldFromLine(line))); } linesPerField[lastField].push_back(AUTrimFieldFromAnnotationLine(line)); } tags.title = mpt::ToUnicode(charset, mpt::join_format(linesPerField["title" ], std::string("\n"))); tags.artist = mpt::ToUnicode(charset, mpt::join_format(linesPerField["artist" ], std::string("\n"))); tags.album = mpt::ToUnicode(charset, mpt::join_format(linesPerField["album" ], std::string("\n"))); tags.trackno = mpt::ToUnicode(charset, mpt::join_format(linesPerField["track" ], std::string("\n"))); tags.genre = mpt::ToUnicode(charset, mpt::join_format(linesPerField["genre" ], std::string("\n"))); tags.comments = mpt::ToUnicode(charset, mpt::join_format(linesPerField["comment"], std::string("\n"))); } else { // Most applications tend to write their own name here, // thus there is little use in interpreting the string as a title. annotation = mpt::trim_right(annotation, std::string("\r\n")); tags.comments = mpt::ToUnicode(charset, annotation); } file.Seek(dataOffset); ModSample &mptSample = Samples[nSample]; DestroySampleThreadsafe(nSample); mptSample.Initialize(); SmpLength length = mpt::saturate_cast(file.BytesLeft()); if(dataSize != 0xFFFFFFFF) LimitMax(length, dataSize); mptSample.nLength = (length * 8u) / (sampleIO.GetEncodedBitsPerSample() * channels); mptSample.nC5Speed = sampleRate; m_szNames[nSample] = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(tags)); if(mayNormalize) { sampleIO.MayNormalize(); } sampleIO.ReadSample(mptSample, file); mptSample.Convert(MOD_TYPE_IT, GetType()); mptSample.PrecomputeLoops(*this, false); return true; } ///////////////////////////////////////////////////////////////////////////////////////// // ITS Samples bool CSoundFile::ReadITSSample(SAMPLEINDEX nSample, FileReader &file, bool rewind) { if(rewind) { file.Rewind(); } ITSample sampleHeader; if(!file.ReadStruct(sampleHeader) || memcmp(sampleHeader.id, "IMPS", 4)) { return false; } DestroySampleThreadsafe(nSample); ModSample &sample = Samples[nSample]; file.Seek(sampleHeader.ConvertToMPT(sample)); m_szNames[nSample] = mpt::String::ReadBuf(mpt::String::spacePaddedNull, sampleHeader.name); if(sample.uFlags[CHN_ADLIB]) { OPLPatch patch; file.ReadArray(patch); sample.SetAdlib(true, patch); InitOPL(); if(!SupportsOPL()) { AddToLog(LogInformation, U_("OPL instruments are not supported by this format.")); } } else if(!sample.uFlags[SMP_KEEPONDISK]) { sampleHeader.GetSampleFormat().ReadSample(sample, file); } else { // External sample size_t strLen; file.ReadVarInt(strLen); #ifdef MPT_EXTERNAL_SAMPLES std::string filenameU8; file.ReadString(filenameU8, strLen); mpt::PathString filename = mpt::PathString::FromUTF8(filenameU8); if(!filename.empty()) { if(file.GetOptionalFileName()) { filename = mpt::RelativePathToAbsolute(filename, file.GetOptionalFileName()->GetDirectoryWithDrive()); } if(!LoadExternalSample(nSample, filename)) { AddToLog(LogWarning, U_("Unable to load sample: ") + filename.ToUnicode()); } } else { sample.uFlags.reset(SMP_KEEPONDISK); } #else file.Skip(strLen); #endif // MPT_EXTERNAL_SAMPLES } sample.Convert(MOD_TYPE_IT, GetType()); sample.PrecomputeLoops(*this, false); return true; } bool CSoundFile::ReadITISample(SAMPLEINDEX nSample, FileReader &file) { ITInstrument instrumentHeader; file.Rewind(); if(!file.ReadStruct(instrumentHeader) || memcmp(instrumentHeader.id, "IMPI", 4)) { return false; } file.Rewind(); ModInstrument dummy; ITInstrToMPT(file, dummy, instrumentHeader.trkvers); // Old SchismTracker versions set nos=0 const SAMPLEINDEX nsamples = std::max(static_cast(instrumentHeader.nos), *std::max_element(std::begin(dummy.Keyboard), std::end(dummy.Keyboard))); if(!nsamples) return false; // Preferably read the middle-C sample auto sample = dummy.Keyboard[NOTE_MIDDLEC - NOTE_MIN]; if(sample > 0) sample--; else sample = 0; file.Seek(file.GetPosition() + sample * sizeof(ITSample)); return ReadITSSample(nSample, file, false); } bool CSoundFile::ReadITIInstrument(INSTRUMENTINDEX nInstr, FileReader &file) { ITInstrument instrumentHeader; SAMPLEINDEX smp = 0; file.Rewind(); if(!file.ReadStruct(instrumentHeader) || memcmp(instrumentHeader.id, "IMPI", 4)) { return false; } if(nInstr > GetNumInstruments()) m_nInstruments = nInstr; ModInstrument *pIns = new (std::nothrow) ModInstrument(); if(pIns == nullptr) { return false; } DestroyInstrument(nInstr, deleteAssociatedSamples); Instruments[nInstr] = pIns; file.Rewind(); ITInstrToMPT(file, *pIns, instrumentHeader.trkvers); // Old SchismTracker versions set nos=0 const SAMPLEINDEX nsamples = std::max(static_cast(instrumentHeader.nos), *std::max_element(std::begin(pIns->Keyboard), std::end(pIns->Keyboard))); // In order to properly compute the position, in file, of eventual extended settings // such as "attack" we need to keep the "real" size of the last sample as those extra // setting will follow this sample in the file FileReader::pos_type extraOffset = file.GetPosition(); // Reading Samples std::vector samplemap(nsamples, 0); for(SAMPLEINDEX i = 0; i < nsamples; i++) { smp = GetNextFreeSample(nInstr, smp + 1); if(smp == SAMPLEINDEX_INVALID) break; samplemap[i] = smp; const FileReader::pos_type offset = file.GetPosition(); if(!ReadITSSample(smp, file, false)) smp--; extraOffset = std::max(extraOffset, file.GetPosition()); file.Seek(offset + sizeof(ITSample)); } if(GetNumSamples() < smp) m_nSamples = smp; // Adjust sample assignment for(auto &sample : pIns->Keyboard) { if(sample > 0 && sample <= nsamples) { sample = samplemap[sample - 1]; } } if(file.Seek(extraOffset)) { // Read MPT crap LoadExtendedInstrumentProperties(mpt::as_span(&Instruments[nInstr], 1), file); } pIns->Convert(MOD_TYPE_IT, GetType()); pIns->Sanitize(GetType()); return true; } #ifndef MODPLUG_NO_FILESAVE bool CSoundFile::SaveITIInstrument(INSTRUMENTINDEX nInstr, std::ostream &f, const mpt::PathString &filename, bool compress, bool allowExternal) const { ITInstrument iti; ModInstrument *pIns = Instruments[nInstr]; if((!pIns) || (filename.empty() && allowExternal)) return false; auto instSize = iti.ConvertToIT(*pIns, false, *this); // Create sample assignment table std::vector smptable; std::vector smpmap(GetNumSamples(), 0); static_assert(NOTE_MAX >= 120); for(size_t i = 0; i < 120; i++) { const SAMPLEINDEX smp = pIns->Keyboard[i]; if(smp && smp <= GetNumSamples()) { if(!smpmap[smp - 1]) { // We haven't considered this sample yet. smptable.push_back(smp); smpmap[smp - 1] = static_cast(smptable.size()); } iti.keyboard[i * 2 + 1] = smpmap[smp - 1]; } else { iti.keyboard[i * 2 + 1] = 0; } } iti.nos = static_cast(smptable.size()); smpmap.clear(); uint32 filePos = instSize; mpt::IO::WritePartial(f, iti, instSize); filePos += mpt::saturate_cast(smptable.size() * sizeof(ITSample)); // Writing sample headers + data std::vector sampleFlags; for(auto smp : smptable) { ITSample itss; itss.ConvertToIT(Samples[smp], GetType(), compress, compress, allowExternal); const bool isExternal = itss.cvt == ITSample::cvtExternalSample; mpt::String::WriteBuf(mpt::String::nullTerminated, itss.name) = m_szNames[smp]; itss.samplepointer = filePos; mpt::IO::Write(f, itss); // Write sample auto curPos = mpt::IO::TellWrite(f); mpt::IO::SeekAbsolute(f, filePos); if(!isExternal) { filePos += mpt::saturate_cast(itss.GetSampleFormat(0x0214).WriteSample(f, Samples[smp])); } else { #ifdef MPT_EXTERNAL_SAMPLES const std::string filenameU8 = mpt::AbsolutePathToRelative(GetSamplePath(smp), filename.GetDirectoryWithDrive()).ToUTF8(); const size_t strSize = filenameU8.size(); size_t intBytes = 0; if(mpt::IO::WriteVarInt(f, strSize, &intBytes)) { filePos += mpt::saturate_cast(intBytes + strSize); mpt::IO::WriteRaw(f, filenameU8.data(), strSize); } #endif // MPT_EXTERNAL_SAMPLES } mpt::IO::SeekAbsolute(f, curPos); } mpt::IO::SeekEnd(f); SaveExtendedInstrumentProperties(nInstr, MOD_TYPE_MPT, f); return true; } #endif // MODPLUG_NO_FILESAVE /////////////////////////////////////////////////////////////////////////////////////////////////// // 8SVX / 16SVX / MAUD Samples // IFF File Header struct IFFHeader { char form[4]; // "FORM" uint32be size; char magic[4]; // "8SVX", "16SV", "MAUD" }; MPT_BINARY_STRUCT(IFFHeader, 12) // General IFF Chunk header struct IFFChunk { // 32-Bit chunk identifiers enum ChunkIdentifiers { // 8SVX / 16SV idVHDR = MagicBE("VHDR"), idBODY = MagicBE("BODY"), idCHAN = MagicBE("CHAN"), // MAUD idMHDR = MagicBE("MHDR"), idMDAT = MagicBE("MDAT"), idNAME = MagicBE("NAME"), idANNO = MagicBE("ANNO"), }; uint32be id; // See ChunkIdentifiers uint32be length; // Chunk size without header size_t GetLength() const { if(length == 0 && id == idBODY) // Broken files return std::numeric_limits::max(); return length; } ChunkIdentifiers GetID() const { return static_cast(id.get()); } }; MPT_BINARY_STRUCT(IFFChunk, 8) struct IFFSampleHeader { uint32be oneShotHiSamples; // Samples in the high octave 1-shot part uint32be repeatHiSamples; // Samples in the high octave repeat part uint32be samplesPerHiCycle; // Samples/cycle in high octave, else 0 uint16be samplesPerSec; // Data sampling rate uint8be octave; // Octaves of waveforms uint8be compression; // Data compression technique used uint32be volume; }; MPT_BINARY_STRUCT(IFFSampleHeader, 20) bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file, bool allowLittleEndian, uint8 octave) { file.Rewind(); IFFHeader fileHeader; if(!file.ReadStruct(fileHeader) || memcmp(fileHeader.form, "FORM", 4) || (memcmp(fileHeader.magic, "8SVX", 4) && memcmp(fileHeader.magic, "16SV", 4) && memcmp(fileHeader.magic, "MAUD", 4))) { return false; } const auto chunks = file.ReadChunks(2); FileReader sampleData; SampleIO sampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM); uint32 numSamples = 0, sampleRate = 0, loopStart = 0, loopLength = 0, volume = 0; if(!memcmp(fileHeader.magic, "MAUD", 4)) { FileReader mhdrChunk = chunks.GetChunk(IFFChunk::idMHDR); sampleData = chunks.GetChunk(IFFChunk::idMDAT); if(!mhdrChunk.LengthIs(32) || !sampleData.IsValid()) { return false; } numSamples = mhdrChunk.ReadUint32BE(); const uint16 bitsPerSample = mhdrChunk.ReadUint16BE(); mhdrChunk.Skip(2); // bits per sample after decompression sampleRate = mhdrChunk.ReadUint32BE(); const auto [clockDivide, channelInformation, numChannels, compressionType] = mhdrChunk.ReadArray(); if(!clockDivide) return false; else sampleRate /= clockDivide; if(numChannels != (channelInformation + 1)) return false; if(numChannels == 2) sampleIO |= SampleIO::stereoInterleaved; if(bitsPerSample == 8 && compressionType == 0) sampleIO |= SampleIO::unsignedPCM; else if(bitsPerSample == 8 && compressionType == 2) sampleIO |= SampleIO::aLaw; else if(bitsPerSample == 8 && compressionType == 3) sampleIO |= SampleIO::uLaw; else if(bitsPerSample == 16 && compressionType == 0) sampleIO |= SampleIO::_16bit; else return false; } else { FileReader vhdrChunk = chunks.GetChunk(IFFChunk::idVHDR); FileReader chanChunk = chunks.GetChunk(IFFChunk::idCHAN); sampleData = chunks.GetChunk(IFFChunk::idBODY); IFFSampleHeader sampleHeader; if(!sampleData.IsValid() || !vhdrChunk.IsValid() || !vhdrChunk.ReadStruct(sampleHeader)) { return false; } const uint8 bytesPerSample = memcmp(fileHeader.magic, "8SVX", 4) ? 2 : 1; const uint8 numChannels = chanChunk.ReadUint32BE() == 6 ? 2 : 1; const uint8 bytesPerFrame = bytesPerSample * numChannels; if(bytesPerSample == 2) sampleIO |= SampleIO::_16bit; if(numChannels == 2) sampleIO |= SampleIO::stereoSplit; loopStart = sampleHeader.oneShotHiSamples / bytesPerFrame; // Loops are a complicated mess in IFF samples. // Some samples (e.g. those from the Ensoniq Mirage for Amiga collection available at https://archive.org/details/mirage4amiga) // have a repeatHiSamples portion that includes garbage. However, these samples also have an appropriate samplesPerHiCycle value set // which indicates the length of one cycle of the repeating waveform. If we just take that one cycle into account, the samples loop cleanly. // However, some other, non-musical 8SVX samples use bogus samplesPerHiCycle values. The following conditions help us spot this sort of samples: // - If samplesPerHiCycle is 32 or lower, we simply ignore it. // - According to the documentation, repeatHiSamples is intended to be a multiple of samplesPerHiCycle if the latter is set (otherwise we wouldn't get a clean loop). // So if this is not the case, we ignore samplesPerHiCycle and only use repeatHiSamples. if(sampleHeader.samplesPerHiCycle > 32 && sampleHeader.samplesPerHiCycle < sampleHeader.repeatHiSamples && (sampleHeader.repeatHiSamples % sampleHeader.samplesPerHiCycle) == 0) loopLength = sampleHeader.samplesPerHiCycle / bytesPerFrame; else loopLength = sampleHeader.repeatHiSamples / bytesPerFrame; sampleRate = sampleHeader.samplesPerSec; volume = sampleHeader.volume; numSamples = mpt::saturate_cast(sampleData.GetLength() / bytesPerFrame); if(octave < sampleHeader.octave) { numSamples = sampleHeader.oneShotHiSamples + sampleHeader.repeatHiSamples; for(uint8 o = 0; o < octave; o++) { sampleData.Skip(numSamples * bytesPerSample * numChannels); numSamples *= 2; loopStart *= 2; loopLength *= 2; } } } DestroySampleThreadsafe(nSample); ModSample &sample = Samples[nSample]; sample.Initialize(); sample.nLength = numSamples; sample.nLoopStart = loopStart; sample.nLoopEnd = sample.nLoopStart + loopLength; if((sample.nLoopStart + 4 < sample.nLoopEnd) && (sample.nLoopEnd <= sample.nLength)) sample.uFlags.set(CHN_LOOP); sample.nC5Speed = sampleRate; if(sample.nC5Speed <= 1) sample.nC5Speed = 22050; sample.nVolume = static_cast((volume + 128) / 256); if(!sample.nVolume || sample.nVolume > 256) sample.nVolume = 256; sample.Convert(MOD_TYPE_IT, GetType()); FileReader nameChunk = chunks.GetChunk(IFFChunk::idNAME); if(nameChunk.IsValid()) nameChunk.ReadString(m_szNames[nSample], mpt::saturate_cast(nameChunk.GetLength())); else m_szNames[nSample] = ""; sampleIO.ReadSample(sample, sampleData); if(allowLittleEndian && !memcmp(fileHeader.magic, "16SV", 4)) { // Fasttracker 2 (and also Awave Studio up to version 11.7) writes little-endian 16-bit data. Great... // It is relatively safe to assume (see raw sample import dialog) that "proper" sample data usually has some smoothness to it, // i.e. its first derivative mostly consists of small-ish values. // When interpreting the sample data with incorrect endianness, however, the first derivative is usually a lot more jumpy. // So we compare the two derivatives when interpreting the data as little-endian and big-endian, // and choose the waveform that has less jumps in it. // Sample data is normalized for those comparisons, otherwise 8-bit data converted to 16-bit will almost always be more optimal // when byte-swapped (as the upper byte is always 0). const uint8 numChannels = sample.GetNumChannels(); auto sample16 = mpt::as_span(sample.sample16(), sample.nLength * numChannels); int32 minNative = int16_max, maxNative = int16_min, minSwapped = int16_max, maxSwapped = int16_min; for(const auto vNative : sample16) { const int16 vSwapped = mpt::byteswap(vNative); if(vNative < minNative) minNative = vNative; if(vNative > maxNative) maxNative = vNative; if(vSwapped < minSwapped) minSwapped = vSwapped; if(vSwapped > maxSwapped) maxSwapped = vSwapped; } const int32 minMaxNative = std::max({int32(1), -minNative, maxNative}); const int32 minMaxSwapped = std::max({int32(1), -minSwapped, maxSwapped}); const double factorNative = 1.0 / minMaxNative, factorSwapped = 1.0 / minMaxSwapped; double errorNative = 0.0, errorSwapped = 0.0; for(uint8 chn = 0; chn < numChannels; chn++) { const int16 *vNative = sample.sample16() + chn; int32 prev = 0; for(SmpLength i = sample.nLength; i != 0; i--, vNative += numChannels) { const double diffNative = (*vNative - prev) * factorNative; errorNative += diffNative * diffNative; const double diffSwapped = (mpt::byteswap(*vNative) - mpt::byteswap(static_cast(prev))) * factorSwapped; errorSwapped += diffSwapped * diffSwapped; prev = *vNative; } } if(errorNative > errorSwapped) { for(auto &v : sample16) { v = mpt::byteswap(v); } } } sample.PrecomputeLoops(*this, false); return true; } #ifndef MODPLUG_NO_FILESAVE static uint32 WriteIFFStringChunk(std::ostream &f, IFFChunk::ChunkIdentifiers id, const std::string &str) { if(str.empty()) return 0; IFFChunk chunk{}; chunk.id = id; chunk.length = static_cast(str.size()); mpt::IO::Write(f, chunk); mpt::IO::WriteText(f, str); uint32 totalSize = sizeof(IFFChunk) + chunk.length; if(totalSize % 2u) { mpt::IO::WriteIntBE(f, 0); totalSize++; } return totalSize; } bool CSoundFile::SaveIFFSample(SAMPLEINDEX smp, std::ostream &f) const { const ModSample &sample = Samples[smp]; if(sample.uFlags[CHN_ADLIB] || !sample.HasSampleData()) return false; mpt::IO::OFile ff(f); IFFHeader fileHeader{}; memcpy(fileHeader.form, "FORM", 4); if(sample.uFlags[CHN_16BIT]) memcpy(fileHeader.magic, "16SV", 4); else memcpy(fileHeader.magic, "8SVX", 4); mpt::IO::Write(f, fileHeader); uint32 totalSize = 4 + sizeof(IFFChunk) + sizeof(IFFSampleHeader); IFFChunk chunk{}; chunk.id = IFFChunk::idVHDR; chunk.length = sizeof(IFFSampleHeader); mpt::IO::Write(f, chunk); IFFSampleHeader sampleHeader{}; uint32 loopStart = sample.nLength, loopEnd = sample.nLength; if(sample.uFlags[CHN_LOOP]) { loopStart = sample.nLoopStart; loopEnd = sample.nLoopEnd; } else if(sample.uFlags[CHN_SUSTAINLOOP]) { loopStart = sample.nSustainStart; loopEnd = sample.nSustainEnd; } const uint8 bps = sample.GetBytesPerSample(); sampleHeader.oneShotHiSamples = loopStart * bps; sampleHeader.repeatHiSamples = (loopEnd - loopStart) * bps; sampleHeader.samplesPerHiCycle = 0; sampleHeader.samplesPerSec = mpt::saturate_cast(sample.GetSampleRate(m_nType)); sampleHeader.octave = 1; sampleHeader.compression = 0; sampleHeader.volume = mpt::saturate_cast(sample.nVolume * 256u); mpt::IO::Write(f, sampleHeader); if(sample.uFlags[CHN_STEREO]) { chunk.id = IFFChunk::idCHAN; chunk.length = 4; mpt::IO::Write(f, chunk); mpt::IO::WriteIntBE(f, 6); totalSize += mpt::saturate_cast(sizeof(chunk) + chunk.length); } totalSize += WriteIFFStringChunk(f, IFFChunk::idNAME, mpt::ToCharset(mpt::Charset::Amiga, GetCharsetInternal(), m_szNames[smp])); totalSize += WriteIFFStringChunk(f, IFFChunk::idANNO, mpt::ToCharset(mpt::Charset::Amiga, Version::Current().GetOpenMPTVersionString())); SampleIO sampleIO( sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, sample.uFlags[CHN_STEREO] ? SampleIO::stereoSplit : SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM); chunk.id = IFFChunk::idBODY; chunk.length = mpt::saturate_cast(sampleIO.CalculateEncodedSize(sample.nLength)); mpt::IO::Write(f, chunk); sampleIO.WriteSample(f, sample); totalSize += mpt::saturate_cast(sizeof(chunk) + chunk.length); if(totalSize % 2u) { mpt::IO::WriteIntBE(f, 0); totalSize++; } fileHeader.size = totalSize; mpt::IO::SeekAbsolute(f, 0); mpt::IO::Write(f, fileHeader); return true; } #endif // MODPLUG_NO_FILESAVE OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_669.cpp0000644000175000017500000002156514667661001020104 00000000000000/* * Load_669.cpp * ------------ * Purpose: Composer 669 / UNIS 669 module loader * Notes : This is better than Schism's 669 loader :) * (some of this code is "heavily inspired" by Storlek's code from Schism Tracker, and improvements have been made where necessary.) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct _669FileHeader { char magic[2]; // 'if' (0x6669, ha ha) or 'JN' char songMessage[108]; // Song Message uint8 samples; // number of samples (1-64) uint8 patterns; // number of patterns (1-128) uint8 restartPos; uint8 orders[128]; uint8 tempoList[128]; uint8 breaks[128]; }; MPT_BINARY_STRUCT(_669FileHeader, 497) struct _669Sample { char filename[13]; uint32le length; uint32le loopStart; uint32le loopEnd; // Convert a 669 sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.nC5Speed = 8363; mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; if(mptSmp.nLoopEnd > mptSmp.nLength && mptSmp.nLoopStart == 0) { mptSmp.nLoopEnd = 0; } else if(mptSmp.nLoopEnd != 0) { mptSmp.uFlags = CHN_LOOP; mptSmp.SanitizeLoops(); } } }; MPT_BINARY_STRUCT(_669Sample, 25) static bool ValidateHeader(const _669FileHeader &fileHeader) { if((std::memcmp(fileHeader.magic, "if", 2) && std::memcmp(fileHeader.magic, "JN", 2)) || fileHeader.samples > 64 || fileHeader.restartPos >= 128 || fileHeader.patterns > 128) { return false; } uint8 invalidCharCount = 0; for(const char c : fileHeader.songMessage) { if(c > 0 && c <= 31 && ++invalidCharCount > 40) return false; } for(std::size_t i = 0; i < std::size(fileHeader.breaks); i++) { if(fileHeader.orders[i] >= 128 && fileHeader.orders[i] < 0xFE) return false; if(fileHeader.orders[i] < 128 && fileHeader.tempoList[i] == 0) return false; if(fileHeader.tempoList[i] > 15) return false; if(fileHeader.breaks[i] >= 64) return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const _669FileHeader &fileHeader) { return fileHeader.samples * sizeof(_669Sample) + fileHeader.patterns * 1536u; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize) { _669FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags) { _669FileHeader fileHeader; file.Rewind(); if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } InitializeGlobals(MOD_TYPE_669, 8); m_nMinPeriod = 28 << 2; m_nMaxPeriod = 1712 << 3; Order().SetDefaultTempoInt(78); Order().SetDefaultSpeed(4); m_playBehaviour.set(kPeriodsAreHertz); m_SongFlags.set(SONG_FASTPORTAS | SONG_AUTO_TONEPORTA); #ifdef MODPLUG_TRACKER // 669 uses frequencies rather than periods, so linear slides mode will sound better in the higher octaves. //m_SongFlags.set(SONG_LINEARSLIDES); #endif // MODPLUG_TRACKER const bool isExtended = !memcmp(fileHeader.magic, "JN", 2); m_modFormat.formatName = UL_("Composer 669"); m_modFormat.type = UL_("669"); m_modFormat.madeWithTracker = isExtended ? UL_("UNIS 669") : UL_("Composer 669"); m_modFormat.charset = mpt::Charset::CP437; m_nSamples = fileHeader.samples; for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { _669Sample sampleHeader; file.ReadStruct(sampleHeader); // Since 669 files have very unfortunate magic bytes ("if") and can // hardly be validated, reject any file with far too big samples. if(sampleHeader.length >= 0x4000000) return false; sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.filename); } // Copy first song message line into song title m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songMessage, 36); // Song Message m_songMessage.ReadFixedLineLength(mpt::byte_cast(fileHeader.songMessage), 108, 36, 0); // Reading Orders ReadOrderFromArray(Order(), fileHeader.orders, std::size(fileHeader.orders), 0xFF, 0xFE); if(Order()[fileHeader.restartPos] < fileHeader.patterns) Order().SetRestartPos(fileHeader.restartPos); // Set up panning for(CHANNELINDEX chn = 0; chn < 8; chn++) { ChnSettings[chn].nPan = (chn & 1) ? 0xD0 : 0x30; } // Reading Patterns Patterns.ResizeArray(fileHeader.patterns); for(PATTERNINDEX pat = 0; pat < fileHeader.patterns; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { file.Skip(64 * 8 * 3); continue; } static constexpr ModCommand::COMMAND effTrans[] = { CMD_AUTO_PORTAUP, // Slide up (param * 80) Hz on every tick CMD_AUTO_PORTADOWN, // Slide down (param * 80) Hz on every tick CMD_TONEPORTAMENTO, // Slide to note by (param * 40) Hz on every tick CMD_S3MCMDEX, // Add (param * 80) Hz to sample frequency CMD_VIBRATO, // Add (param * 669) Hz on every other tick CMD_SPEED, // Set ticks per row CMD_PANNINGSLIDE, // Extended UNIS 669 effect CMD_RETRIG, // Extended UNIS 669 effect }; uint8 effect[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; for(ROWINDEX row = 0; row < 64; row++) { ModCommand *m = Patterns[pat].GetpModCommand(row, 0); for(CHANNELINDEX chn = 0; chn < 8; chn++, m++) { const auto [noteInstr, instrVol, effParam] = file.ReadArray(); uint8 note = noteInstr >> 2; uint8 instr = ((noteInstr & 0x03) << 4) | (instrVol >> 4); uint8 vol = instrVol & 0x0F; if(noteInstr < 0xFE) { m->note = note + 36 + NOTE_MIN; m->instr = instr + 1; effect[chn] = 0xFF; } if(noteInstr <= 0xFE) { m->volcmd = VOLCMD_VOLUME; m->vol = static_cast((vol * 64 + 8) / 15); } if(effParam != 0xFF) effect[chn] = effParam; if(effect[chn] == 0xFF) continue; uint8 command = effect[chn] >> 4; // Weird stuff happening in corehop.669 with effects > 8... they seem to do the same thing as if the high bit wasn't set, but the sample also behaves strangely. if(command < mpt::array_size::size) { m->SetEffectCommand(effTrans[command], effect[chn] & 0x0F); } else { m->command = CMD_NONE; continue; } // Currently not implemented as auto-slides if(m->command != CMD_PANNINGSLIDE) effect[chn] = 0xFF; // Fix some commands switch(command) { case 3: // D - frequency adjust #ifdef MODPLUG_TRACKER // Since we convert to S3M, the finetune command will not quite do what we intend to do (it can adjust the frequency upwards and downwards), so try to approximate it using a fine slide. m->command = CMD_PORTAMENTOUP; m->param |= 0xF0; #else m->param |= 0x20; #endif break; case 4: // E - frequency vibrato - almost like an arpeggio, but does not arpeggiate by a given note but by a frequency amount. #ifdef MODPLUG_TRACKER m->command = CMD_ARPEGGIO; #endif m->param |= (m->param << 4); break; case 5: // F - set tempo // TODO: param 0 is a "super fast tempo" in Unis 669 mode (?) break; case 6: // G - subcommands (extended) switch(m->param) { case 0: // balance fine slide left m->param = 0x4F; break; case 1: // balance fine slide right m->param = 0xF4; break; default: m->command = CMD_NONE; } break; case 7: // H- slot retrig ("This command rapidly fires 4 slots. The command parameter specifies the speed at which to do it. The speed difference across the values is exponential.") if(!m->IsNote() || !isExtended) m->command = CMD_NONE; } } } // Write pattern break if(fileHeader.breaks[pat] < 63) { Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(fileHeader.breaks[pat]).RetryNextRow()); } // And of course the speed... Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, fileHeader.tempoList[pat]).RetryNextRow()); } if(loadFlags & loadSampleData) { // Reading Samples const SampleIO sampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::unsignedPCM); for(SAMPLEINDEX n = 1; n <= m_nSamples; n++) { sampleIO.ReadSample(Samples[n], file); } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleFormatBRR.cpp0000644000175000017500000001037714751676745021577 00000000000000/* * SampleFormatBRR.cpp * ------------------- * Purpose: BRR (SNES Bit Rate Reduction) sample format import. * Notes : This format has no magic bytes, so frame headers are thoroughly validated. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Sndfile.h" #include "../common/FileReader.h" OPENMPT_NAMESPACE_BEGIN static void ProcessBRRSample(int32 sample, int16 *output, uint8 range, uint8 filter) { if(sample >= 8) sample -= 16; if(range <= 12) sample = mpt::rshift_signed(mpt::lshift_signed(sample, range), 1); else sample = (sample < 0) ? -2048 : 0; // Implementations do not fully agree on what to do in this case. This is what bsnes does. // Apply prediction filter // Note 1: It is okay that we may access data before the first sample point because this memory is reserved for interpolation // Note 2: The use of signed shift arithmetic is crucial for some samples (e.g. killer lead.brr, Mac2.brr) // Note 3: Divisors are twice of what is written in the respective comments, as all sample data is divided by 2 (again crucial for accuracy) static_assert(InterpolationLookaheadBufferSize >= 2); switch(filter) { case 1: // y(n) = x(n) + x(n-1) * 15/16 sample += mpt::rshift_signed(output[-1] * 15, 5); break; case 2: // y(n) = x(n) + x(n-1) * 61/32 - x(n-2) * 15/16 sample += mpt::rshift_signed(output[-1] * 61, 6) + mpt::rshift_signed(output[-2] * -15, 5); break; case 3: // y(n) = x(n) + x(n-1) * 115/64 - x(n-2) * 13/16 sample += mpt::rshift_signed(output[-1] * 115, 7) + mpt::rshift_signed(output[-2] * -13, 5); break; } sample = std::clamp(sample, int32(-32768), int32(32767)) * 2; if(sample > 32767) sample -= 65536; else if(sample < -32768) sample += 65536; output[0] = static_cast(sample); } bool CSoundFile::ReadBRRSample(SAMPLEINDEX sample, FileReader &file) { if(!file.LengthIsAtLeast(9) || file.LengthIsAtLeast(65536)) return false; const auto fileSize = file.GetLength(); const bool hasLoopInfo = (fileSize % 9) == 2; if((fileSize % 9) != 0 && !hasLoopInfo) return false; file.Rewind(); SmpLength loopStart = 0; if(hasLoopInfo) { loopStart = file.ReadUint16LE(); if(loopStart >= fileSize) return false; if((loopStart % 9) != 0) return false; } // First scan the file for validity and consistency // Note: There are some files with loop start set but ultimately the loop is never enabled. Cannot use this as a consistency check. // Very few files also have a filter set on the first block, so we cannot reject those either. bool enableLoop = false, first = true; while(!file.EndOfFile()) { const auto block = file.ReadArray(); const bool isLast = (block[0] & 0x01) != 0; const bool isLoop = (block[0] & 0x02) != 0; const uint8 range = block[0] >> 4u; if(isLast != file.EndOfFile()) return false; if(!first && enableLoop != isLoop) { if(!hasLoopInfo) return false; // In some files, the loop flag is only set for the blocks within the loop (except for the first block?) const bool inLoop = file.GetPosition() > loopStart + 11u; if(enableLoop != inLoop) return false; } // While a range of 13 is technically invalid as well, it can be found in the wild. if(range > 13) return false; enableLoop = isLoop; first = false; } file.Seek(hasLoopInfo ? 2 : 0); DestroySampleThreadsafe(sample); ModSample &mptSmp = Samples[sample]; mptSmp.Initialize(); mptSmp.uFlags = CHN_16BIT; mptSmp.nLength = mpt::saturate_cast((fileSize - (hasLoopInfo ? 2 : 0)) * 16 / 9); if(enableLoop) mptSmp.SetLoop(loopStart * 16 / 9, mptSmp.nLength, true, false, *this); mptSmp.nC5Speed = 32000; m_szNames[sample] = ""; if(!mptSmp.AllocateSample()) return false; int16 *output = mptSmp.sample16(); while(!file.EndOfFile()) { const auto block = file.ReadArray(); const uint8 range = block[0] >> 4u; const uint8 filter = (block[0] >> 2) & 0x03; for(int i = 0; i < 8; i++) { ProcessBRRSample(block[i + 1] >> 4u, output, range, filter); ProcessBRRSample(block[i + 1] & 0x0F, output + 1, range, filter); output += 2; } } mptSmp.Convert(MOD_TYPE_IT, GetType()); mptSmp.PrecomputeLoops(*this, false); return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleIO.cpp0000644000175000017500000010774614657606142020304 00000000000000/* * SampleIO.cpp * ------------ * Purpose: Central code for reading and writing samples. Create your SampleIO object and have a go at the ReadSample and WriteSample functions! * Notes : Not all combinations of possible sample format combinations are implemented, especially for WriteSample. * Using the existing generic functions, it should be quite easy to extend the code, though. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "SampleIO.h" #include "BitReader.h" #include "ITCompression.h" #include "Loaders.h" #include "ModSampleCopy.h" #include "SampleCopy.h" #include "SampleNormalize.h" #ifndef MODPLUG_NO_FILESAVE #include "../common/mptFileIO.h" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/io_write/buffer.hpp" #endif #include "openmpt/soundbase/SampleDecode.hpp" OPENMPT_NAMESPACE_BEGIN // Read a sample from memory size_t SampleIO::ReadSample(ModSample &sample, FileReader &file) const { if(!file.IsValid()) { return 0; } LimitMax(sample.nLength, MAX_SAMPLE_LENGTH); FileReader::pos_type bytesRead = 0; // Amount of memory that has been read from file FileReader::pos_type filePosition = file.GetPosition(); const std::byte * sourceBuf = nullptr; FileReader::PinnedView restrictedSampleDataView; FileReader::pos_type fileSize = 0; if(UsesFileReaderForDecoding()) { sourceBuf = nullptr; fileSize = file.BytesLeft(); } else if(!IsVariableLengthEncoded()) { restrictedSampleDataView = file.GetPinnedView(CalculateEncodedSize(sample.nLength)); sourceBuf = restrictedSampleDataView.data(); fileSize = restrictedSampleDataView.size(); if(fileSize < 1) return 0; } else { MPT_ASSERT_NOTREACHED(); } if(!IsVariableLengthEncoded() && sample.nLength > 0x40000) { // Limit sample length to available bytes in file to avoid excessive memory allocation. // However, for ProTracker MODs we need to support samples exceeding the end of file // (see the comment about MOD.shorttune2 in Load_mod.cpp), so as a semi-arbitrary threshold, // we do not apply this limit to samples shorter than 256K. std::size_t maxLength = static_cast(fileSize) - std::min(GetEncodedHeaderSize(), static_cast(fileSize)); uint8 bps = GetEncodedBitsPerSample(); if(bps % 8u != 0) { MPT_ASSERT(GetEncoding() == ADPCM && bps == 4); if(Util::MaxValueOfType(maxLength) / 2u >= maxLength) maxLength *= 2; else maxLength = Util::MaxValueOfType(maxLength); } else { size_t encodedBytesPerSample = GetNumChannels() * GetEncodedBitsPerSample() / 8u; // Check if we can round up without overflowing if(Util::MaxValueOfType(maxLength) - maxLength >= (encodedBytesPerSample - 1u)) maxLength += encodedBytesPerSample - 1u; else maxLength = Util::MaxValueOfType(maxLength); maxLength /= encodedBytesPerSample; } LimitMax(sample.nLength, mpt::saturate_cast(maxLength)); } else if(GetEncoding() == IT214 || GetEncoding() == IT215 || GetEncoding() == MDL || GetEncoding() == DMF) { // In the best case, IT compression represents each sample point as a single bit. // In practice, there is of course the two-byte header per compressed block and the initial bit width change. // As a result, if we have a file length of n, we know that the sample can be at most n*8 sample points long. // For DMF, there are at least two bits per sample, and for MDL at least 5 (so both are worse than IT). size_t maxLength = fileSize; uint8 maxSamplesPerByte = 8 / GetNumChannels(); if(Util::MaxValueOfType(maxLength) / maxSamplesPerByte >= maxLength) maxLength *= maxSamplesPerByte; else maxLength = Util::MaxValueOfType(maxLength); LimitMax(sample.nLength, mpt::saturate_cast(maxLength)); } else if(GetEncoding() == AMS) { if(fileSize <= 9) return 0; file.Skip(4); // Target sample size (we already know this) SmpLength maxLength = std::min(file.ReadUint32LE(), mpt::saturate_cast(fileSize)); file.SkipBack(8); // In the best case, every byte triplet can decode to 255 bytes, which is a ratio of exactly 1:85 if(Util::MaxValueOfType(maxLength) / 85 >= maxLength) maxLength *= 85; else maxLength = Util::MaxValueOfType(maxLength); LimitMax(sample.nLength, maxLength / (m_bitdepth / 8u)); } if(sample.nLength < 1) { return 0; } sample.uFlags.set(CHN_16BIT, GetBitDepth() >= 16); sample.uFlags.set(CHN_STEREO, GetChannelFormat() != mono); size_t sampleSize = sample.AllocateSample(); // Target sample size in bytes if(sampleSize == 0) { sample.nLength = 0; return 0; } MPT_ASSERT(sampleSize >= sample.GetSampleSizeInBytes()); ////////////////////////////////////////////////////// // Compressed samples if(*this == SampleIO(_8bit, mono, littleEndian, ADPCM)) { // 4-Bit ADPCM data int8 compressionTable[16]; // ADPCM Compression LUT if(file.ReadArray(compressionTable)) { size_t readLength = (sample.nLength + 1) / 2; LimitMax(readLength, mpt::saturate_cast(file.BytesLeft())); const uint8 *inBuf = mpt::byte_cast(sourceBuf) + sizeof(compressionTable); int8 *outBuf = sample.sample8(); int8 delta = 0; for(size_t i = readLength; i != 0; i--) { delta += compressionTable[*inBuf & 0x0F]; *(outBuf++) = delta; delta += compressionTable[(*inBuf >> 4) & 0x0F]; *(outBuf++) = delta; inBuf++; } bytesRead = sizeof(compressionTable) + readLength; } } else if(GetEncoding() == IT214 || GetEncoding() == IT215) { // IT 2.14 / 2.15 compressed samples ITDecompression(file, sample, GetEncoding() == IT215); bytesRead = file.GetPosition() - filePosition; } else if(GetEncoding() == AMS && GetChannelFormat() == mono) { // AMS compressed samples file.Skip(4); // Target sample size (we already know this) uint32 sourceSize = file.ReadUint32LE(); int8 packCharacter = file.ReadUint8(); bytesRead += 9; FileReader::PinnedView packedDataView = file.ReadPinnedView(sourceSize); LimitMax(sourceSize, mpt::saturate_cast(packedDataView.size())); bytesRead += sourceSize; AMSUnpack(packedDataView.span(), mpt::as_span(sample.sampleb(), sample.GetSampleSizeInBytes()), packCharacter); if(sample.uFlags[CHN_16BIT] && !mpt::endian_is_little()) { auto p = sample.sample16(); for(SmpLength length = sample.nLength; length != 0; length--, p++) { *p = mpt::bit_cast(*p); } } } else if(GetEncoding() == PTM8Dto16 && GetChannelFormat() == mono && GetBitDepth() == 16) { // PTM 8-Bit delta to 16-Bit sample bytesRead = CopyMonoSample(sample, sourceBuf, fileSize); } else if(GetEncoding() == MDL && GetChannelFormat() == mono && GetBitDepth() <= 16) { // Huffman MDL compressed samples if(file.CanRead(8) && (fileSize = file.ReadUint32LE()) >= 4) { BitReader chunk = file.ReadChunk(fileSize); bytesRead = chunk.GetLength() + 4; uint8 dlt = 0, lowbyte = 0; const bool is16bit = GetBitDepth() == 16; try { for(SmpLength j = 0; j < sample.nLength; j++) { uint8 hibyte; if(is16bit) { lowbyte = static_cast(chunk.ReadBits(8)); } bool sign = chunk.ReadBits(1) != 0; if(chunk.ReadBits(1)) { hibyte = static_cast(chunk.ReadBits(3)); } else { hibyte = 8; while(!chunk.ReadBits(1)) { hibyte += 0x10; } hibyte += static_cast(chunk.ReadBits(4)); } if(sign) { hibyte = ~hibyte; } dlt += hibyte; if(!is16bit) { sample.sample8()[j] = dlt; } else { sample.sample16()[j] = lowbyte | (dlt << 8); } } } catch(const BitReader::eof &) { // Data is not sufficient to decode the whole sample //AddToLog(LogWarning, "Truncated MDL sample block"); } } } else if(GetEncoding() == DMF && GetChannelFormat() == mono && GetBitDepth() <= 16) { // DMF Huffman compression if(fileSize > 4) { bytesRead = DMFUnpack(file, mpt::byte_cast(sample.sampleb()), sample.GetSampleSizeInBytes()); } } else if((GetEncoding() == uLaw || GetEncoding() == aLaw) && GetBitDepth() == 16 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved)) { SmpLength readLength = sample.nLength * GetNumChannels(); LimitMax(readLength, mpt::saturate_cast(fileSize)); bytesRead = readLength; const std::byte *inBuf = sourceBuf; int16 *outBuf = sample.sample16(); if(GetEncoding() == uLaw) { SC::DecodeInt16uLaw conv; while(readLength--) { *(outBuf++) = conv(inBuf++); } } else { SC::DecodeInt16ALaw conv; while(readLength--) { *(outBuf++) = conv(inBuf++); } } } ///////////////////////// // Uncompressed samples ////////////////////////////////////////////////////// // 8-Bit / Mono / PCM else if(GetBitDepth() == 8 && GetChannelFormat() == mono) { switch(GetEncoding()) { case signedPCM: // 8-Bit / Mono / Signed / PCM bytesRead = CopyMonoSample(sample, sourceBuf, fileSize); break; case unsignedPCM: // 8-Bit / Mono / Unsigned / PCM bytesRead = CopyMonoSample(sample, sourceBuf, fileSize); break; case deltaPCM: // 8-Bit / Mono / Delta / PCM case MT2: bytesRead = CopyMonoSample(sample, sourceBuf, fileSize); break; default: MPT_ASSERT_NOTREACHED(); break; } } ////////////////////////////////////////////////////// // 8-Bit / Stereo Split / PCM else if(GetBitDepth() == 8 && GetChannelFormat() == stereoSplit) { switch(GetEncoding()) { case signedPCM: // 8-Bit / Stereo Split / Signed / PCM bytesRead = CopyStereoSplitSample(sample, sourceBuf, fileSize); break; case unsignedPCM: // 8-Bit / Stereo Split / Unsigned / PCM bytesRead = CopyStereoSplitSample(sample, sourceBuf, fileSize); break; case deltaPCM: // 8-Bit / Stereo Split / Delta / PCM case MT2: // same as deltaPCM, but right channel is stored as a difference from the left channel bytesRead = CopyStereoSplitSample(sample, sourceBuf, fileSize); if(GetEncoding() == MT2) { for(int8 *p = sample.sample8(), *pEnd = p + sample.nLength * 2; p < pEnd; p += 2) { p[1] = static_cast(static_cast(p[0]) + static_cast(p[1])); } } break; default: MPT_ASSERT_NOTREACHED(); break; } } ////////////////////////////////////////////////////// // 8-Bit / Stereo Interleaved / PCM else if(GetBitDepth() == 8 && GetChannelFormat() == stereoInterleaved) { switch(GetEncoding()) { case signedPCM: // 8-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyStereoInterleavedSample(sample, sourceBuf, fileSize); break; case unsignedPCM: // 8-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyStereoInterleavedSample(sample, sourceBuf, fileSize); break; case deltaPCM: // 8-Bit / Stereo Interleaved / Delta / PCM bytesRead = CopyStereoInterleavedSample(sample, sourceBuf, fileSize); break; default: MPT_ASSERT_NOTREACHED(); break; } } ////////////////////////////////////////////////////// // 16-Bit / Mono / Little Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == mono && GetEndianness() == littleEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyMonoSample >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyMonoSample >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Interleaved / Delta / PCM case MT2: bytesRead = CopyMonoSample >(sample, sourceBuf, fileSize); break; default: MPT_ASSERT_NOTREACHED(); break; } } ////////////////////////////////////////////////////// // 16-Bit / Mono / Big Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == mono && GetEndianness() == bigEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Mono / Signed / PCM bytesRead = CopyMonoSample >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Mono / Unsigned / PCM bytesRead = CopyMonoSample >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Mono / Delta / PCM bytesRead = CopyMonoSample >(sample, sourceBuf, fileSize); break; default: MPT_ASSERT_NOTREACHED(); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Split / Little Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoSplit && GetEndianness() == littleEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Split / Signed / PCM bytesRead = CopyStereoSplitSample >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Split / Unsigned / PCM bytesRead = CopyStereoSplitSample >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Split / Delta / PCM case MT2: // same as deltaPCM, but right channel is stored as a difference from the left channel bytesRead = CopyStereoSplitSample >(sample, sourceBuf, fileSize); if(GetEncoding() == MT2) { for(int16 *p = sample.sample16(), *pEnd = p + sample.nLength * 2; p < pEnd; p += 2) { p[1] = static_cast(static_cast(p[0]) + static_cast(p[1])); } } break; default: MPT_ASSERT_NOTREACHED(); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Split / Big Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoSplit && GetEndianness() == bigEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Split / Signed / PCM bytesRead = CopyStereoSplitSample >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Split / Unsigned / PCM bytesRead = CopyStereoSplitSample >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Split / Delta / PCM bytesRead = CopyStereoSplitSample >(sample, sourceBuf, fileSize); break; default: MPT_ASSERT_NOTREACHED(); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Interleaved / Little Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoInterleaved && GetEndianness() == littleEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyStereoInterleavedSample >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyStereoInterleavedSample >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Interleaved / Delta / PCM bytesRead = CopyStereoInterleavedSample >(sample, sourceBuf, fileSize); break; default: MPT_ASSERT_NOTREACHED(); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Interleaved / Big Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoInterleaved && GetEndianness() == bigEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyStereoInterleavedSample >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyStereoInterleavedSample >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Interleaved / Delta / PCM bytesRead = CopyStereoInterleavedSample >(sample, sourceBuf, fileSize); break; default: MPT_ASSERT_NOTREACHED(); break; } } ////////////////////////////////////////////////////// // 24-Bit / Signed / Mono / PCM else if(GetBitDepth() == 24 && GetChannelFormat() == mono && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyMonoSample, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 24-Bit / Signed / Stereo Interleaved / PCM else if(GetBitDepth() == 24 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyStereoInterleavedSample, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Signed / Mono / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyMonoSample, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Signed / Stereo Interleaved / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyStereoInterleavedSample, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 64-Bit / Signed / Mono / PCM else if(GetBitDepth() == 64 && GetChannelFormat() == mono && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample, SC::DecodeInt64<0, littleEndian64> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyMonoSample, SC::DecodeInt64<0, bigEndian64> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 64-Bit / Signed / Stereo Interleaved / PCM else if(GetBitDepth() == 64 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample, SC::DecodeInt64<0, littleEndian64> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyStereoInterleavedSample, SC::DecodeInt64<0, bigEndian64> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Mono / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample, SC::DecodeFloat32 > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyMonoSample, SC::DecodeFloat32 > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample, SC::DecodeFloat32 > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyStereoInterleavedSample, SC::DecodeFloat32 > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 64-Bit / Float / Mono / PCM else if(GetBitDepth() == 64 && GetChannelFormat() == mono && GetEncoding() == floatPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample, SC::DecodeFloat64 > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyMonoSample, SC::DecodeFloat64 > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 64-Bit / Float / Stereo Interleaved / PCM else if(GetBitDepth() == 64 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample, SC::DecodeFloat64 > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyStereoInterleavedSample, SC::DecodeFloat64 > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 24-Bit / Signed / Mono, Stereo Interleaved / PCM else if(GetBitDepth() == 24 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == signedPCMnormalize) { // Normalize to 16-Bit uint32 srcPeak = uint32(1)<<31; if(GetEndianness() == littleEndian) { bytesRead = CopyAndNormalizeSample, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize, &srcPeak); } else { bytesRead = CopyAndNormalizeSample, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize, &srcPeak); } if(bytesRead && srcPeak != uint32(1)<<31) { // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. sample.nGlobalVol = static_cast(Clamp(Util::muldivr_unsigned(sample.nGlobalVol, srcPeak, uint32(1)<<31), uint32(1), uint32(64))); sample.uFlags.set(SMP_MODIFIED); } } ////////////////////////////////////////////////////// // 32-Bit / Signed / Mono, Stereo Interleaved / PCM else if(GetBitDepth() == 32 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == signedPCMnormalize) { // Normalize to 16-Bit uint32 srcPeak = uint32(1)<<31; if(GetEndianness() == littleEndian) { bytesRead = CopyAndNormalizeSample, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } else { bytesRead = CopyAndNormalizeSample, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } if(bytesRead && srcPeak != uint32(1)<<31) { // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. sample.nGlobalVol = static_cast(Clamp(Util::muldivr_unsigned(sample.nGlobalVol, srcPeak, uint32(1)<<31), uint32(1), uint32(64))); sample.uFlags.set(SMP_MODIFIED); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Mono, Stereo Interleaved / PCM else if(GetBitDepth() == 32 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == floatPCMnormalize) { // Normalize to 16-Bit somefloat32 srcPeak = 1.0f; if(GetEndianness() == littleEndian) { bytesRead = CopyAndNormalizeSample, SC::DecodeFloat32 > >(sample, sourceBuf, fileSize, &srcPeak); } else { bytesRead = CopyAndNormalizeSample, SC::DecodeFloat32 > >(sample, sourceBuf, fileSize, &srcPeak); } if(bytesRead && srcPeak != 1.0f) { // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. sample.nGlobalVol = mpt::saturate_round(Clamp(sample.nGlobalVol * srcPeak, 1.0f, 64.0f)); sample.uFlags.set(SMP_MODIFIED); } } ////////////////////////////////////////////////////// // 64-Bit / Float / Mono, Stereo Interleaved / PCM else if(GetBitDepth() == 64 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == floatPCMnormalize) { // Normalize to 16-Bit somefloat64 srcPeak = 1.0; if(GetEndianness() == littleEndian) { bytesRead = CopyAndNormalizeSample, SC::DecodeFloat64 > >(sample, sourceBuf, fileSize, &srcPeak); } else { bytesRead = CopyAndNormalizeSample, SC::DecodeFloat64 > >(sample, sourceBuf, fileSize, &srcPeak); } if(bytesRead && srcPeak != 1.0) { // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. sample.nGlobalVol = mpt::saturate_round(Clamp(sample.nGlobalVol * srcPeak, 1.0, 64.0)); sample.uFlags.set(SMP_MODIFIED); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Mono / PCM / full scale 2^15 else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM15) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain, SC::DecodeScaledFloat32 > (SC::Convert(), SC::DecodeScaledFloat32(1.0f / static_cast(1<<15))) ); } else { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain, SC::DecodeScaledFloat32 > (SC::Convert(), SC::DecodeScaledFloat32(1.0f / static_cast(1<<15))) ); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^15 else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM15) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain, SC::DecodeScaledFloat32 > (SC::Convert(), SC::DecodeScaledFloat32(1.0f / static_cast(1<<15))) ); } else { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain, SC::DecodeScaledFloat32 > (SC::Convert(), SC::DecodeScaledFloat32(1.0f / static_cast(1<<15))) ); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^23 else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM23) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain, SC::DecodeScaledFloat32 > (SC::Convert(), SC::DecodeScaledFloat32(1.0f / static_cast(1<<23))) ); } else { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain, SC::DecodeScaledFloat32 > (SC::Convert(), SC::DecodeScaledFloat32(1.0f / static_cast(1<<23))) ); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^23 else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM23) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain, SC::DecodeScaledFloat32 > (SC::Convert(), SC::DecodeScaledFloat32(1.0f / static_cast(1<<23))) ); } else { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain, SC::DecodeScaledFloat32 > (SC::Convert(), SC::DecodeScaledFloat32(1.0f / static_cast(1<<23))) ); } } //////////////// // Unsupported else { MPT_ASSERT_NOTREACHED(); } MPT_ASSERT(filePosition + bytesRead <= file.GetLength()); file.Seek(filePosition + bytesRead); return bytesRead; } #ifndef MODPLUG_NO_FILESAVE // Write a sample to file size_t SampleIO::WriteSample(std::ostream &f, const ModSample &sample, SmpLength maxSamples) const { if(sample.uFlags[CHN_ADLIB]) { mpt::IO::Write(f, sample.adlib); return sizeof(sample.adlib); } if(!sample.HasSampleData()) { return 0; } std::array writeBuffer; mpt::IO::WriteBuffer fb{f, mpt::as_span(writeBuffer)}; SmpLength numSamples = sample.nLength; if(maxSamples && numSamples > maxSamples) { numSamples = maxSamples; } std::size_t len = CalculateEncodedSize(numSamples); if(GetBitDepth() == 16 && GetChannelFormat() == mono && GetEndianness() == littleEndian && (GetEncoding() == signedPCM || GetEncoding() == unsignedPCM || GetEncoding() == deltaPCM)) { // 16-bit little-endian mono samples MPT_ASSERT(len == numSamples * 2); const int16 *const pSample16 = sample.sample16(); const int16 *p = pSample16; int s_old = 0; const int s_ofs = (GetEncoding() == unsignedPCM) ? 0x8000 : 0; for(SmpLength j = 0; j < numSamples; j++) { int s_new = *p; p++; if(sample.uFlags[CHN_STEREO]) { // Downmix stereo s_new = (s_new + (*p) + 1) / 2; p++; } if(GetEncoding() == deltaPCM) { mpt::IO::Write(fb, mpt::as_le(static_cast(s_new - s_old))); s_old = s_new; } else { mpt::IO::Write(fb, mpt::as_le(static_cast(s_new + s_ofs))); } } } else if(GetBitDepth() == 8 && GetChannelFormat() == stereoSplit && (GetEncoding() == signedPCM || GetEncoding() == unsignedPCM || GetEncoding() == deltaPCM)) { // 8-bit Stereo samples (not interleaved) MPT_ASSERT(len == numSamples * 2); const int8 *const pSample8 = sample.sample8(); const int s_ofs = (GetEncoding() == unsignedPCM) ? 0x80 : 0; for (uint32 iCh=0; iCh<2; iCh++) { const int8 *p = pSample8 + iCh; int s_old = 0; for (SmpLength j = 0; j < numSamples; j++) { int s_new = *p; p += 2; if (GetEncoding() == deltaPCM) { mpt::IO::Write(fb, static_cast(s_new - s_old)); s_old = s_new; } else { mpt::IO::Write(fb, static_cast(s_new + s_ofs)); } } } } else if(GetBitDepth() == 16 && GetChannelFormat() == stereoSplit && GetEndianness() == littleEndian && (GetEncoding() == signedPCM || GetEncoding() == unsignedPCM || GetEncoding() == deltaPCM)) { // 16-bit little-endian Stereo samples (not interleaved) MPT_ASSERT(len == numSamples * 4); const int16 *const pSample16 = sample.sample16(); const int s_ofs = (GetEncoding() == unsignedPCM) ? 0x8000 : 0; for (uint32 iCh=0; iCh<2; iCh++) { const int16 *p = pSample16 + iCh; int s_old = 0; for (SmpLength j = 0; j < numSamples; j++) { int s_new = *p; p += 2; if (GetEncoding() == deltaPCM) { mpt::IO::Write(fb, mpt::as_le(static_cast(s_new - s_old))); s_old = s_new; } else { mpt::IO::Write(fb, mpt::as_le(static_cast(s_new + s_ofs))); } } } } else if(GetBitDepth() == 8 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM) { // Stereo signed interleaved MPT_ASSERT(len == numSamples * 2); const int8 *const pSample8 = sample.sample8(); mpt::IO::Write(f, mpt::as_span(pSample8, len)); } else if(GetBitDepth() == 16 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM && GetEndianness() == littleEndian) { // Stereo signed interleaved, little-endian MPT_ASSERT(len == numSamples * 4); const int16 *const pSample16 = sample.sample16(); const int16 *p = pSample16; for(SmpLength j = 0; j < numSamples; j++) { mpt::IO::Write(fb, mpt::as_le(p[0])); mpt::IO::Write(fb, mpt::as_le(p[1])); p += 2; } } else if(GetBitDepth() == 16 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM && GetEndianness() == bigEndian) { // Stereo signed interleaved, big-endian MPT_ASSERT(len == numSamples * 4); const int16 *const pSample16 = sample.sample16(); const int16 *p = pSample16; for(SmpLength j = 0; j < numSamples; j++) { mpt::IO::Write(fb, mpt::as_be(p[0])); mpt::IO::Write(fb, mpt::as_be(p[1])); p += 2; } } else if(GetBitDepth() == 16 && (GetChannelFormat() == stereoSplit || GetChannelFormat() == mono) && (GetEncoding() == signedPCM || GetEncoding() == unsignedPCM) && GetEndianness() == bigEndian) { // Stereo split / mono signed 16-bit, big-endian const uint8 numChannels = GetNumChannels(); const uint16 offset = (GetEncoding() == unsignedPCM) ? 0x8000 : 0; MPT_ASSERT(len == numSamples * numChannels * 2); for(uint8 chn = 0; chn < numChannels; chn++) { const int16 *p = sample.sample16() + chn; for(SmpLength j = 0; j < numSamples; j++) { mpt::IO::Write(fb, mpt::as_be(static_cast(static_cast(*p) + offset))); p += numChannels; } } } else if(GetBitDepth() == 8 && GetChannelFormat() == stereoInterleaved && GetEncoding() == unsignedPCM) { // Stereo unsigned interleaved MPT_ASSERT(len == numSamples * 2); const int8 *const pSample8 = sample.sample8(); for(SmpLength j = 0; j < numSamples * 2; j++) { mpt::IO::Write(fb, static_cast(static_cast(pSample8[j]) + 0x80)); } } else if(GetEncoding() == IT214 || GetEncoding() == IT215) { // IT2.14-encoded samples ITCompression its(sample, GetEncoding() == IT215, &f, numSamples); len = its.GetCompressedSize(); } // Default: assume 8-bit PCM data else { MPT_ASSERT(GetBitDepth() == 8); MPT_ASSERT(len == numSamples); if(sample.uFlags[CHN_16BIT]) { const int16 *p = sample.sample16(); int s_old = 0; const int s_ofs = (GetEncoding() == unsignedPCM) ? 0x80 : 0; for(SmpLength j = 0; j < numSamples; j++) { int s_new = mpt::rshift_signed(*p, 8); p++; if(sample.uFlags[CHN_STEREO]) { s_new = (s_new + mpt::rshift_signed(*p, 8) + 1) / 2; p++; } if(GetEncoding() == deltaPCM) { mpt::IO::Write(fb, static_cast(s_new - s_old)); s_old = s_new; } else { mpt::IO::Write(fb, static_cast(s_new + s_ofs)); } } } else { const int8 *const pSample8 = sample.sample8(); const int8 *p = pSample8; int s_old = 0; const int s_ofs = (GetEncoding() == unsignedPCM) ? 0x80 : 0; for(SmpLength j = 0; j < numSamples; j++) { int s_new = *p; p++; if(sample.uFlags[CHN_STEREO]) { s_new = (s_new + (static_cast(*p)) + 1) / 2; p++; } if(GetEncoding() == deltaPCM) { mpt::IO::Write(fb, static_cast(s_new - s_old)); s_old = s_new; } else { mpt::IO::Write(fb, static_cast(s_new + s_ofs)); } } } } return len; } #endif // MODPLUG_NO_FILESAVE OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MIDIMacros.cpp0000644000175000017500000002554714400163120020474 00000000000000/* * MIDIMacros.cpp * -------------- * Purpose: Helper functions / classes for MIDI Macro functionality. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "MIDIMacros.h" #include "../soundlib/MIDIEvents.h" #ifdef MODPLUG_TRACKER #include "Sndfile.h" #include "plugins/PlugInterface.h" #endif // MODPLUG_TRACKER OPENMPT_NAMESPACE_BEGIN ParameteredMacro MIDIMacroConfig::GetParameteredMacroType(uint32 macroIndex) const { const std::string macro = SFx[macroIndex].NormalizedString(); for(uint32 i = 0; i < kSFxMax; i++) { ParameteredMacro sfx = static_cast(i); if(sfx != kSFxCustom) { if(macro == CreateParameteredMacro(sfx)) return sfx; } } // Special macros with additional "parameter": if(macro.size() == 5 && macro.compare(CreateParameteredMacro(kSFxCC, MIDIEvents::MIDICC_start)) >= 0 && macro.compare(CreateParameteredMacro(kSFxCC, MIDIEvents::MIDICC_end)) <= 0) return kSFxCC; if(macro.size() == 7 && macro.compare(CreateParameteredMacro(kSFxPlugParam, 0)) >= 0 && macro.compare(CreateParameteredMacro(kSFxPlugParam, 0x17F)) <= 0) return kSFxPlugParam; return kSFxCustom; // custom / unknown } // Retrieve Zxx (Z80-ZFF) type from current macro configuration FixedMacro MIDIMacroConfig::GetFixedMacroType() const { // Compare with all possible preset patterns for(uint32 i = 0; i < kZxxMax; i++) { FixedMacro zxx = static_cast(i); if(zxx != kZxxCustom) { // Prepare macro pattern to compare decltype(Zxx) fixedMacros{}; CreateFixedMacro(fixedMacros, zxx); if(fixedMacros == Zxx) return zxx; } } return kZxxCustom; // Custom setup } void MIDIMacroConfig::CreateParameteredMacro(Macro ¶meteredMacro, ParameteredMacro macroType, int subType) const { switch(macroType) { case kSFxUnused: parameteredMacro = ""; break; case kSFxCutoff: parameteredMacro = "F0F000z"; break; case kSFxReso: parameteredMacro = "F0F001z"; break; case kSFxFltMode: parameteredMacro = "F0F002z"; break; case kSFxDryWet: parameteredMacro = "F0F003z"; break; case kSFxCC: parameteredMacro = MPT_AFORMAT("Bc{}z")(mpt::afmt::HEX0<2>(subType & 0x7F)); break; case kSFxPlugParam: parameteredMacro = MPT_AFORMAT("F0F{}z")(mpt::afmt::HEX0<3>(std::min(subType, 0x17F) + 0x80)); break; case kSFxChannelAT: parameteredMacro = "Dcz"; break; case kSFxPolyAT: parameteredMacro = "Acnz"; break; case kSFxPitch: parameteredMacro = "Ec00z"; break; case kSFxProgChange: parameteredMacro = "Ccz"; break; case kSFxCustom: default: MPT_ASSERT_NOTREACHED(); break; } } std::string MIDIMacroConfig::CreateParameteredMacro(ParameteredMacro macroType, int subType) const { Macro parameteredMacro{}; CreateParameteredMacro(parameteredMacro, macroType, subType); return parameteredMacro; } // Create Zxx (Z80 - ZFF) from preset void MIDIMacroConfig::CreateFixedMacro(std::array &fixedMacros, FixedMacro macroType) const { for(uint32 i = 0; i < kZxxMacros; i++) { uint32 param = i; switch(macroType) { case kZxxUnused: fixedMacros[i] = ""; break; case kZxxReso4Bit: param = i * 8; if(i < 16) fixedMacros[i] = MPT_AFORMAT("F0F001{}")(mpt::afmt::HEX0<2>(param)); else fixedMacros[i] = ""; break; case kZxxReso7Bit: fixedMacros[i] = MPT_AFORMAT("F0F001{}")(mpt::afmt::HEX0<2>(param)); break; case kZxxCutoff: fixedMacros[i] = MPT_AFORMAT("F0F000{}")(mpt::afmt::HEX0<2>(param)); break; case kZxxFltMode: fixedMacros[i] = MPT_AFORMAT("F0F002{}")(mpt::afmt::HEX0<2>(param)); break; case kZxxResoFltMode: param = (i & 0x0F) * 8; if(i < 16) fixedMacros[i] = MPT_AFORMAT("F0F001{}")(mpt::afmt::HEX0<2>(param)); else if(i < 32) fixedMacros[i] = MPT_AFORMAT("F0F002{}")(mpt::afmt::HEX0<2>(param)); else fixedMacros[i] = ""; break; case kZxxChannelAT: fixedMacros[i] = MPT_AFORMAT("Dc{}")(mpt::afmt::HEX0<2>(param)); break; case kZxxPolyAT: fixedMacros[i] = MPT_AFORMAT("Acn{}")(mpt::afmt::HEX0<2>(param)); break; case kZxxPitch: fixedMacros[i] = MPT_AFORMAT("Ec00{}")(mpt::afmt::HEX0<2>(param)); break; case kZxxProgChange: fixedMacros[i] = MPT_AFORMAT("Cc{}")(mpt::afmt::HEX0<2>(param)); break; case kZxxCustom: default: MPT_ASSERT_NOTREACHED(); continue; } } } bool MIDIMacroConfig::operator== (const MIDIMacroConfig &other) const { return std::equal(begin(), end(), other.begin()); } #ifdef MODPLUG_TRACKER // Returns macro description including plugin parameter / MIDI CC information CString MIDIMacroConfig::GetParameteredMacroName(uint32 macroIndex, IMixPlugin *plugin) const { const ParameteredMacro macroType = GetParameteredMacroType(macroIndex); switch(macroType) { case kSFxPlugParam: { const int param = MacroToPlugParam(macroIndex); CString formattedName; formattedName.Format(_T("Param %d"), param); #ifndef NO_PLUGINS if(plugin != nullptr) { CString paramName = plugin->GetParamName(param); if(!paramName.IsEmpty()) { formattedName += _T(" (") + paramName + _T(")"); } } else #else MPT_UNREFERENCED_PARAMETER(plugin); #endif // NO_PLUGINS { formattedName += _T(" (N/A)"); } return formattedName; } case kSFxCC: { CString formattedCC; formattedCC.Format(_T("MIDI CC %d"), MacroToMidiCC(macroIndex)); return formattedCC; } default: return GetParameteredMacroName(macroType); } } // Returns generic macro description. CString MIDIMacroConfig::GetParameteredMacroName(ParameteredMacro macroType) const { switch(macroType) { case kSFxUnused: return _T("Unused"); case kSFxCutoff: return _T("Set Filter Cutoff"); case kSFxReso: return _T("Set Filter Resonance"); case kSFxFltMode: return _T("Set Filter Mode"); case kSFxDryWet: return _T("Set Plugin Dry/Wet Ratio"); case kSFxPlugParam: return _T("Control Plugin Parameter..."); case kSFxCC: return _T("MIDI CC..."); case kSFxChannelAT: return _T("Channel Aftertouch"); case kSFxPolyAT: return _T("Polyphonic Aftertouch"); case kSFxPitch: return _T("Pitch Bend"); case kSFxProgChange: return _T("MIDI Program Change"); case kSFxCustom: default: return _T("Custom"); } } // Returns generic macro description. CString MIDIMacroConfig::GetFixedMacroName(FixedMacro macroType) const { switch(macroType) { case kZxxUnused: return _T("Unused"); case kZxxReso4Bit: return _T("Z80 - Z8F controls Resonant Filter Resonance"); case kZxxReso7Bit: return _T("Z80 - ZFF controls Resonant Filter Resonance"); case kZxxCutoff: return _T("Z80 - ZFF controls Resonant Filter Cutoff"); case kZxxFltMode: return _T("Z80 - ZFF controls Resonant Filter Mode"); case kZxxResoFltMode: return _T("Z80 - Z9F controls Resonance + Filter Mode"); case kZxxChannelAT: return _T("Z80 - ZFF controls Channel Aftertouch"); case kZxxPolyAT: return _T("Z80 - ZFF controls Polyphonic Aftertouch"); case kZxxPitch: return _T("Z80 - ZFF controls Pitch Bend"); case kZxxProgChange: return _T("Z80 - ZFF controls MIDI Program Change"); case kZxxCustom: default: return _T("Custom"); } } PlugParamIndex MIDIMacroConfig::MacroToPlugParam(uint32 macroIndex) const { const std::string macro = SFx[macroIndex].NormalizedString(); PlugParamIndex code = 0; const char *param = macro.c_str(); param += 4; if ((param[0] >= '0') && (param[0] <= '9')) code = (param[0] - '0') << 4; else if ((param[0] >= 'A') && (param[0] <= 'F')) code = (param[0] - 'A' + 0x0A) << 4; if ((param[1] >= '0') && (param[1] <= '9')) code += (param[1] - '0'); else if ((param[1] >= 'A') && (param[1] <= 'F')) code += (param[1] - 'A' + 0x0A); if (macro.size() >= 4 && macro[3] == '0') return (code - 128); else return (code + 128); } int MIDIMacroConfig::MacroToMidiCC(uint32 macroIndex) const { const std::string macro = SFx[macroIndex].NormalizedString(); int code = 0; const char *param = macro.c_str(); param += 2; if ((param[0] >= '0') && (param[0] <= '9')) code = (param[0] - '0') << 4; else if ((param[0] >= 'A') && (param[0] <= 'F')) code = (param[0] - 'A' + 0x0A) << 4; if ((param[1] >= '0') && (param[1] <= '9')) code += (param[1] - '0'); else if ((param[1] >= 'A') && (param[1] <= 'F')) code += (param[1] - 'A' + 0x0A); return code; } int MIDIMacroConfig::FindMacroForParam(PlugParamIndex param) const { for(int macroIndex = 0; macroIndex < kSFxMacros; macroIndex++) { if(GetParameteredMacroType(macroIndex) == kSFxPlugParam && MacroToPlugParam(macroIndex) == param) { return macroIndex; } } return -1; } #endif // MODPLUG_TRACKER // Check if the MIDI Macro configuration used is the default one, // i.e. the configuration that is assumed when loading a file that has no macros embedded. bool MIDIMacroConfig::IsMacroDefaultSetupUsed() const { return *this == MIDIMacroConfig{}; } // Reset MIDI macro config to default values. void MIDIMacroConfig::Reset() { std::fill(begin(), end(), Macro{}); Global[MIDIOUT_START] = "FF"; Global[MIDIOUT_STOP] = "FC"; Global[MIDIOUT_NOTEON] = "9c n v"; Global[MIDIOUT_NOTEOFF] = "9c n 0"; Global[MIDIOUT_PROGRAM] = "Cc p"; // SF0: Z00-Z7F controls cutoff CreateParameteredMacro(0, kSFxCutoff); // Z80-Z8F controls resonance CreateFixedMacro(kZxxReso4Bit); } // Clear all Zxx macros so that they do nothing. void MIDIMacroConfig::ClearZxxMacros() { std::fill(SFx.begin(), SFx.end(), Macro{}); std::fill(Zxx.begin(), Zxx.end(), Macro{}); } // Sanitize all macro config strings. void MIDIMacroConfig::Sanitize() { for(auto ¯o : *this) { macro.Sanitize(); } } // Fix old-format (not conforming to IT's MIDI macro definitions) MIDI config strings. void MIDIMacroConfig::UpgradeMacros() { for(auto ¯o : SFx) { macro.UpgradeLegacyMacro(); } for(auto ¯o : Zxx) { macro.UpgradeLegacyMacro(); } } // Normalize by removing blanks and other unwanted characters from macro strings for internal usage. std::string MIDIMacroConfig::Macro::NormalizedString() const { std::string sanitizedMacro = *this; std::string::size_type pos; while((pos = sanitizedMacro.find_first_not_of("0123456789ABCDEFabchmnopsuvxyz")) != std::string::npos) { sanitizedMacro.erase(pos, 1); } return sanitizedMacro; } void MIDIMacroConfig::Macro::Sanitize() noexcept { m_data.back() = '\0'; const auto length = Length(); std::fill(m_data.begin() + length, m_data.end(), '\0'); for(size_t i = 0; i < length; i++) { if(m_data[i] < 32 || m_data[i] >= 127) m_data[i] = ' '; } } void MIDIMacroConfig::Macro::UpgradeLegacyMacro() noexcept { for(auto &c : m_data) { if(c >= 'a' && c <= 'f') // Both A-F and a-f were treated as hex constants { c = c - 'a' + 'A'; } else if(c == 'K' || c == 'k') // Channel was K or k { c = 'c'; } else if(c == 'X' || c == 'x' || c == 'Y' || c == 'y') // Those were pointless { c = 'z'; } } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Sndmix.cpp0000644000175000017500000027372514743273743020101 00000000000000/* * Sndmix.cpp * ----------- * Purpose: Pattern playback, effect processing * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Sndfile.h" #include "MixerLoops.h" #include "MIDIEvents.h" #include "Tables.h" #ifdef MODPLUG_TRACKER #include "../mptrack/TrackerSettings.h" #endif // MODPLUG_TRACKER #ifndef NO_PLUGINS #include "plugins/PlugInterface.h" #endif // NO_PLUGINS #include "OPL.h" OPENMPT_NAMESPACE_BEGIN // Log tables for pre-amp // Pre-amp (or more precisely: Pre-attenuation) depends on the number of channels, // Which this table takes care of. static constexpr uint8 PreAmpTable[16] = { 0x60, 0x60, 0x60, 0x70, // 0-7 0x80, 0x88, 0x90, 0x98, // 8-15 0xA0, 0xA4, 0xA8, 0xAC, // 16-23 0xB0, 0xB4, 0xB8, 0xBC, // 24-31 }; #ifndef NO_AGC static constexpr uint8 PreAmpAGCTable[16] = { 0x60, 0x60, 0x60, 0x64, 0x68, 0x70, 0x78, 0x80, 0x84, 0x88, 0x8C, 0x90, 0x92, 0x94, 0x96, 0x98, }; #endif void CSoundFile::SetMixerSettings(const MixerSettings &mixersettings) { SetPreAmp(mixersettings.m_nPreAmp); // adjust agc bool reset = false; if( (mixersettings.gdwMixingFreq != m_MixerSettings.gdwMixingFreq) || (mixersettings.gnChannels != m_MixerSettings.gnChannels) || (mixersettings.MixerFlags != m_MixerSettings.MixerFlags)) reset = true; m_MixerSettings = mixersettings; InitPlayer(reset); } void CSoundFile::SetResamplerSettings(const CResamplerSettings &resamplersettings) { m_Resampler.m_Settings = resamplersettings; m_Resampler.UpdateTables(); InitAmigaResampler(); } void CSoundFile::InitPlayer(bool bReset) { if(bReset) { ResetMixStat(); m_dryLOfsVol = m_dryROfsVol = 0; m_surroundLOfsVol = m_surroundROfsVol = 0; InitAmigaResampler(); } m_Resampler.UpdateTables(); #ifndef NO_REVERB m_Reverb.Initialize(bReset, m_RvbROfsVol, m_RvbLOfsVol, m_MixerSettings.gdwMixingFreq); #endif #ifndef NO_DSP m_Surround.Initialize(bReset, m_MixerSettings.gdwMixingFreq); #endif #ifndef NO_DSP m_MegaBass.Initialize(bReset, m_MixerSettings.gdwMixingFreq); #endif #ifndef NO_EQ m_EQ.Initialize(bReset, m_MixerSettings.gdwMixingFreq); #endif #ifndef NO_AGC m_AGC.Initialize(bReset, m_MixerSettings.gdwMixingFreq); #endif #ifndef NO_DSP m_BitCrush.Initialize(bReset, m_MixerSettings.gdwMixingFreq); #endif #ifdef MODPLUG_TRACKER m_metronomeChn.pCurrentSample = nullptr; #endif if(m_opl) { m_opl->Initialize(m_MixerSettings.gdwMixingFreq); } } bool CSoundFile::FadeSong(uint32 msec) { samplecount_t nsamples = Util::muldiv(msec, m_MixerSettings.gdwMixingFreq, 1000); if (nsamples <= 0) return false; if (nsamples > 0x100000) nsamples = 0x100000; m_PlayState.m_nBufferCount = nsamples; int32 nRampLength = static_cast(m_PlayState.m_nBufferCount); // Ramp everything down for (uint32 noff=0; noff < m_nMixChannels; noff++) { ModChannel &pramp = m_PlayState.Chn[m_PlayState.ChnMix[noff]]; pramp.newRightVol = pramp.newLeftVol = 0; pramp.leftRamp = -pramp.leftVol * (1 << VOLUMERAMPPRECISION) / nRampLength; pramp.rightRamp = -pramp.rightVol * (1 << VOLUMERAMPPRECISION) / nRampLength; pramp.rampLeftVol = pramp.leftVol * (1 << VOLUMERAMPPRECISION); pramp.rampRightVol = pramp.rightVol * (1 << VOLUMERAMPPRECISION); pramp.nRampLength = nRampLength; pramp.dwFlags.set(CHN_VOLUMERAMP); } return true; } // Apply stereo separation factor on an interleaved stereo/quad stream. // count = Number of stereo sample pairs to process // separation = -256...256 (negative values = swap L/R, 0 = mono, 128 = normal) static void ApplyStereoSeparation(mixsample_t *mixBuf, std::size_t count, int32 separation) { #ifdef MPT_INTMIXER const mixsample_t factor_num = separation; // 128 =^= 1.0f const mixsample_t factor_den = MixerSettings::StereoSeparationScale; // 128 const mixsample_t normalize_den = 2; // mid/side pre/post normalization const mixsample_t mid_den = normalize_den; const mixsample_t side_num = factor_num; const mixsample_t side_den = factor_den * normalize_den; #else const float normalize_factor = 0.5f; // cumulative mid/side normalization factor (1/sqrt(2))*(1/sqrt(2)) const float factor = static_cast(separation) / static_cast(MixerSettings::StereoSeparationScale); // sep / 128 const float mid_factor = normalize_factor; const float side_factor = factor * normalize_factor; #endif for(std::size_t i = 0; i < count; i++) { mixsample_t l = mixBuf[0]; mixsample_t r = mixBuf[1]; mixsample_t m = l + r; mixsample_t s = l - r; #ifdef MPT_INTMIXER m /= mid_den; s = Util::muldiv(s, side_num, side_den); #else m *= mid_factor; s *= side_factor; #endif l = m + s; r = m - s; mixBuf[0] = l; mixBuf[1] = r; mixBuf += 2; } } static void ApplyStereoSeparation(mixsample_t *SoundFrontBuffer, mixsample_t *SoundRearBuffer, std::size_t channels, std::size_t countChunk, int32 separation) { if(separation == MixerSettings::StereoSeparationScale) { // identity return; } if(channels >= 2) ApplyStereoSeparation(SoundFrontBuffer, countChunk, separation); if(channels >= 4) ApplyStereoSeparation(SoundRearBuffer , countChunk, separation); } void CSoundFile::ProcessInputChannels(IAudioSource &source, std::size_t countChunk) { for(std::size_t channel = 0; channel < NUMMIXINPUTBUFFERS; ++channel) { std::fill(&(MixInputBuffer[channel][0]), &(MixInputBuffer[channel][countChunk]), 0); } mixsample_t * buffers[NUMMIXINPUTBUFFERS]; for(std::size_t channel = 0; channel < NUMMIXINPUTBUFFERS; ++channel) { buffers[channel] = MixInputBuffer[channel]; } source.Process(mpt::audio_span_planar(buffers, m_MixerSettings.NumInputChannels, countChunk)); } // Read one tick but skip all expensive rendering options samplecount_t CSoundFile::ReadOneTick() { const auto origMaxMixChannels = m_MixerSettings.m_nMaxMixChannels; m_MixerSettings.m_nMaxMixChannels = 0; ResetMixStat(); while(m_PlayState.m_nBufferCount) { auto framesToRender = std::min(m_PlayState.m_nBufferCount, samplecount_t(MIXBUFFERSIZE)); CreateStereoMix(framesToRender); m_PlayState.m_nBufferCount -= framesToRender; m_PlayState.m_lTotalSampleCount += framesToRender; } m_MixerSettings.m_nMaxMixChannels = origMaxMixChannels; if(ReadNote()) return m_PlayState.m_nBufferCount; else return 0; } samplecount_t CSoundFile::Read(samplecount_t count, IAudioTarget &target, IAudioSource &source, std::optional> outputMonitor, std::optional> inputMonitor) { MPT_ASSERT_ALWAYS(m_MixerSettings.IsValid()); samplecount_t countRendered = 0; samplecount_t countToRender = count; while(!m_PlayState.m_flags[SONG_ENDREACHED] && countToRender > 0) { // Update Channel Data if(!m_PlayState.m_nBufferCount) { // Last tick or fade completely processed, find out what to do next if(m_PlayState.m_flags[SONG_FADINGSONG]) { // Song was faded out m_PlayState.m_flags.set(SONG_ENDREACHED); } else if(ReadNote()) { // Render next tick (normal progress) MPT_ASSERT(m_PlayState.m_nBufferCount > 0); #ifdef MODPLUG_TRACKER // Save pattern cue points for WAV rendering here (if we reached a new pattern, that is.) if(m_PatternCuePoints != nullptr && (m_PatternCuePoints->empty() || m_PlayState.m_nCurrentOrder != m_PatternCuePoints->back().order)) { PatternCuePoint cue; cue.offset = countRendered; cue.order = m_PlayState.m_nCurrentOrder; cue.processed = false; // We don't know the base offset in the file here. It has to be added in the main conversion loop. m_PatternCuePoints->push_back(cue); } #endif } else { // No new pattern data if(IsRenderingToDisc()) { // Disable song fade when rendering or when requested in libopenmpt. m_PlayState.m_flags.set(SONG_ENDREACHED); } else { // end of song reached, fade it out if(FadeSong(FADESONGDELAY)) // sets m_nBufferCount xor returns false { // FadeSong sets m_nBufferCount here MPT_ASSERT(m_PlayState.m_nBufferCount > 0); m_PlayState.m_flags.set(SONG_FADINGSONG); } else { m_PlayState.m_flags.set(SONG_ENDREACHED); } } } } if(m_PlayState.m_flags[SONG_ENDREACHED]) { // Mix done. // If we decide to continue the mix (possible in libopenmpt), the tick count // is valid right now (0), meaning that no new row data will be processed. // This would effectively prolong the last played row. m_PlayState.m_nTickCount = m_PlayState.TicksOnRow(); break; } MPT_ASSERT(m_PlayState.m_nBufferCount > 0); // assert that we have actually something to do const samplecount_t countChunk = std::min({ static_cast(MIXBUFFERSIZE), static_cast(m_PlayState.m_nBufferCount), static_cast(countToRender) }); if(m_MixerSettings.NumInputChannels > 0) { ProcessInputChannels(source, countChunk); } if(inputMonitor) { mixsample_t *buffers[NUMMIXINPUTBUFFERS]; for(std::size_t channel = 0; channel < NUMMIXINPUTBUFFERS; ++channel) { buffers[channel] = MixInputBuffer[channel]; } inputMonitor->get().Process(mpt::audio_span_planar(buffers, m_MixerSettings.NumInputChannels, countChunk)); } CreateStereoMix(countChunk); if(m_opl) { m_opl->Mix(MixSoundBuffer, countChunk, m_OPLVolumeFactor * m_nVSTiVolume / 48); } #ifndef NO_REVERB m_Reverb.Process(MixSoundBuffer, ReverbSendBuffer, m_RvbROfsVol, m_RvbLOfsVol, countChunk); #endif // NO_REVERB #ifndef NO_PLUGINS if(m_loadedPlugins) { ProcessPlugins(countChunk); } #endif // NO_PLUGINS if(m_MixerSettings.gnChannels == 1) { MonoFromStereo(MixSoundBuffer, countChunk); } if(m_PlayConfig.getGlobalVolumeAppliesToMaster()) { ProcessGlobalVolume(countChunk); } if(m_MixerSettings.m_nStereoSeparation != MixerSettings::StereoSeparationScale) { ProcessStereoSeparation(countChunk); } if(m_MixerSettings.DSPMask) { ProcessDSP(countChunk); } #ifdef MODPLUG_TRACKER // Metronome needs to be mixed last, so that it is not affected by global volume, plugins, DSP effects, etc... // It will still be visible on VU Meters though, which is not optimal. if(IsMetronomeEnabled()) { MixChannel(countChunk, m_metronomeChn, CHANNELINDEX_INVALID, true); } #endif // MODPLUG_TRACKER if(m_MixerSettings.gnChannels == 4) { InterleaveFrontRear(MixSoundBuffer, MixRearBuffer, countChunk); } if(outputMonitor) { outputMonitor->get().Process(mpt::audio_span_interleaved(MixSoundBuffer, m_MixerSettings.gnChannels, countChunk)); } target.Process(mpt::audio_span_interleaved(MixSoundBuffer, m_MixerSettings.gnChannels, countChunk)); // Buffer ready countRendered += countChunk; countToRender -= countChunk; m_PlayState.m_nBufferCount -= countChunk; m_PlayState.m_lTotalSampleCount += countChunk; const ROWINDEX rowsPerBeat = m_PlayState.m_nCurrentRowsPerBeat ? m_PlayState.m_nCurrentRowsPerBeat : DEFAULT_ROWS_PER_BEAT; if(!m_PlayState.m_nBufferCount && !m_PlayState.m_flags[SONG_PAUSED]) m_PlayState.m_ppqPosFract += 1.0 / (rowsPerBeat * m_PlayState.TicksOnRow()); #ifdef MODPLUG_TRACKER if(IsRenderingToDisc()) { // Stop playback on F00 if no more voices are active. // F00 sets the tick count to 65536 in FT2, so it just generates a reaaaally long row. // Usually this command can be found at the end of a song to effectively stop playback. // Since we don't want to render hours of silence, we are going to check if there are // still any channels playing, and if that is no longer the case, we stop playback at // the end of the next tick. if(m_PlayState.m_nMusicSpeed == uint16_max && (m_nMixStat == 0 || m_PlayState.m_nGlobalVolume == 0) && GetType() == MOD_TYPE_XM && !m_PlayState.m_nBufferCount) { m_PlayState.m_flags.set(SONG_ENDREACHED); } } #endif // MODPLUG_TRACKER } // mix done return countRendered; } void CSoundFile::ProcessDSP(uint32 countChunk) { #ifndef NO_DSP if(m_MixerSettings.DSPMask & SNDDSP_SURROUND) { m_Surround.Process(MixSoundBuffer, MixRearBuffer, countChunk, m_MixerSettings.gnChannels); } #endif // NO_DSP #ifndef NO_DSP if(m_MixerSettings.DSPMask & SNDDSP_MEGABASS) { m_MegaBass.Process(MixSoundBuffer, MixRearBuffer, countChunk, m_MixerSettings.gnChannels); } #endif // NO_DSP #ifndef NO_EQ if(m_MixerSettings.DSPMask & SNDDSP_EQ) { m_EQ.Process(MixSoundBuffer, MixRearBuffer, countChunk, m_MixerSettings.gnChannels); } #endif // NO_EQ #ifndef NO_AGC if(m_MixerSettings.DSPMask & SNDDSP_AGC) { m_AGC.Process(MixSoundBuffer, MixRearBuffer, countChunk, m_MixerSettings.gnChannels); } #endif // NO_AGC #ifndef NO_DSP if(m_MixerSettings.DSPMask & SNDDSP_BITCRUSH) { m_BitCrush.Process(MixSoundBuffer, MixRearBuffer, countChunk, m_MixerSettings.gnChannels); } #endif // NO_DSP #if defined(NO_DSP) && defined(NO_EQ) && defined(NO_AGC) MPT_UNREFERENCED_PARAMETER(countChunk); #endif } ///////////////////////////////////////////////////////////////////////////// // Handles navigation/effects bool CSoundFile::ProcessRow() { while(++m_PlayState.m_nTickCount >= m_PlayState.TicksOnRow()) { const auto [ignoreRow, patternTransition] = NextRow(m_PlayState, m_PlayState.m_flags[SONG_BREAKTOROW]); #ifdef MODPLUG_TRACKER HandleRowTransitionEvents(patternTransition); // "Lock row" editing feature if(m_lockRowStart != ROWINDEX_INVALID && (m_PlayState.m_nRow < m_lockRowStart || m_PlayState.m_nRow > m_lockRowEnd) && !IsRenderingToDisc()) { m_PlayState.m_nRow = m_lockRowStart; } // "Lock order" editing feature if(Order().IsPositionLocked(m_PlayState.m_nCurrentOrder) && !IsRenderingToDisc()) { m_PlayState.m_nCurrentOrder = m_lockOrderStart; } #endif // MODPLUG_TRACKER m_PlayState.UpdatePPQ(patternTransition); // Check if pattern is valid if(!m_PlayState.m_flags[SONG_PATTERNLOOP]) { const size_t songEnd = m_maxOrderPosition ? m_maxOrderPosition : Order().size(); m_PlayState.m_nPattern = (m_PlayState.m_nCurrentOrder < songEnd) ? Order()[m_PlayState.m_nCurrentOrder] : PATTERNINDEX_INVALID; if(m_PlayState.m_nPattern < Patterns.Size() && !Patterns[m_PlayState.m_nPattern].IsValid()) m_PlayState.m_nPattern = PATTERNINDEX_SKIP; while(m_PlayState.m_nPattern >= Patterns.Size()) { // End of song? if ((m_PlayState.m_nPattern == PATTERNINDEX_INVALID) || (m_PlayState.m_nCurrentOrder >= songEnd)) { ORDERINDEX restartPosOverride = m_maxOrderPosition ? m_restartOverridePos : Order().GetRestartPos(); if(restartPosOverride == 0 && m_PlayState.m_nCurrentOrder <= songEnd && m_PlayState.m_nCurrentOrder > 0) { // Subtune detection. Subtunes are separated by "---" order items, so if we're in a // subtune and there's no restart position, we go to the first order of the subtune // (i.e. the first order after the previous "---" item) for(ORDERINDEX ord = m_PlayState.m_nCurrentOrder - 1; ord > 0; ord--) { if(Order()[ord] == PATTERNINDEX_INVALID) { // Jump back to first order of this subtune restartPosOverride = ord + 1; break; } } } // If channel resetting is disabled in MPT, we will emulate a pattern break (and we always do it if we're not in MPT) #ifdef MODPLUG_TRACKER if(!(TrackerSettings::Instance().patternSetup & PatternSetup::ResetChannelsOnLoop)) #endif // MODPLUG_TRACKER { m_PlayState.m_flags.set(SONG_BREAKTOROW); } if (restartPosOverride == 0 && !m_PlayState.m_flags[SONG_BREAKTOROW]) { //rewbs.instroVSTi: stop all VSTi at end of song, if looping. StopAllVsti(); m_PlayState.m_nMusicSpeed = Order().GetDefaultSpeed(); m_PlayState.m_nMusicTempo = Order().GetDefaultTempo(); m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume; for(CHANNELINDEX i = 0; i < m_PlayState.Chn.size(); i++) { auto &chn = m_PlayState.Chn[i]; if(chn.dwFlags[CHN_ADLIB] && m_opl) { m_opl->NoteCut(i); } chn.dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); chn.nFadeOutVol = 0; if(i < GetNumChannels()) { chn.nGlobalVol = ChnSettings[i].nVolume; chn.nVolume = ChnSettings[i].nVolume; chn.nPan = ChnSettings[i].nPan; chn.nPanSwing = chn.nVolSwing = 0; chn.nCutSwing = chn.nResSwing = 0; chn.nOldVolParam = 0; chn.oldOffset = 0; chn.nOldHiOffset = 0; chn.nPortamentoDest = 0; if(!chn.nLength) { chn.dwFlags = ChnSettings[i].dwFlags; chn.nLoopStart = 0; chn.nLoopEnd = 0; chn.pModInstrument = nullptr; chn.pModSample = nullptr; } } } } //Handle Repeat position m_PlayState.m_nCurrentOrder = restartPosOverride; m_PlayState.m_flags.reset(SONG_BREAKTOROW); //If restart pos points to +++, move along while(m_PlayState.m_nCurrentOrder < Order().size() && Order()[m_PlayState.m_nCurrentOrder] == PATTERNINDEX_SKIP) { m_PlayState.m_nCurrentOrder++; } //Check for end of song or bad pattern if (m_PlayState.m_nCurrentOrder >= Order().size() || !Order().IsValidPat(m_PlayState.m_nCurrentOrder)) { m_visitedRows.Initialize(true); return false; } } else { m_PlayState.m_nCurrentOrder++; } if (m_PlayState.m_nCurrentOrder < Order().size()) m_PlayState.m_nPattern = Order()[m_PlayState.m_nCurrentOrder]; else m_PlayState.m_nPattern = PATTERNINDEX_INVALID; if (m_PlayState.m_nPattern < Patterns.Size() && !Patterns[m_PlayState.m_nPattern].IsValid()) m_PlayState.m_nPattern = PATTERNINDEX_SKIP; } m_PlayState.m_nNextOrder = m_PlayState.m_nCurrentOrder; } // Weird stuff? if (!Patterns.IsValidPat(m_PlayState.m_nPattern)) return false; // Did we jump to an invalid row? if (m_PlayState.m_nRow >= Patterns[m_PlayState.m_nPattern].GetNumRows()) m_PlayState.m_nRow = 0; // Has this row been visited before? We might want to stop playback now. // But: We will not mark the row as modified if the song is not in loop mode but // the pattern loop (editor flag, not to be confused with the pattern loop effect) // flag is set - because in that case, the module would stop after the first pattern loop... const bool overrideLoopCheck = (m_nRepeatCount != -1) && m_PlayState.m_flags[SONG_PATTERNLOOP]; if(!overrideLoopCheck && m_visitedRows.Visit(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow, m_PlayState.Chn, ignoreRow)) { if(m_nRepeatCount) { // repeat count == -1 means repeat infinitely. if(m_nRepeatCount > 0) { m_nRepeatCount--; } // Forget all but the current row. m_visitedRows.Initialize(true); m_visitedRows.Visit(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow, m_PlayState.Chn, ignoreRow); } else { #ifdef MODPLUG_TRACKER // Let's check again if this really is the end of the song. // The visited rows vector might have been screwed up while editing... // This is of course not possible during rendering to WAV, so we ignore that case. bool isReallyAtEnd = IsRenderingToDisc(); if(!isReallyAtEnd) { for(const auto &t : GetLength(eNoAdjust, GetLengthTarget(true))) { if(t.restartOrder == m_PlayState.m_nCurrentOrder && t.restartRow == m_PlayState.m_nRow) { isReallyAtEnd = true; break; } } } if(isReallyAtEnd) { // This is really the song's end! m_visitedRows.Initialize(true); return false; } else { // Ok, this is really dirty, but we have to update the visited rows vector... GetLength(eAdjustOnlyVisitedRows, GetLengthTarget(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow)); } #else if(m_SongFlags[SONG_PLAYALLSONGS]) { // When playing all subsongs consecutively, first search for any hidden subsongs... if(!m_visitedRows.GetFirstUnvisitedRow(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow, true)) { // ...and then try the next sequence. m_PlayState.m_nNextOrder = m_PlayState.m_nCurrentOrder = 0; m_PlayState.m_nNextRow = m_PlayState.m_nRow = 0; if(Order.GetCurrentSequenceIndex() >= Order.GetNumSequences() - 1) { Order.SetSequence(0); m_visitedRows.Initialize(true); return false; } Order.SetSequence(Order.GetCurrentSequenceIndex() + 1); m_visitedRows.Initialize(true); } // When jumping to the next subsong, stop all playing notes from the previous song... const auto muteFlag = CSoundFile::GetChannelMuteFlag(); for(CHANNELINDEX i = 0; i < m_PlayState.Chn.size(); i++) m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i, muteFlag); StopAllVsti(); // ...and the global playback information. m_PlayState.m_nMusicSpeed = Order().GetDefaultSpeed(); m_PlayState.m_nMusicTempo = Order().GetDefaultTempo(); m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume; m_PlayState.m_nNextOrder = m_PlayState.m_nCurrentOrder; m_PlayState.m_nNextRow = m_PlayState.m_nRow; if(Order().size() > m_PlayState.m_nCurrentOrder) m_PlayState.m_nPattern = Order()[m_PlayState.m_nCurrentOrder]; m_visitedRows.Visit(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow, m_PlayState.Chn, ignoreRow); if (!Patterns.IsValidPat(m_PlayState.m_nPattern)) return false; } else { m_visitedRows.Initialize(true); return false; } #endif // MODPLUG_TRACKER } } SetupNextRow(m_PlayState, m_PlayState.m_flags[SONG_PATTERNLOOP]); // Reset channel values ModCommand *m = Patterns[m_PlayState.m_nPattern].GetpModCommand(m_PlayState.m_nRow, 0); for(ModChannel &chn : m_PlayState.PatternChannels(*this)) { // First, handle some quirks that happen after the last tick of the previous row... if(m_playBehaviour[KST3PortaAfterArpeggio] && chn.nCommand == CMD_ARPEGGIO // Previous row state! && (m->command == CMD_PORTAMENTOUP || m->command == CMD_PORTAMENTODOWN)) { // In ST3, a portamento immediately following an arpeggio continues where the arpeggio left off. // Test case: PortaAfterArp.s3m chn.nPeriod = GetPeriodFromNote(chn.nArpeggioLastNote, chn.nFineTune, chn.nC5Speed); } if(m_playBehaviour[kMODOutOfRangeNoteDelay] && !m->IsNote() && chn.rowCommand.IsNote() && chn.rowCommand.command == CMD_MODCMDEX && (chn.rowCommand.param & 0xF0) == 0xD0 && (chn.rowCommand.param & 0x0Fu) >= m_PlayState.m_nMusicSpeed) { // In ProTracker, a note triggered by an out-of-range note delay can be heard on the next row // if there is no new note on that row. // Test case: NoteDelay-NextRow.mod chn.nPeriod = GetPeriodFromNote(chn.rowCommand.note, chn.nFineTune, 0); } if(m_playBehaviour[kST3TonePortaWithAdlibNote] && !m->IsNote() && chn.dwFlags[CHN_ADLIB] && chn.nPortamentoDest && chn.rowCommand.IsNote() && chn.rowCommand.IsTonePortamento()) { // ST3: Adlib Note + Tone Portamento does not execute the slide, but changes to the target note instantly on the next row (unless there is another note with tone portamento) // Test case: TonePortamentoWithAdlibNote.s3m chn.nPeriod = chn.nPortamentoDest; } if(m_playBehaviour[kMODTempoOnSecondTick] && !m_playBehaviour[kMODVBlankTiming] && m_PlayState.m_nMusicSpeed == 1 && chn.rowCommand.command == CMD_TEMPO) { // ProTracker sets the tempo after the first tick. This block handles the case of one tick per row. // Test case: TempoChange.mod m_PlayState.m_nMusicTempo = TEMPO(std::max(ModCommand::PARAM(1), chn.rowCommand.param), 0); } chn.rightVol = chn.newRightVol; chn.leftVol = chn.newLeftVol; chn.dwFlags.reset(CHN_VIBRATO | CHN_TREMOLO); if(!m_playBehaviour[kITVibratoTremoloPanbrello]) chn.nPanbrelloOffset = 0; chn.nCommand = CMD_NONE; chn.m_plugParamValueStep = 0; chn.rowCommand = *m++; } // Now that we know which pattern we're on, we can update time signatures (global or pattern-specific) m_PlayState.UpdateTimeSignature(*this); if(ignoreRow) { m_PlayState.m_nTickCount = m_PlayState.m_nMusicSpeed; continue; } break; } // Should we process tick0 effects? if (!m_PlayState.m_nMusicSpeed) m_PlayState.m_nMusicSpeed = 1; //End of row? stop pattern step (aka "play row"). #ifdef MODPLUG_TRACKER if (m_PlayState.m_nTickCount >= m_PlayState.TicksOnRow() - 1) { if(m_PlayState.m_flags[SONG_STEP]) { m_PlayState.m_flags.reset(SONG_STEP); m_PlayState.m_flags.set(SONG_PAUSED); } } #endif // MODPLUG_TRACKER if (m_PlayState.m_nTickCount) { m_PlayState.m_flags.reset(SONG_FIRSTTICK); if(!(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)) && (GetType() != MOD_TYPE_MOD || m_SongFlags[SONG_PT_MODE]) // Fix infinite loop in "GamerMan " by MrGamer, which was made with FT2 && m_PlayState.m_nTickCount < m_PlayState.TicksOnRow()) { // Emulate first tick behaviour if Row Delay is set. // Test cases: PatternDelaysRetrig.it, PatternDelaysRetrig.s3m, PatternDelaysRetrig.xm, PatternDelaysRetrig.mod if(!(m_PlayState.m_nTickCount % (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay))) { m_PlayState.m_flags.set(SONG_FIRSTTICK); } } } else { m_PlayState.m_flags.set(SONG_FIRSTTICK); m_PlayState.m_flags.reset(SONG_BREAKTOROW); } // Update Effects return ProcessEffects(); } std::pair CSoundFile::NextRow(PlayState &playState, const bool breakRow) const { // When having an EEx effect on the same row as a Dxx jump, the target row is not played in ProTracker. // Test case: DelayBreak.mod (based on condom_corruption by Travolta) const bool ignoreRow = playState.m_nPatternDelay > 1 && breakRow && GetType() == MOD_TYPE_MOD; // Done with the last row of the pattern or jumping somewhere else (could also be a result of pattern loop to row 0, but that doesn't matter here) const bool patternTransition = playState.m_nNextRow == 0 || breakRow; if(patternTransition && GetType() == MOD_TYPE_S3M) { // Reset pattern loop start // Test case: LoopReset.s3m for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { playState.Chn[i].nPatternLoop = 0; } } playState.m_nPatternDelay = 0; playState.m_nFrameDelay = 0; playState.m_nTickCount = 0; playState.m_nRow = playState.m_nNextRow; playState.m_nCurrentOrder = playState.m_nNextOrder; return {ignoreRow, patternTransition}; } void CSoundFile::SetupNextRow(PlayState &playState, const bool patternLoop) const { playState.m_nNextRow = playState.m_nRow + 1; if(playState.m_nNextRow >= Patterns[playState.m_nPattern].GetNumRows()) { if(!patternLoop) playState.m_nNextOrder = playState.m_nCurrentOrder + 1; playState.m_nNextRow = 0; // FT2 idiosyncrasy: When E60 is used on a pattern row x, the following pattern also starts from row x // instead of the beginning of the pattern, unless there was a Bxx or Dxx effect. if(m_playBehaviour[kFT2LoopE60Restart]) { playState.m_nNextRow = playState.m_nextPatStartRow; playState.m_nextPatStartRow = 0; } } } //////////////////////////////////////////////////////////////////////////////////////////// // Channel effect processing // Calculate delta for Vibrato / Tremolo / Panbrello effect int CSoundFile::GetVibratoDelta(int type, int position) const { // IT compatibility: IT has its own, more precise tables if(m_playBehaviour[kITVibratoTremoloPanbrello]) { position &= 0xFF; switch(type & 0x03) { case 0: // Sine default: return ITSinusTable[position]; case 1: // Ramp down return 64 - (position + 1) / 2; case 2: // Square return position < 128 ? 64 : 0; case 3: // Random return mpt::random(AccessPRNG()) - 0x40; } } else if(GetType() & (MOD_TYPE_DIGI | MOD_TYPE_DBM)) { // Other waveforms are not supported. static constexpr int8 DBMSinus[] = { 33, 52, 69, 84, 96, 107, 116, 122, 125, 127, 125, 122, 116, 107, 96, 84, 69, 52, 33, 13, -8, -31, -54, -79, -104,-128, -104, -79, -54, -31, -8, 13, }; return DBMSinus[(position / 2u) & 0x1F]; } else { position &= 0x3F; switch(type & 0x03) { case 0: // Sine default: return ModSinusTable[position]; case 1: // Ramp down return (position < 32 ? 0 : 255) - position * 4; case 2: // Square return position < 32 ? 127 : -127; case 3: // Random return ModRandomTable[position]; } } } void CSoundFile::ProcessVolumeSwing(ModChannel &chn, int &vol) const { if(m_playBehaviour[kITSwingBehaviour]) { vol += chn.nVolSwing; Limit(vol, 0, 64); } else if(m_playBehaviour[kMPTOldSwingBehaviour]) { vol += chn.nVolSwing; Limit(vol, 0, 256); } else { chn.nVolume += chn.nVolSwing; Limit(chn.nVolume, 0, 256); vol = chn.nVolume; chn.nVolSwing = 0; } } void CSoundFile::ProcessPanningSwing(ModChannel &chn) const { if(m_playBehaviour[kITSwingBehaviour] || m_playBehaviour[kMPTOldSwingBehaviour]) { chn.nRealPan = chn.nPan + chn.nPanSwing; Limit(chn.nRealPan, 0, 256); } else { chn.nPan += chn.nPanSwing; Limit(chn.nPan, 0, 256); chn.nPanSwing = 0; chn.nRealPan = chn.nPan; } } void CSoundFile::ProcessTremolo(ModChannel &chn, int &vol) const { if (chn.dwFlags[CHN_TREMOLO]) { if(m_SongFlags[SONG_PT_MODE] && m_PlayState.m_flags[SONG_FIRSTTICK]) { // ProTracker doesn't apply tremolo nor advance on the first tick. // Test case: VibratoReset.mod return; } // IT compatibility: Why would you not want to execute tremolo at volume 0? if(vol > 0 || m_playBehaviour[kITVibratoTremoloPanbrello]) { // IT compatibility: We don't need a different attenuation here because of the different tables we're going to use const uint8 attenuation = ((GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD)) || m_playBehaviour[kITVibratoTremoloPanbrello]) ? 5 : 6; int delta = GetVibratoDelta(chn.nTremoloType, chn.nTremoloPos); if((chn.nTremoloType & 0x03) == 1 && m_playBehaviour[kFT2MODTremoloRampWaveform]) { // FT2 compatibility: Tremolo ramp down / triangle implementation is weird and affected by vibrato position (copy-paste bug) // Test case: TremoloWaveforms.xm, TremoloVibrato.xm uint8 ramp = (chn.nTremoloPos * 4u) & 0x7F; // Volume-column vibrato gets executed first in FT2, so we may need to advance the vibrato position first uint32 vibPos = chn.nVibratoPos; if(!m_PlayState.m_flags[SONG_FIRSTTICK] && chn.dwFlags[CHN_VIBRATO]) vibPos += chn.nVibratoSpeed; if((vibPos & 0x3F) >= 32) ramp ^= 0x7F; if((chn.nTremoloPos & 0x3F) >= 32) delta = -ramp; else delta = ramp; } if(GetType() != MOD_TYPE_DMF) { vol += (delta * chn.nTremoloDepth) / (1 << attenuation); } else { // Tremolo in DMF always attenuates by a percentage of the current note volume vol -= (vol * chn.nTremoloDepth * (64 - delta)) / (128 * 64); } } if(!m_PlayState.m_flags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS])) { // IT compatibility: IT has its own, more precise tables if(m_playBehaviour[kITVibratoTremoloPanbrello]) chn.nTremoloPos += static_cast(4u * chn.nTremoloSpeed); else chn.nTremoloPos += chn.nTremoloSpeed; } } } void CSoundFile::ProcessTremor(CHANNELINDEX nChn, int &vol) { ModChannel &chn = m_PlayState.Chn[nChn]; if(m_playBehaviour[kFT2Tremor]) { // FT2 Compatibility: Weird XM tremor. // Test case: Tremor.xm if(chn.nTremorCount & 0x80) { if(!m_PlayState.m_flags[SONG_FIRSTTICK] && chn.nCommand == CMD_TREMOR) { chn.nTremorCount &= ~0x20; if(chn.nTremorCount == 0x80) { // Reached end of off-time chn.nTremorCount = (chn.nTremorParam >> 4) | 0xC0; } else if(chn.nTremorCount == 0xC0) { // Reached end of on-time chn.nTremorCount = (chn.nTremorParam & 0x0F) | 0x80; } else { chn.nTremorCount--; } chn.dwFlags.set(CHN_FASTVOLRAMP); } if((chn.nTremorCount & 0xE0) == 0x80) { vol = 0; } } } else if(chn.nCommand == CMD_TREMOR) { // IT compatibility 12. / 13.: Tremor if(m_playBehaviour[kITTremor]) { if((chn.nTremorCount & 0x80) && chn.nLength) { if (chn.nTremorCount == 0x80) chn.nTremorCount = (chn.nTremorParam >> 4) | 0xC0; else if (chn.nTremorCount == 0xC0) chn.nTremorCount = (chn.nTremorParam & 0x0F) | 0x80; else chn.nTremorCount--; } if((chn.nTremorCount & 0xC0) == 0x80) vol = 0; } else { uint8 ontime = chn.nTremorParam >> 4; uint8 n = ontime + (chn.nTremorParam & 0x0F); // Total tremor cycle time (On + Off) if ((!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) || m_SongFlags[SONG_ITOLDEFFECTS]) { n += 2; ontime++; } uint8 tremcount = chn.nTremorCount; if(!(GetType() & MOD_TYPE_XM)) { if (tremcount >= n) tremcount = 0; if (tremcount >= ontime) vol = 0; chn.nTremorCount = tremcount + 1; } else { if(m_PlayState.m_flags[SONG_FIRSTTICK]) { // tremcount is only 0 on the first tremor tick after triggering a note. if(tremcount > 0) { tremcount--; } } else { chn.nTremorCount = tremcount + 1; } if (tremcount % n >= ontime) vol = 0; } } chn.dwFlags.set(CHN_FASTVOLRAMP); } #ifndef NO_PLUGINS // Plugin tremor if(chn.nCommand == CMD_TREMOR && chn.pModInstrument && chn.pModInstrument->nMixPlug && !chn.pModInstrument->dwFlags[INS_MUTE] && !chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE] && ModCommand::IsNote(chn.nLastNote)) { const ModInstrument *pIns = chn.pModInstrument; IMixPlugin *pPlugin = m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin; if(pPlugin) { const bool isPlaying = pPlugin->IsNotePlaying(chn.nLastNote, nChn); if(vol == 0 && isPlaying) pPlugin->MidiCommand(*pIns, chn.nLastNote | IMixPlugin::MIDI_NOTE_OFF, 0, nChn); else if(vol != 0 && !isPlaying) pPlugin->MidiCommand(*pIns, chn.nLastNote, static_cast(chn.nVolume), nChn); } } #endif // NO_PLUGINS } bool CSoundFile::IsEnvelopeProcessed(const ModChannel &chn, EnvelopeType env) const { if(chn.pModInstrument == nullptr) { return false; } const InstrumentEnvelope &insEnv = chn.pModInstrument->GetEnvelope(env); // IT Compatibility: S77/S79/S7B do not disable the envelope, they just pause the counter // Test cases: s77.it, EnvLoops.xm, PanSustainRelease.xm bool playIfPaused = m_playBehaviour[kITEnvelopePositionHandling] || m_playBehaviour[kFT2PanSustainRelease]; return ((chn.GetEnvelope(env).flags[ENV_ENABLED] || (insEnv.dwFlags[ENV_ENABLED] && playIfPaused)) && !insEnv.empty()); } void CSoundFile::ProcessVolumeEnvelope(ModChannel &chn, int &vol) const { if(IsEnvelopeProcessed(chn, ENV_VOLUME)) { const ModInstrument *pIns = chn.pModInstrument; if(m_playBehaviour[kITEnvelopePositionHandling] && chn.VolEnv.nEnvPosition == 0) { // If the envelope is disabled at the very same moment as it is triggered, we do not process anything. return; } const int envpos = chn.VolEnv.nEnvPosition - (m_playBehaviour[kITEnvelopePositionHandling] ? 1 : 0); // Get values in [0, 256] int envval = pIns->VolEnv.GetValueFromPosition(envpos, 256); // if we are in the release portion of the envelope, // rescale envelope factor so that it is proportional to the release point // and release envelope beginning. if(pIns->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET && chn.VolEnv.nEnvValueAtReleaseJump != NOT_YET_RELEASED) { int envValueAtReleaseJump = chn.VolEnv.nEnvValueAtReleaseJump; int envValueAtReleaseNode = pIns->VolEnv[pIns->VolEnv.nReleaseNode].value * 4; //If we have just hit the release node, force the current env value //to be that of the release node. This works around the case where // we have another node at the same position as the release node. if(envpos == pIns->VolEnv[pIns->VolEnv.nReleaseNode].tick) envval = envValueAtReleaseNode; if(m_playBehaviour[kLegacyReleaseNode]) { // Old, hard to grasp release node behaviour (additive) int relativeVolumeChange = (envval - envValueAtReleaseNode) * 2; envval = envValueAtReleaseJump + relativeVolumeChange; } else { // New behaviour, truly relative to release node if(envValueAtReleaseNode > 0) envval = envValueAtReleaseJump * envval / envValueAtReleaseNode; else envval = 0; } } vol = (vol * Clamp(envval, 0, 512)) / 256; } } void CSoundFile::ProcessPanningEnvelope(ModChannel &chn) const { if(IsEnvelopeProcessed(chn, ENV_PANNING)) { const ModInstrument *pIns = chn.pModInstrument; if(m_playBehaviour[kITEnvelopePositionHandling] && chn.PanEnv.nEnvPosition == 0) { // If the envelope is disabled at the very same moment as it is triggered, we do not process anything. return; } const int envpos = chn.PanEnv.nEnvPosition - (m_playBehaviour[kITEnvelopePositionHandling] ? 1 : 0); // Get values in [-32, 32] const int envval = pIns->PanEnv.GetValueFromPosition(envpos, 64) - 32; int pan = chn.nRealPan; if(pan >= 128) { pan += (envval * (256 - pan)) / 32; } else { pan += (envval * (pan)) / 32; } chn.nRealPan = Clamp(pan, 0, 256); } } int CSoundFile::ProcessPitchFilterEnvelope(ModChannel &chn, int32 &period) const { if(IsEnvelopeProcessed(chn, ENV_PITCH)) { const ModInstrument *pIns = chn.pModInstrument; if(m_playBehaviour[kITEnvelopePositionHandling] && chn.PitchEnv.nEnvPosition == 0) { // If the envelope is disabled at the very same moment as it is triggered, we do not process anything. return -1; } const int envpos = chn.PitchEnv.nEnvPosition - (m_playBehaviour[kITEnvelopePositionHandling] ? 1 : 0); // Get values in [-256, 256] #ifdef MODPLUG_TRACKER const int32 range = ENVELOPE_MAX; const int32 amp = 512; #else // TODO: AMS2 envelopes behave differently when linear slides are off - emulate with 15 * (-128...127) >> 6 // Copy over vibrato behaviour for that? const int32 range = GetType() == MOD_TYPE_AMS ? uint8_max : uint8(ENVELOPE_MAX); int32 amp; switch(GetType()) { case MOD_TYPE_AMS: amp = 64; break; case MOD_TYPE_MDL: amp = 192; break; default: amp = 512; } #endif const int envval = pIns->PitchEnv.GetValueFromPosition(envpos, amp, range) - amp / 2; if(chn.PitchEnv.flags[ENV_FILTER]) { // Filter Envelope: controls cutoff frequency return SetupChannelFilter(chn, !chn.dwFlags[CHN_FILTER], envval); } else { // Pitch Envelope if(chn.HasCustomTuning()) { if(chn.nFineTune != envval) { chn.nFineTune = mpt::saturate_cast(envval); chn.m_CalculateFreq = true; //Preliminary tests indicated that this behavior //is very close to original(with 12TET) when finestep count //is 15. } } else //Original behavior { const bool useFreq = PeriodsAreFrequencies(); const uint32 (&upTable)[256] = useFreq ? LinearSlideUpTable : LinearSlideDownTable; const uint32 (&downTable)[256] = useFreq ? LinearSlideDownTable : LinearSlideUpTable; int l = envval; if(l < 0) { l = -l; LimitMax(l, 255); period = Util::muldiv(period, downTable[l], 65536); } else { LimitMax(l, 255); period = Util::muldiv(period, upTable[l], 65536); } } //End: Original behavior. } } return -1; } void CSoundFile::IncrementEnvelopePosition(ModChannel &chn, EnvelopeType envType) const { ModChannel::EnvInfo &chnEnv = chn.GetEnvelope(envType); if(chn.pModInstrument == nullptr || !chnEnv.flags[ENV_ENABLED]) { return; } // Increase position uint32 position = chnEnv.nEnvPosition + (m_playBehaviour[kITEnvelopePositionHandling] ? 0 : 1); const InstrumentEnvelope &insEnv = chn.pModInstrument->GetEnvelope(envType); if(insEnv.empty()) { return; } bool endReached = false; if(!m_playBehaviour[kITEnvelopePositionHandling]) { // FT2-style envelope processing. if(insEnv.dwFlags[ENV_LOOP]) { // Normal loop active uint32 end = insEnv[insEnv.nLoopEnd].tick; if(!(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) end++; // FT2 compatibility: If the sustain point is at the loop end and the sustain loop has been released, don't loop anymore. // Test case: EnvLoops.xm const bool escapeLoop = (insEnv.nLoopEnd == insEnv.nSustainEnd && insEnv.dwFlags[ENV_SUSTAIN] && chn.dwFlags[CHN_KEYOFF] && m_playBehaviour[kFT2EnvelopeEscape]); if(position == end && !escapeLoop) { position = insEnv[insEnv.nLoopStart].tick; } } if(insEnv.dwFlags[ENV_SUSTAIN] && !chn.dwFlags[CHN_KEYOFF]) { // Envelope sustained if(position == insEnv[insEnv.nSustainEnd].tick + 1u) { position = insEnv[insEnv.nSustainStart].tick; // FT2 compatibility: If the panning envelope reaches its sustain point before key-off, it stays there forever. // Test case: PanSustainRelease.xm if(m_playBehaviour[kFT2PanSustainRelease] && envType == ENV_PANNING && !chn.dwFlags[CHN_KEYOFF]) { chnEnv.flags.reset(ENV_ENABLED); } } } else { // Limit to last envelope point if(position > insEnv.back().tick) { // Env of envelope position = insEnv.back().tick; endReached = true; } } } else { // IT envelope processing. // Test case: EnvLoops.it uint32 start, end; // IT compatiblity: OpenMPT processes the key-off flag earlier than IT. Grab the flag from the previous tick instead. // Test case: EnvOffLength.it if(insEnv.dwFlags[ENV_SUSTAIN] && !chn.dwOldFlags[CHN_KEYOFF] && (chnEnv.nEnvValueAtReleaseJump == NOT_YET_RELEASED || m_playBehaviour[kReleaseNodePastSustainBug])) { // Envelope sustained start = insEnv[insEnv.nSustainStart].tick; end = insEnv[insEnv.nSustainEnd].tick + 1; } else if(insEnv.dwFlags[ENV_LOOP]) { // Normal loop active start = insEnv[insEnv.nLoopStart].tick; end = insEnv[insEnv.nLoopEnd].tick + 1; } else { // Limit to last envelope point start = end = insEnv.back().tick; if(position > end) { // Env of envelope endReached = true; } } if(position >= end) { position = start; } } if(envType == ENV_VOLUME && endReached) { // Special handling for volume envelopes at end of envelope if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) || (chn.dwFlags[CHN_KEYOFF] && GetType() != MOD_TYPE_MDL)) { chn.dwFlags.set(CHN_NOTEFADE); } if(insEnv.back().value == 0 && (chn.nMasterChn > 0 || (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)))) { // Stop channel if the last envelope node is silent anyway. chn.dwFlags.set(CHN_NOTEFADE); chn.nFadeOutVol = 0; chn.nRealVolume = 0; chn.nCalcVolume = 0; } } chnEnv.nEnvPosition = position + (m_playBehaviour[kITEnvelopePositionHandling] ? 1 : 0); } void CSoundFile::IncrementEnvelopePositions(ModChannel &chn) const { if (chn.isFirstTick && GetType() == MOD_TYPE_MED) return; IncrementEnvelopePosition(chn, ENV_VOLUME); IncrementEnvelopePosition(chn, ENV_PANNING); IncrementEnvelopePosition(chn, ENV_PITCH); } void CSoundFile::ProcessInstrumentFade(ModChannel &chn, int &vol) const { // FadeOut volume if(chn.dwFlags[CHN_NOTEFADE] && chn.pModInstrument != nullptr) { const ModInstrument *pIns = chn.pModInstrument; uint32 fadeout = pIns->nFadeOut; if (fadeout) { chn.nFadeOutVol -= fadeout * 2; if (chn.nFadeOutVol <= 0) chn.nFadeOutVol = 0; vol = (vol * chn.nFadeOutVol) / 65536; } else if (!chn.nFadeOutVol) { vol = 0; } } } void CSoundFile::ProcessPitchPanSeparation(int32 &pan, int note, const ModInstrument &instr) { if(!instr.nPPS || note == NOTE_NONE) return; // with PPS = 16 / PPC = C-5, E-6 will pan hard right (and D#6 will not) int32 delta = (note - instr.nPPC - NOTE_MIN) * instr.nPPS / 2; pan = Clamp(pan + delta, 0, 256); } void CSoundFile::ProcessPanbrello(ModChannel &chn) const { int pdelta = chn.nPanbrelloOffset; if(chn.rowCommand.command == CMD_PANBRELLO) { uint32 panpos; // IT compatibility: IT has its own, more precise tables if(m_playBehaviour[kITVibratoTremoloPanbrello]) panpos = chn.nPanbrelloPos; else panpos = ((chn.nPanbrelloPos + 0x10) >> 2); pdelta = GetVibratoDelta(chn.nPanbrelloType, panpos); // IT compatibility: Sample-and-hold style random panbrello (tremolo and vibrato don't use this mechanism in IT) // Test case: RandomWaveform.it if(m_playBehaviour[kITSampleAndHoldPanbrello] && chn.nPanbrelloType == 3) { if(chn.nPanbrelloPos == 0 || chn.nPanbrelloPos >= chn.nPanbrelloSpeed) { chn.nPanbrelloPos = 0; chn.nPanbrelloRandomMemory = static_cast(pdelta); } chn.nPanbrelloPos++; pdelta = chn.nPanbrelloRandomMemory; } else { chn.nPanbrelloPos += chn.nPanbrelloSpeed; } // IT compatibility: Panbrello effect is active until next note or panning command. // Test case: PanbrelloHold.it if(m_playBehaviour[kITPanbrelloHold]) { chn.nPanbrelloOffset = static_cast(pdelta); } } if(pdelta) { pdelta = ((pdelta * (int)chn.nPanbrelloDepth) + 2) / 8; pdelta += chn.nRealPan; chn.nRealPan = Clamp(pdelta, 0, 256); } } void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int32 &period, Tuning::NOTEINDEXTYPE &arpeggioSteps) { ModChannel &chn = m_PlayState.Chn[nChn]; #ifndef NO_PLUGINS // Plugin arpeggio if(chn.pModInstrument && chn.pModInstrument->nMixPlug && !chn.pModInstrument->dwFlags[INS_MUTE] && !chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE]) { const ModInstrument *pIns = chn.pModInstrument; IMixPlugin *pPlugin = m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin; if(pPlugin) { const bool arpOnRow = (chn.rowCommand.command == CMD_ARPEGGIO); const ModCommand::NOTE lastNote = chn.lastMidiNoteWithoutArp; ModCommand::NOTE arpNote = chn.lastMidiNoteWithoutArp; if(arpOnRow) { const uint32 tick = m_PlayState.m_nTickCount % (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay); switch(tick % 3) { case 1: arpNote += chn.nArpeggio >> 4; break; case 2: arpNote += chn.nArpeggio & 0x0F; break; } } // Trigger new note: // - If there's an arpeggio on this row and // - the note to trigger is not the same as the previous arpeggio note or // - a pattern note has just been triggered on this tick // - If there's no arpeggio // - but an arpeggio note is still active and // - there's no note stop or new note that would stop it anyway if((arpOnRow && chn.nArpeggioLastNote != arpNote && (!chn.isFirstTick || !chn.rowCommand.IsNote() || chn.rowCommand.IsTonePortamento())) || (!arpOnRow && (chn.rowCommand.note == NOTE_NONE || chn.rowCommand.IsTonePortamento()) && chn.nArpeggioLastNote != NOTE_NONE)) SendMIDINote(nChn, arpNote | IMixPlugin::MIDI_NOTE_ARPEGGIO, static_cast(chn.nVolume)); // Stop note: // - If some arpeggio note is still registered or // - When starting an arpeggio on a row with no other note on it, stop some possibly still playing note. if(chn.nArpeggioLastNote != NOTE_NONE) { if(!arpOnRow || chn.nArpeggioLastNote != arpNote) SendMIDINote(nChn, chn.nArpeggioLastNote | IMixPlugin::MIDI_NOTE_OFF, 0); } else if(arpOnRow && chn.isFirstTick && !chn.rowCommand.IsNote() && ModCommand::IsNote(lastNote)) { SendMIDINote(nChn, lastNote | IMixPlugin::MIDI_NOTE_OFF, 0); } if(chn.rowCommand.command == CMD_ARPEGGIO) chn.nArpeggioLastNote = arpNote; else chn.nArpeggioLastNote = NOTE_NONE; } } #endif // NO_PLUGINS if(chn.nCommand == CMD_ARPEGGIO) { if(chn.HasCustomTuning()) { switch(m_PlayState.m_nTickCount % 3) { case 0: arpeggioSteps = 0; break; case 1: arpeggioSteps = chn.nArpeggio >> 4; break; case 2: arpeggioSteps = chn.nArpeggio & 0x0F; break; } chn.m_CalculateFreq = true; chn.m_ReCalculateFreqOnFirstTick = true; } else { if(GetType() == MOD_TYPE_MT2 && m_PlayState.m_flags[SONG_FIRSTTICK]) { // MT2 resets any previous portamento when an arpeggio occurs. chn.nPeriod = period = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed); } if(m_playBehaviour[kITArpeggio]) { //IT playback compatibility 01 & 02 // Pattern delay restarts tick counting. // Test case: JxxTicks.it const uint32 tick = m_PlayState.m_nTickCount % (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay); if(chn.nArpeggio != 0) { uint32 arpRatio = 65536; switch(tick % 3) { case 1: arpRatio = LinearSlideUpTable[(chn.nArpeggio >> 4) * 16]; break; case 2: arpRatio = LinearSlideUpTable[(chn.nArpeggio & 0x0F) * 16]; break; } if(PeriodsAreFrequencies()) period = Util::muldivr(period, arpRatio, 65536); else period = Util::muldivr(period, 65536, arpRatio); } } else if(m_playBehaviour[kFT2Arpeggio]) { // FastTracker 2: Swedish tracker logic (TM) arpeggio if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { // Arpeggio is added on top of current note, but cannot do it the IT way because of // the behaviour in ArpeggioClamp.xm. // Test case: ArpSlide.xm uint32 note = 0; // The fact that arpeggio behaves in a totally fucked up way at 16 ticks/row or more is that the arpeggio offset LUT only has 16 entries in FT2. // At more than 16 ticks/row, FT2 reads into the vibrato table, which is placed right after the arpeggio table. // Test case: Arpeggio.xm int arpPos = m_PlayState.m_nMusicSpeed - (m_PlayState.m_nTickCount % m_PlayState.m_nMusicSpeed); if(arpPos > 16) arpPos = 2; else if(arpPos == 16) arpPos = 0; else arpPos %= 3; switch(arpPos) { case 1: note = (chn.nArpeggio >> 4); break; case 2: note = (chn.nArpeggio & 0x0F); break; } if(arpPos != 0) { // Arpeggio is added on top of current note, but cannot do it the IT way because of // the behaviour in ArpeggioClamp.xm. // Test case: ArpSlide.xm note += GetNoteFromPeriod(period, chn.nFineTune, chn.nC5Speed); period = GetPeriodFromNote(note, chn.nFineTune, chn.nC5Speed); // FT2 compatibility: FT2 has a different note limit for Arpeggio. // Test case: ArpeggioClamp.xm if(note >= 108 + NOTE_MIN) { period = std::max(static_cast(period), GetPeriodFromNote(108 + NOTE_MIN, 0, chn.nC5Speed)); } } } } // Other trackers else { uint32 tick = m_PlayState.m_nTickCount; // TODO other likely formats for MOD case: MED, OKT, etc uint8 note = (GetType() != MOD_TYPE_MOD) ? chn.nNote : static_cast(GetNoteFromPeriod(period, chn.nFineTune, chn.nC5Speed)); if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI)) tick += 2; // SFX uses a 0-1-2-0-2-1 pattern (fixed at 6 ticks per row) if(GetType() == MOD_TYPE_SFX && tick > 3) tick ^= 3; switch(tick % 3) { case 1: note += (chn.nArpeggio >> 4); break; case 2: note += (chn.nArpeggio & 0x0F); break; } if(note != chn.nNote || (GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI | MOD_TYPE_STM)) || m_playBehaviour[KST3PortaAfterArpeggio]) { if(m_SongFlags[SONG_PT_MODE]) { // Weird arpeggio wrap-around in ProTracker. // Test case: ArpWraparound.mod, and the snare sound in "Jim is dead" by doh. if(note == NOTE_MIDDLEC + 24) { period = int32_max; return; } else if(note > NOTE_MIDDLEC + 24) { note -= 37; } } period = GetPeriodFromNote(note, chn.nFineTune, chn.nC5Speed); if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI | MOD_TYPE_PSM | MOD_TYPE_STM | MOD_TYPE_OKT | MOD_TYPE_SFX)) { // The arpeggio note offset remains effective after the end of the current row in ScreamTracker 2. // This fixes the flute lead in MORPH.STM by Skaven, pattern 27. // Note that ScreamTracker 2.24 handles arpeggio slightly differently: It only considers the lower // nibble, and switches to that note halfway through the row. chn.nPeriod = period; } else if(m_playBehaviour[KST3PortaAfterArpeggio]) { chn.nArpeggioLastNote = note; } } } } } else if(chn.rowCommand.command == CMD_HMN_MEGA_ARP) { uint8 note = static_cast(GetNoteFromPeriod(period, chn.nFineTune, chn.nC5Speed)); note += HisMastersNoiseMegaArp[chn.rowCommand.param & 0x0F][chn.nArpeggio & 0x0F]; chn.nArpeggio++; period = GetPeriodFromNote(note, chn.nFineTune, chn.nC5Speed); } } void CSoundFile::ProcessVibrato(CHANNELINDEX nChn, int32 &period, Tuning::RATIOTYPE &vibratoFactor) { ModChannel &chn = m_PlayState.Chn[nChn]; if(chn.dwFlags[CHN_VIBRATO]) { const bool advancePosition = !m_PlayState.m_flags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_MED)) && !(m_SongFlags[SONG_ITOLDEFFECTS])); if(GetType() == MOD_TYPE_669) { if(chn.nVibratoPos % 2u) { period += chn.nVibratoDepth * 167; // Already multiplied by 4, and it seems like the real factor here is 669... how original =) } chn.nVibratoPos++; return; } // IT compatibility: IT has its own, more precise tables and pre-increments the vibrato position if(advancePosition && m_playBehaviour[kITVibratoTremoloPanbrello]) chn.nVibratoPos += static_cast(4u * chn.nVibratoSpeed); int vdelta = GetVibratoDelta(chn.nVibratoType, chn.nVibratoPos); if(chn.HasCustomTuning()) { //Hack implementation: Scaling vibratofactor to [0.95; 1.05] //using figure from above tables and vibratodepth parameter vibratoFactor += 0.05f * static_cast(vdelta * static_cast(chn.nVibratoDepth)) / (128.0f * 60.0f); chn.m_CalculateFreq = true; chn.m_ReCalculateFreqOnFirstTick = false; if(m_PlayState.m_nTickCount + 1 == m_PlayState.m_nMusicSpeed) chn.m_ReCalculateFreqOnFirstTick = true; } else { // Original behaviour if((m_SongFlags[SONG_PT_MODE] || (GetType() & (MOD_TYPE_DIGI | MOD_TYPE_DBM))) && m_PlayState.m_flags[SONG_FIRSTTICK]) { // ProTracker doesn't apply vibrato nor advance on the first tick. // Test case: VibratoReset.mod return; } else if((GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD)) && (chn.nVibratoType & 0x03) == 1) { // FT2 compatibility: Vibrato ramp down table is upside down. // Test case: VibratoWaveforms.xm vdelta = -vdelta; } uint32 vdepth; // IT compatibility: correct vibrato depth if(m_playBehaviour[kITVibratoTremoloPanbrello]) { // Yes, vibrato goes backwards with old effects enabled! if(m_SongFlags[SONG_ITOLDEFFECTS]) { // Test case: vibrato-oldfx.it vdepth = 5; } else { // Test case: vibrato.it vdepth = 6; vdelta = -vdelta; } } else { if(m_SongFlags[SONG_S3MOLDVIBRATO]) vdepth = 5; else if(GetType() == MOD_TYPE_DTM) vdepth = 8; else if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_MTM)) vdepth = 7; else if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]) vdepth = 7; else vdepth = 6; // ST3 compatibility: Do not distinguish between vibrato types in effect memory // Test case: VibratoTypeChange.s3m if(m_playBehaviour[kST3VibratoMemory] && chn.rowCommand.command == CMD_FINEVIBRATO) vdepth += 2; } vdelta = (-vdelta * static_cast(chn.nVibratoDepth)) / (1 << vdepth); DoFreqSlide(chn, period, vdelta); // Process MIDI vibrato for plugins: #ifndef NO_PLUGINS IMixPlugin *plugin = GetChannelInstrumentPlugin(m_PlayState.Chn[nChn]); if(plugin != nullptr) { // If the Pitch Wheel Depth is configured correctly (so it's the same as the plugin's PWD), // MIDI vibrato will sound identical to vibrato with linear slides enabled. int8 pwd = 2; if(chn.pModInstrument != nullptr) { pwd = chn.pModInstrument->midiPWD; } plugin->MidiVibrato(vdelta, pwd, nChn); } #endif // NO_PLUGINS } // Advance vibrato position - IT updates on every tick, unless "old effects" are enabled (in this case it only updates on non-first ticks like other trackers) // IT compatibility: IT has its own, more precise tables and pre-increments the vibrato position if(advancePosition && !m_playBehaviour[kITVibratoTremoloPanbrello]) chn.nVibratoPos += chn.nVibratoSpeed; } else if(chn.dwOldFlags[CHN_VIBRATO]) { // Stop MIDI vibrato for plugins: #ifndef NO_PLUGINS IMixPlugin *plugin = GetChannelInstrumentPlugin(m_PlayState.Chn[nChn]); if(plugin != nullptr) { plugin->MidiVibrato(0, 0, nChn); } #endif // NO_PLUGINS } } void CSoundFile::ProcessSampleAutoVibrato(ModChannel &chn, int32 &period, Tuning::RATIOTYPE &vibratoFactor, int &nPeriodFrac) const { // Sample Auto-Vibrato if(chn.pModSample != nullptr && chn.pModSample->nVibDepth) { const ModSample *pSmp = chn.pModSample; const bool hasTuning = chn.HasCustomTuning(); // In IT compatible mode, we use always frequencies, otherwise we use periods, which are upside down. // In this context, the "up" tables refer to the tables that increase frequency, and the down tables are the ones that decrease frequency. const bool useFreq = PeriodsAreFrequencies(); const uint32 (&upTable)[256] = useFreq ? LinearSlideUpTable : LinearSlideDownTable; const uint32 (&downTable)[256] = useFreq ? LinearSlideDownTable : LinearSlideUpTable; const uint32 (&fineUpTable)[16] = useFreq ? FineLinearSlideUpTable : FineLinearSlideDownTable; const uint32 (&fineDownTable)[16] = useFreq ? FineLinearSlideDownTable : FineLinearSlideUpTable; // IT compatibility: Autovibrato is so much different in IT that I just put this in a separate code block, to get rid of a dozen IsCompatibilityMode() calls. if(m_playBehaviour[kITVibratoTremoloPanbrello] && !hasTuning && GetType() != MOD_TYPE_MT2) { if(!pSmp->nVibRate) return; // Schism's autovibrato code /* X86 Assembler from ITTECH.TXT: 1) Mov AX, [SomeVariableNameRelatingToVibrato] 2) Add AL, Rate 3) AdC AH, 0 4) AH contains the depth of the vibrato as a fine-linear slide. 5) Mov [SomeVariableNameRelatingToVibrato], AX ; For the next cycle. */ const int vibpos = chn.nAutoVibPos & 0xFF; int adepth = chn.nAutoVibDepth; // (1) adepth += pSmp->nVibSweep; // (2 & 3) LimitMax(adepth, static_cast(pSmp->nVibDepth * 256u)); chn.nAutoVibDepth = adepth; // (5) adepth /= 256; // (4) chn.nAutoVibPos += pSmp->nVibRate; int vdelta; switch(pSmp->nVibType) { case VIB_RANDOM: vdelta = mpt::random(AccessPRNG()) - 0x40; break; case VIB_RAMP_DOWN: vdelta = 64 - (vibpos + 1) / 2; break; case VIB_RAMP_UP: vdelta = ((vibpos + 1) / 2) - 64; break; case VIB_SQUARE: vdelta = vibpos < 128 ? 64 : 0; break; case VIB_SINE: default: vdelta = ITSinusTable[vibpos]; break; } vdelta = (vdelta * adepth) / 64; uint32 l = std::abs(vdelta); LimitMax(period, Util::MaxValueOfType(period) / 256); period *= 256; if(vdelta < 0) { vdelta = Util::muldiv(period, downTable[l / 4u], 0x10000) - period; if (l & 0x03) { vdelta += Util::muldiv(period, fineDownTable[l & 0x03], 0x10000) - period; } } else { vdelta = Util::muldiv(period, upTable[l / 4u], 0x10000) - period; if (l & 0x03) { vdelta += Util::muldiv(period, fineUpTable[l & 0x03], 0x10000) - period; } } if(Util::MaxValueOfType(period) - period >= vdelta) { period = (period + vdelta) / 256; nPeriodFrac = vdelta & 0xFF; } else { period = Util::MaxValueOfType(period) / 256; nPeriodFrac = 0; } } else { // MPT's autovibrato code int32 autoVibDepth = chn.nAutoVibDepth; const int32 fullDepth = pSmp->nVibDepth * 256u; if (pSmp->nVibSweep == 0 && !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) { autoVibDepth = fullDepth; } else { // Calculate current autovibrato depth using vibsweep if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) { autoVibDepth += pSmp->nVibSweep * 2u; LimitMax(autoVibDepth, fullDepth); chn.nAutoVibDepth = autoVibDepth; } else { if(!chn.dwFlags[CHN_KEYOFF] && autoVibDepth <= fullDepth) { autoVibDepth += fullDepth / pSmp->nVibSweep; chn.nAutoVibDepth = autoVibDepth; } // FT2 compatibility: Key-off before auto-vibrato sweep-in is complete resets auto-vibrato depth // Test case: AutoVibratoSweepKeyOff.xm if(autoVibDepth > fullDepth) autoVibDepth = fullDepth; else if(chn.dwFlags[CHN_KEYOFF] && m_playBehaviour[kFT2AutoVibratoAbortSweep]) autoVibDepth = fullDepth / pSmp->nVibSweep; } } chn.nAutoVibPos += pSmp->nVibRate; int vdelta; switch(pSmp->nVibType) { case VIB_RANDOM: vdelta = ModRandomTable[chn.nAutoVibPos & 0x3F]; chn.nAutoVibPos++; break; case VIB_RAMP_DOWN: vdelta = ((0x40 - (chn.nAutoVibPos / 2u)) & 0x7F) - 0x40; break; case VIB_RAMP_UP: vdelta = ((0x40 + (chn.nAutoVibPos / 2u)) & 0x7F) - 0x40; break; case VIB_SQUARE: vdelta = (chn.nAutoVibPos & 128) ? +64 : -64; break; case VIB_SINE: default: if(GetType() != MOD_TYPE_MT2) { vdelta = -ITSinusTable[chn.nAutoVibPos & 0xFF]; } else { // Fix flat-sounding pads in "another worlds" by Eternal Engine. // Vibrato starts at the maximum amplitude of the sine wave // and the vibrato frequency never decreases below the original note's frequency. vdelta = (-ITSinusTable[(chn.nAutoVibPos + 192) & 0xFF] + 64) / 2; } } int n = (vdelta * autoVibDepth) / 256; if(hasTuning) { //Vib sweep is not taken into account here. vibratoFactor += 0.05f * static_cast(static_cast(pSmp->nVibDepth) * vdelta) / 4096.0f; //4096 == 64^2 //See vibrato for explanation. chn.m_CalculateFreq = true; /* Finestep vibrato: const float autoVibDepth = pSmp->nVibDepth * val / 4096.0f; //4096 == 64^2 vibratoFineSteps += static_cast(chn.pModInstrument->pTuning->GetFineStepCount() * autoVibDepth); chn.m_CalculateFreq = true; */ } else //Original behavior { if (GetType() != MOD_TYPE_XM) { int df1, df2; if (n < 0) { n = -n; uint32 n1 = n / 256; df1 = downTable[n1]; df2 = downTable[n1+1]; } else { uint32 n1 = n / 256; df1 = upTable[n1]; df2 = upTable[n1+1]; } n /= 4; period = Util::muldiv(period, df1 + ((df2 - df1) * (n & 0x3F) / 64), 256); nPeriodFrac = period & 0xFF; period /= 256; } else { period += (n / 64); } } //Original MPT behavior } } } void CSoundFile::ProcessRamping(ModChannel &chn) const { chn.leftRamp = chn.rightRamp = 0; LimitMax(chn.newLeftVol, int32_max >> VOLUMERAMPPRECISION); LimitMax(chn.newRightVol, int32_max >> VOLUMERAMPPRECISION); if(chn.dwFlags[CHN_VOLUMERAMP] && (chn.leftVol != chn.newLeftVol || chn.rightVol != chn.newRightVol)) { const bool rampUp = (chn.newLeftVol > chn.leftVol) || (chn.newRightVol > chn.rightVol); int32 rampLength, globalRampLength, instrRampLength = 0; rampLength = globalRampLength = (rampUp ? m_MixerSettings.GetVolumeRampUpSamples() : m_MixerSettings.GetVolumeRampDownSamples()); //XXXih: add real support for bidi ramping here if(m_playBehaviour[kFT2VolumeRamping] && (GetType() & MOD_TYPE_XM)) { // apply FT2-style super-soft volume ramping (5ms), overriding openmpt settings rampLength = globalRampLength = Util::muldivr(5, m_MixerSettings.gdwMixingFreq, 1000); } if(chn.pModInstrument != nullptr && rampUp) { instrRampLength = chn.pModInstrument->nVolRampUp; rampLength = instrRampLength ? (m_MixerSettings.gdwMixingFreq * instrRampLength / 100000) : globalRampLength; } const bool enableCustomRamp = (instrRampLength > 0); if(!rampLength) { rampLength = 1; } int32 leftDelta = ((chn.newLeftVol - chn.leftVol) * (1 << VOLUMERAMPPRECISION)); int32 rightDelta = ((chn.newRightVol - chn.rightVol) * (1 << VOLUMERAMPPRECISION)); if(!enableCustomRamp) { // Extra-smooth ramping, unless we're forced to use the default values if((chn.leftVol | chn.rightVol) && (chn.newLeftVol | chn.newRightVol) && !chn.dwFlags[CHN_FASTVOLRAMP]) { rampLength = m_PlayState.m_nBufferCount; Limit(rampLength, globalRampLength, int32(1 << (VOLUMERAMPPRECISION - 1))); } } chn.leftRamp = leftDelta / rampLength; chn.rightRamp = rightDelta / rampLength; chn.leftVol = chn.newLeftVol - ((chn.leftRamp * rampLength) / (1 << VOLUMERAMPPRECISION)); chn.rightVol = chn.newRightVol - ((chn.rightRamp * rampLength) / (1 << VOLUMERAMPPRECISION)); if (chn.leftRamp|chn.rightRamp) { chn.nRampLength = rampLength; } else { chn.dwFlags.reset(CHN_VOLUMERAMP); chn.leftVol = chn.newLeftVol; chn.rightVol = chn.newRightVol; } } else { chn.dwFlags.reset(CHN_VOLUMERAMP); chn.leftVol = chn.newLeftVol; chn.rightVol = chn.newRightVol; } chn.rampLeftVol = chn.leftVol * (1 << VOLUMERAMPPRECISION); chn.rampRightVol = chn.rightVol * (1 << VOLUMERAMPPRECISION); chn.dwFlags.reset(CHN_FASTVOLRAMP); } int CSoundFile::HandleNoteChangeFilter(ModChannel &chn) const { int cutoff = -1; if(!chn.triggerNote) return cutoff; bool useFilter = !m_PlayState.m_flags[SONG_MPTFILTERMODE]; if(const ModInstrument *pIns = chn.pModInstrument; pIns != nullptr) { if(pIns->IsResonanceEnabled()) { chn.nResonance = pIns->GetResonance(); useFilter = true; } if(pIns->IsCutoffEnabled()) { chn.nCutOff = pIns->GetCutoff(); useFilter = true; } if(useFilter && (pIns->filterMode != FilterMode::Unchanged)) { chn.nFilterMode = pIns->filterMode; } } else { chn.nVolSwing = chn.nPanSwing = 0; chn.nCutSwing = chn.nResSwing = 0; } if((chn.nCutOff < 0x7F || m_playBehaviour[kITFilterBehaviour]) && useFilter) { cutoff = SetupChannelFilter(chn, true); if(cutoff >= 0) cutoff = chn.nCutOff / 2u; } return cutoff; } // Returns channel increment and frequency with FREQ_FRACBITS fractional bits std::pair CSoundFile::GetChannelIncrement(const ModChannel &chn, uint32 period, int periodFrac) const { uint32 freq; if(!chn.HasCustomTuning()) freq = GetFreqFromPeriod(period, chn.nC5Speed, periodFrac); else freq = chn.nPeriod; const ModInstrument *ins = chn.pModInstrument; if(int32 finetune = chn.microTuning; finetune != 0) { if(ins) finetune *= ins->midiPWD; if(finetune) freq = mpt::saturate_round(freq * std::pow(2.0, finetune / (12.0 * 256.0 * 128.0))); } // Applying Pitch/Tempo lock if(ins && ins->pitchToTempoLock.GetRaw()) { freq = Util::muldivr(freq, m_PlayState.m_nMusicTempo.GetRaw(), ins->pitchToTempoLock.GetRaw()); } // Avoid increment to overflow and become negative with unrealisticly high frequencies. LimitMax(freq, uint32(int32_max)); return {SamplePosition::Ratio(freq, m_MixerSettings.gdwMixingFreq << FREQ_FRACBITS), freq}; } //////////////////////////////////////////////////////////////////////////////////////////// // Handles envelopes & mixer setup bool CSoundFile::ReadNote() { #ifdef MODPLUG_TRACKER // Checking end of row ? if(m_PlayState.m_flags[SONG_PAUSED]) { m_PlayState.m_nTickCount = 0; if (!m_PlayState.m_nMusicSpeed) m_PlayState.m_nMusicSpeed = 6; if (!m_PlayState.m_nMusicTempo.GetRaw()) m_PlayState.m_nMusicTempo.Set(125); } else #endif // MODPLUG_TRACKER { if(!ProcessRow()) return false; } //////////////////////////////////////////////////////////////////////////////////// if (m_PlayState.m_nMusicTempo.GetRaw() == 0) return false; m_PlayState.m_globalScriptState.NextTick(m_PlayState, *this); m_PlayState.m_nSamplesPerTick = GetTickDuration(m_PlayState); m_PlayState.m_nBufferCount = m_PlayState.m_nSamplesPerTick; // Master Volume + Pre-Amplification / Attenuation setup uint32 nMasterVol; { CHANNELINDEX nchn32 = Clamp(GetNumChannels(), CHANNELINDEX(1), CHANNELINDEX(31)); uint32 mastervol; if (m_PlayConfig.getUseGlobalPreAmp()) { int realmastervol = m_MixerSettings.m_nPreAmp; if (realmastervol > 0x80) { //Attenuate global pre-amp depending on num channels realmastervol = 0x80 + ((realmastervol - 0x80) * (nchn32 + 4)) / 16; } mastervol = (realmastervol * (m_nSamplePreAmp)) / 64; } else { //Preferred option: don't use global pre-amp at all. mastervol = m_nSamplePreAmp; } if (m_PlayConfig.getUseGlobalPreAmp()) { uint32 attenuation = #ifndef NO_AGC (m_MixerSettings.DSPMask & SNDDSP_AGC) ? PreAmpAGCTable[nchn32 / 2u] : #endif PreAmpTable[nchn32 / 2u]; if(attenuation < 1) attenuation = 1; nMasterVol = (mastervol << 7) / attenuation; } else { nMasterVol = mastervol; } } //////////////////////////////////////////////////////////////////////////////////// // Update channels data m_nMixChannels = 0; for(CHANNELINDEX nChn = 0; nChn < m_PlayState.Chn.size(); nChn++) { ModChannel &chn = m_PlayState.Chn[nChn]; // FT2 Compatibility: Prevent notes to be stopped after a fadeout. This way, a portamento effect can pick up a faded instrument which is long enough. // This occurs for example in the bassline (channel 11) of jt_burn.xm. I hope this won't break anything else... // I also suppose this could decrease mixing performance a bit, but hey, which CPU can't handle 32 muted channels these days... :-) if(chn.dwFlags[CHN_NOTEFADE] && (!(chn.nFadeOutVol|chn.leftVol|chn.rightVol)) && !m_playBehaviour[kFT2ProcessSilentChannels]) { chn.nLength = 0; chn.nROfs = chn.nLOfs = 0; } // Increment age of NNA channels if(chn.nMasterChn && nChn < GetNumChannels() && chn.nnaChannelAge < Util::MaxValueOfType(chn.nnaChannelAge)) chn.nnaChannelAge++; // Check for unused channel if(chn.dwFlags[CHN_MUTE] || (nChn >= GetNumChannels() && !chn.nLength)) { if(nChn < GetNumChannels()) { // Process MIDI macros on channels that are currently muted. ProcessMacroOnChannel(nChn); } chn.nLeftVU = chn.nRightVU = 0; continue; } // Reset channel data chn.increment = SamplePosition(0); chn.nRealVolume = 0; chn.nCalcVolume = 0; chn.nRampLength = 0; //Aux variables Tuning::RATIOTYPE vibratoFactor = 1; Tuning::NOTEINDEXTYPE arpeggioSteps = 0; const ModInstrument *pIns = chn.pModInstrument; // Calc Frequency int32 period = 0; chn.synthState.NextTick(m_PlayState, nChn, *this); // Also process envelopes etc. when there's a plugin on this channel, for possible fake automation using volume and pan data. // We only care about master channels, though, since automation only "happens" on them. const bool samplePlaying = (chn.nPeriod && chn.nLength); const bool plugAssigned = (nChn < GetNumChannels()) && (ChnSettings[nChn].nMixPlugin || (chn.pModInstrument != nullptr && chn.pModInstrument->nMixPlug)); if (samplePlaying || plugAssigned) { int vol = chn.nVolume; int insVol = chn.nInsVol; // This is the "SV * IV" value in ITTECH.TXT ProcessVolumeSwing(chn, m_playBehaviour[kITSwingBehaviour] ? insVol : vol); ProcessPanningSwing(chn); ProcessTremolo(chn, vol); ProcessTremor(nChn, vol); // Clip volume and multiply (extend to 14 bits) Limit(vol, 0, 256); vol <<= 6; // Process Envelopes if (pIns) { if(m_playBehaviour[kITEnvelopePositionHandling]) { // In IT compatible mode, envelope position indices are shifted by one for proper envelope pausing, // so we have to update the position before we actually process the envelopes. // When using MPT behaviour, we get the envelope position for the next tick while we are still calculating the current tick, // which then results in wrong position information when the envelope is paused on the next row. // Test cases: s77.it IncrementEnvelopePositions(chn); } ProcessVolumeEnvelope(chn, vol); ProcessInstrumentFade(chn, vol); ProcessPanningEnvelope(chn); if(!m_playBehaviour[kITPitchPanSeparation] && chn.nNote != NOTE_NONE && chn.pModInstrument && chn.pModInstrument->nPPS != 0) ProcessPitchPanSeparation(chn.nRealPan, chn.nNote, *chn.pModInstrument); } else { // No Envelope: key off => note cut if(chn.dwFlags[CHN_NOTEFADE]) // 1.41-: CHN_KEYOFF|CHN_NOTEFADE { chn.nFadeOutVol = 0; vol = 0; } } if(chn.isPaused) vol = 0; // vol is 14-bits if (vol) { // IMPORTANT: chn.nRealVolume is 14 bits !!! // -> Util::muldiv( 14+8, 6+6, 18); => RealVolume: 14-bit result (22+12-20) if(chn.dwFlags[CHN_SYNCMUTE]) { chn.nRealVolume = 0; } else if (m_PlayConfig.getGlobalVolumeAppliesToMaster()) { // Don't let global volume affect level of sample if // Global volume is going to be applied to master output anyway. chn.nRealVolume = Util::muldiv(vol * MAX_GLOBAL_VOLUME, chn.nGlobalVol * insVol, 1 << 20); } else { chn.nRealVolume = Util::muldiv(vol * m_PlayState.m_nGlobalVolume, chn.nGlobalVol * insVol, 1 << 20); } } chn.nCalcVolume = vol; // Update calculated volume for MIDI macros // ST3 only clamps the final output period, but never the channel's internal period. // Test case: PeriodLimit.s3m if (chn.nPeriod < m_nMinPeriod && GetType() != MOD_TYPE_S3M && !PeriodsAreFrequencies()) { chn.nPeriod = m_nMinPeriod; } else if(chn.nPeriod >= m_nMaxPeriod && m_playBehaviour[kApplyUpperPeriodLimit] && !PeriodsAreFrequencies()) { // ...but on the other hand, ST3's SoundBlaster driver clamps the maximum channel period. // Test case: PeriodLimitUpper.s3m chn.nPeriod = m_nMaxPeriod; } if(m_playBehaviour[kFT2Periods]) Clamp(chn.nPeriod, 1, 31999); period = chn.nPeriod; // When glissando mode is set to semitones, clamp to the next halftone. if((chn.dwFlags & (CHN_GLISSANDO | CHN_PORTAMENTO)) == (CHN_GLISSANDO | CHN_PORTAMENTO) && (!m_SongFlags[SONG_PT_MODE] || (chn.rowCommand.IsTonePortamento() && !m_PlayState.m_flags[SONG_FIRSTTICK]))) { if(period != chn.cachedPeriod) { // Only recompute this whole thing in case the base period has changed. chn.cachedPeriod = period; chn.glissandoPeriod = GetPeriodFromNote(GetNoteFromPeriod(period, chn.nFineTune, chn.nC5Speed), chn.nFineTune, chn.nC5Speed); } period = chn.glissandoPeriod; } ProcessArpeggio(nChn, period, arpeggioSteps); // Preserve Amiga freq limits. // In ST3, the frequency is always clamped to periods 113 to 856, while in ProTracker, // the limit is variable, depending on the finetune of the sample. // The int32_max test is for the arpeggio wrap-around in ProcessArpeggio(). // Test case: AmigaLimits.s3m, AmigaLimitsFinetune.mod if(m_SongFlags[SONG_AMIGALIMITS | SONG_PT_MODE] && period != int32_max) { int limitLow = 113 * 4, limitHigh = 856 * 4; if(GetType() != MOD_TYPE_S3M) { const int tableOffset = XM2MODFineTune(chn.nFineTune) * 12; limitLow = ProTrackerTunedPeriods[tableOffset + 11] / 2; limitHigh = ProTrackerTunedPeriods[tableOffset] * 2; // Amiga cannot actually keep up with lower periods if(limitLow < 113 * 4) limitLow = 113 * 4; } Limit(period, limitLow, limitHigh); Limit(chn.nPeriod, limitLow, limitHigh); } ProcessPanbrello(chn); } // IT Compatibility: Ensure that there is no pan swing, panbrello, panning envelopes, etc. applied on surround channels. // Test case: surround-pan.it if(chn.dwFlags[CHN_SURROUND] && !m_PlayState.m_flags[SONG_SURROUNDPAN] && m_playBehaviour[kITNoSurroundPan]) { chn.nRealPan = 128; } // Setup Initial Filter for this note if(int cutoff = HandleNoteChangeFilter(chn); cutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl) m_opl->Volume(nChn, static_cast(cutoff), true); // Now that all relevant envelopes etc. have been processed, we can parse the MIDI macro data. ProcessMacroOnChannel(nChn); // After MIDI macros have been processed, we can also process the pitch / filter envelope and other pitch-related things. if(samplePlaying) { int envCutoff = ProcessPitchFilterEnvelope(chn, period); // Cutoff doubles as modulator intensity for FM instruments if(envCutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl) m_opl->Volume(nChn, static_cast(envCutoff / 4), true); } if(chn.rowCommand.volcmd == VOLCMD_VIBRATODEPTH && (chn.rowCommand.command == CMD_VIBRATO || chn.rowCommand.command == CMD_VIBRATOVOL || chn.rowCommand.command == CMD_FINEVIBRATO)) { if(GetType() == MOD_TYPE_XM) { // XM Compatibility: Vibrato should be advanced twice (but not added up) if both volume-column and effect column vibrato is present. // Effect column vibrato parameter has precedence if non-zero. // Test case: VibratoDouble.xm if(!m_PlayState.m_flags[SONG_FIRSTTICK]) chn.nVibratoPos += chn.nVibratoSpeed; } else if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) { // IT Compatibility: Vibrato should be applied twice if both volume-colum and effect column vibrato is present. // Volume column vibrato parameter has precedence if non-zero. // Test case: VibratoDouble.it Vibrato(chn, chn.rowCommand.vol); ProcessVibrato(nChn, period, vibratoFactor); } } // Plugins may also receive vibrato ProcessVibrato(nChn, period, vibratoFactor); if(samplePlaying) { chn.synthState.ApplyChannelState(chn, period, *this); m_PlayState.m_globalScriptState.ApplyChannelState(m_PlayState, nChn, period, *this); int nPeriodFrac = 0; ProcessSampleAutoVibrato(chn, period, vibratoFactor, nPeriodFrac); // Final Period // ST3 only clamps the final output period, but never the channel's internal period. // Test case: PeriodLimit.s3m if (period <= m_nMinPeriod) { if(m_playBehaviour[kST3LimitPeriod]) chn.nLength = 0; // Pattern 15 in watcha.s3m period = m_nMinPeriod; } const bool hasTuning = chn.HasCustomTuning(); if(hasTuning) { if(chn.m_CalculateFreq || (chn.m_ReCalculateFreqOnFirstTick && m_PlayState.m_nTickCount == 0)) { chn.RecalcTuningFreq(vibratoFactor, arpeggioSteps, *this); if(!chn.m_CalculateFreq) chn.m_ReCalculateFreqOnFirstTick = false; else chn.m_CalculateFreq = false; } } auto [ninc, freq] = GetChannelIncrement(chn, period, nPeriodFrac); #ifndef MODPLUG_TRACKER ninc.MulDiv(m_nFreqFactor, 65536); #endif // !MODPLUG_TRACKER if(ninc.IsZero()) { ninc.Set(0, 1); } chn.increment = ninc; if((chn.dwFlags & (CHN_ADLIB | CHN_MUTE | CHN_SYNCMUTE)) == CHN_ADLIB && m_opl) { const bool doProcess = m_playBehaviour[kOPLFlexibleNoteOff] || !chn.dwFlags[CHN_NOTEFADE] || GetType() == MOD_TYPE_S3M; if(doProcess && !(GetType() == MOD_TYPE_S3M && chn.dwFlags[CHN_KEYOFF])) { // In ST3, a sample rate of 8363 Hz is mapped to middle-C, which is 261.625 Hz in a tempered scale at A4 = 440. // Hence, we have to translate our "sample rate" into pitch. auto milliHertz = Util::muldivr_unsigned(freq, 261625, 8363 << FREQ_FRACBITS); #ifndef MODPLUG_TRACKER milliHertz = Util::muldivr_unsigned(milliHertz, m_nFreqFactor, 65536); #endif // !MODPLUG_TRACKER const bool keyOff = chn.dwFlags[CHN_KEYOFF] || (chn.dwFlags[CHN_NOTEFADE] && chn.nFadeOutVol == 0); if(!m_playBehaviour[kOPLNoteStopWith0Hz] || !keyOff) m_opl->Frequency(nChn, milliHertz, keyOff, m_playBehaviour[kOPLBeatingOscillators]); } if(doProcess) { // Scale volume to OPL range (0...63). m_opl->Volume(nChn, static_cast(Util::muldivr_unsigned(chn.nCalcVolume * chn.nGlobalVol * chn.nInsVol, 63, 1 << 26)), false); chn.nRealPan = m_opl->Pan(nChn, chn.nRealPan) * 128 + 128; } // Deallocate OPL channels for notes that are most definitely never going to play again. if(const auto *ins = chn.pModInstrument; ins != nullptr && (ins->VolEnv.dwFlags & (ENV_ENABLED | ENV_LOOP | ENV_SUSTAIN)) == ENV_ENABLED && !ins->VolEnv.empty() && chn.GetEnvelope(ENV_VOLUME).nEnvPosition >= ins->VolEnv.back().tick && ins->VolEnv.back().value == 0) { m_opl->NoteCut(nChn); if(!m_playBehaviour[kOPLNoResetAtEnvelopeEnd]) chn.dwFlags.reset(CHN_ADLIB); chn.dwFlags.set(CHN_NOTEFADE); chn.nFadeOutVol = 0; } else if(m_playBehaviour[kOPLFlexibleNoteOff] && chn.dwFlags[CHN_NOTEFADE] && chn.nFadeOutVol == 0) { m_opl->NoteCut(nChn); chn.dwFlags.reset(CHN_ADLIB); } } } // Increment envelope positions if(pIns != nullptr && !m_playBehaviour[kITEnvelopePositionHandling]) { // In IT and FT2 compatible mode, envelope positions are updated above. // Test cases: s77.it, EnvLoops.xm IncrementEnvelopePositions(chn); } // Volume ramping chn.dwFlags.set(CHN_VOLUMERAMP, (chn.nRealVolume | chn.rightVol | chn.leftVol) != 0 && !chn.dwFlags[CHN_ADLIB]); constexpr uint8 VUMETER_DECAY = 4; chn.nLeftVU = (chn.nLeftVU > VUMETER_DECAY) ? (chn.nLeftVU - VUMETER_DECAY) : 0; chn.nRightVU = (chn.nRightVU > VUMETER_DECAY) ? (chn.nRightVU - VUMETER_DECAY) : 0; chn.newLeftVol = chn.newRightVol = 0; chn.pCurrentSample = (chn.pModSample && chn.pModSample->HasSampleData() && chn.nLength && chn.IsSamplePlaying()) ? chn.pModSample->samplev() : nullptr; if(chn.pCurrentSample || (chn.HasMIDIOutput() && !chn.dwFlags[CHN_KEYOFF | CHN_NOTEFADE])) { // Update VU-Meter (nRealVolume is 14-bit) uint32 vul = (chn.nRealVolume * (256-chn.nRealPan)) / (1 << 14); if (vul > 127) vul = 127; if (chn.nLeftVU > 127) chn.nLeftVU = (uint8)vul; vul /= 2; if (chn.nLeftVU < vul) chn.nLeftVU = (uint8)vul; uint32 vur = (chn.nRealVolume * chn.nRealPan) / (1 << 14); if (vur > 127) vur = 127; if (chn.nRightVU > 127) chn.nRightVU = (uint8)vur; vur /= 2; if (chn.nRightVU < vur) chn.nRightVU = (uint8)vur; } else { // Note change but no sample if (chn.nLeftVU > 128) chn.nLeftVU = 0; if (chn.nRightVU > 128) chn.nRightVU = 0; } if (chn.pCurrentSample) { #ifdef MODPLUG_TRACKER const uint32 kChnMasterVol = chn.dwFlags[CHN_EXTRALOUD] ? (uint32)m_PlayConfig.getNormalSamplePreAmp() : nMasterVol; #else const uint32 kChnMasterVol = nMasterVol; #endif // MODPLUG_TRACKER // Adjusting volumes { int32 pan = (m_MixerSettings.gnChannels >= 2) ? Clamp(chn.nRealPan, 0, 256) : 128; int32 realvol = (chn.nRealVolume * kChnMasterVol) / 128; // Extra attenuation required here if we're bypassing pre-amp. if(!m_PlayConfig.getUseGlobalPreAmp()) realvol /= 2; const PanningMode panningMode = m_PlayConfig.getPanningMode(); if(panningMode == PanningMode::SoftPanning || (panningMode == PanningMode::Undetermined && (m_MixerSettings.MixerFlags & SNDMIX_SOFTPANNING))) { if(pan < 128) { chn.newLeftVol = (realvol * 128) / 256; chn.newRightVol = (realvol * pan) / 256; } else { chn.newLeftVol = (realvol * (256 - pan)) / 256; chn.newRightVol = (realvol * 128) / 256; } } else if(panningMode == PanningMode::FT2Panning) { // FT2 uses square root panning. There is a 257-entry LUT for this, // but FT2's internal panning ranges from 0 to 255 only, meaning that // you can never truly achieve 100% right panning in FT2, only 100% left. // Test case: FT2PanLaw.xm LimitMax(pan, 255); const int panL = pan > 0 ? XMPanningTable[256 - pan] : 65536; const int panR = XMPanningTable[pan]; chn.newLeftVol = (realvol * panL) / 65536; chn.newRightVol = (realvol * panR) / 65536; } else { chn.newLeftVol = (realvol * (256 - pan)) / 256; chn.newRightVol = (realvol * pan) / 256; } } // Clipping volumes //if (chn.nNewRightVol > 0xFFFF) chn.nNewRightVol = 0xFFFF; //if (chn.nNewLeftVol > 0xFFFF) chn.nNewLeftVol = 0xFFFF; if(chn.pModInstrument && Resampling::IsKnownMode(chn.pModInstrument->resampling)) { // For defined resampling modes, use per-instrument resampling mode if set chn.resamplingMode = chn.pModInstrument->resampling; } else if(Resampling::IsKnownMode(m_nResampling)) { chn.resamplingMode = m_nResampling; } else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga != Resampling::AmigaFilter::Off) { // Enforce Amiga resampler for Amiga modules chn.resamplingMode = SRCMODE_AMIGA; } else { // Default to global mixer settings chn.resamplingMode = m_Resampler.m_Settings.SrcMode; } if(chn.increment.IsUnity() && !(chn.dwFlags[CHN_VIBRATO] || chn.nAutoVibDepth || chn.resamplingMode == SRCMODE_AMIGA)) { // Exact sample rate match, do not interpolate at all // - unless vibrato is applied, because in this case the constant enabling and disabling // of resampling can introduce clicks (this is easily observable with a sine sample // played at the mix rate). chn.resamplingMode = SRCMODE_NEAREST; } const int extraAttenuation = m_PlayConfig.getExtraSampleAttenuation(); chn.newLeftVol /= (1 << extraAttenuation); chn.newRightVol /= (1 << extraAttenuation); // Dolby Pro-Logic Surround if(chn.dwFlags[CHN_SURROUND] && m_MixerSettings.gnChannels == 2) chn.newRightVol = -chn.newRightVol; // Checking Ping-Pong Loops if(chn.dwFlags[CHN_PINGPONGFLAG]) chn.increment.Negate(); // Setting up volume ramp ProcessRamping(chn); // Adding the channel in the channel list if(!chn.dwFlags[CHN_ADLIB]) { m_PlayState.ChnMix[m_nMixChannels++] = nChn; } } else { chn.rightVol = chn.leftVol = 0; chn.nLength = 0; // Put the channel back into the mixer for end-of-sample pop reduction if(chn.nLOfs || chn.nROfs) m_PlayState.ChnMix[m_nMixChannels++] = nChn; } chn.dwOldFlags = chn.dwFlags; chn.triggerNote = false; // For SONG_PAUSED mode } // If there are more channels being mixed than allowed, order them by volume and discard the most quiet ones if(m_nMixChannels >= m_MixerSettings.m_nMaxMixChannels) { std::partial_sort(std::begin(m_PlayState.ChnMix), std::begin(m_PlayState.ChnMix) + m_MixerSettings.m_nMaxMixChannels, std::begin(m_PlayState.ChnMix) + m_nMixChannels, [this](CHANNELINDEX i, CHANNELINDEX j) { return (m_PlayState.Chn[i].nRealVolume > m_PlayState.Chn[j].nRealVolume); }); } return true; } void CSoundFile::ProcessMacroOnChannel(CHANNELINDEX nChn) { ModChannel &chn = m_PlayState.Chn[nChn]; if(nChn < GetNumChannels()) { // TODO evaluate per-plugin macros here //ProcessMIDIMacro(m_PlayState, nChn, false, m_MidiCfg.Global[MIDIOUT_PAN]); //ProcessMIDIMacro(m_PlayState, nChn, false, m_MidiCfg.Global[MIDIOUT_VOLUME]); if((chn.rowCommand.command == CMD_MIDI && m_PlayState.m_flags[SONG_FIRSTTICK]) || chn.rowCommand.command == CMD_SMOOTHMIDI) { if(chn.rowCommand.param < 0x80) ProcessMIDIMacro(m_PlayState, nChn, (chn.rowCommand.command == CMD_SMOOTHMIDI), m_MidiCfg.SFx[chn.nActiveMacro], chn.rowCommand.param); else ProcessMIDIMacro(m_PlayState, nChn, (chn.rowCommand.command == CMD_SMOOTHMIDI), m_MidiCfg.Zxx[chn.rowCommand.param & 0x7F], chn.rowCommand.param); } } } #ifndef NO_PLUGINS void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn) { ModChannel &chn = m_PlayState.Chn[nChn]; // Do we need to process MIDI? // For now there is no difference between mute and sync mute with VSTis. if(chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE] || !chn.HasMIDIOutput()) return; // Get instrument info and plugin reference const ModInstrument *pIns = chn.pModInstrument; // Can't be nullptr at this point, as we have valid MIDI output. // No instrument or muted instrument? if(pIns->dwFlags[INS_MUTE]) { return; } // Check instrument plugins const PLUGINDEX nPlugin = GetBestPlugin(chn, nChn, PrioritiseInstrument, RespectMutes); IMixPlugin *pPlugin = nullptr; if(nPlugin > 0 && nPlugin <= MAX_MIXPLUGINS) { pPlugin = m_MixPlugins[nPlugin - 1].pMixPlugin; } // Couldn't find a valid plugin if(pPlugin == nullptr) return; const ModCommand::NOTE note = chn.rowCommand.note; // Check for volume commands uint8 vol = 0xFF; if(chn.rowCommand.volcmd == VOLCMD_VOLUME) vol = std::min(chn.rowCommand.vol, uint8(64)) * 2u; else if(chn.rowCommand.command == CMD_VOLUME) vol = std::min(chn.rowCommand.param, uint8(64)) * 2u; else if(chn.rowCommand.command == CMD_VOLUME8) vol = static_cast((chn.rowCommand.param + 1u) / 2u); const bool hasVolCommand = (vol != 0xFF); if(m_playBehaviour[kMIDICCBugEmulation]) { if(note != NOTE_NONE) { ModCommand::NOTE realNote = note; if(ModCommand::IsNote(note)) realNote = pIns->NoteMap[note - NOTE_MIN]; SendMIDINote(nChn, realNote, static_cast(chn.nVolume), m_playBehaviour[kMIDINotesFromChannelPlugin] ? pPlugin : nullptr); } else if(hasVolCommand) { pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Fine, vol / 2u, nChn); } return; } const uint32 defaultVolume = pIns->nGlobalVol; //If new note, determine notevelocity to use. if(note != NOTE_NONE) { int32 velocity = static_cast(4 * defaultVolume); switch(pIns->pluginVelocityHandling) { case PLUGIN_VELOCITYHANDLING_CHANNEL: velocity = hasVolCommand ? vol * 2 : chn.nVolume; break; default: break; } int32 swing = chn.nVolSwing; if(m_playBehaviour[kITSwingBehaviour]) swing *= 4; velocity += swing; Limit(velocity, 0, 256); ModCommand::NOTE realNote = note; if(ModCommand::IsNote(note)) realNote = pIns->NoteMap[note - NOTE_MIN]; // Experimental VST panning //ProcessMIDIMacro(nChn, false, m_MidiCfg.Global[MIDIOUT_PAN], 0, nPlugin); if(m_playBehaviour[kPluginIgnoreTonePortamento] || !chn.rowCommand.IsTonePortamento()) SendMIDINote(nChn, realNote, static_cast(velocity), m_playBehaviour[kMIDINotesFromChannelPlugin] ? pPlugin : nullptr); } const bool processVolumeAlsoOnNote = (pIns->pluginVelocityHandling == PLUGIN_VELOCITYHANDLING_VOLUME); const bool hasNote = m_playBehaviour[kMIDIVolumeOnNoteOffBug] ? (note != NOTE_NONE) : ModCommand::IsNote(note); if((hasVolCommand && !hasNote) || (hasNote && processVolumeAlsoOnNote)) { switch(pIns->pluginVolumeHandling) { case PLUGIN_VOLUMEHANDLING_DRYWET: if(hasVolCommand) pPlugin->SetDryRatio(1.0f - vol / 127.0f); else pPlugin->SetDryRatio(1.0f - static_cast(2 * defaultVolume) / 127.0f); break; case PLUGIN_VOLUMEHANDLING_MIDI: if(hasVolCommand) pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, std::min(uint8(127), vol), nChn); else pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, static_cast(std::min(uint32(127), static_cast(2 * defaultVolume))), nChn); break; default: break; } } } #endif // NO_PLUGINS template MPT_FORCEINLINE void ApplyGlobalVolumeWithRamping(int32 *SoundBuffer, int32 *RearBuffer, uint32 lCount, int32 m_nGlobalVolume, int32 step, int32 &m_nSamplesToGlobalVolRampDest, int32 &m_lHighResRampingGlobalVolume) { const bool isStereo = (channels >= 2); const bool hasRear = (channels >= 4); for(uint32 pos = 0; pos < lCount; ++pos) { if(m_nSamplesToGlobalVolRampDest > 0) { // Ramping required m_lHighResRampingGlobalVolume += step; SoundBuffer[0] = Util::muldiv(SoundBuffer[0], m_lHighResRampingGlobalVolume, MAX_GLOBAL_VOLUME << VOLUMERAMPPRECISION); if constexpr(isStereo) SoundBuffer[1] = Util::muldiv(SoundBuffer[1], m_lHighResRampingGlobalVolume, MAX_GLOBAL_VOLUME << VOLUMERAMPPRECISION); if constexpr(hasRear) RearBuffer[0] = Util::muldiv(RearBuffer[0] , m_lHighResRampingGlobalVolume, MAX_GLOBAL_VOLUME << VOLUMERAMPPRECISION); else MPT_UNUSED_VARIABLE(RearBuffer); if constexpr(hasRear) RearBuffer[1] = Util::muldiv(RearBuffer[1] , m_lHighResRampingGlobalVolume, MAX_GLOBAL_VOLUME << VOLUMERAMPPRECISION); else MPT_UNUSED_VARIABLE(RearBuffer); m_nSamplesToGlobalVolRampDest--; } else { SoundBuffer[0] = Util::muldiv(SoundBuffer[0], m_nGlobalVolume, MAX_GLOBAL_VOLUME); if constexpr(isStereo) SoundBuffer[1] = Util::muldiv(SoundBuffer[1], m_nGlobalVolume, MAX_GLOBAL_VOLUME); if constexpr(hasRear) RearBuffer[0] = Util::muldiv(RearBuffer[0] , m_nGlobalVolume, MAX_GLOBAL_VOLUME); else MPT_UNUSED_VARIABLE(RearBuffer); if constexpr(hasRear) RearBuffer[1] = Util::muldiv(RearBuffer[1] , m_nGlobalVolume, MAX_GLOBAL_VOLUME); else MPT_UNUSED_VARIABLE(RearBuffer); m_lHighResRampingGlobalVolume = m_nGlobalVolume << VOLUMERAMPPRECISION; } SoundBuffer += isStereo ? 2 : 1; if constexpr(hasRear) RearBuffer += 2; } } void CSoundFile::ProcessGlobalVolume(samplecount_t lCount) { // should we ramp? if(IsGlobalVolumeUnset()) { // do not ramp if no global volume was set before (which is the case at song start), to prevent audible glitches when default volume is > 0 and it is set to 0 in the first row m_PlayState.m_nGlobalVolumeDestination = m_PlayState.m_nGlobalVolume; m_PlayState.m_nSamplesToGlobalVolRampDest = 0; m_PlayState.m_nGlobalVolumeRampAmount = 0; } else if(m_PlayState.m_nGlobalVolumeDestination != m_PlayState.m_nGlobalVolume) { // User has provided new global volume // m_nGlobalVolume: the last global volume which got set e.g. by a pattern command // m_nGlobalVolumeDestination: the current target of the ramping algorithm const bool rampUp = m_PlayState.m_nGlobalVolume > m_PlayState.m_nGlobalVolumeDestination; m_PlayState.m_nGlobalVolumeDestination = m_PlayState.m_nGlobalVolume; m_PlayState.m_nSamplesToGlobalVolRampDest = m_PlayState.m_nGlobalVolumeRampAmount = rampUp ? m_MixerSettings.GetVolumeRampUpSamples() : m_MixerSettings.GetVolumeRampDownSamples(); } // calculate ramping step int32 step = 0; if (m_PlayState.m_nSamplesToGlobalVolRampDest > 0) { // Still some ramping left to do. int32 highResGlobalVolumeDestination = static_cast(m_PlayState.m_nGlobalVolumeDestination) << VOLUMERAMPPRECISION; const int32 delta = highResGlobalVolumeDestination - m_PlayState.m_lHighResRampingGlobalVolume; step = delta / m_PlayState.m_nSamplesToGlobalVolRampDest; if(m_nMixLevels == MixLevels::v1_17RC2) { // Define max step size as some factor of user defined ramping value: the lower the value, the more likely the click. // If step is too big (might cause click), extend ramp length. // Warning: This increases the volume ramp length by EXTREME amounts (factors of 100 are easily reachable) // compared to the user-defined setting, so this really should not be used! int32 maxStep = std::max(int32(50), static_cast((10000 / (m_PlayState.m_nGlobalVolumeRampAmount + 1)))); while(std::abs(step) > maxStep) { m_PlayState.m_nSamplesToGlobalVolRampDest += m_PlayState.m_nGlobalVolumeRampAmount; step = delta / static_cast(m_PlayState.m_nSamplesToGlobalVolRampDest); } } } // apply volume and ramping if(m_MixerSettings.gnChannels == 1) { ApplyGlobalVolumeWithRamping<1>(MixSoundBuffer, MixRearBuffer, lCount, m_PlayState.m_nGlobalVolume, step, m_PlayState.m_nSamplesToGlobalVolRampDest, m_PlayState.m_lHighResRampingGlobalVolume); } else if(m_MixerSettings.gnChannels == 2) { ApplyGlobalVolumeWithRamping<2>(MixSoundBuffer, MixRearBuffer, lCount, m_PlayState.m_nGlobalVolume, step, m_PlayState.m_nSamplesToGlobalVolRampDest, m_PlayState.m_lHighResRampingGlobalVolume); } else if(m_MixerSettings.gnChannels == 4) { ApplyGlobalVolumeWithRamping<4>(MixSoundBuffer, MixRearBuffer, lCount, m_PlayState.m_nGlobalVolume, step, m_PlayState.m_nSamplesToGlobalVolRampDest, m_PlayState.m_lHighResRampingGlobalVolume); } } void CSoundFile::ProcessStereoSeparation(samplecount_t countChunk) { ApplyStereoSeparation(MixSoundBuffer, MixRearBuffer, m_MixerSettings.gnChannels, countChunk, m_MixerSettings.m_nStereoSeparation); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_rtm.cpp0000644000175000017500000003013314644610543020351 00000000000000/* * Load_rtm.cpp * ------------ * Purpose: Real Tracker 2 (RTM) module Loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct RTMObjectHeader { char id[4]; // "RTMM" for song header, "RTND" for patterns, "RTIN" for instruments, "RTSM" for samples uint8 space; char name[32]; uint8 eof; uint16le version; uint16le objectSize; bool IsValid() const { return !memcmp(id, "RTMM", 4) && space == 0x20 && eof == 0x1A && version >= 0x100 && version <= 0x112 && objectSize >= 98; } }; MPT_BINARY_STRUCT(RTMObjectHeader, 42) struct RTMMHeader { enum SongFlags { songLinearSlides = 0x01, songTrackNames = 0x02, }; char software[20]; char composer[32]; uint16le flags; uint8 numChannels; uint8 numInstruments; uint16le numOrders; uint16le numPatterns; uint8 speed; uint8 tempo; int8 panning[32]; uint32le extraDataSize; // Order list / track names char originalName[32]; bool IsValid() const { return numChannels > 0 && numChannels <= 32 && numOrders <= 999 && numPatterns <= 999 && speed != 0 && extraDataSize < 0x10000; } static constexpr size_t HeaderProbingSize() { return offsetof(RTMMHeader, originalName); } uint32 GetHeaderMinimumAdditionalSize() const { return extraDataSize; } }; MPT_BINARY_STRUCT(RTMMHeader, 130) // Pattern header (RTND magic bytes) struct RTMPatternHeader { uint16le flags; // Always 1 uint8 numTracks; uint16le numRows; uint32le packedSize; }; MPT_BINARY_STRUCT(RTMPatternHeader, 9) struct RTMEnvelope { enum EnvelopeFlags { envEnabled = 0x01, envSustain = 0x02, envLoop = 0x04, }; struct EnvPoint { uint32le x; int32le y; }; uint8 numPoints; EnvPoint points[12]; uint8 sustainPoint; uint8 loopStart; uint8 loopEnd; uint16le flags; void ConvertToMPT(InstrumentEnvelope &mptEnv, int8 offset) const { mptEnv.resize(std::min(numPoints, uint8(12))); mptEnv.nSustainStart = mptEnv.nSustainEnd = sustainPoint; mptEnv.nLoopStart = loopStart; mptEnv.nLoopEnd = loopEnd; mptEnv.dwFlags.set(ENV_ENABLED, flags & envEnabled); mptEnv.dwFlags.set(ENV_SUSTAIN, flags & envSustain); mptEnv.dwFlags.set(ENV_LOOP, flags & envLoop); for(size_t i = 0; i < mptEnv.size(); i++) { mptEnv[i].tick = mpt::saturate_cast(points[i].x.get()); mptEnv[i].value = mpt::saturate_cast(points[i].y + offset); } } }; MPT_BINARY_STRUCT(RTMEnvelope, 102) // Instrument header (RTIN magic bytes) struct RTINHeader { enum InstrumentFlags { insDefaultPanning = 0x01, insMuteSamples = 0x02, }; uint8 numSamples; uint16le flags; uint8 samples[120]; RTMEnvelope volumeEnv; RTMEnvelope panningEnv; uint8 vibratoType; uint8 vibratoSweep; uint8 vibratoDepth; uint8 vibratoRate; uint16le fadeOut; uint8 midiPort; uint8 midiChannel; uint8 midiProgram; uint8 midiEnable; int8 midiTranspose; uint8 midiBenderRange; uint8 midiBaseVolume; uint8 midiUseVelocity; void ConvertToMPT(ModInstrument &mptIns, SAMPLEINDEX baseSample) const { mptIns.nFadeOut = fadeOut / 2; volumeEnv.ConvertToMPT(mptIns.VolEnv, 0); panningEnv.ConvertToMPT(mptIns.PanEnv, ENVELOPE_MID); if(flags & insMuteSamples) mptIns.nGlobalVol = 0; static_assert(mpt::array_size::size <= mpt::array_size::size); for(size_t i = 0; i < std::size(samples); i++) { mptIns.Keyboard[i] = baseSample + samples[i]; } if(midiEnable) { mptIns.nMidiChannel = MidiFirstChannel + midiChannel; mptIns.nMidiProgram = midiProgram + 1; mptIns.midiPWD = midiBenderRange; } } }; MPT_BINARY_STRUCT(RTINHeader, 341) // Sample header (RTSM magic bytes) struct RTSMHeader { enum SampleFlags { smp16Bit = 0x02, smpDelta = 0x04, }; uint16le flags; uint8 baseVolume; // 0...64 uint8 defaultVolume; // 0...64 uint32le length; uint8 loopType; // 0 = no loop, 1 = forward loop, 2 = ping-pong loop char reserved[3]; uint32le loopStart; uint32le loopEnd; uint32le sampleRate; uint8 baseNote; int8 panning; // -64...64 void ConvertToMPT(ModSample &mptSmp, const RTINHeader &insHeader) const { mptSmp.Initialize(MOD_TYPE_IT); mptSmp.nVolume = defaultVolume * 4; mptSmp.nGlobalVol = baseVolume; mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; if(flags & smp16Bit) { mptSmp.nLength /= 2; mptSmp.nLoopStart /= 2; mptSmp.nLoopEnd /= 2; } mptSmp.uFlags.set(CHN_PANNING, insHeader.flags & RTINHeader::insDefaultPanning); mptSmp.uFlags.set(CHN_LOOP, loopType != 0); mptSmp.uFlags.set(CHN_SUSTAINLOOP, loopType == 2); mptSmp.nC5Speed = sampleRate; mptSmp.Transpose((48 - baseNote) / 12.0); mptSmp.nPan = static_cast((panning + 64) * 2); mptSmp.nVibType = static_cast(insHeader.vibratoType); mptSmp.nVibDepth = insHeader.vibratoDepth * 2; mptSmp.nVibRate = insHeader.vibratoRate / 2; mptSmp.nVibSweep = insHeader.vibratoSweep; if(mptSmp.nVibSweep != 0) mptSmp.nVibSweep = mpt::saturate_cast(Util::muldivr_unsigned(mptSmp.nVibDepth, 256, mptSmp.nVibSweep)); else mptSmp.nVibSweep = 255; } SampleIO GetSampleFormat() const { return SampleIO{(flags & smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, (flags & smpDelta) ? SampleIO::deltaPCM: SampleIO::signedPCM}; } }; MPT_BINARY_STRUCT(RTSMHeader, 26) static void ConvertRTMEffect(ModCommand &m, const uint8 command, const uint8 param, const CSoundFile &sndFile) { // Commands not handled: M (Select MIDI controller), V (Select MIDI controller value) if(command == 8) m.SetEffectCommand(CMD_PANNING8, mpt::saturate_cast(param * 2)); else if(command == 'S' - 55 && (param & 0xF0) == 0xA0) m.SetEffectCommand(CMD_S3MCMDEX, param); else if(command <= 'X' - 55) { CSoundFile::ConvertModCommand(m, command, param); m.Convert(MOD_TYPE_XM, MOD_TYPE_IT, sndFile); } else if(command == 36) m.SetEffectCommand(CMD_VOLUMESLIDE, param); else if(command == 37) m.SetEffectCommand(CMD_PORTAMENTOUP, param); else if(command == 38) m.SetEffectCommand(CMD_PORTAMENTODOWN, param); else if(command == 39) m.SetEffectCommand(CMD_VIBRATOVOL, param); else if(command == 40) m.SetEffectCommand(CMD_SPEED, param); } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderRTM(MemoryFileReader file, const uint64* pfilesize) { RTMObjectHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; RTMMHeader songHeader; if(file.ReadStructPartial(songHeader, RTMMHeader::HeaderProbingSize()) < RTMMHeader::HeaderProbingSize()) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.objectSize - RTMMHeader::HeaderProbingSize() + songHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadRTM(FileReader& file, ModLoadingFlags loadFlags) { file.Rewind(); RTMObjectHeader fileHeader; if(!file.ReadStruct(fileHeader)) return false; if(!fileHeader.IsValid()) return false; RTMMHeader songHeader; if(file.ReadStructPartial(songHeader, fileHeader.objectSize) < fileHeader.objectSize) return false; if(!songHeader.IsValid()) return false; if(!file.CanRead(songHeader.GetHeaderMinimumAdditionalSize())) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_IT, songHeader.numChannels); m_nInstruments = std::min(static_cast(songHeader.numInstruments), static_cast(MAX_INSTRUMENTS - 1)); m_SongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS; m_SongFlags.set(SONG_LINEARSLIDES, songHeader.flags & RTMMHeader::songLinearSlides); Order().SetDefaultTempoInt(songHeader.tempo); Order().SetDefaultSpeed(songHeader.speed); m_songArtist = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::maybeNullTerminated, songHeader.composer)); m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.name); if(fileHeader.version >= 0x112) { if(m_songName.empty()) m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, songHeader.originalName); else m_songMessage.SetRaw(mpt::String::ReadBuf(mpt::String::maybeNullTerminated, songHeader.originalName)); } FileReader extraData = file.ReadChunk(songHeader.extraDataSize); ReadOrderFromFile(Order(), extraData, songHeader.numOrders); for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = static_cast((songHeader.panning[chn] + 64) * 2); if(songHeader.flags & RTMMHeader::songTrackNames) extraData.ReadString(ChnSettings[chn].szName, 16); } m_modFormat.formatName = MPT_UFORMAT("Real Tracker {}.{}")(fileHeader.version >> 8, mpt::ufmt::hex0<2>(fileHeader.version & 0xFF)); m_modFormat.type = UL_("rtm"); m_modFormat.madeWithTracker = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::maybeNullTerminated, songHeader.software)); m_modFormat.charset = mpt::Charset::CP437; Patterns.ResizeArray(songHeader.numPatterns); for(PATTERNINDEX pat = 0; pat < songHeader.numPatterns; pat++) { RTMObjectHeader objectHeader; if(!file.ReadStruct(objectHeader)) return false; RTMPatternHeader patHeader; file.ReadStructPartial(patHeader, objectHeader.objectSize); FileReader patternData = file.ReadChunk(patHeader.packedSize); if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, patHeader.numRows)) continue; Patterns[pat].SetName(mpt::String::ReadBuf(mpt::String::maybeNullTerminated, objectHeader.name)); ROWINDEX row = 0; CHANNELINDEX chn = 0; auto rowData = Patterns[pat].GetRow(0); while(row < patHeader.numRows && patternData.CanRead(1)) { const uint8 b = patternData.ReadUint8(); if(b == 0) { row++; chn = 0; if(row < patHeader.numRows) rowData = Patterns[pat].GetRow(row); continue; } if(b & 0x01) chn = patternData.ReadUint8(); if(chn >= GetNumChannels()) return false; ModCommand &m = rowData[chn]; if(b & 0x02) { uint8 note = patternData.ReadUint8(); if(note == 0xFE) m.note = NOTE_KEYOFF; else if(note < 120) m.note = note + NOTE_MIDDLEC - 48; } if(b & 0x04) m.instr = patternData.ReadUint8(); uint8 cmd1 = 0, param1 = 0, cmd2 = 0, param2 = 0; if(b & 0x08) cmd1 = patternData.ReadUint8(); if(b & 0x10) param1 = patternData.ReadUint8(); if(b & 0x20) cmd2 = patternData.ReadUint8(); if(b & 0x40) param2 = patternData.ReadUint8(); if(cmd1 || param1) ConvertRTMEffect(m, cmd1, param1, *this); if(cmd2 || param2) { ModCommand dummy; ConvertRTMEffect(dummy, cmd2, param2, *this); m.FillInTwoCommands(m.command, m.param, dummy.command, dummy.param); } chn++; } } for(INSTRUMENTINDEX instr = 1; instr <= m_nInstruments; instr++) { RTMObjectHeader objectHeader; if(!file.ReadStruct(objectHeader)) return false; RTINHeader insHeader; file.ReadStructPartial(insHeader, objectHeader.objectSize); if(!AllocateInstrument(instr)) return false; insHeader.ConvertToMPT(*Instruments[instr], m_nSamples + 1); Instruments[instr]->name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, objectHeader.name); for(SAMPLEINDEX smp = 0; smp < insHeader.numSamples; smp++) { RTMObjectHeader smpObjectHeader; if(!file.ReadStruct(smpObjectHeader)) return false; RTSMHeader smpHeader; file.ReadStructPartial(smpHeader, smpObjectHeader.objectSize); FileReader sampleData = file.ReadChunk(smpHeader.length); if(!CanAddMoreSamples()) continue; ModSample &mptSmp = Samples[++m_nSamples]; smpHeader.ConvertToMPT(mptSmp, insHeader); m_szNames[m_nSamples] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, smpObjectHeader.name); if(loadFlags & loadSampleData) smpHeader.GetSampleFormat().ReadSample(mptSmp, sampleData); } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/IntMixer.h0000644000175000017500000003267014376464777020046 00000000000000/* * IntMixer.h * ---------- * Purpose: Fixed point mixer classes * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Resampler.h" #include "MixerInterface.h" #include "Paula.h" OPENMPT_NAMESPACE_BEGIN template struct IntToIntTraits : public MixerTraits { using base_t = MixerTraits; using input_t = typename base_t::input_t; using output_t = typename base_t::output_t; static MPT_CONSTEXPRINLINE output_t Convert(const input_t x) { static_assert(std::numeric_limits::is_integer, "Input must be integer"); static_assert(std::numeric_limits::is_integer, "Output must be integer"); static_assert(sizeof(out) * 8 >= mixPrecision, "Mix precision is higher than output type can handle"); static_assert(sizeof(in) * 8 <= mixPrecision, "Mix precision is lower than input type"); return static_cast(x) * (1<<(mixPrecision - sizeof(in) * 8)); } }; using Int8MToIntS = IntToIntTraits<2, 1, mixsample_t, int8, 16>; using Int16MToIntS = IntToIntTraits<2, 1, mixsample_t, int16, 16>; using Int8SToIntS = IntToIntTraits<2, 2, mixsample_t, int8, 16>; using Int16SToIntS = IntToIntTraits<2, 2, mixsample_t, int16, 16>; ////////////////////////////////////////////////////////////////////////// // Interpolation templates template struct AmigaBlepInterpolation { SamplePosition subIncrement; Paula::State &paula; const Paula::BlepArray &WinSincIntegral; const int numSteps; unsigned int remainingSamples = 0; MPT_FORCEINLINE AmigaBlepInterpolation(ModChannel &chn, const CResampler &resampler, unsigned int numSamples) : paula{chn.paulaState} , WinSincIntegral{resampler.blepTables.GetAmigaTable(resampler.m_Settings.emulateAmiga, chn.dwFlags[CHN_AMIGAFILTER])} , numSteps{chn.paulaState.numSteps} { if(numSteps) { subIncrement = chn.increment / numSteps; // May we read past the start or end of sample if we do partial sample increments? // If that's the case, don't apply any sub increments on the source sample if we reached the last output sample // Note that this should only happen with notes well outside the Amiga note range, e.g. in software-mixed formats like MED const int32 targetPos = (chn.position + chn.increment * numSamples).GetInt(); if(static_cast(targetPos) > chn.nLength) remainingSamples = numSamples; } } MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo) { if(--remainingSamples == 0) subIncrement = {}; SamplePosition pos(0, posLo); // First, process steps of full length (one Amiga clock interval) for(int step = numSteps; step > 0; step--) { typename Traits::output_t inSample = 0; int32 posInt = pos.GetInt() * Traits::numChannelsIn; for(int32 i = 0; i < Traits::numChannelsIn; i++) inSample += Traits::Convert(inBuffer[posInt + i]); paula.InputSample(static_cast(inSample / (4 * Traits::numChannelsIn))); paula.Clock(Paula::MINIMUM_INTERVAL); pos += subIncrement; } paula.remainder += paula.stepRemainder; // Now, process any remaining integer clock amount < MINIMUM_INTERVAL uint32 remainClocks = paula.remainder.GetInt(); if(remainClocks) { typename Traits::output_t inSample = 0; int32 posInt = pos.GetInt() * Traits::numChannelsIn; for(int32 i = 0; i < Traits::numChannelsIn; i++) inSample += Traits::Convert(inBuffer[posInt + i]); paula.InputSample(static_cast(inSample / (4 * Traits::numChannelsIn))); paula.Clock(remainClocks); paula.remainder.RemoveInt(); } auto out = paula.OutputSample(WinSincIntegral); for(int i = 0; i < Traits::numChannelsOut; i++) outSample[i] = out; } }; template struct LinearInterpolation { MPT_FORCEINLINE LinearInterpolation(const ModChannel &, const CResampler &, unsigned int) { } MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo) { static_assert(static_cast(Traits::numChannelsIn) <= static_cast(Traits::numChannelsOut), "Too many input channels"); const typename Traits::output_t fract = posLo >> 18u; for(int i = 0; i < Traits::numChannelsIn; i++) { typename Traits::output_t srcVol = Traits::Convert(inBuffer[i]); typename Traits::output_t destVol = Traits::Convert(inBuffer[i + Traits::numChannelsIn]); outSample[i] = srcVol + ((fract * (destVol - srcVol)) / 16384); } } }; template struct FastSincInterpolation { MPT_FORCEINLINE FastSincInterpolation(const ModChannel &, const CResampler &, unsigned int) { } MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo) { static_assert(static_cast(Traits::numChannelsIn) <= static_cast(Traits::numChannelsOut), "Too many input channels"); const int16 *lut = CResampler::FastSincTable + ((posLo >> 22) & 0x3FC); for(int i = 0; i < Traits::numChannelsIn; i++) { outSample[i] = (lut[0] * Traits::Convert(inBuffer[i - Traits::numChannelsIn]) + lut[1] * Traits::Convert(inBuffer[i]) + lut[2] * Traits::Convert(inBuffer[i + Traits::numChannelsIn]) + lut[3] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn])) / 16384; } } }; template struct PolyphaseInterpolation { const SINC_TYPE *sinc; MPT_FORCEINLINE PolyphaseInterpolation(const ModChannel &chn, const CResampler &resampler, unsigned int) { #ifdef MODPLUG_TRACKER // Otherwise causes "warning C4100: 'resampler' : unreferenced formal parameter" // because all 3 tables are static members. // #pragma warning fails with this templated case for unknown reasons. MPT_UNREFERENCED_PARAMETER(resampler); #endif // MODPLUG_TRACKER sinc = (((chn.increment > SamplePosition(0x130000000ll)) || (chn.increment < SamplePosition(-0x130000000ll))) ? (((chn.increment > SamplePosition(0x180000000ll)) || (chn.increment < SamplePosition(-0x180000000ll))) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc); } MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo) { static_assert(static_cast(Traits::numChannelsIn) <= static_cast(Traits::numChannelsOut), "Too many input channels"); const SINC_TYPE *lut = sinc + ((posLo >> (32 - SINC_PHASES_BITS)) & SINC_MASK) * SINC_WIDTH; for(int i = 0; i < Traits::numChannelsIn; i++) { outSample[i] = (lut[0] * Traits::Convert(inBuffer[i - 3 * Traits::numChannelsIn]) + lut[1] * Traits::Convert(inBuffer[i - 2 * Traits::numChannelsIn]) + lut[2] * Traits::Convert(inBuffer[i - Traits::numChannelsIn]) + lut[3] * Traits::Convert(inBuffer[i]) + lut[4] * Traits::Convert(inBuffer[i + Traits::numChannelsIn]) + lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn]) + lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn]) + lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn])) / (1 << SINC_QUANTSHIFT); } } }; template struct FIRFilterInterpolation { const int16 *WFIRlut; MPT_FORCEINLINE FIRFilterInterpolation(const ModChannel &, const CResampler &resampler, unsigned int) { WFIRlut = resampler.m_WindowedFIR.lut; } MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo) { static_assert(static_cast(Traits::numChannelsIn) <= static_cast(Traits::numChannelsOut), "Too many input channels"); const int16 * const lut = WFIRlut + ((((posLo >> 16) + WFIR_FRACHALVE) >> WFIR_FRACSHIFT) & WFIR_FRACMASK); for(int i = 0; i < Traits::numChannelsIn; i++) { typename Traits::output_t vol1 = (lut[0] * Traits::Convert(inBuffer[i - 3 * Traits::numChannelsIn])) + (lut[1] * Traits::Convert(inBuffer[i - 2 * Traits::numChannelsIn])) + (lut[2] * Traits::Convert(inBuffer[i - Traits::numChannelsIn])) + (lut[3] * Traits::Convert(inBuffer[i])); typename Traits::output_t vol2 = (lut[4] * Traits::Convert(inBuffer[i + 1 * Traits::numChannelsIn])) + (lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn])) + (lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn])) + (lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn])); outSample[i] = ((vol1 / 2) + (vol2 / 2)) / (1 << (WFIR_16BITSHIFT - 1)); } } }; ////////////////////////////////////////////////////////////////////////// // Mixing templates (add sample to stereo mix) template struct NoRamp { typename Traits::output_t lVol, rVol; MPT_FORCEINLINE NoRamp(const ModChannel &chn) { lVol = chn.leftVol; rVol = chn.rightVol; } }; struct Ramp { ModChannel &channel; int32 lRamp, rRamp; MPT_FORCEINLINE Ramp(ModChannel &chn) : channel{chn} { lRamp = chn.rampLeftVol; rRamp = chn.rampRightVol; } MPT_FORCEINLINE ~Ramp() { channel.rampLeftVol = lRamp; channel.leftVol = lRamp >> VOLUMERAMPPRECISION; channel.rampRightVol = rRamp; channel.rightVol = rRamp >> VOLUMERAMPPRECISION; } }; // Legacy optimization: If chn.nLeftVol == chn.nRightVol, save one multiplication instruction template struct MixMonoFastNoRamp : public NoRamp { using base_t = NoRamp; MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer) { typename Traits::output_t vol = outSample[0] * base_t::lVol; for(int i = 0; i < Traits::numChannelsOut; i++) { outBuffer[i] += vol; } } }; template struct MixMonoNoRamp : public NoRamp { using base_t = NoRamp; MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer) { outBuffer[0] += outSample[0] * base_t::lVol; outBuffer[1] += outSample[0] * base_t::rVol; } }; template struct MixMonoRamp : public Ramp { MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const MPT_RESTRICT outBuffer) { lRamp += chn.leftRamp; rRamp += chn.rightRamp; outBuffer[0] += outSample[0] * (lRamp >> VOLUMERAMPPRECISION); outBuffer[1] += outSample[0] * (rRamp >> VOLUMERAMPPRECISION); } }; template struct MixStereoNoRamp : public NoRamp { using base_t = NoRamp; MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer) { outBuffer[0] += outSample[0] * base_t::lVol; outBuffer[1] += outSample[1] * base_t::rVol; } }; template struct MixStereoRamp : public Ramp { MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const MPT_RESTRICT outBuffer) { lRamp += chn.leftRamp; rRamp += chn.rightRamp; outBuffer[0] += outSample[0] * (lRamp >> VOLUMERAMPPRECISION); outBuffer[1] += outSample[1] * (rRamp >> VOLUMERAMPPRECISION); } }; ////////////////////////////////////////////////////////////////////////// // Filter templates template struct NoFilter { MPT_FORCEINLINE NoFilter(const ModChannel &) { } MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &, const ModChannel &) { } }; // Resonant filter template struct ResonantFilter { ModChannel &channel; // Filter history typename Traits::output_t fy[Traits::numChannelsIn][2]; MPT_FORCEINLINE ResonantFilter(ModChannel &chn) : channel{chn} { for(int i = 0; i < Traits::numChannelsIn; i++) { fy[i][0] = chn.nFilter_Y[i][0]; fy[i][1] = chn.nFilter_Y[i][1]; } } MPT_FORCEINLINE ~ResonantFilter() { for(int i = 0; i < Traits::numChannelsIn; i++) { channel.nFilter_Y[i][0] = fy[i][0]; channel.nFilter_Y[i][1] = fy[i][1]; } } // To avoid a precision loss in the state variables especially with quiet samples at low cutoff and high mix rate, we pre-amplify the sample. #define MIXING_FILTER_PREAMP 256 // Filter values are clipped to double the input range #define ClipFilter(x) Clamp(x, int16_min * 2 * MIXING_FILTER_PREAMP, int16_max * 2 * MIXING_FILTER_PREAMP) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const ModChannel &chn) { static_assert(static_cast(Traits::numChannelsIn) <= static_cast(Traits::numChannelsOut), "Too many input channels"); for(int i = 0; i < Traits::numChannelsIn; i++) { const auto inputAmp = outSample[i] * MIXING_FILTER_PREAMP; typename Traits::output_t val = static_cast(mpt::rshift_signed( Util::mul32to64(inputAmp, chn.nFilter_A0) + Util::mul32to64(ClipFilter(fy[i][0]), chn.nFilter_B0) + Util::mul32to64(ClipFilter(fy[i][1]), chn.nFilter_B1) + (1 << (MIXING_FILTER_PRECISION - 1)), MIXING_FILTER_PRECISION)); fy[i][1] = fy[i][0]; fy[i][0] = val - (inputAmp & chn.nFilter_HP); outSample[i] = val / MIXING_FILTER_PREAMP; } } #undef ClipFilter }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_imf.cpp0000644000175000017500000004170614717445260020335 00000000000000/* * Load_imf.cpp * ------------ * Purpose: IMF (Imago Orpheus) module loader * Notes : Reverb and Chorus are not supported. * Authors: Storlek (Original author - http://schismtracker.org/ - code ported with permission) * Johannes Schultz (OpenMPT Port, tweaks) * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct IMFChannel { char name[12]; // Channel name (ASCIIZ-String, max 11 chars) uint8 chorus; // Default chorus uint8 reverb; // Default reverb uint8 panning; // Pan positions 00-FF uint8 status; // Channel status: 0 = enabled, 1 = mute, 2 = disabled (ignore effects!) }; MPT_BINARY_STRUCT(IMFChannel, 16) struct IMFFileHeader { enum SongFlags { linearSlides = 0x01, }; char title[32]; // Songname (ASCIIZ-String, max. 31 chars) uint16le ordNum; // Number of orders saved uint16le patNum; // Number of patterns saved uint16le insNum; // Number of instruments saved uint16le flags; // See SongFlags uint8le unused1[8]; uint8le tempo; // Default tempo (Axx, 1...255) uint8le bpm; // Default beats per minute (BPM) (Txx, 32...255) uint8le master; // Default master volume (Vxx, 0...64) uint8le amp; // Amplification factor (mixing volume, 4...127) uint8le unused2[8]; char im10[4]; // 'IM10' IMFChannel channels[32]; // Channel settings CHANNELINDEX GetNumChannels() const { uint8 detectedChannels = 0; for(uint8 chn = 0; chn < 32; chn++) { if(channels[chn].status < 2) detectedChannels = chn + 1; else if(channels[chn].status > 2) return 0; } return detectedChannels; } }; MPT_BINARY_STRUCT(IMFFileHeader, 576) struct IMFEnvelope { enum EnvFlags { envEnabled = 0x01, envSustain = 0x02, envLoop = 0x04, }; uint8 points; // Number of envelope points uint8 sustain; // Envelope sustain point uint8 loopStart; // Envelope loop start point uint8 loopEnd; // Envelope loop end point uint8 flags; // See EnvFlags uint8 unused[3]; }; MPT_BINARY_STRUCT(IMFEnvelope, 8) struct IMFEnvNode { uint16le tick; uint16le value; }; MPT_BINARY_STRUCT(IMFEnvNode, 4) struct IMFInstrument { enum EnvTypes { volEnv = 0, panEnv = 1, filterEnv = 2, }; char name[32]; // Inst. name (ASCIIZ-String, max. 31 chars) uint8le map[120]; // Multisample settings uint8le unused[8]; IMFEnvNode nodes[3][16]; IMFEnvelope env[3]; uint16le fadeout; // Fadeout rate (0...0FFFH) uint16le smpNum; // Number of samples in instrument char ii10[4]; // 'II10' (not verified by Orpheus) void ConvertEnvelope(InstrumentEnvelope &mptEnv, EnvTypes e) const { const uint8 shift = (e == volEnv) ? 0 : 2; const uint8 mirror = (e == filterEnv) ? 0xFF : 0x00; mptEnv.dwFlags.set(ENV_ENABLED, (env[e].flags & 1) != 0); mptEnv.dwFlags.set(ENV_SUSTAIN, (env[e].flags & 2) != 0); mptEnv.dwFlags.set(ENV_LOOP, (env[e].flags & 4) != 0); mptEnv.resize(Clamp(env[e].points, uint8(2), uint8(16))); mptEnv.nLoopStart = env[e].loopStart; mptEnv.nLoopEnd = env[e].loopEnd; mptEnv.nSustainStart = mptEnv.nSustainEnd = env[e].sustain; uint16 minTick = 0; // minimum tick value for next node for(uint32 n = 0; n < mptEnv.size(); n++) { mptEnv[n].tick = minTick = std::max(minTick, nodes[e][n].tick.get()); minTick++; uint8 value = static_cast(nodes[e][n].value ^ mirror) >> shift; mptEnv[n].value = std::min(value, uint8(ENVELOPE_MAX)); } mptEnv.Convert(MOD_TYPE_XM, MOD_TYPE_IT); } // Convert an IMFInstrument to OpenMPT's internal instrument representation. void ConvertToMPT(ModInstrument &mptIns, SAMPLEINDEX firstSample) const { mptIns.name = mpt::String::ReadBuf(mpt::String::nullTerminated, name); if(smpNum) { for(size_t note = 0; note < std::min(std::size(map), std::size(mptIns.Keyboard) - 12u); note++) { mptIns.Keyboard[note + 12] = firstSample + map[note]; } } mptIns.nFadeOut = fadeout; mptIns.midiPWD = 1; // For CMD_FINETUNE ConvertEnvelope(mptIns.VolEnv, volEnv); ConvertEnvelope(mptIns.PanEnv, panEnv); ConvertEnvelope(mptIns.PitchEnv, filterEnv); if(mptIns.PitchEnv.dwFlags[ENV_ENABLED]) mptIns.PitchEnv.dwFlags.set(ENV_FILTER); // hack to get === to stop notes if(!mptIns.VolEnv.dwFlags[ENV_ENABLED] && !mptIns.nFadeOut) mptIns.nFadeOut = 32767; } }; MPT_BINARY_STRUCT(IMFInstrument, 384) struct IMFSample { enum SampleFlags { smpLoop = 0x01, smpPingPongLoop = 0x02, smp16Bit = 0x04, smpPanning = 0x08, }; char filename[13]; // Sample filename (12345678.ABC) */ uint8le unused1[3]; uint32le length; // Length (in bytes) uint32le loopStart; // Loop start (in bytes) uint32le loopEnd; // Loop end (in bytes) uint32le c5Speed; // Samplerate uint8le volume; // Default volume (0...64) uint8le panning; // Default pan (0...255) uint8le unused2[14]; uint8le flags; // Sample flags uint8le unused3[5]; uint16le ems; // Reserved for internal usage uint32le dram; // Reserved for internal usage char is10[4]; // 'IS10' or 'IW10' (not verified by Orpheus) // Convert an IMFSample to OpenMPT's internal sample representation. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(MOD_TYPE_IMF); mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename); mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; mptSmp.nC5Speed = c5Speed; mptSmp.nVolume = volume * 4; mptSmp.nPan = panning; if(flags & smpLoop) mptSmp.uFlags.set(CHN_LOOP); if(flags & smpPingPongLoop) mptSmp.uFlags.set(CHN_PINGPONGLOOP); if(flags & smp16Bit) { mptSmp.uFlags.set(CHN_16BIT); mptSmp.nLength /= 2; mptSmp.nLoopStart /= 2; mptSmp.nLoopEnd /= 2; } if(flags & smpPanning) mptSmp.uFlags.set(CHN_PANNING); } }; MPT_BINARY_STRUCT(IMFSample, 64) static constexpr EffectCommand imfEffects[] = { CMD_NONE, CMD_SPEED, // 0x01 1xx Set Tempo CMD_TEMPO, // 0x02 2xx Set BPM CMD_TONEPORTAMENTO, // 0x03 3xx Tone Portamento CMD_TONEPORTAVOL, // 0x04 4xy Tone Portamento + Volume Slide CMD_VIBRATO, // 0x05 5xy Vibrato CMD_VIBRATOVOL, // 0x06 6xy Vibrato + Volume Slide CMD_FINEVIBRATO, // 0x07 7xy Fine Vibrato CMD_TREMOLO, // 0x08 8xy Tremolo CMD_ARPEGGIO, // 0x09 9xy Arpeggio CMD_PANNING8, // 0x0A Axx Set Pan Position CMD_PANNINGSLIDE, // 0x0B Bxy Pan Slide CMD_VOLUME, // 0x0C Cxx Set Volume CMD_VOLUMESLIDE, // 0x0D Dxy Volume Slide CMD_VOLUMESLIDE, // 0x0E Exy Fine Volume Slide CMD_FINETUNE, // 0x0F Fxx Set Finetune CMD_NOTESLIDEUP, // 0x10 Gxy Note Slide Up CMD_NOTESLIDEDOWN, // 0x11 Hxy Note Slide Down CMD_PORTAMENTOUP, // 0x12 Ixx Slide Up CMD_PORTAMENTODOWN, // 0x13 Jxx Slide Down CMD_PORTAMENTOUP, // 0x14 Kxx Fine Slide Up CMD_PORTAMENTODOWN, // 0x15 Lxx Fine Slide Down CMD_MIDI, // 0x16 Mxx Set Filter Cutoff CMD_MIDI, // 0x17 Nxy Filter Slide + Resonance CMD_OFFSET, // 0x18 Oxx Set Sample Offset CMD_NONE, // 0x19 Pxx Set Fine Sample Offset - XXX CMD_KEYOFF, // 0x1A Qxx Key Off CMD_RETRIG, // 0x1B Rxy Retrig CMD_TREMOR, // 0x1C Sxy Tremor CMD_POSITIONJUMP, // 0x1D Txx Position Jump CMD_PATTERNBREAK, // 0x1E Uxx Pattern Break CMD_GLOBALVOLUME, // 0x1F Vxx Set Mastervolume CMD_GLOBALVOLSLIDE, // 0x20 Wxy Mastervolume Slide CMD_S3MCMDEX, // 0x21 Xxx Extended Effect // X1x Set Filter // X3x Glissando // X5x Vibrato Waveform // X8x Tremolo Waveform // XAx Pattern Loop // XBx Pattern Delay // XCx Note Cut // XDx Note Delay // XEx Ignore Envelope // XFx Invert Loop CMD_NONE, // 0x22 Yxx Chorus - XXX CMD_NONE, // 0x23 Zxx Reverb - XXX }; static std::pair TranslateIMFEffect(uint8 command, uint8 param) { uint8 n; // fix some of them switch(command) { case 0xE: // fine volslide // hackaround to get almost-right behavior for fine slides (i think!) if(param == 0) /* nothing */; else if(param == 0xF0) param = 0xEF; else if(param == 0x0F) param = 0xFE; else if(param & 0xF0) param |= 0x0F; else param |= 0xF0; break; case 0xF: // set finetune param ^= 0x80; break; case 0x14: // fine slide up case 0x15: // fine slide down // this is about as close as we can do... if(param >> 4) param = 0xF0 | (param >> 4); else param |= 0xE0; break; case 0x16: // cutoff param = static_cast((0xFF - param) / 2u); break; case 0x17: // cutoff slide + resonance (TODO: cutoff slide is currently not handled) param = 0x80 | (param & 0x0F); break; case 0x1F: // set global volume param = mpt::saturate_cast(param * 2); break; case 0x21: n = 0; switch(param >> 4) { case 0: /* undefined, but since S0x does nothing in IT anyway, we won't care. this is here to allow S00 to pick up the previous value (assuming IMF even does that -- I haven't actually tried it) */ break; default: // undefined case 0x1: // set filter case 0xF: // invert loop command = 0; break; case 0x3: // glissando n = 0x20; break; case 0x5: // vibrato waveform n = 0x30; break; case 0x8: // tremolo waveform n = 0x40; break; case 0xA: // pattern loop n = 0xB0; break; case 0xB: // pattern delay n = 0xE0; break; case 0xC: // note cut case 0xD: // note delay // Apparently, Imago Orpheus doesn't cut samples on tick 0. if(!param) command = 0; break; case 0xE: // ignore envelope switch(param & 0x0F) { // All envelopes // Predicament: we can only disable one envelope at a time. Volume is probably most noticeable, so let's go with that. case 0: param = 0x77; break; // Volume case 1: param = 0x77; break; // Panning case 2: param = 0x79; break; // Filter case 3: param = 0x7B; break; } break; case 0x18: // sample offset // O00 doesn't pick up the previous value if(!param) command = 0; break; } if(n) param = n | (param & 0x0F); break; } return {(command < std::size(imfEffects)) ? imfEffects[command] : CMD_NONE, param}; } static bool ValidateHeader(const IMFFileHeader &fileHeader) { if(std::memcmp(fileHeader.im10, "IM10", 4) || fileHeader.ordNum > 256 || fileHeader.insNum >= MAX_INSTRUMENTS || fileHeader.bpm < 32 || fileHeader.master > 64 || fileHeader.amp < 4 || fileHeader.amp > 127 || !fileHeader.GetNumChannels()) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const IMFFileHeader &fileHeader) { return 256 + fileHeader.patNum * 4 + fileHeader.insNum * sizeof(IMFInstrument); } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize) { IMFFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags) { IMFFileHeader fileHeader; file.Rewind(); if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_IMF, fileHeader.GetNumChannels()); m_modFormat.formatName = UL_("Imago Orpheus"); m_modFormat.type = UL_("imf"); m_modFormat.charset = mpt::Charset::CP437; // Read channel configuration std::bitset<32> ignoreChannels; // bit set for each channel that's completely disabled uint64 channelMuteStatus = 0; for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = static_cast(fileHeader.channels[chn].panning * 256 / 255); ChnSettings[chn].szName = mpt::String::ReadBuf(mpt::String::nullTerminated, fileHeader.channels[chn].name); channelMuteStatus |= static_cast(fileHeader.channels[chn].status) << (chn * 2); // TODO: reverb/chorus? switch(fileHeader.channels[chn].status) { case 0: // enabled; don't worry about it break; case 1: // mute ChnSettings[chn].dwFlags = CHN_MUTE; break; case 2: // disabled ChnSettings[chn].dwFlags = CHN_MUTE; ignoreChannels[chn] = true; break; } } // BEHIND.IMF: All channels but the first are muted // mikmod refers to this as an Orpheus bug, but I haven't seen any other files like this, so maybe it's just an incorrectly saved file? if(GetNumChannels() == 16 && channelMuteStatus == 0x5555'5554) { for(CHANNELINDEX chn = 1; chn < GetNumChannels(); chn++) ChnSettings[chn].dwFlags.reset(CHN_MUTE); } // Song Name m_songName = mpt::String::ReadBuf(mpt::String::nullTerminated, fileHeader.title); m_SongFlags.set(SONG_LINEARSLIDES, fileHeader.flags & IMFFileHeader::linearSlides); Order().SetDefaultSpeed(fileHeader.tempo); Order().SetDefaultTempoInt(fileHeader.bpm); m_nDefaultGlobalVolume = fileHeader.master * 4u; m_nSamplePreAmp = fileHeader.amp; m_nInstruments = fileHeader.insNum; m_nSamples = 0; // Will be incremented later uint8 orders[256]; file.ReadArray(orders); ReadOrderFromArray(Order(), orders, fileHeader.ordNum, uint16_max, 0xFF); // Read patterns if(loadFlags & loadPatternData) Patterns.ResizeArray(fileHeader.patNum); for(PATTERNINDEX pat = 0; pat < fileHeader.patNum; pat++) { const uint16 length = file.ReadUint16LE(), numRows = file.ReadUint16LE(); FileReader patternChunk = file.ReadChunk(length - 4); if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, numRows)) { continue; } ModCommand dummy; ROWINDEX row = 0; while(row < numRows) { uint8 mask = patternChunk.ReadUint8(); if(mask == 0) { row++; continue; } uint8 channel = mask & 0x1F; ModCommand &m = (channel < GetNumChannels()) ? *Patterns[pat].GetpModCommand(row, channel) : dummy; if(mask & 0x20) { // Read note/instrument const auto [note, instr] = patternChunk.ReadArray(); m.note = note; m.instr = instr; if(m.note == 160) { m.note = NOTE_KEYOFF; } else if(m.note == 255) { m.note = NOTE_NONE; } else { m.note = static_cast((m.note >> 4) * 12 + (m.note & 0x0F) + 12 + 1); if(!m.IsNoteOrEmpty()) { m.note = NOTE_NONE; } } } if((mask & 0xC0) == 0xC0) { // Read both effects and figure out what to do with them const auto [e1c, e1d, e2c, e2d] = patternChunk.ReadArray(); // Command 1, Data 1, Command 2, Data 2 const auto [command1, param1] = TranslateIMFEffect(e1c, e1d); const auto [command2, param2] = TranslateIMFEffect(e2c, e2d); m.FillInTwoCommands(command1, param1, command2, param2, true); } else if(mask & 0xC0) { // There's one effect, just stick it in the effect column (unless it's a volume command) const auto [e1c, e1d] = patternChunk.ReadArray(); // Command 1, Data 1, Command 2, Data 2 const auto [command, param] = TranslateIMFEffect(e1c, e1d); if(command == CMD_VOLUME) m.SetVolumeCommand(VOLCMD_VOLUME, param); else m.SetEffectCommand(command, param); } if(ignoreChannels[channel] && m.IsGlobalCommand()) m.command = CMD_NONE; } } SAMPLEINDEX firstSample = 1; // first sample index of the current instrument // read instruments for(INSTRUMENTINDEX ins = 0; ins < GetNumInstruments(); ins++) { ModInstrument *instr = AllocateInstrument(ins + 1); IMFInstrument instrumentHeader; if(!file.ReadStruct(instrumentHeader) || instr == nullptr) { continue; } // Orpheus does not check this! //if(memcmp(instrumentHeader.ii10, "II10", 4) != 0) // return false; instrumentHeader.ConvertToMPT(*instr, firstSample); // Read this instrument's samples for(SAMPLEINDEX smp = 0; smp < instrumentHeader.smpNum; smp++) { IMFSample sampleHeader; file.ReadStruct(sampleHeader); const SAMPLEINDEX smpID = firstSample + smp; if(smpID >= MAX_SAMPLES) { file.Skip(sampleHeader.length); continue; } m_nSamples = smpID; ModSample &sample = Samples[smpID]; sampleHeader.ConvertToMPT(sample); m_szNames[smpID] = sample.filename; if(sampleHeader.length) { FileReader sampleChunk = file.ReadChunk(sampleHeader.length); if(loadFlags & loadSampleData) { SampleIO( sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(sample, sampleChunk); } } } firstSample += instrumentHeader.smpNum; } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/AudioCriticalSection.h0000644000175000017500000000401114052666041022307 00000000000000/* * AudioCriticalSection.h * --------- * Purpose: Implementation of OpenMPT's critical section for access to CSoundFile. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #if defined(MODPLUG_TRACKER) #include "../misc/mptMutex.h" #endif OPENMPT_NAMESPACE_BEGIN #if defined(MODPLUG_TRACKER) namespace mpt { class recursive_mutex_with_lock_count; } // namespace mpt namespace Tracker { // implemented in mptrack/Mptrack.cpp mpt::recursive_mutex_with_lock_count & GetGlobalMutexRef(); } // namespace Tracker // Critical section handling done in (safe) RAII style. // Create a CriticalSection object whenever you need exclusive access to CSoundFile. // One object = one lock / critical section. // The critical section is automatically left when the object is destroyed, but // Enter() and Leave() can also be called manually if needed. class CriticalSection { private: mpt::recursive_mutex_with_lock_count & m_refGlobalMutex; protected: bool inSection; public: enum class InitialState { Locked = 0, Unlocked = 1, }; public: #if MPT_COMPILER_MSVC _Acquires_lock_(m_refGlobalMutex.mutex) #endif // MPT_COMPILER_MSVC CriticalSection(); CriticalSection(CriticalSection &&other) noexcept; explicit CriticalSection(InitialState state); #if MPT_COMPILER_MSVC _Acquires_lock_(m_refGlobalMutex.mutex) #endif // MPT_COMPILER_MSVC void Enter(); #if MPT_COMPILER_MSVC _Requires_lock_held_(m_refGlobalMutex.mutex) _Releases_lock_(m_refGlobalMutex.mutex) #endif // MPT_COMPILER_MSVC void Leave(); ~CriticalSection(); }; #else // !MODPLUG_TRACKER class CriticalSection { public: enum class InitialState { Locked = 0, Unlocked = 1, }; public: CriticalSection() {} CriticalSection(CriticalSection &&) noexcept {} explicit CriticalSection(InitialState) {} void Enter() {} void Leave() {} ~CriticalSection() {} }; #endif // MODPLUG_TRACKER OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleFormatFLAC.cpp0000644000175000017500000006275215000450035021625 00000000000000/* * SampleFormatFLAC.cpp * -------------------- * Purpose: FLAC sample import. * Notes : * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Sndfile.h" #ifdef MODPLUG_TRACKER #include "../mptrack/TrackerSettings.h" #endif //MODPLUG_TRACKER #ifndef MODPLUG_NO_FILESAVE #include "mpt/io_file/fstream.hpp" #include "../common/mptFileIO.h" #endif #include "../common/misc_util.h" #include "Tagging.h" #include "Loaders.h" #include "WAVTools.h" #include "../common/FileReader.h" #include "modsmp_ctrl.h" #include "openmpt/soundbase/Copy.hpp" #include "openmpt/soundbase/SampleConvert.hpp" #include "openmpt/soundbase/SampleDecode.hpp" #include "../soundlib/SampleCopy.h" #include "../soundlib/ModSampleCopy.h" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/parse/parse.hpp" //#include "mpt/crc/crc.hpp" #include "OggStream.h" #include #if MPT_PLATFORM_MULTITHREADED && !defined(MPT_COMPILER_QUIRK_NO_STDCPP_THREADS) #include #endif #ifdef MPT_WITH_OGG #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif // MPT_COMPILER_CLANG #include #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #endif // MPT_WITH_OGG #ifdef MPT_WITH_FLAC #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif // MPT_COMPILER_CLANG #include #include #include #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #endif // MPT_WITH_FLAC OPENMPT_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////////////////////////// // FLAC Samples #ifdef MPT_WITH_FLAC struct FLACDecoder { FileReader &m_file; CSoundFile &m_sndFile; const SAMPLEINDEX m_sample; bool m_ready = false; FLACDecoder(FileReader &f, CSoundFile &sf, SAMPLEINDEX smp) : m_file(f), m_sndFile(sf), m_sample(smp) { } static FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *client_data) { FileReader &file = static_cast(client_data)->m_file; if(*bytes > 0) { FileReader::pos_type readBytes = *bytes; LimitMax(readBytes, file.BytesLeft()); file.ReadRaw(mpt::byte_cast(mpt::span(buffer, readBytes))); *bytes = readBytes; if(*bytes == 0) return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; else return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } else { return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } } static FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *, FLAC__uint64 absolute_byte_offset, void *client_data) { FileReader &file = static_cast(client_data)->m_file; if(!file.Seek(static_cast(absolute_byte_offset))) return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; else return FLAC__STREAM_DECODER_SEEK_STATUS_OK; } static FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *, FLAC__uint64 *absolute_byte_offset, void *client_data) { FileReader &file = static_cast(client_data)->m_file; *absolute_byte_offset = file.GetPosition(); return FLAC__STREAM_DECODER_TELL_STATUS_OK; } static FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *, FLAC__uint64 *stream_length, void *client_data) { FileReader &file = static_cast(client_data)->m_file; *stream_length = file.GetLength(); return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; } static FLAC__bool eof_cb(const FLAC__StreamDecoder *, void *client_data) { FileReader &file = static_cast(client_data)->m_file; return file.NoBytesLeft(); } static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) { FLACDecoder &client = *static_cast(client_data); ModSample &sample = client.m_sndFile.GetSample(client.m_sample); if(frame->header.number.sample_number >= sample.nLength || !client.m_ready) { // We're reading beyond the sample size already, or we aren't even ready to decode yet! return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } // Number of samples to be copied in this call const SmpLength copySamples = std::min(static_cast(frame->header.blocksize), static_cast(sample.nLength - frame->header.number.sample_number)); // Number of target channels const uint8 modChannels = sample.GetNumChannels(); // Offset (in samples) into target data const size_t offset = static_cast(frame->header.number.sample_number) * modChannels; // Source size in bytes const size_t srcSize = frame->header.blocksize * 4; // Source bit depth const unsigned int bps = frame->header.bits_per_sample; MPT_ASSERT((bps <= 8 && sample.GetElementarySampleSize() == 1) || (bps > 8 && sample.GetElementarySampleSize() == 2)); MPT_ASSERT(modChannels <= FLAC__stream_decoder_get_channels(decoder)); MPT_ASSERT(bps == FLAC__stream_decoder_get_bits_per_sample(decoder)); MPT_UNREFERENCED_PARAMETER(decoder); // decoder is unused if ASSERTs are compiled out // Do the sample conversion for(uint8 chn = 0; chn < modChannels; chn++) { if(bps <= 8) { int8 *sampleData8 = sample.sample8() + offset; CopySample, SC::DecodeIdentity > >(sampleData8 + chn, copySamples, modChannels, buffer[chn], srcSize, 1); } else if(bps <= 16) { int16 *sampleData16 = sample.sample16() + offset; CopySample, SC::DecodeIdentity > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1); } else if(bps <= 24) { int16 *sampleData16 = sample.sample16() + offset; CopySample, SC::DecodeIdentity > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1); } else if(bps <= 32) { int16 *sampleData16 = sample.sample16() + offset; CopySample, SC::DecodeIdentity > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1); } } return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } static void metadata_cb(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *client_data) { FLACDecoder &client = *static_cast(client_data); if(client.m_sample > client.m_sndFile.GetNumSamples()) { client.m_sndFile.m_nSamples = client.m_sample; } ModSample &sample = client.m_sndFile.GetSample(client.m_sample); if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && metadata->data.stream_info.total_samples != 0) { // Init sample information client.m_sndFile.DestroySampleThreadsafe(client.m_sample); client.m_sndFile.m_szNames[client.m_sample] = ""; sample.Initialize(); sample.uFlags.set(CHN_16BIT, metadata->data.stream_info.bits_per_sample > 8); sample.uFlags.set(CHN_STEREO, metadata->data.stream_info.channels > 1); sample.nLength = mpt::saturate_cast(metadata->data.stream_info.total_samples); LimitMax(sample.nLength, MAX_SAMPLE_LENGTH); sample.nC5Speed = metadata->data.stream_info.sample_rate; client.m_ready = (sample.AllocateSample() != 0); } else if(metadata->type == FLAC__METADATA_TYPE_APPLICATION && !memcmp(metadata->data.application.id, "riff", 4) && client.m_ready) { // Try reading RIFF loop points and other sample information FileReader data(mpt::as_span(metadata->data.application.data, metadata->length)); FileReader::ChunkList chunks = data.ReadChunks(2); // We're not really going to read a WAV file here because there will be only one RIFF chunk per metadata event, but we can still re-use the code for parsing RIFF metadata... WAVReader riffReader(data); riffReader.FindMetadataChunks(chunks); riffReader.ApplySampleSettings(sample, client.m_sndFile.GetCharsetInternal(), client.m_sndFile.m_szNames[client.m_sample]); } else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && client.m_ready) { // Try reading Vorbis Comments for sample title, sample rate and loop points SmpLength loopStart = 0, loopLength = 0; for(FLAC__uint32 i = 0; i < metadata->data.vorbis_comment.num_comments; i++) { const char *tag = mpt::byte_cast(metadata->data.vorbis_comment.comments[i].entry); const FLAC__uint32 length = metadata->data.vorbis_comment.comments[i].length; if(length > 6 && !mpt::CompareNoCaseAscii(tag, "TITLE=", 6)) { client.m_sndFile.m_szNames[client.m_sample] = mpt::ToCharset(client.m_sndFile.GetCharsetInternal(), mpt::Charset::UTF8, mpt::String::ReadBuf(mpt::String::maybeNullTerminated, tag + 6, length - 6)); } else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "SAMPLERATE=", 11)) { uint32 sampleRate = mpt::parse(tag + 11); if(sampleRate > 0) sample.nC5Speed = sampleRate; } else if(length > 10 && !mpt::CompareNoCaseAscii(tag, "LOOPSTART=", 10)) { loopStart = mpt::parse(tag + 10); } else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "LOOPLENGTH=", 11)) { loopLength = mpt::parse(tag + 11); } } if(loopLength > 0) { sample.nLoopStart = loopStart; sample.nLoopEnd = loopStart + loopLength; sample.uFlags.set(CHN_LOOP); sample.SanitizeLoops(); } } } static void error_cb(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus, void *) { } }; #endif // MPT_WITH_FLAC bool CSoundFile::ReadFLACSample(SAMPLEINDEX sample, FileReader &file) { #ifdef MPT_WITH_FLAC file.Rewind(); bool isOgg = false; #ifdef MPT_WITH_OGG uint32 oggFlacBitstreamSerial = 0; #endif // Check whether we are dealing with native FLAC, OggFlac or no FLAC at all. if(file.ReadMagic("fLaC")) { // ok isOgg = false; #ifdef MPT_WITH_OGG } else if(file.ReadMagic("OggS")) { // use libogg to find the first OggFlac stream header file.Rewind(); bool oggOK = false; bool needMoreData = true; constexpr long bufsize = 65536; std::size_t readSize = 0; char *buf = nullptr; ogg_sync_state oy; MemsetZero(oy); ogg_page og; MemsetZero(og); std::map oggStreams; ogg_packet op; MemsetZero(op); if(ogg_sync_init(&oy) != 0) { return false; } while(needMoreData) { if(file.NoBytesLeft()) { // stop at EOF oggOK = false; needMoreData = false; break; } buf = ogg_sync_buffer(&oy, bufsize); if(!buf) { oggOK = false; needMoreData = false; break; } readSize = file.ReadRaw(mpt::span(buf, bufsize)).size(); if(ogg_sync_wrote(&oy, static_cast(readSize)) != 0) { oggOK = false; needMoreData = false; break; } while(ogg_sync_pageout(&oy, &og) == 1) { if(!ogg_page_bos(&og)) { // we stop scanning when seeing the first noo-begin-of-stream page oggOK = false; needMoreData = false; break; } uint32 serial = ogg_page_serialno(&og); if(!oggStreams[serial]) { // previously unseen stream serial oggStreams[serial] = new ogg_stream_state(); MemsetZero(*(oggStreams[serial])); if(ogg_stream_init(oggStreams[serial], serial) != 0) { delete oggStreams[serial]; oggStreams.erase(serial); oggOK = false; needMoreData = false; break; } } if(ogg_stream_pagein(oggStreams[serial], &og) != 0) { // invalid page oggOK = false; needMoreData = false; break; } if(ogg_stream_packetout(oggStreams[serial], &op) != 1) { // partial or broken packet, continue with more data continue; } if(op.packetno != 0) { // non-begin-of-stream packet. // This should not appear on first page for any known ogg codec, // but deal gracefully with badly mused streams in that regard. continue; } FileReader packet(mpt::as_span(op.packet, op.bytes)); if(packet.ReadIntLE() == 0x7f && packet.ReadMagic("FLAC")) { // looks like OggFlac oggOK = true; oggFlacBitstreamSerial = serial; needMoreData = false; break; } } } while(oggStreams.size() > 0) { uint32 serial = oggStreams.begin()->first; ogg_stream_clear(oggStreams[serial]); delete oggStreams[serial]; oggStreams.erase(serial); } ogg_sync_clear(&oy); if(!oggOK) { return false; } isOgg = true; #else // !MPT_WITH_OGG } else if(file.CanRead(78) && file.ReadMagic("OggS")) { // first OggFlac page is exactly 78 bytes long // only support plain OggFlac here with the FLAC logical bitstream being the first one uint8 oggPageVersion = file.ReadIntLE(); uint8 oggPageHeaderType = file.ReadIntLE(); uint64 oggPageGranulePosition = file.ReadIntLE(); uint32 oggPageBitstreamSerialNumber = file.ReadIntLE(); uint32 oggPageSequenceNumber = file.ReadIntLE(); uint32 oggPageChecksum = file.ReadIntLE(); uint8 oggPageSegments = file.ReadIntLE(); uint8 oggPageSegmentLength = file.ReadIntLE(); if(oggPageVersion != 0) { // unknown Ogg version return false; } if(!(oggPageHeaderType & 0x02) || (oggPageHeaderType& 0x01)) { // not BOS or continuation return false; } if(oggPageGranulePosition != 0) { // not starting position return false; } if(oggPageSequenceNumber != 0) { // not first page return false; } // skip CRC check for now if(oggPageSegments != 1) { // first OggFlac page must contain exactly 1 segment return false; } if(oggPageSegmentLength != 51) { // segment length must be 51 bytes in OggFlac mapping return false; } if(file.ReadIntLE() != 0x7f) { // OggFlac mapping demands 0x7f packet type return false; } if(!file.ReadMagic("FLAC")) { // OggFlac magic return false; } if(file.ReadIntLE() != 0x01) { // OggFlac major version return false; } // by now, we are pretty confident that we are not parsing random junk isOgg = true; #endif // MPT_WITH_OGG } else { return false; } file.Rewind(); FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new(); if(decoder == nullptr) { return false; } #ifdef MPT_WITH_OGG if(isOgg) { // force flac decoding of the logical bitstream that actually is OggFlac if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, oggFlacBitstreamSerial)) { FLAC__stream_decoder_delete(decoder); return false; } } #endif // Give me all the metadata! FLAC__stream_decoder_set_metadata_respond_all(decoder); FLACDecoder client(file, *this, sample); // Init decoder FLAC__StreamDecoderInitStatus initStatus = isOgg ? FLAC__stream_decoder_init_ogg_stream(decoder, FLACDecoder::read_cb, FLACDecoder::seek_cb, FLACDecoder::tell_cb, FLACDecoder::length_cb, FLACDecoder::eof_cb, FLACDecoder::write_cb, FLACDecoder::metadata_cb, FLACDecoder::error_cb, &client) : FLAC__stream_decoder_init_stream(decoder, FLACDecoder::read_cb, FLACDecoder::seek_cb, FLACDecoder::tell_cb, FLACDecoder::length_cb, FLACDecoder::eof_cb, FLACDecoder::write_cb, FLACDecoder::metadata_cb, FLACDecoder::error_cb, &client) ; if(initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) { FLAC__stream_decoder_delete(decoder); return false; } // Decode file FLAC__stream_decoder_process_until_end_of_stream(decoder); FLAC__stream_decoder_finish(decoder); FLAC__stream_decoder_delete(decoder); if(client.m_ready && Samples[sample].HasSampleData()) { Samples[sample].Convert(MOD_TYPE_IT, GetType()); Samples[sample].PrecomputeLoops(*this, false); return true; } #else MPT_UNREFERENCED_PARAMETER(sample); MPT_UNREFERENCED_PARAMETER(file); #endif // MPT_WITH_FLAC return false; } #ifdef MPT_WITH_FLAC // RAII-style helper struct for FLAC encoder struct FLAC__StreamEncoder_RAII { std::ostream &f; FLAC__StreamEncoder *encoder = nullptr; operator FLAC__StreamEncoder *() { return encoder; } FLAC__StreamEncoder_RAII(std::ostream &f_) : f(f_), encoder(FLAC__stream_encoder_new()) { } ~FLAC__StreamEncoder_RAII() { FLAC__stream_encoder_delete(encoder); } static FLAC__StreamEncoderWriteStatus StreamEncoderWriteCallback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data) { mpt::IO::ofstream & file = *mpt::void_ptr(client_data); MPT_UNUSED_VARIABLE(encoder); MPT_UNUSED_VARIABLE(samples); MPT_UNUSED_VARIABLE(current_frame); if(!mpt::IO::WriteRaw(file, mpt::as_span(buffer, bytes))) { return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; } return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; } static FLAC__StreamEncoderSeekStatus StreamEncoderSeekCallback(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) { mpt::IO::ofstream & file = *mpt::void_ptr(client_data); MPT_UNUSED_VARIABLE(encoder); if(!mpt::in_range(absolute_byte_offset)) { return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; } if(!mpt::IO::SeekAbsolute(file, static_cast(absolute_byte_offset))) { return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; } return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; } static FLAC__StreamEncoderTellStatus StreamEncoderTellCallback(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) { mpt::IO::ofstream & file = *mpt::void_ptr(client_data); MPT_UNUSED_VARIABLE(encoder); mpt::IO::Offset pos = mpt::IO::TellWrite(file); if(pos < 0) { return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; } if(!mpt::in_range(pos)) { return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; } *absolute_byte_offset = static_cast(pos); return FLAC__STREAM_ENCODER_TELL_STATUS_OK; } }; class FLAC__StreamMetadata_RAII : public std::vector { public: FLAC__StreamMetadata_RAII(std::initializer_list init) : std::vector(init) { } ~FLAC__StreamMetadata_RAII() { for(auto m : *this) { FLAC__metadata_object_delete(m); } } }; #endif #ifndef MODPLUG_NO_FILESAVE bool CSoundFile::SaveFLACSample(SAMPLEINDEX nSample, std::ostream &f) const { #ifdef MPT_WITH_FLAC const ModSample &sample = Samples[nSample]; if(sample.uFlags[CHN_ADLIB] || !sample.HasSampleData()) return false; FLAC__StreamEncoder_RAII encoder(f); if(encoder == nullptr) return false; uint32 sampleRate = sample.GetSampleRate(GetType()); // First off, set up all the metadata... FLAC__StreamMetadata_RAII metadata = { FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), // MPT sample information FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), // Loop points FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), // Cue points }; unsigned numBlocks = 2; if(metadata[0]) { // Store sample name FLAC__StreamMetadata_VorbisComment_Entry entry; FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "TITLE", mpt::ToCharset(mpt::Charset::UTF8, GetCharsetInternal(), m_szNames[nSample]).c_str()); FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false); FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ENCODER", mpt::ToCharset(mpt::Charset::UTF8, Version::Current().GetOpenMPTVersionString()).c_str()); FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false); if(sampleRate > FLAC__MAX_SAMPLE_RATE) { // FLAC only supports a sample rate of up to 1048575 Hz. // Store the real sample rate in a custom Vorbis comment. FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "SAMPLERATE", mpt::afmt::val(sampleRate).c_str()); FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false); } } if(metadata[1]) { // Write MPT sample information memcpy(metadata[1]->data.application.id, "riff", 4); struct { RIFFChunk header; WAVExtraChunk mptInfo; } chunk; chunk.header.id = RIFFChunk::idxtra; chunk.header.length = sizeof(WAVExtraChunk); chunk.mptInfo.ConvertToWAV(sample, GetType()); const uint32 length = sizeof(RIFFChunk) + sizeof(WAVExtraChunk); FLAC__metadata_object_application_set_data(metadata[1], reinterpret_cast(&chunk), length, true); } if(metadata[numBlocks] && (sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP] || ModCommand::IsNote(sample.rootNote))) { // Store loop points / root note information memcpy(metadata[numBlocks]->data.application.id, "riff", 4); struct { RIFFChunk header; WAVSampleInfoChunk info; WAVSampleLoop loops[2]; } chunk; chunk.header.id = RIFFChunk::idsmpl; chunk.header.length = sizeof(WAVSampleInfoChunk); chunk.info.ConvertToWAV(sample.GetSampleRate(GetType()), sample.rootNote); if(sample.uFlags[CHN_SUSTAINLOOP]) { chunk.loops[chunk.info.numLoops++].ConvertToWAV(sample.nSustainStart, sample.nSustainEnd, sample.uFlags[CHN_PINGPONGSUSTAIN]); chunk.header.length += sizeof(WAVSampleLoop); } if(sample.uFlags[CHN_LOOP]) { chunk.loops[chunk.info.numLoops++].ConvertToWAV(sample.nLoopStart, sample.nLoopEnd, sample.uFlags[CHN_PINGPONGLOOP]); chunk.header.length += sizeof(WAVSampleLoop); } else if(sample.uFlags[CHN_SUSTAINLOOP]) { // Invent zero-length loop to distinguish sustain loop from normal loop chunk.loops[chunk.info.numLoops++].ConvertToWAV(0, 0, false); chunk.header.length += sizeof(WAVSampleLoop); } const uint32 length = sizeof(RIFFChunk) + chunk.header.length; FLAC__metadata_object_application_set_data(metadata[numBlocks], reinterpret_cast(&chunk), length, true); numBlocks++; } if(metadata[numBlocks] && sample.HasCustomCuePoints()) { // Store cue points memcpy(metadata[numBlocks]->data.application.id, "riff", 4); struct { RIFFChunk header; uint32le numPoints; WAVCuePoint cues[mpt::array_size::size]; } chunk{}; chunk.header.id = RIFFChunk::idcue_; chunk.header.length = 4 + sizeof(chunk.cues); chunk.numPoints = mpt::saturate_cast(std::size(sample.cues)); for(uint32 i = 0; i < std::size(sample.cues); i++) { chunk.cues[i] = ConvertToWAVCuePoint(i, sample.cues[i]); } const uint32 length = sizeof(RIFFChunk) + chunk.header.length; FLAC__metadata_object_application_set_data(metadata[numBlocks], reinterpret_cast(&chunk), length, true); numBlocks++; } // FLAC allows a maximum sample rate of 1048575 Hz. // If the real rate is higher, we store it in a Vorbis comment above. LimitMax(sampleRate, FLAC__MAX_SAMPLE_RATE); if(!FLAC__format_sample_rate_is_subset(sampleRate)) { // FLAC only supports 10 Hz granularity for frequencies above 65535 Hz if the streamable subset is chosen, and only a maximum frequency of 655350 Hz. FLAC__stream_encoder_set_streamable_subset(encoder, false); } FLAC__stream_encoder_set_channels(encoder, sample.GetNumChannels()); FLAC__stream_encoder_set_bits_per_sample(encoder, sample.GetElementarySampleSize() * 8); FLAC__stream_encoder_set_sample_rate(encoder, sampleRate); FLAC__stream_encoder_set_total_samples_estimate(encoder, sample.nLength); FLAC__stream_encoder_set_metadata(encoder, metadata.data(), numBlocks); #ifdef MODPLUG_TRACKER FLAC__stream_encoder_set_compression_level(encoder, TrackerSettings::Instance().m_FLACCompressionLevel); #if (FLAC_API_VERSION_CURRENT >= 14) && MPT_PLATFORM_MULTITHREADED && !defined(MPT_COMPILER_QUIRK_NO_STDCPP_THREADS) uint32 threads = TrackerSettings::Instance().m_FLACMultithreading ? static_cast(std::max(std::thread::hardware_concurrency(), static_cast(1))) : static_cast(1); // Work-around . //FLAC__stream_encoder_set_num_threads(encoder, threads); while((FLAC__stream_encoder_set_num_threads(encoder, threads) == FLAC__STREAM_ENCODER_SET_NUM_THREADS_TOO_MANY_THREADS) && (threads > 1)) { threads = ((threads > 256) ? 256 : (threads - 1)); } #endif #endif // MODPLUG_TRACKER bool success = FLAC__stream_encoder_init_stream(encoder, &FLAC__StreamEncoder_RAII::StreamEncoderWriteCallback, &FLAC__StreamEncoder_RAII::StreamEncoderSeekCallback, &FLAC__StreamEncoder_RAII::StreamEncoderTellCallback, nullptr, &encoder.f) == FLAC__STREAM_ENCODER_INIT_STATUS_OK; // Convert and encode sample data SmpLength framesRemain = sample.nLength, framesRead = 0; const uint8 numChannels = sample.GetNumChannels(); FLAC__int32 buffer[mpt::IO::BUFFERSIZE_TINY]; while(framesRemain && success) { const SmpLength copyFrames = std::min(framesRemain, mpt::saturate_cast(std::size(buffer) / numChannels)); // First, convert to a 32-bit integer buffer switch(sample.GetElementarySampleSize()) { case 1: std::copy(sample.sample8() + framesRead * numChannels, sample.sample8() + (framesRead + copyFrames) * numChannels, std::begin(buffer)); break; case 2: std::copy(sample.sample16() + framesRead * numChannels, sample.sample16() + (framesRead + copyFrames) * numChannels, std::begin(buffer)); break; default: MPT_ASSERT_NOTREACHED(); } // Now do the actual encoding success = FLAC__stream_encoder_process_interleaved(encoder, buffer, copyFrames) != static_cast(false); framesRead += copyFrames; framesRemain -= copyFrames; } FLAC__stream_encoder_finish(encoder); return success; #else MPT_UNREFERENCED_PARAMETER(nSample); MPT_UNREFERENCED_PARAMETER(f); return false; #endif // MPT_WITH_FLAC } #endif // MODPLUG_NO_FILESAVE OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Snd_flt.cpp0000644000175000017500000001416714405407610020204 00000000000000/* * Snd_flt.cpp * ----------- * Purpose: Calculation of resonant filter coefficients. * Notes : Extended filter range was introduced in MPT 1.12 and went up to 8652 Hz. * MPT 1.16 upped this to the current 10670 Hz. * We have no way of telling whether a file was made with MPT 1.12 or 1.16 though. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Sndfile.h" #include "../common/misc_util.h" #include "mpt/base/numbers.hpp" OPENMPT_NAMESPACE_BEGIN // AWE32: cutoff = reg[0-255] * 31.25 + 100 -> [100Hz-8060Hz] // EMU10K1 docs: cutoff = reg[0-127]*62+100 uint8 CSoundFile::FrequencyToCutOff(double frequency) const { // IT Cutoff is computed as cutoff = 110 * 2 ^ (0.25 + x/y), where x is the cutoff and y defines the filter range. // Reversed, this gives us x = (log2(cutoff / 110) - 0.25) * y. // <==========> Rewrite as x = (log2(cutoff) - log2(110) - 0.25) * y. // <==========> Rewrite as x = (ln(cutoff) - ln(110) - 0.25*ln(2)) * y/ln(2). // <4.8737671609324025> double cutoff = (std::log(frequency) - 4.8737671609324025) * (m_SongFlags[SONG_EXFILTERRANGE] ? (20.0 / mpt::numbers::ln2) : (24.0 / mpt::numbers::ln2)); Limit(cutoff, 0.0, 127.0); return mpt::saturate_round(cutoff); } float CSoundFile::CutOffToFrequency(uint32 nCutOff, int envModifier) const { MPT_ASSERT(nCutOff < 128); float computedCutoff = static_cast(nCutOff * (envModifier + 256)); // 0...127*512 float frequency; if(GetType() != MOD_TYPE_IMF) { frequency = 110.0f * std::pow(2.0f, 0.25f + computedCutoff / (m_SongFlags[SONG_EXFILTERRANGE] ? 20.0f * 512.0f : 24.0f * 512.0f)); } else { // EMU8000: Documentation says the cutoff is in quarter semitones, with 0x00 being 125 Hz and 0xFF being 8 kHz // The first half of the sentence contradicts the second, though. frequency = 125.0f * std::pow(2.0f, computedCutoff * 6.0f / (127.0f * 512.0f)); } Limit(frequency, 120.0f, 20000.0f); LimitMax(frequency, static_cast(m_MixerSettings.gdwMixingFreq) * 0.5f); return frequency; } // Update channels with instrument filter settings updated through tracker UI void CSoundFile::UpdateInstrumentFilter(const ModInstrument &ins, bool updateMode, bool updateCutoff, bool updateResonance) { for(auto &chn : m_PlayState.Chn) { if(chn.pModInstrument != &ins) continue; bool change = false; if(updateMode && ins.filterMode != FilterMode::Unchanged && chn.nFilterMode != ins.filterMode) { chn.nFilterMode = ins.filterMode; change = true; } if(updateCutoff) { chn.nCutOff = ins.IsCutoffEnabled() ? ins.GetCutoff() : 0x7F; change |= (chn.nCutOff < 0x7F || chn.dwFlags[CHN_FILTER]); } if(updateResonance) { chn.nResonance = ins.IsResonanceEnabled() ? ins.GetResonance() : 0; change |= (chn.nResonance > 0 || chn.dwFlags[CHN_FILTER]); } // If filter envelope is active, the filter will be updated in the next player tick anyway. if(change && (!ins.PitchEnv.dwFlags[ENV_FILTER] || !IsEnvelopeProcessed(chn, ENV_PITCH))) SetupChannelFilter(chn, false); } } // Simple 2-poles resonant filter. Returns computed cutoff in range [0, 254] or -1 if filter is not applied. int CSoundFile::SetupChannelFilter(ModChannel &chn, bool bReset, int envModifier) const { int cutoff = static_cast(chn.nCutOff) + chn.nCutSwing; int resonance = static_cast(chn.nResonance & 0x7F) + chn.nResSwing; Limit(cutoff, 0, 127); Limit(resonance, 0, 127); if(!m_playBehaviour[kMPTOldSwingBehaviour]) { chn.nCutOff = (uint8)cutoff; chn.nCutSwing = 0; chn.nResonance = (uint8)resonance; chn.nResSwing = 0; } // envModifier is in [-256, 256], so cutoff is in [0, 127 * 2] after this calculation. const int computedCutoff = cutoff * (envModifier + 256) / 256; // Filtering is only ever done in IT if either cutoff is not full or if resonance is set. if(m_playBehaviour[kITFilterBehaviour] && resonance == 0 && computedCutoff >= 254) { if(chn.triggerNote) { // Z7F next to a note disables the filter, however in other cases this should not happen. // Test cases: filter-reset.it, filter-reset-carry.it, filter-reset-envelope.it, filter-nna.it, FilterResetPatDelay.it, FilterPortaSmpChange.it, FilterPortaSmpChange-InsMode.it chn.dwFlags.reset(CHN_FILTER); } return -1; } chn.dwFlags.set(CHN_FILTER); // 2 * damping factor const float dmpfac = std::pow(10.0f, static_cast(-resonance) * ((24.0f / 128.0f) / 20.0f)); const float fc = CutOffToFrequency(cutoff, envModifier) * (2.0f * mpt::numbers::pi_v); float d, e; if(m_playBehaviour[kITFilterBehaviour] && !m_SongFlags[SONG_EXFILTERRANGE]) { const float r = static_cast(m_MixerSettings.gdwMixingFreq) / fc; d = dmpfac * r + dmpfac - 1.0f; e = r * r; } else { const float r = fc / static_cast(m_MixerSettings.gdwMixingFreq); d = (1.0f - 2.0f * dmpfac) * r; LimitMax(d, 2.0f); d = (2.0f * dmpfac - d) / r; e = 1.0f / (r * r); } float fg = 1.0f / (1.0f + d + e); float fb0 = (d + e + e) / (1 + d + e); float fb1 = -e / (1.0f + d + e); #if defined(MPT_INTMIXER) #define MPT_FILTER_CONVERT(x) mpt::saturate_round((x) * (1 << MIXING_FILTER_PRECISION)) #else #define MPT_FILTER_CONVERT(x) (x) #endif switch(chn.nFilterMode) { case FilterMode::HighPass: chn.nFilter_A0 = MPT_FILTER_CONVERT(1.0f - fg); chn.nFilter_B0 = MPT_FILTER_CONVERT(fb0); chn.nFilter_B1 = MPT_FILTER_CONVERT(fb1); #ifdef MPT_INTMIXER chn.nFilter_HP = -1; #else chn.nFilter_HP = 1.0f; #endif // MPT_INTMIXER break; default: chn.nFilter_A0 = MPT_FILTER_CONVERT(fg); chn.nFilter_B0 = MPT_FILTER_CONVERT(fb0); chn.nFilter_B1 = MPT_FILTER_CONVERT(fb1); #ifdef MPT_INTMIXER if(chn.nFilter_A0 == 0) chn.nFilter_A0 = 1; // Prevent silence at low filter cutoff and very high sampling rate chn.nFilter_HP = 0; #else chn.nFilter_HP = 0; #endif // MPT_INTMIXER break; } #undef MPT_FILTER_CONVERT if (bReset) { chn.nFilter_Y[0][0] = chn.nFilter_Y[0][1] = 0; chn.nFilter_Y[1][0] = chn.nFilter_Y[1][1] = 0; } return computedCutoff; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/pattern.cpp0000644000175000017500000003766315005732677020311 00000000000000/* * Pattern.cpp * ----------- * Purpose: Module Pattern header class * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "pattern.h" #include "patternContainer.h" #include "../common/serialization_utils.h" #include "../common/version.h" #include "ITTools.h" #include "Sndfile.h" #include "mod_specifications.h" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" OPENMPT_NAMESPACE_BEGIN CSoundFile& CPattern::GetSoundFile() noexcept { return m_rPatternContainer.GetSoundFile(); } const CSoundFile& CPattern::GetSoundFile() const noexcept { return m_rPatternContainer.GetSoundFile(); } CHANNELINDEX CPattern::GetNumChannels() const noexcept { return GetSoundFile().GetNumChannels(); } // Check if there is any note data on a given row. bool CPattern::IsEmptyRow(ROWINDEX row) const noexcept { if(m_ModCommands.empty() || !IsValidRow(row)) return true; for(const auto &m : GetRow(row)) { if(!m.IsEmpty()) return false; } return true; } // Check if the row contains any position jumps or pattern breaks. bool CPattern::RowHasJump(ROWINDEX row) const noexcept { if(m_ModCommands.empty() || !IsValidRow(row)) return false; for(const auto &m : GetRow(row)) { if(m.command == CMD_PATTERNBREAK || m.command == CMD_POSITIONJUMP) return true; } return false; } bool CPattern::SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure) noexcept { if(!IsValidSignature(rowsPerBeat, rowsPerMeasure)) return false; m_RowsPerBeat = rowsPerBeat; m_RowsPerMeasure = rowsPerMeasure; return true; } bool CPattern::IsValidSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure) noexcept { return rowsPerBeat > 0 && rowsPerBeat <= MAX_ROWS_PER_BEAT && rowsPerBeat <= rowsPerMeasure && rowsPerMeasure <= MAX_ROWS_PER_MEASURE; } // Add or remove rows from the pattern. bool CPattern::Resize(const ROWINDEX newRowCount, bool enforceFormatLimits, bool resizeAtEnd) { CSoundFile &sndFile = GetSoundFile(); if(newRowCount == m_Rows || newRowCount < 1 || newRowCount > MAX_PATTERN_ROWS) { return false; } if(enforceFormatLimits) { auto &specs = sndFile.GetModSpecifications(); if(newRowCount > specs.patternRowsMax || newRowCount < specs.patternRowsMin) return false; } try { size_t count = ((newRowCount > m_Rows) ? (newRowCount - m_Rows) : (m_Rows - newRowCount)) * GetNumChannels(); if(newRowCount > m_Rows) m_ModCommands.insert(resizeAtEnd ? m_ModCommands.end() : m_ModCommands.begin(), count, ModCommand{}); else if(resizeAtEnd) m_ModCommands.erase(m_ModCommands.end() - count, m_ModCommands.end()); else m_ModCommands.erase(m_ModCommands.begin(), m_ModCommands.begin() + count); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); return false; } m_Rows = newRowCount; return true; } void CPattern::ClearCommands() noexcept { std::fill(m_ModCommands.begin(), m_ModCommands.end(), ModCommand{}); } bool CPattern::AllocatePattern(ROWINDEX rows) { size_t newSize = GetNumChannels() * rows; if(rows == 0) { return false; } else if(rows == GetNumRows() && m_ModCommands.size() == newSize) { // Re-use allocated memory ClearCommands(); return true; } else { // Do this in two steps in order to keep the old pattern data in case of OOM decltype(m_ModCommands) newPattern(newSize, ModCommand{}); m_ModCommands = std::move(newPattern); } m_Rows = rows; return true; } void CPattern::Deallocate() { m_Rows = m_RowsPerBeat = m_RowsPerMeasure = 0; m_ModCommands.clear(); m_tempoSwing.clear(); m_PatternName.clear(); } CPattern& CPattern::operator= (const CPattern &pat) { if(GetNumChannels() != pat.GetNumChannels()) return *this; m_ModCommands = pat.m_ModCommands; m_Rows = pat.m_Rows; m_RowsPerBeat = pat.m_RowsPerBeat; m_RowsPerMeasure = pat.m_RowsPerMeasure; m_tempoSwing = pat.m_tempoSwing; m_PatternName = pat.m_PatternName; if(GetSoundFile().GetType() != pat.GetSoundFile().GetType()) { for(ModCommand &m : m_ModCommands) { m.Convert(GetSoundFile().GetType(), pat.GetSoundFile().GetType(), GetSoundFile()); } } return *this; } bool CPattern::operator== (const CPattern &other) const noexcept { return GetNumRows() == other.GetNumRows() && GetNumChannels() == other.GetNumChannels() && GetOverrideSignature() == other.GetOverrideSignature() && GetRowsPerBeat() == other.GetRowsPerBeat() && GetRowsPerMeasure() == other.GetRowsPerMeasure() && GetTempoSwing() == other.GetTempoSwing() && m_ModCommands == other.m_ModCommands; } #ifdef MODPLUG_TRACKER bool CPattern::Expand() { const ROWINDEX newRows = m_Rows * 2; const CHANNELINDEX nChns = GetNumChannels(); if(m_ModCommands.empty() || newRows > GetSoundFile().GetModSpecifications().patternRowsMax) { return false; } decltype(m_ModCommands) newPattern; try { newPattern.assign(m_ModCommands.size() * 2, ModCommand{}); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); return false; } for(auto mSrc = m_ModCommands.begin(), mDst = newPattern.begin(); mSrc != m_ModCommands.end(); mSrc += nChns, mDst += 2 * nChns) { std::copy(mSrc, mSrc + nChns, mDst); } m_ModCommands = std::move(newPattern); m_Rows = newRows; return true; } bool CPattern::Shrink() { if (m_ModCommands.empty() || m_Rows < GetSoundFile().GetModSpecifications().patternRowsMin * 2) { return false; } m_Rows /= 2; const CHANNELINDEX nChns = GetNumChannels(); for(ROWINDEX y = 0; y < m_Rows; y++) { const auto srcRow = GetRow(y * 2); const auto nextSrcRow = GetRow(y * 2 + 1); auto destRow = GetRow(y); for(CHANNELINDEX x = 0; x < nChns; x++) { const ModCommand &src = srcRow[x]; const ModCommand &srcNext = nextSrcRow[x]; ModCommand &dest = destRow[x]; dest = src; if(dest.note == NOTE_NONE && !dest.instr) { // Fill in data from next row if field is empty dest.note = srcNext.note; dest.instr = srcNext.instr; if(srcNext.volcmd != VOLCMD_NONE) { dest.volcmd = srcNext.volcmd; dest.vol = srcNext.vol; } if(dest.command == CMD_NONE) { dest.command = srcNext.command; dest.param = srcNext.param; } } } } m_ModCommands.resize(m_Rows * nChns); return true; } #endif // MODPLUG_TRACKER bool CPattern::SetName(std::string newName) { m_PatternName = std::move(newName); return true; } bool CPattern::SetName(const char *newName, size_t maxChars) { if(newName == nullptr || maxChars == 0) { return false; } const auto nameEnd = std::find(newName, newName + maxChars, '\0'); m_PatternName.assign(newName, nameEnd); return true; } // Write some kind of effect data to the pattern. Exact data to be written and write behaviour can be found in the EffectWriter object. bool CPattern::WriteEffect(EffectWriter &settings) { // First, reject invalid parameters. if(m_ModCommands.empty() || settings.m_row >= GetNumRows() || (settings.m_channel >= GetNumChannels() && settings.m_channel != CHANNELINDEX_INVALID)) { return false; } CHANNELINDEX scanChnMin = settings.m_channel, scanChnMax = settings.m_channel; // Scan all channels if(settings.m_channel == CHANNELINDEX_INVALID) { scanChnMin = 0; scanChnMax = GetNumChannels() - 1; } ModCommand * const baseCommand = GetpModCommand(settings.m_row, scanChnMin); ModCommand *m; // Scan channel(s) for same effect type - if an effect of the same type is already present, exit. if(!settings.m_allowMultiple) { m = baseCommand; for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++) { if(!settings.m_isVolEffect && m->command == settings.m_command) return true; if(settings.m_isVolEffect && m->volcmd == settings.m_volcmd) return true; } } // Easy case: check if there's some space left to put the effect somewhere m = baseCommand; for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++) { if(!settings.m_isVolEffect && m->command == CMD_NONE) { m->command = settings.m_command; m->param = settings.m_param; return true; } if(settings.m_isVolEffect && m->volcmd == VOLCMD_NONE) { m->volcmd = settings.m_volcmd; m->vol = settings.m_vol; return true; } } // Ok, apparently there's no space. If we haven't tried already, try to map it to the volume column or effect column instead. if(settings.m_retry) { const bool isS3M = (GetSoundFile().GetType() & MOD_TYPE_S3M); // Move some effects that also work in the volume column, so there's place for our new effect. if(!settings.m_isVolEffect) { m = baseCommand; for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++) { switch(m->command) { case CMD_VOLUME: if(!GetSoundFile().GetModSpecifications().HasVolCommand(VOLCMD_VOLUME)) { break; } m->volcmd = VOLCMD_VOLUME; m->vol = m->param; m->command = settings.m_command; m->param = settings.m_param; return true; case CMD_PANNING8: if(isS3M && m->param > 0x80) { break; } m->volcmd = VOLCMD_PANNING; m->command = settings.m_command; if(isS3M) m->vol = static_cast((m->param + 1u) / 2u); else m->vol = static_cast((m->param + 2u) / 4u); m->param = settings.m_param; return true; default: break; } } } // Let's try it again by writing into the "other" effect column. if(settings.m_isVolEffect) { // Convert volume effect to normal effect ModCommand::COMMAND newCommand = CMD_NONE; ModCommand::PARAM newParam = settings.m_vol; switch(settings.m_volcmd) { case VOLCMD_PANNING: newCommand = CMD_PANNING8; newParam = mpt::saturate_cast(settings.m_vol * (isS3M ? 2u : 4u)); break; case VOLCMD_VOLUME: newCommand = CMD_VOLUME; break; default: break; } if(newCommand != CMD_NONE) { settings.m_command = static_cast(newCommand); settings.m_param = newParam; settings.m_retry = false; } } else { // Convert normal effect to volume effect VolumeCommand newVolCmd = VOLCMD_NONE; ModCommand::VOL newVol = 0; if(settings.m_command == CMD_PANNING8 && isS3M) { // This needs some manual fixing. if(settings.m_param <= 0x80) { // Can't have surround in volume column, only normal panning newVolCmd = VOLCMD_PANNING; newVol = settings.m_param / 2u; } } else { std::tie(newVolCmd, newVol) = ModCommand::ConvertToVolCommand(settings.m_command, settings.m_param, true); } if(newVolCmd != VOLCMD_NONE) { settings.m_volcmd = newVolCmd; settings.m_vol = newVol; settings.m_retry = false; } } if(!settings.m_retry) { settings.m_isVolEffect = !settings.m_isVolEffect; if(WriteEffect(settings)) { return true; } } } // Try in the next row if possible (this may also happen if we already retried) if(settings.m_retryMode == EffectWriter::rmTryNextRow && settings.m_row + 1 < GetNumRows()) { settings.m_row++; settings.m_retry = true; return WriteEffect(settings); } else if(settings.m_retryMode == EffectWriter::rmTryPreviousRow && settings.m_row > 0) { settings.m_row--; settings.m_retry = true; return WriteEffect(settings); } return false; } //////////////////////////////////////////////////////////////////////// // // Pattern serialization functions // //////////////////////////////////////////////////////////////////////// enum maskbits { noteBit = (1 << 0), instrBit = (1 << 1), volcmdBit = (1 << 2), volBit = (1 << 3), commandBit = (1 << 4), effectParamBit = (1 << 5), extraData = (1 << 6) }; void WriteData(std::ostream& oStrm, const CPattern& pat); void ReadData(std::istream& iStrm, CPattern& pat, const size_t nSize = 0); void WriteModPattern(std::ostream& oStrm, const CPattern& pat) { srlztn::SsbWrite ssb(oStrm); ssb.BeginWrite(FileIdPattern, Version::Current().GetRawVersion()); ssb.WriteItem(pat, "data", &WriteData); // pattern time signature if(pat.GetOverrideSignature()) { ssb.WriteItem(pat.GetRowsPerBeat(), "RPB."); ssb.WriteItem(pat.GetRowsPerMeasure(), "RPM."); } if(pat.HasTempoSwing()) { ssb.WriteItem(pat.GetTempoSwing(), "SWNG", TempoSwing::Serialize); } ssb.FinishWrite(); } void ReadModPattern(std::istream& iStrm, CPattern& pat, const size_t) { srlztn::SsbRead ssb(iStrm); ssb.BeginRead(FileIdPattern, Version::Current().GetRawVersion()); if(ssb.HasFailed()) { return; } ssb.ReadItem(pat, "data", &ReadData); // pattern time signature uint32 rpb = 0, rpm = 0; ssb.ReadItem(rpb, "RPB."); ssb.ReadItem(rpm, "RPM."); pat.SetSignature(rpb, rpm); TempoSwing swing; ssb.ReadItem(swing, "SWNG", TempoSwing::Deserialize); if(!swing.empty()) swing.resize(pat.GetRowsPerBeat()); pat.SetTempoSwing(swing); } static uint8 CreateDiffMask(const ModCommand &chnMC, const ModCommand &newMC) { uint8 mask = 0; if(chnMC.note != newMC.note) mask |= noteBit; if(chnMC.instr != newMC.instr) mask |= instrBit; if(chnMC.volcmd != newMC.volcmd) mask |= volcmdBit; if(chnMC.vol != newMC.vol) mask |= volBit; if(chnMC.command != newMC.command) mask |= commandBit; if(chnMC.param != newMC.param) mask |= effectParamBit; return mask; } // Writes pattern data. Adapted from SaveIT. void WriteData(std::ostream& oStrm, const CPattern& pat) { if(!pat.IsValid()) return; const ROWINDEX rows = pat.GetNumRows(); const CHANNELINDEX chns = pat.GetNumChannels(); std::vector lastChnMC(chns); for(ROWINDEX r = 0; r(c+1); if(diffmask != 0) chval |= IT_bitmask_patternChanEnabled_c; mpt::IO::WriteIntLE(oStrm, chval); if(diffmask) { lastChnMC[c] = m; mpt::IO::WriteIntLE(oStrm, diffmask); if(diffmask & noteBit) mpt::IO::WriteIntLE(oStrm, m.note); if(diffmask & instrBit) mpt::IO::WriteIntLE(oStrm, m.instr); if(diffmask & volcmdBit) mpt::IO::WriteIntLE(oStrm, m.volcmd); if(diffmask & volBit) mpt::IO::WriteIntLE(oStrm, m.vol); if(diffmask & commandBit) mpt::IO::WriteIntLE(oStrm, m.command); if(diffmask & effectParamBit) mpt::IO::WriteIntLE(oStrm, m.param); } } mpt::IO::WriteIntLE(oStrm, 0); // Write end of row marker. } } #define READITEM(itembit,id, type) \ if(diffmask & itembit) \ { \ mpt::IO::ReadIntLE(iStrm, temp); \ if(ch < chns) \ lastChnMC[ch].id = static_cast(temp); \ } \ if(ch < chns) \ m.id = lastChnMC[ch].id; void ReadData(std::istream& iStrm, CPattern& pat, const size_t) { if (!pat.IsValid()) // Expecting patterns to be allocated and resized properly. return; const CHANNELINDEX chns = pat.GetNumChannels(); const ROWINDEX rows = pat.GetNumRows(); std::vector lastChnMC(chns); ROWINDEX row = 0; while(row < rows && iStrm.good()) { uint8 t = 0; mpt::IO::ReadIntLE(iStrm, t); if(t == 0) { row++; continue; } CHANNELINDEX ch = (t & IT_bitmask_patternChanField_c); if(ch > 0) ch--; uint8 diffmask = 0; if((t & IT_bitmask_patternChanEnabled_c) != 0) mpt::IO::ReadIntLE(iStrm, diffmask); uint8 temp = 0; ModCommand dummy{}; ModCommand &m = (ch < chns) ? *pat.GetpModCommand(row, ch) : dummy; READITEM(noteBit, note, ModCommand::NOTE); READITEM(instrBit, instr, ModCommand::INSTR); READITEM(volcmdBit, volcmd, ModCommand::VOLCMD); READITEM(volBit, vol, ModCommand::VOL); READITEM(commandBit, command, ModCommand::COMMAND); READITEM(effectParamBit, param, ModCommand::PARAM); if(diffmask & extraData) { //Ignore additional data. uint8 size; mpt::IO::ReadIntLE(iStrm, size); iStrm.ignore(size); } } } #undef READITEM OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ContainerUMX.cpp0000644000175000017500000000436514201257116021124 00000000000000/* * ContainerUMX.cpp * ---------------- * Purpose: UMX (Unreal Music) module ripper * Notes : Obviously, this code only rips modules from older Unreal Engine games, such as Unreal 1, Unreal Tournament 1 and Deus Ex. * Authors: OpenMPT Devs (inspired by code from http://wiki.beyondunreal.com/Legacy:Package_File_Format) * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "UMXTools.h" #include "Container.h" #include "Sndfile.h" OPENMPT_NAMESPACE_BEGIN CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderUMX(MemoryFileReader file, const uint64 *pfilesize) { return UMX::ProbeFileHeader(file, pfilesize, "music"); } bool UnpackUMX(std::vector &containerItems, FileReader &file, ContainerLoadingFlags loadFlags) { file.Rewind(); containerItems.clear(); UMX::FileHeader fileHeader; if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) return false; // Note that this can be a false positive, e.g. Unreal maps will have music and sound // in their name table because they usually import such files. However, it spares us // from wildly seeking through the file, as the name table is usually right at the // start of the file, so it is hopefully a good enough heuristic for our purposes. if(!UMX::FindNameTableEntry(file, fileHeader, "music")) return false; else if(!file.CanRead(fileHeader.GetMinimumAdditionalFileSize())) return false; else if(loadFlags == ContainerOnlyVerifyHeader) return true; const std::vector names = UMX::ReadNameTable(file, fileHeader); const std::vector classes = UMX::ReadImportTable(file, fileHeader, names); // Read export table file.Seek(fileHeader.exportOffset); for(uint32 i = 0; i < fileHeader.exportCount && file.CanRead(8); i++) { auto [fileChunk, objName] = UMX::ReadExportTableEntry(file, fileHeader, classes, names, "music"); if(!fileChunk.IsValid()) continue; ContainerItem item; if(objName >= 0 && static_cast(objName) < names.size()) { item.name = mpt::ToUnicode(mpt::Charset::Windows1252, names[objName]); } item.file = fileChunk; containerItems.push_back(std::move(item)); } return !containerItems.empty(); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ModSequence.cpp0000644000175000017500000005253114704715777021042 00000000000000/* * ModSequence.cpp * --------------- * Purpose: Order and sequence handling. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "ModSequence.h" #include "mod_specifications.h" #include "Sndfile.h" #include "../common/version.h" #include "../common/serialization_utils.h" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" OPENMPT_NAMESPACE_BEGIN ModSequence::ModSequence(CSoundFile &sndFile) : m_sndFile(sndFile) { } ModSequence& ModSequence::operator=(const ModSequence &other) { if(&other == this) return *this; std::vector::assign(other.begin(), other.end()); m_name = other.m_name; m_restartPos = other.m_restartPos; return *this; } bool ModSequence::operator== (const ModSequence &other) const noexcept { return static_cast &>(*this) == other && m_name == other.m_name && m_restartPos == other.m_restartPos; } void ModSequence::SetDefaultTempo(TEMPO tempo) noexcept { if(!tempo.GetInt()) tempo.Set(125); else LimitMax(tempo, TEMPO{uint16_max, 0}); m_defaultTempo = tempo; } bool ModSequence::NeedsExtraDatafield() const noexcept { return (m_sndFile.GetType() == MOD_TYPE_MPT && m_sndFile.Patterns.GetNumPatterns() > 0xFD); } void ModSequence::AdjustToNewModType(const MODTYPE oldtype) { auto &specs = m_sndFile.GetModSpecifications(); if(oldtype != MOD_TYPE_NONE) { // If not supported, remove "+++" separator order items. if(!specs.hasIgnoreIndex) { RemovePattern(PATTERNINDEX_SKIP); } // If not supported, remove "---" items between patterns. if(!specs.hasStopIndex) { RemovePattern(PATTERNINDEX_INVALID); } } //Resize orderlist if needed. if(specs.ordersMax < size()) { // Order list too long? Remove "unnecessary" order items first. if(oldtype != MOD_TYPE_NONE && specs.ordersMax < GetLengthTailTrimmed()) { erase(std::remove_if(begin(), end(), [&] (PATTERNINDEX pat) { return !m_sndFile.Patterns.IsValidPat(pat); }), end()); if(GetLengthTailTrimmed() > specs.ordersMax) { m_sndFile.AddToLog(LogWarning, U_("WARNING: Order list has been trimmed!")); } } resize(specs.ordersMax); } } ORDERINDEX ModSequence::GetLengthTailTrimmed() const noexcept { if(empty()) return 0; auto last = std::find_if(rbegin(), rend(), [] (PATTERNINDEX pat) { return pat != PATTERNINDEX_INVALID; }); return static_cast(std::distance(begin(), last.base())); } ORDERINDEX ModSequence::GetLengthFirstEmpty() const noexcept { return static_cast(std::distance(begin(), std::find(begin(), end(), PATTERNINDEX_INVALID))); } ORDERINDEX ModSequence::GetRemainingCapacity(ORDERINDEX startingFrom, bool enforceFormatLimits) const noexcept { const ORDERINDEX ordersMax = enforceFormatLimits ? m_sndFile.GetModSpecifications().ordersMax : MAX_ORDERS; ORDERINDEX length = GetLengthTailTrimmed(); if(startingFrom != ORDERINDEX_INVALID && startingFrom > length) length = startingFrom; if(length >= ordersMax) return 0; else return ordersMax - length; } ORDERINDEX ModSequence::GetNextOrderIgnoringSkips(const ORDERINDEX start) const noexcept { if(empty()) return 0; auto length = GetLength(); ORDERINDEX next = std::min(ORDERINDEX(length - 1), ORDERINDEX(start + 1)); while(next + 1 < length && (*this)[next] == PATTERNINDEX_SKIP) next++; return next; } ORDERINDEX ModSequence::GetPreviousOrderIgnoringSkips(const ORDERINDEX start) const noexcept { const ORDERINDEX last = GetLastIndex(); if(start == 0 || last == 0) return 0; ORDERINDEX prev = std::min(ORDERINDEX(start - 1), last); while(prev > 0 && (*this)[prev] == PATTERNINDEX_SKIP) prev--; return prev; } ORDERINDEX ModSequence::GetFirstValidIndex() const noexcept { const ORDERINDEX length = GetLength(); for(ORDERINDEX ord = 0; ord < length; ord++) { if(IsValidPat(ord)) return ord; } return ORDERINDEX_INVALID; } void ModSequence::Remove(ORDERINDEX posBegin, ORDERINDEX posEnd) noexcept { if(posEnd < posBegin || posEnd >= size()) return; erase(begin() + posBegin, begin() + posEnd + 1); } // Remove all references to a given pattern index from the order list. Jump commands are updated accordingly. void ModSequence::RemovePattern(PATTERNINDEX pat) { // First, calculate the offset that needs to be applied to jump commands const ORDERINDEX orderLength = GetLengthTailTrimmed(); std::vector newPosition(orderLength); ORDERINDEX maxJump = 0; for(ORDERINDEX i = 0; i < orderLength; i++) { newPosition[i] = i - maxJump; if((*this)[i] == pat) { maxJump++; } } if(!maxJump) { return; } erase(std::remove(begin(), end(), pat), end()); // Only apply to patterns actually found in this sequence for(auto p : *this) { if(!m_sndFile.Patterns.IsValidPat(p)) continue; for(auto &m : m_sndFile.Patterns[p]) { if(m.command == CMD_POSITIONJUMP && m.param < newPosition.size()) { m.param = static_cast(newPosition[m.param]); } } } if(m_restartPos < newPosition.size()) { m_restartPos = newPosition[m_restartPos]; } } void ModSequence::assign(ORDERINDEX newSize, PATTERNINDEX pat) { LimitMax(newSize, m_sndFile.GetModSpecifications().ordersMax); std::vector::assign(newSize, pat); } ORDERINDEX ModSequence::insert(ORDERINDEX pos, ORDERINDEX count, PATTERNINDEX fill, bool enforceFormatLimits) { const ORDERINDEX ordersMax = enforceFormatLimits ? m_sndFile.GetModSpecifications().ordersMax : MAX_ORDERS; // Limit number of orders to be inserted so that we don't exceed the format limit or drop items at the end of the order list. LimitMax(count, GetRemainingCapacity(pos, enforceFormatLimits)); if(pos >= ordersMax || GetLengthTailTrimmed() >= ordersMax || count == 0) return 0; reserve(std::max(pos, GetLength()) + count); // Inserting past the end of the container? if(pos > size()) resize(pos); std::vector::insert(begin() + pos, count, fill); // Did we overgrow? Remove patterns at end. if(size() > ordersMax) resize(ordersMax); return count; } ORDERINDEX ModSequence::insert(ORDERINDEX pos, const mpt::span orders, bool enforceFormatLimits) { MPT_ASSERT(reinterpret_cast(orders.data()) < reinterpret_cast(data()) || reinterpret_cast(orders.data()) > reinterpret_cast(data() + size())); ORDERINDEX count = insert(pos, mpt::saturate_cast(orders.size()), 0, enforceFormatLimits); std::copy(orders.begin(), orders.begin() + count, begin() + pos); return count; } bool ModSequence::IsValidPat(ORDERINDEX ord) const noexcept { if(ord < size()) return m_sndFile.Patterns.IsValidPat((*this)[ord]); return false; } CPattern *ModSequence::PatternAt(ORDERINDEX ord) const noexcept { if(!IsValidPat(ord)) return nullptr; return &m_sndFile.Patterns[(*this)[ord]]; } ORDERINDEX ModSequence::FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt, bool searchForward) const noexcept { const ORDERINDEX length = GetLength(); if(startSearchAt >= length) return ORDERINDEX_INVALID; ORDERINDEX ord = startSearchAt; for(ORDERINDEX p = 0; p < length; p++) { if((*this)[ord] == pat) { return ord; } if(searchForward) { if(++ord >= length) ord = 0; } else { if(ord-- == 0) ord = length - 1; } } return ORDERINDEX_INVALID; } PATTERNINDEX ModSequence::EnsureUnique(ORDERINDEX ord) { if(ord >= size()) return PATTERNINDEX_INVALID; PATTERNINDEX pat = (*this)[ord]; if(!IsValidPat(ord)) return pat; for(const auto &sequence : m_sndFile.Order) { ORDERINDEX ords = sequence.GetLength(); for(ORDERINDEX o = 0; o < ords; o++) { if(sequence[o] == pat && (o != ord || &sequence != this)) { // Found duplicate usage. PATTERNINDEX newPat = m_sndFile.Patterns.Duplicate(pat); if(newPat != PATTERNINDEX_INVALID) { (*this)[ord] = newPat; return newPat; } } } } return pat; } ///////////////////////////////////// // ModSequenceSet ///////////////////////////////////// ModSequenceSet::ModSequenceSet(CSoundFile &sndFile) : m_sndFile(sndFile) { Initialize(); } ModSequenceSet& ModSequenceSet::operator=(const ModSequenceSet &other) { if(&other == this) return *this; m_Sequences = other.m_Sequences; if(m_Sequences.size() > m_sndFile.GetModSpecifications().sequencesMax) m_Sequences.resize(m_sndFile.GetModSpecifications().sequencesMax, ModSequence{m_sndFile}); if(m_currentSeq >= m_Sequences.size()) m_currentSeq = 0; return *this; } void ModSequenceSet::Initialize() { m_currentSeq = 0; m_Sequences.assign(1, ModSequence(m_sndFile)); } void ModSequenceSet::SetSequence(SEQUENCEINDEX n) noexcept { if(n < m_Sequences.size()) m_currentSeq = n; } SEQUENCEINDEX ModSequenceSet::AddSequence() { if(GetNumSequences() >= MAX_SEQUENCES) return SEQUENCEINDEX_INVALID; m_Sequences.push_back(ModSequence{m_sndFile}); SetSequence(GetNumSequences() - 1); return GetNumSequences() - 1; } void ModSequenceSet::RemoveSequence(SEQUENCEINDEX i) { // Do nothing if index is invalid or if there's only one sequence left. if(i >= m_Sequences.size() || m_Sequences.size() <= 1) return; m_Sequences.erase(m_Sequences.begin() + i); if(i < m_currentSeq || m_currentSeq >= GetNumSequences()) m_currentSeq--; } #ifdef MODPLUG_TRACKER bool ModSequenceSet::Rearrange(const std::vector &newOrder) { if(newOrder.empty() || newOrder.size() > MAX_SEQUENCES) return false; const auto oldSequences = std::move(m_Sequences); m_Sequences.assign(newOrder.size(), ModSequence{m_sndFile}); for(size_t i = 0; i < newOrder.size(); i++) { if(newOrder[i] < oldSequences.size()) m_Sequences[i] = oldSequences[newOrder[i]]; } if(m_currentSeq > m_Sequences.size()) m_currentSeq = GetNumSequences() - 1u; return true; } void ModSequenceSet::OnModTypeChanged(MODTYPE oldType) { for(auto &seq : m_Sequences) { seq.AdjustToNewModType(oldType); } if(m_sndFile.GetModSpecifications(oldType).sequencesMax > 1 && m_sndFile.GetModSpecifications().sequencesMax <= 1) MergeSequences(); } bool ModSequenceSet::CanSplitSubsongs() const noexcept { return GetNumSequences() == 1 && m_sndFile.GetModSpecifications().sequencesMax > 1 && m_Sequences[0].HasSubsongs(); } bool ModSequenceSet::SplitSubsongsToMultipleSequences() { if(!CanSplitSubsongs()) return false; bool modified = false; const ORDERINDEX length = m_Sequences[0].GetLengthTailTrimmed(); for(ORDERINDEX ord = 0; ord < length; ord++) { // End of subsong? if(!m_Sequences[0].IsValidPat(ord) && m_Sequences[0][ord] != PATTERNINDEX_SKIP) { // Remove all separator patterns between current and next subsong first while(ord < length && !m_sndFile.Patterns.IsValidPat(m_Sequences[0][ord])) { m_Sequences[0][ord] = PATTERNINDEX_INVALID; ord++; modified = true; } if(ord >= length) break; const SEQUENCEINDEX newSeq = AddSequence(); if(newSeq == SEQUENCEINDEX_INVALID) break; const ORDERINDEX startOrd = ord; m_Sequences[newSeq].reserve(length - startOrd); modified = true; // Now, move all following orders to the new sequence while(ord < length && m_Sequences[0][ord] != PATTERNINDEX_INVALID) { PATTERNINDEX copyPat = m_Sequences[0][ord]; m_Sequences[newSeq].push_back(copyPat); m_Sequences[0][ord] = PATTERNINDEX_INVALID; ord++; // Is this a valid pattern? adjust pattern jump commands, if necessary. if(m_sndFile.Patterns.IsValidPat(copyPat)) { for(auto &m : m_sndFile.Patterns[copyPat]) { if(m.command == CMD_POSITIONJUMP && m.param >= startOrd) { m.param = static_cast(m.param - startOrd); } } } } ord--; } } SetSequence(0); return modified; } // Convert the sequence's restart position and tempo information to a pattern command. bool ModSequenceSet::WriteGlobalsToPattern(SEQUENCEINDEX seq, bool writeRestartPos, bool writeTempo) { bool result = true; auto length = m_sndFile.GetLength(eNoAdjust, GetLengthTarget(true).StartPos(seq, 0, 0)); ModSequence &order = m_Sequences[seq]; for(const auto &subSong : length) { if(writeRestartPos && subSong.endOrder != ORDERINDEX_INVALID && subSong.endRow != ROWINDEX_INVALID) { if(mpt::in_range(order.GetRestartPos())) { PATTERNINDEX writePat = order.EnsureUnique(subSong.endOrder); result &= m_sndFile.Patterns[writePat].WriteEffect( EffectWriter(CMD_POSITIONJUMP, static_cast(order.GetRestartPos())).Row(subSong.endRow).RetryNextRow()); } else { result = false; } } if(writeTempo && subSong.startOrder != ORDERINDEX_INVALID && subSong.startRow != ORDERINDEX_INVALID) { PATTERNINDEX writePat = order.EnsureUnique(subSong.startOrder); result &= m_sndFile.Patterns[writePat].WriteEffect( EffectWriter(CMD_TEMPO, mpt::saturate_round(order.GetDefaultTempo().ToDouble())).Row(subSong.startRow).RetryNextRow()); result &= m_sndFile.Patterns[writePat].WriteEffect( EffectWriter(CMD_SPEED, mpt::saturate_cast(order.GetDefaultSpeed())).Row(subSong.startRow).RetryNextRow()); } } order.SetRestartPos(0); return result; } bool ModSequenceSet::MergeSequences() { if(GetNumSequences() <= 1) return false; ModSequence &firstSeq = m_Sequences[0]; firstSeq.resize(firstSeq.GetLengthTailTrimmed()); std::vector patternsFixed(m_sndFile.Patterns.Size(), SEQUENCEINDEX_INVALID); // pattern fixed by other sequence already? // Mark patterns handled in first sequence for(auto pat : firstSeq) { if(m_sndFile.Patterns.IsValidPat(pat)) patternsFixed[pat] = 0; } for(SEQUENCEINDEX seqNum = 1; seqNum < GetNumSequences(); seqNum++) { ModSequence &sourceSeq = m_Sequences[seqNum]; const ORDERINDEX firstOrder = firstSeq.GetLength() + 1; // +1 for separator item const ORDERINDEX lengthTrimmed = sourceSeq.GetLengthTailTrimmed(); if(firstOrder + lengthTrimmed > m_sndFile.GetModSpecifications().ordersMax) { m_sndFile.AddToLog(LogWarning, MPT_UFORMAT("WARNING: Cannot merge Sequence {} (too long!)")(seqNum + 1)); continue; } firstSeq.reserve(firstOrder + lengthTrimmed); firstSeq.push_back(); // Separator item WriteGlobalsToPattern(seqNum, true, sourceSeq.GetDefaultTempo() != firstSeq.GetDefaultTempo() || sourceSeq.GetDefaultSpeed() != firstSeq.GetDefaultSpeed()); patternsFixed.resize(m_sndFile.Patterns.Size(), SEQUENCEINDEX_INVALID); // Previous line might have increased pattern count for(ORDERINDEX ord = 0; ord < lengthTrimmed; ord++) { PATTERNINDEX pat = sourceSeq[ord]; firstSeq.push_back(pat); // Try to fix pattern jump commands if(!m_sndFile.Patterns.IsValidPat(pat)) continue; auto m = m_sndFile.Patterns[pat].begin(); for(size_t len = 0; len < m_sndFile.Patterns[pat].GetNumRows() * m_sndFile.GetNumChannels(); m++, len++) { if(m->command == CMD_POSITIONJUMP) { if(patternsFixed[pat] != SEQUENCEINDEX_INVALID && patternsFixed[pat] != seqNum) { // Oops, some other sequence uses this pattern already. const PATTERNINDEX newPat = m_sndFile.Patterns.Duplicate(pat, true); if(newPat != PATTERNINDEX_INVALID) { // Could create new pattern - copy data over and continue from here. firstSeq[firstOrder + ord] = newPat; m = m_sndFile.Patterns[newPat].begin() + len; if(newPat >= patternsFixed.size()) patternsFixed.resize(newPat + 1, SEQUENCEINDEX_INVALID); pat = newPat; } else { // Cannot create new pattern: notify the user m_sndFile.AddToLog(LogWarning, MPT_UFORMAT("CONFLICT: Pattern break commands in Pattern {} might be broken since it has been used in several sequences!")(pat)); } } m->param = static_cast(m->param + firstOrder); patternsFixed[pat] = seqNum; } } } } m_Sequences.erase(m_Sequences.begin() + 1, m_Sequences.end()); m_currentSeq = 0; firstSeq.SetName({}); return true; } // Check if a playback position is currently locked (inaccessible) bool ModSequence::IsPositionLocked(ORDERINDEX position) const noexcept { return(m_sndFile.m_lockOrderStart != ORDERINDEX_INVALID && (position < m_sndFile.m_lockOrderStart || position > m_sndFile.m_lockOrderEnd)); } bool ModSequence::HasSubsongs() const noexcept { const auto endPat = begin() + GetLengthTailTrimmed(); return std::find_if(begin(), endPat, [&](PATTERNINDEX pat) { return pat != PATTERNINDEX_SKIP && !m_sndFile.Patterns.IsValidPat(pat); }) != endPat; } #endif // MODPLUG_TRACKER ///////////////////////////////////// // Read/Write ///////////////////////////////////// #ifndef MODPLUG_NO_FILESAVE size_t ModSequence::WriteAsByte(std::ostream &f, const ORDERINDEX count, uint8 stopIndex, uint8 ignoreIndex) const { const size_t limit = std::min(count, GetLength()); for(size_t i = 0; i < limit; i++) { const PATTERNINDEX pat = (*this)[i]; uint8 temp = static_cast(pat); if(pat == PATTERNINDEX_INVALID) temp = stopIndex; else if(pat == PATTERNINDEX_SKIP || pat > 0xFF) temp = ignoreIndex; mpt::IO::WriteIntLE(f, temp); } // Fill non-existing order items with stop indices for(size_t i = limit; i < count; i++) { mpt::IO::WriteIntLE(f, stopIndex); } return count; //Returns the number of bytes written. } #endif // MODPLUG_NO_FILESAVE void ReadModSequenceOld(std::istream& iStrm, ModSequenceSet& seq, const size_t) { uint16 size; mpt::IO::ReadIntLE(iStrm, size); if(size > ModSpecs::mptm.ordersMax) { seq.m_sndFile.AddToLog(LogWarning, MPT_UFORMAT("Module has sequence of length {}; it will be truncated to maximum supported length, {}.")(size, ModSpecs::mptm.ordersMax)); size = ModSpecs::mptm.ordersMax; } seq(0).resize(size); for(auto &pat : seq(0)) { uint16 temp; mpt::IO::ReadIntLE(iStrm, temp); pat = temp; } } #ifndef MODPLUG_NO_FILESAVE void WriteModSequenceOld(std::ostream& oStrm, const ModSequenceSet& seq) { const uint16 size = seq().GetLength(); mpt::IO::WriteIntLE(oStrm, size); for(auto pat : seq()) { mpt::IO::WriteIntLE(oStrm, static_cast(pat)); } } #endif // MODPLUG_NO_FILESAVE #ifndef MODPLUG_NO_FILESAVE void WriteModSequence(std::ostream& oStrm, const ModSequence& seq) { srlztn::SsbWrite ssb(oStrm); ssb.BeginWrite(FileIdSequence, Version::Current().GetRawVersion()); int8 useUTF8 = 1; ssb.WriteItem(useUTF8, "u"); ssb.WriteItem(mpt::ToCharset(mpt::Charset::UTF8, seq.GetName()), "n"); const uint16 length = seq.GetLengthTailTrimmed(); ssb.WriteItem(length, "l"); ssb.WriteItem(seq, "a", srlztn::VectorWriter(length)); if(seq.GetRestartPos() > 0) ssb.WriteItem(seq.GetRestartPos(), "r"); ssb.WriteItem(seq.GetDefaultTempo().GetRaw(), "t"); ssb.WriteItem(seq.GetDefaultSpeed(), "s"); ssb.FinishWrite(); } #endif // MODPLUG_NO_FILESAVE void ReadModSequence(std::istream& iStrm, ModSequence& seq, const size_t, mpt::Charset defaultCharset) { srlztn::SsbRead ssb(iStrm); ssb.BeginRead(FileIdSequence, Version::Current().GetRawVersion()); if(ssb.HasFailed()) { return; } int8 useUTF8 = 0; ssb.ReadItem(useUTF8, "u"); std::string str; ssb.ReadItem(str, "n"); seq.SetName(mpt::ToUnicode(useUTF8 ? mpt::Charset::UTF8 : defaultCharset, str)); ORDERINDEX nSize = 0; ssb.ReadItem(nSize, "l"); LimitMax(nSize, ModSpecs::mptm.ordersMax); ssb.ReadItem(seq, "a", srlztn::VectorReader(nSize)); ORDERINDEX restartPos = ORDERINDEX_INVALID; if(ssb.ReadItem(restartPos, "r") && restartPos < nSize) { seq.SetRestartPos(restartPos); } TEMPO::store_t defaultTempo = 0; if(ssb.ReadItem(defaultTempo, "t") && defaultTempo > 0) { seq.SetDefaultTempo(TEMPO{}.SetRaw(defaultTempo)); } uint32 defaultSpeed = 0; if(ssb.ReadItem(defaultSpeed, "s") && defaultSpeed > 0) { seq.SetDefaultSpeed(defaultSpeed); } } #ifndef MODPLUG_NO_FILESAVE void WriteModSequences(std::ostream& oStrm, const ModSequenceSet& seq) { srlztn::SsbWrite ssb(oStrm); ssb.BeginWrite(FileIdSequences, Version::Current().GetRawVersion()); const uint8 nSeqs = seq.GetNumSequences(); const uint8 nCurrent = seq.GetCurrentSequenceIndex(); ssb.WriteItem(nSeqs, "n"); ssb.WriteItem(nCurrent, "c"); for(uint8 i = 0; i < nSeqs; i++) { ssb.WriteItem(seq(i), srlztn::ID::FromInt(i), &WriteModSequence); } ssb.FinishWrite(); } #endif // MODPLUG_NO_FILESAVE void ReadModSequences(std::istream& iStrm, ModSequenceSet& seq, const size_t, mpt::Charset defaultCharset) { srlztn::SsbRead ssb(iStrm); ssb.BeginRead(FileIdSequences, Version::Current().GetRawVersion()); if(ssb.HasFailed()) { return; } SEQUENCEINDEX seqs = 0; uint8 currentSeq = 0; ssb.ReadItem(seqs, "n"); if (seqs == 0) return; LimitMax(seqs, MAX_SEQUENCES); ssb.ReadItem(currentSeq, "c"); if (seq.GetNumSequences() < seqs) seq.m_Sequences.resize(seqs, ModSequence(seq.m_sndFile)); // There used to be only one restart position / tempo / speed for all sequences const auto legacyRestartPos = seq(0).GetRestartPos(); const auto legacyTempo = seq(0).GetDefaultTempo(); const auto legacySpeed = seq(0).GetDefaultSpeed(); for(SEQUENCEINDEX i = 0; i < seqs; i++) { seq(i).SetRestartPos(legacyRestartPos); seq(i).SetDefaultTempo(legacyTempo); seq(i).SetDefaultSpeed(legacySpeed); ssb.ReadItem(seq(i), srlztn::ID::FromInt(i), [defaultCharset](std::istream &iStrm, ModSequence &seq, std::size_t dummy) { return ReadModSequence(iStrm, seq, dummy, defaultCharset); }); } seq.m_currentSeq = (currentSeq < seq.GetNumSequences()) ? currentSeq : 0; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Mixer.h0000644000175000017500000000444714144043206017341 00000000000000/* * Mixer.h * ------- * Purpose: Basic mixer constants * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/soundbase/MixSample.hpp" OPENMPT_NAMESPACE_BEGIN #define MPT_INTMIXER #ifdef MPT_INTMIXER using mixsample_t = MixSampleIntTraits::sample_type; enum { MIXING_FILTER_PRECISION = MixSampleIntTraits::filter_precision_bits }; // Fixed point resonant filter bits #else using mixsample_t = MixSampleFloat; #endif enum { MIXING_ATTENUATION = MixSampleIntTraits::mix_headroom_bits }; enum { MIXING_FRACTIONAL_BITS = MixSampleIntTraits::mix_fractional_bits }; inline constexpr float MIXING_SCALEF = MixSampleIntTraits::mix_scale; #ifdef MPT_INTMIXER static_assert(sizeof(mixsample_t) == 4); static_assert(MIXING_FILTER_PRECISION == 24); static_assert(MIXING_ATTENUATION == 4); static_assert(MIXING_FRACTIONAL_BITS == 27); static_assert(MixSampleIntTraits::mix_clip_max == int32(0x7FFFFFF)); static_assert(MixSampleIntTraits::mix_clip_min == (0 - int32(0x7FFFFFF))); static_assert(MIXING_SCALEF == 134217728.0f); #else static_assert(sizeof(mixsample_t) == 4); #endif #define MIXBUFFERSIZE 512 #define NUMMIXINPUTBUFFERS 4 #define VOLUMERAMPPRECISION 12 // Fractional bits in volume ramp variables // The absolute maximum number of sampling points any interpolation algorithm is going to look at in any direction from the current sampling point // Currently, the maximum is 4 sampling points forwards and 3 sampling points backwards (Polyphase / FIR algorithms). // Hence, this value must be at least 4. inline constexpr uint8 InterpolationMaxLookahead = 4; // While we could directly use the previous value in various places such as the interpolation wrap-around handling at loop points, // choosing a higher value (e.g. 16) will reduce CPU usage when using many extremely short (length < 16) samples. inline constexpr uint8 InterpolationLookaheadBufferSize = 16; static_assert(InterpolationLookaheadBufferSize >= InterpolationMaxLookahead); // Maximum size of a sampling point of a sample, in bytes. // The biggest sampling point size is currently 16-bit stereo = 2 * 2 bytes. inline constexpr uint8 MaxSamplingPointSize = 4; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/InstrumentExtensions.cpp0000644000175000017500000005762514754142465023064 00000000000000/* * InstrumentExtensions.cpp * ------------------------ * Purpose: Instrument properties I/O * Notes : Welcome to the absolutely horrible abominations that are the "extended instrument properties" * which are some of the earliest additions OpenMPT did to the IT / XM format. They are ugly, * and the way they work even differs between IT/XM/ITI/XI and ITI/XI/ITP. * Yes, the world would be a better place without this stuff. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #ifndef MODPLUG_NO_FILESAVE #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include #endif OPENMPT_NAMESPACE_BEGIN /*--------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------- MODULAR (in/out) ModInstrument : ----------------------------------------------------------------------------------------------- * to update: ------------ - both following functions need to be updated when adding a new member in ModInstrument: - SaveExtendedInstrumentProperties - ReadInstrumentHeaderField - see below for body declaration. * members: ---------- - 32bit identification CODE tag (must be unique) - 16bit content SIZE in byte(s) - member field * CODE tag naming convention: ----------------------------- - have a look below in current tag dictionnary - take the initial ones of the field name - 4 characters code (not more, not less) - must be filled with '.' characters if code has less than 4 characters - for arrays, must include a '[' character following significant characters ('.' not significant!!!) - use only characters used in full member name, ordered as they appear in it - match character attribute (small, capital) Example with "PanEnv.nLoopEnd" , "PitchEnv.nLoopEnd" & "VolEnv.Values[MAX_ENVPOINTS]" members: - use 'PLE.' for PanEnv.nLoopEnd - use 'PiLE' for PitchEnv.nLoopEnd - use 'VE[.' for VolEnv.Values[MAX_ENVPOINTS] * In use CODE tag dictionary (alphabetical order): -------------------------------------------------- AERN RW PanEnv.nReleaseNode AFLG R PanEnv.dwFlags CS.. RW nCutSwing DCT. R nDCT dF.. R dwFlags DNA. R nDNA FM.. RW filterMode fn[. R filename[12] FO.. RW nFadeOut GV.. R nGlobalVol IFC. R nIFC IFR. R nIFR K[.. Keyboard[128] MB.. RW wMidiBank MC.. RW nMidiChannel MiP. RW nMixPlug MP.. RW nMidiProgram MPWD RW MIDI Pitch Wheel Depth n[.. R name[32] NM[. R NoteMap[128] NNA. R nNNA P... RW nPan PE.. RW PanEnv.nNodes PE[. RW PanEnv.Values[MAX_ENVPOINTS] PERN RW PitchEnv.nReleaseNode PFLG R PitchEnv.dwFlags PiE. RW PitchEnv.nNodes PiE[ RW PitchEnv.Values[MAX_ENVPOINTS] PiLE R PitchEnv.nLoopEnd PiLS R PitchEnv.nLoopStart PiP[ RW PitchEnv.Ticks[MAX_ENVPOINTS] PiSB R PitchEnv.nSustainStart PiSE R PitchEnv.nSustainEnd PLE. R PanEnv.nLoopEnd PLS. R PanEnv.nLoopStart PP[. RW PanEnv.Ticks[MAX_ENVPOINTS] PPC. R nPPC PPS. R nPPS PS.. R nPanSwing PSB. R PanEnv.nSustainStart PSE. R PanEnv.nSustainEnd PTTF RW pitchToTempoLock (fractional part) PTTL RW pitchToTempoLock (integer part) PVEH RW pluginVelocityHandling PVOH RW pluginVolumeHandling R... RW Resampling RS.. RW nResSwing VE.. RW VolEnv.nNodes VE[. RW VolEnv.Values[MAX_ENVPOINTS] VERN RW VolEnv.nReleaseNode VFLG R VolEnv.dwFlags VLE. R VolEnv.nLoopEnd VLS. R VolEnv.nLoopStart VP[. RW VolEnv.Ticks[MAX_ENVPOINTS] VR.. RW nVolRampUp VS.. R nVolSwing VSB. R VolEnv.nSustainStart VSE. R VolEnv.nSustainEnd Note that many of these extensions were only relevant for ITP files, and thus there is no code for writing them, only reading. Some of them used to be written but were never read ("K[.." sample map - it was only relevant for ITP files, but even there it was always ignored, because sample indices may change when loading external instruments). ----------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------*/ #ifndef MODPLUG_NO_FILESAVE // We want constexpr ModInstrument{} due to bad code generation with temporary objects mostly in MSVC, // however most stdlib implementations of C++20 fail to provide constexpr std::vector in C++20 mode, // which is required for the envelopes. Thus we only activate that for C++23. // For libopenmpt, this code path is only required for test suite, // and inefficient code generation does not really matter. #if MPT_CXX_AT_LEAST(23) || (MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_CXX20_CONSTEXPR_CONTAINER)) #define MODINSTRUMENT_DEFAULT MPT_FORCE_CONSTEXPR_VALUE(ModInstrument{}) #elif defined(LIBOPENMPT_BUILD) #define MODINSTRUMENT_DEFAULT ModInstrument{} #else #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #pragma clang diagnostic ignored "-Wexit-time-destructors" #endif // MPT_COMPILER_CLANG static MPT_CONSTEXPR20_CONTAINER_VAR ModInstrument ModInstrumentDefault; #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #define MODINSTRUMENT_DEFAULT ModInstrumentDefault #endif template inline bool IsPropertyNonDefault(const ModInstrument &ins) { return MODINSTRUMENT_DEFAULT.*Member != ins.*Member; } template constexpr uint16 PropertySize() noexcept { return sizeof(ModInstrument{}.*Member); } template struct PropertyWriterBase { PropertyNeededFunc IsPropertyNeeded; static constexpr auto Size = PropertySizeFunc; PropertyWriterBase(PropertyNeededFunc propertyNeededFunc = IsPropertyNonDefault) : IsPropertyNeeded{std::move(propertyNeededFunc)} { } }; template ), auto PropertySizeFunc = PropertySize> struct PropertyWriterInt : PropertyWriterBase { using PropertyWriterBase::PropertyWriterBase; static void Write(std::ostream &file, const ModInstrument &ins) { mpt::IO::WriteIntLE(file, ins.*Member); } }; template ), auto PropertySizeFunc = PropertySize> struct PropertyWriterEnum : PropertyWriterBase { using PropertyWriterBase::PropertyWriterBase; static void Write(std::ostream &file, const ModInstrument &ins) { const auto value = ins.*Member; static_assert(std::is_enum_v); mpt::IO::WriteIntLE(file, mpt::to_underlying(value)); } }; struct PropertyWriterReleaseNode { bool IsPropertyNeeded(const ModInstrument &ins) const noexcept { return MODINSTRUMENT_DEFAULT.GetEnvelope(type).nReleaseNode != ins.GetEnvelope(type).nReleaseNode; } static constexpr uint16 Size() noexcept { return sizeof(InstrumentEnvelope{}.nReleaseNode); } void Write(std::ostream &file, const ModInstrument &ins) const { mpt::IO::WriteIntLE(file, ins.GetEnvelope(type).nReleaseNode); } const EnvelopeType type; }; struct PropertyWriterEnvelopeBase { PropertyWriterEnvelopeBase(uint32 nodes, EnvelopeType type) : nodes{nodes}, type{type} {} static bool IsPropertyNeeded(const ModInstrument &) noexcept { return true; } const uint32 nodes; const EnvelopeType type; }; struct PropertyWriterEnvelopeSize : PropertyWriterEnvelopeBase { using PropertyWriterEnvelopeBase::PropertyWriterEnvelopeBase; static constexpr uint16 Size() noexcept { return sizeof(uint32le); } void Write(std::ostream &file, const ModInstrument &ins) const { mpt::IO::WriteIntLE(file, ins.GetEnvelope(type).size()); } }; struct PropertyWriterEnvelopeTicks : PropertyWriterEnvelopeBase { using PropertyWriterEnvelopeBase::PropertyWriterEnvelopeBase; uint16 Size() const noexcept { return static_cast(sizeof(uint16le) * nodes); } void Write(std::ostream &file, const ModInstrument &ins) const { const auto &env = ins.GetEnvelope(type); const uint32 maxNodes = std::min(nodes, static_cast(env.size())); for(uint32 i = 0; i < maxNodes; ++i) { mpt::IO::WriteIntLE(file, static_cast(env[i].tick)); } // Not every instrument's envelope will be the same length. fill up with zeros. uint16le padding{}; for(uint32 i = maxNodes; i < nodes; ++i) { mpt::IO::Write(file, padding); } } }; struct PropertyWriterEnvelopeValues : PropertyWriterEnvelopeBase { using PropertyWriterEnvelopeBase::PropertyWriterEnvelopeBase; uint16 Size() const noexcept { return static_cast(sizeof(uint8) * nodes); } void Write(std::ostream &file, const ModInstrument &ins) const { const auto &env = ins.GetEnvelope(type); const uint32 maxNodes = std::min(nodes, static_cast(env.size())); for(uint32 i = 0; i < maxNodes; ++i) { mpt::IO::WriteIntLE(file, static_cast(env[i].value)); } // Not every instrument's envelope will be the same length. fill up with zeros. uint8 padding{}; for(uint32 i = maxNodes; i < nodes; ++i) { mpt::IO::Write(file, padding); } } }; struct PropertyWriterPitchTempoLock { static constexpr auto IsPropertyNeeded = IsPropertyNonDefault<&ModInstrument::pitchToTempoLock>; static constexpr uint16 Size() noexcept { return sizeof(uint16le); } PropertyWriterPitchTempoLock(bool intPart) : m_intPart{intPart} {} void Write(std::ostream &file, const ModInstrument &ins) { mpt::IO::WriteIntLE(file, static_cast(m_intPart ? ins.pitchToTempoLock.GetInt() : ins.pitchToTempoLock.GetFract())); } const bool m_intPart; }; template static void WriteProperty(std::ostream &f, uint32 code, mpt::span instruments, PropertyWriter property) { bool writeProperty = false; for(const ModInstrument *ins : instruments) { if(ins != nullptr && property.IsPropertyNeeded(*ins)) { writeProperty = true; break; } } if(!writeProperty) return; mpt::IO::WriteIntLE(f, code); mpt::IO::WriteIntLE(f, property.Size()); for(const ModInstrument *ins : instruments) { property.Write(f, ins ? *ins : MODINSTRUMENT_DEFAULT); } } void CSoundFile::SaveExtendedInstrumentProperties(INSTRUMENTINDEX instr, MODTYPE forceType, std::ostream &f) const { const bool allInstruments = (instr < 1 || instr > GetNumInstruments()); const auto instruments = mpt::as_span(Instruments).subspan(allInstruments ? 1 : instr, allInstruments ? GetNumInstruments() : 1); SaveExtendedInstrumentProperties(instruments, forceType, f, allInstruments); } void CSoundFile::SaveExtendedInstrumentProperties(mpt::span instruments, MODTYPE forceType, std::ostream &f, bool allInstruments) { uint32 code = MagicBE("MPTX"); // write extension header code mpt::IO::WriteIntLE(f, code); WriteProperty(f, MagicBE("VR.."), instruments, PropertyWriterInt<&ModInstrument::nVolRampUp>{}); WriteProperty(f, MagicBE("MiP."), instruments, PropertyWriterInt<&ModInstrument::nMixPlug>{}); WriteProperty(f, MagicBE("R..."), instruments, PropertyWriterEnum<&ModInstrument::resampling>{}); WriteProperty(f, MagicBE("PVEH"), instruments, PropertyWriterEnum<&ModInstrument::pluginVelocityHandling>{}); WriteProperty(f, MagicBE("PVOH"), instruments, PropertyWriterEnum<&ModInstrument::pluginVolumeHandling>{}); if(!(forceType & MOD_TYPE_XM)) { // XM instrument headers already stores full-precision fade-out WriteProperty(f, MagicBE("FO.."), instruments, PropertyWriterInt<&ModInstrument::nFadeOut>{[](const ModInstrument &ins) { return (ins.nFadeOut % 32u) || ins.nFadeOut > 8192; }}); // XM instrument headers already have support for this // Note: For ITI we always want to write this property, hence the allInstruments check int32 prevPWD = allInstruments ? int32_min : int32_max; WriteProperty(f, MagicBE("MPWD"), instruments, PropertyWriterInt<&ModInstrument::midiPWD, std::function>{[&prevPWD](const ModInstrument& ins) { if((prevPWD != int32_min && ins.midiPWD != prevPWD) || (ins.midiPWD < 0)) return true; prevPWD = ins.midiPWD; return false; }}); // We never supported these as hacks in XM (luckily!) WriteProperty(f, MagicBE("P..."), instruments, PropertyWriterInt<&ModInstrument::nPan>{[](const ModInstrument &ins) { return ins.dwFlags[INS_SETPANNING] && (ins.nPan % 4u); }}); WriteProperty(f, MagicBE("CS.."), instruments, PropertyWriterInt<&ModInstrument::nCutSwing>{}); WriteProperty(f, MagicBE("RS.."), instruments, PropertyWriterInt<&ModInstrument::nResSwing>{}); WriteProperty(f, MagicBE("FM.."), instruments, PropertyWriterEnum<&ModInstrument::filterMode>{}); WriteProperty(f, MagicBE("PTTL"), instruments, PropertyWriterPitchTempoLock{true}); WriteProperty(f, MagicLE("PTTF"), instruments, PropertyWriterPitchTempoLock{false}); } else { WriteProperty(f, MagicBE("MC.."), instruments, PropertyWriterInt<&ModInstrument::nMidiChannel>{[](const ModInstrument &ins) { return ins.nMidiChannel == MidiMappedChannel; }}); // Can be saved in XM, but it's not possible to NOT save a MIDI program if a MIDI channel is set WriteProperty(f, MagicBE("MP.."), instruments, PropertyWriterInt<&ModInstrument::nMidiProgram>{[](const ModInstrument &ins) { return ins.HasValidMIDIChannel() == (ins.nMidiProgram == 0); }}); WriteProperty(f, MagicBE("MB.."), instruments, PropertyWriterInt<&ModInstrument::wMidiBank>{}); } if(forceType & MOD_TYPE_MPT) { uint32 maxNodes[3] = { 0, 0, 0 }; for(const ModInstrument *ins : instruments) { if(ins == nullptr) continue; maxNodes[0] = std::max(maxNodes[0], ins->VolEnv.size()); maxNodes[1] = std::max(maxNodes[1], ins->PanEnv.size()); maxNodes[2] = std::max(maxNodes[2], ins->PitchEnv.size()); } // write full envelope information for MPTM files (more env points) if(maxNodes[0] > 25) { WriteProperty(f, MagicBE("VE.."), instruments, PropertyWriterEnvelopeSize{maxNodes[0], ENV_VOLUME}); WriteProperty(f, MagicBE("VP[."), instruments, PropertyWriterEnvelopeTicks{maxNodes[0], ENV_VOLUME}); WriteProperty(f, MagicBE("VE[."), instruments, PropertyWriterEnvelopeValues{maxNodes[0], ENV_VOLUME}); } if(maxNodes[1] > 25) { WriteProperty(f, MagicBE("PE.."), instruments, PropertyWriterEnvelopeSize{maxNodes[1], ENV_PANNING}); WriteProperty(f, MagicBE("PP[."), instruments, PropertyWriterEnvelopeTicks{maxNodes[1], ENV_PANNING}); WriteProperty(f, MagicBE("PE[."), instruments, PropertyWriterEnvelopeValues{maxNodes[1], ENV_PANNING}); } if(maxNodes[2] > 25) { WriteProperty(f, MagicBE("PiE."), instruments, PropertyWriterEnvelopeSize{maxNodes[2], ENV_PITCH}); WriteProperty(f, MagicBE("PiP["), instruments, PropertyWriterEnvelopeTicks{maxNodes[2], ENV_PITCH}); WriteProperty(f, MagicBE("PiE["), instruments, PropertyWriterEnvelopeValues{maxNodes[2], ENV_PITCH}); } WriteProperty(f, MagicBE("VERN"), instruments, PropertyWriterReleaseNode{ENV_VOLUME}); WriteProperty(f, MagicBE("AERN"), instruments, PropertyWriterReleaseNode{ENV_PANNING}); WriteProperty(f, MagicBE("PERN"), instruments, PropertyWriterReleaseNode{ENV_PITCH}); } } #undef MODINSTRUMENT_DEFAULT #endif // !MODPLUG_NO_FILESAVE // Convert instrument flags which were read from 'dF..' extension to proper internal representation. static void ConvertInstrumentFlags(ModInstrument &ins, uint32 flags) { ins.VolEnv.dwFlags.set(ENV_ENABLED, (flags & 0x0001) != 0); ins.VolEnv.dwFlags.set(ENV_SUSTAIN, (flags & 0x0002) != 0); ins.VolEnv.dwFlags.set(ENV_LOOP, (flags & 0x0004) != 0); ins.VolEnv.dwFlags.set(ENV_CARRY, (flags & 0x0800) != 0); ins.PanEnv.dwFlags.set(ENV_ENABLED, (flags & 0x0008) != 0); ins.PanEnv.dwFlags.set(ENV_SUSTAIN, (flags & 0x0010) != 0); ins.PanEnv.dwFlags.set(ENV_LOOP, (flags & 0x0020) != 0); ins.PanEnv.dwFlags.set(ENV_CARRY, (flags & 0x1000) != 0); ins.PitchEnv.dwFlags.set(ENV_ENABLED, (flags & 0x0040) != 0); ins.PitchEnv.dwFlags.set(ENV_SUSTAIN, (flags & 0x0080) != 0); ins.PitchEnv.dwFlags.set(ENV_LOOP, (flags & 0x0100) != 0); ins.PitchEnv.dwFlags.set(ENV_CARRY, (flags & 0x2000) != 0); ins.PitchEnv.dwFlags.set(ENV_FILTER, (flags & 0x0400) != 0); ins.dwFlags.set(INS_SETPANNING, (flags & 0x0200) != 0); ins.dwFlags.set(INS_MUTE, (flags & 0x4000) != 0); } // Convert VFLG / PFLG / AFLG static void ConvertEnvelopeFlags(ModInstrument &instr, uint32 flags, EnvelopeType envType) { InstrumentEnvelope &env = instr.GetEnvelope(envType); env.dwFlags.set(ENV_ENABLED, (flags & 0x01) != 0); env.dwFlags.set(ENV_LOOP, (flags & 0x02) != 0); env.dwFlags.set(ENV_SUSTAIN, (flags & 0x04) != 0); env.dwFlags.set(ENV_CARRY, (flags & 0x08) != 0); env.dwFlags.set(ENV_FILTER, (envType == ENV_PITCH) && (flags & 0x10) != 0); } static void ReadInstrumentHeaderField(ModInstrument &ins, uint32 fcode, FileReader &file) { const size_t size = static_cast(file.GetLength()); // Note: Various int / enum members have changed their size over the past. // Hence we use ReadSizedIntLE everywhere to allow reading both truncated and oversized values. constexpr auto ReadInt = [](FileReader &file, auto size, auto &member) { using T = std::remove_reference_t; member = file.ReadSizedIntLE(size); }; constexpr auto ReadEnum = [](FileReader &file, auto size, auto &member) { using T = std::remove_reference_t; static_assert(std::is_enum_v); member = static_cast(file.ReadSizedIntLE>(size)); }; constexpr auto ReadEnvelopeTicks = [](FileReader &file, auto size, InstrumentEnvelope &env) { const uint32 points = std::min(env.size(), static_cast(size / 2)); for(uint32 i = 0; i < points; i++) { env[i].tick = file.ReadUint16LE(); } }; constexpr auto ReadEnvelopeValues = [](FileReader &file, auto size, InstrumentEnvelope &env) { const uint32 points = std::min(env.size(), static_cast(size)); for(uint32 i = 0; i < points; i++) { env[i].value = file.ReadUint8(); } }; // Members which can be found in this table but not in the write table are only required in the legacy ITP format. switch(fcode) { case MagicBE("FO.."): ReadInt(file, size, ins.nFadeOut); break; case MagicBE("GV.."): ReadInt(file, size, ins.nGlobalVol); break; case MagicBE("P..."): ReadInt(file, size, ins.nPan); break; case MagicBE("VLS."): ReadInt(file, size, ins.VolEnv.nLoopStart); break; case MagicBE("VLE."): ReadInt(file, size, ins.VolEnv.nLoopEnd); break; case MagicBE("VSB."): ReadInt(file, size, ins.VolEnv.nSustainStart); break; case MagicBE("VSE."): ReadInt(file, size, ins.VolEnv.nSustainEnd); break; case MagicBE("PLS."): ReadInt(file, size, ins.PanEnv.nLoopStart); break; case MagicBE("PLE."): ReadInt(file, size, ins.PanEnv.nLoopEnd); break; case MagicBE("PSB."): ReadInt(file, size, ins.PanEnv.nSustainStart); break; case MagicBE("PSE."): ReadInt(file, size, ins.PanEnv.nSustainEnd); break; case MagicBE("PiLS"): ReadInt(file, size, ins.PitchEnv.nLoopStart); break; case MagicBE("PiLE"): ReadInt(file, size, ins.PitchEnv.nLoopEnd); break; case MagicBE("PiSB"): ReadInt(file, size, ins.PitchEnv.nSustainStart); break; case MagicBE("PiSE"): ReadInt(file, size, ins.PitchEnv.nSustainEnd); break; case MagicBE("NNA."): ReadEnum(file, size, ins.nNNA); break; case MagicBE("DCT."): ReadEnum(file, size, ins.nDCT); break; case MagicBE("DNA."): ReadEnum(file, size, ins.nDNA); break; case MagicBE("PS.."): ReadInt(file, size, ins.nPanSwing); break; case MagicBE("VS.."): ReadInt(file, size, ins.nVolSwing); break; case MagicBE("IFC."): ReadInt(file, size, ins.nIFC); break; case MagicBE("IFR."): ReadInt(file, size, ins.nIFR); break; case MagicBE("MB.."): ReadInt(file, size, ins.wMidiBank); break; case MagicBE("MP.."): ReadInt(file, size, ins.nMidiProgram); break; case MagicBE("MC.."): ReadInt(file, size, ins.nMidiChannel); break; case MagicBE("PPS."): ReadInt(file, size, ins.nPPS); break; case MagicBE("PPC."): ReadInt(file, size, ins.nPPC); break; case MagicBE("VP[."): ReadEnvelopeTicks(file, size, ins.VolEnv); break; case MagicBE("PP[."): ReadEnvelopeTicks(file, size, ins.PanEnv); break; case MagicBE("PiP["): ReadEnvelopeTicks(file, size, ins.PitchEnv); break; case MagicBE("VE[."): ReadEnvelopeValues(file, size, ins.VolEnv); break; case MagicBE("PE[."): ReadEnvelopeValues(file, size, ins.PanEnv); break; case MagicBE("PiE["): ReadEnvelopeValues(file, size, ins.PitchEnv); break; case MagicBE("MiP."): ReadInt(file, size, ins.nMixPlug); break; case MagicBE("VR.."): ReadInt(file, size, ins.nVolRampUp); break; case MagicBE("CS.."): ReadInt(file, size, ins.nCutSwing); break; case MagicBE("RS.."): ReadInt(file, size, ins.nResSwing); break; case MagicBE("FM.."): ReadEnum(file, size, ins.filterMode); break; case MagicBE("PVEH"): ReadEnum(file, size, ins.pluginVelocityHandling); break; case MagicBE("PVOH"): ReadEnum(file, size, ins.pluginVolumeHandling); break; case MagicBE("PERN"): ReadInt(file, size, ins.PitchEnv.nReleaseNode); break; case MagicBE("AERN"): ReadInt(file, size, ins.PanEnv.nReleaseNode); break; case MagicBE("VERN"): ReadInt(file, size, ins.VolEnv.nReleaseNode); break; case MagicBE("MPWD"): ReadInt(file, size, ins.midiPWD); break; case MagicBE("dF.."): ConvertInstrumentFlags(ins, file.ReadSizedIntLE(size)); break; case MagicBE("VFLG"): ConvertEnvelopeFlags(ins, file.ReadSizedIntLE(size), ENV_VOLUME); break; case MagicBE("AFLG"): ConvertEnvelopeFlags(ins, file.ReadSizedIntLE(size), ENV_PANNING); break; case MagicBE("PFLG"): ConvertEnvelopeFlags(ins, file.ReadSizedIntLE(size), ENV_PITCH); break; case MagicBE("NM[."): for(std::size_t i = 0; i < std::min(size, ins.NoteMap.size()); i++) { ins.NoteMap[i] = file.ReadUint8(); } break; case MagicBE("n[.."): { char name[32] = ""; file.ReadString(name, size); ins.name = name; } break; case MagicBE("fn[."): { char filename[32] = ""; file.ReadString(filename, size); ins.filename = filename; } break; case MagicBE("R..."): // Resampling has been written as various sizes including uint16 and uint32 in the past if(uint32 resampling = file.ReadSizedIntLE(size); Resampling::IsKnownMode(resampling)) ins.resampling = static_cast(resampling); break; case MagicBE("PTTL"): // Integer part of pitch/tempo lock ins.pitchToTempoLock.Set(file.ReadSizedIntLE(size), ins.pitchToTempoLock.GetFract()); break; case MagicLE("PTTF"): // Fractional part of pitch/tempo lock ins.pitchToTempoLock.Set(ins.pitchToTempoLock.GetInt(), file.ReadSizedIntLE(size)); break; case MagicBE("VE.."): ins.VolEnv.resize(std::min(uint32(MAX_ENVPOINTS), file.ReadSizedIntLE(size))); break; case MagicBE("PE.."): ins.PanEnv.resize(std::min(uint32(MAX_ENVPOINTS), file.ReadSizedIntLE(size))); break; case MagicBE("PiE."): ins.PitchEnv.resize(std::min(uint32(MAX_ENVPOINTS), file.ReadSizedIntLE(size))); break; } } // For ITP and internal usage void CSoundFile::ReadExtendedInstrumentProperty(mpt::span instruments, const uint32 code, FileReader &file) { uint16 size = file.ReadUint16LE(); for(ModInstrument *ins : instruments) { FileReader chunk = file.ReadChunk(size); if(ins && chunk.GetLength() == size) ReadInstrumentHeaderField(*ins, code, chunk); } } // For IT / XM / MO3 / ITI / XI bool CSoundFile::LoadExtendedInstrumentProperties(mpt::span instruments, FileReader &file) { if(!file.ReadMagic("XTPM")) // 'MPTX' return false; while(file.CanRead(6)) { uint32 code = file.ReadUint32LE(); if(code == MagicBE("MPTS") // Reached song extensions, break out of this loop || code == MagicLE("228\x04") // Reached MPTM extensions (in case there are no song extensions) || (code & 0x80808080) || !(code & 0x60606060)) // Non-ASCII chunk ID { file.SkipBack(4); break; } ReadExtendedInstrumentProperty(instruments, code, file); } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MixerInterface.h0000644000175000017500000000770514616613571021176 00000000000000/* * MixerInterface.h * ---------------- * Purpose: The basic mixer interface and main mixer loop, completely agnostic of the actual sample input / output formats. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" #include "ModChannel.h" OPENMPT_NAMESPACE_BEGIN class CResampler; ////////////////////////////////////////////////////////////////////////// // Sample conversion traits template struct MixerTraits { static constexpr int numChannelsIn = channelsIn; // Number of channels in sample static constexpr int numChannelsOut = channelsOut; // Number of mixer output channels using output_t = out; // Output buffer sample type using input_t = in; // Input buffer sample type using outbuf_t = out[channelsOut]; // Output buffer sampling point type // To perform sample conversion, add a function with the following signature to your derived classes: // static MPT_CONSTEXPRINLINE output_t Convert(const input_t x) }; ////////////////////////////////////////////////////////////////////////// // Interpolation templates template struct NoInterpolation { ModChannel &channel; MPT_FORCEINLINE NoInterpolation(ModChannel &c, const CResampler &, unsigned int) : channel{c} { // Adding 0.5 to the sample position before the interpolation loop starts // effectively gives us nearest-neighbour with rounding instead of truncation. // This gives us more consistent behaviour between forward and reverse playing of a sample. c.position += SamplePosition::Ratio(1, 2); } MPT_FORCEINLINE ~NoInterpolation() { channel.position -= SamplePosition::Ratio(1, 2); } MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32) { static_assert(static_cast(Traits::numChannelsIn) <= static_cast(Traits::numChannelsOut), "Too many input channels"); for(int i = 0; i < Traits::numChannelsIn; i++) { outSample[i] = Traits::Convert(inBuffer[i]); } } }; // Other interpolation algorithms depend on the input format type (integer / float) and can thus be found in FloatMixer.h and IntMixer.h ////////////////////////////////////////////////////////////////////////// // Main sample render loop template // Template parameters: // Traits: A class derived from MixerTraits that defines the number of channels, sample buffer types, etc.. // InterpolationFunc: Functor for reading the sample data and doing the SRC // FilterFunc: Functor for applying the resonant filter // MixFunc: Functor for mixing the computed sample data into the output buffer template inline void SampleLoop(ModChannel &chn, const CResampler &resampler, typename Traits::output_t * MPT_RESTRICT outBuffer, unsigned int numSamples) { ModChannel &c = chn; const typename Traits::input_t * MPT_RESTRICT inSample = static_cast(c.pCurrentSample); InterpolationFunc interpolate{c, resampler, numSamples}; FilterFunc filter{c}; MixFunc mix{c}; unsigned int samples = numSamples; SamplePosition smpPos = c.position; // Fixed-point sample position const SamplePosition increment = c.increment; // Fixed-point sample increment while(samples--) { typename Traits::outbuf_t outSample; interpolate(outSample, inSample + smpPos.GetInt() * Traits::numChannelsIn, smpPos.GetFract()); filter(outSample, c); mix(outSample, c, outBuffer); outBuffer += Traits::numChannelsOut; smpPos += increment; } c.position = smpPos; } // Type of the SampleLoop function above using MixFuncInterface = void (*)(ModChannel &, const CResampler &, mixsample_t *, unsigned int); OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_amf.cpp0000644000175000017500000005102014644610543020310 00000000000000/* * Load_amf.cpp * ------------ * Purpose: AMF module loader * Notes : There are two types of AMF files, the ASYLUM Music Format (used in Crusader: No Remorse and Crusader: No Regret) * and Advanced Music Format (DSMI / Digital Sound And Music Interface, used in various games such as Pinball World). * Both module types are handled here. * To make things complete, there appears to be a (potentially unofficial) variant of the DSMI AMF format called DMF, * used in various games published by Webfoot (Tronic, H2O, PowBall, ...). * It mostly resembles "normal" AMF files, but with all song and sample names removed and using delta-encoded samples * (probably the origin of the "D" in DMF). * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "mpt/endian/int24.hpp" #include OPENMPT_NAMESPACE_BEGIN // ASYLUM AMF File Header struct AsylumFileHeader { char signature[32]; uint8 defaultSpeed; uint8 defaultTempo; uint8 numSamples; uint8 numPatterns; uint8 numOrders; uint8 restartPos; }; MPT_BINARY_STRUCT(AsylumFileHeader, 38) // ASYLUM AMF Sample Header struct AsylumSampleHeader { char name[22]; uint8le finetune; uint8le defaultVolume; int8le transpose; uint32le length; uint32le loopStart; uint32le loopLength; // Convert an AMF sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.nFineTune = MOD2XMFineTune(finetune); mptSmp.nVolume = std::min(defaultVolume.get(), uint8(64)) * 4u; mptSmp.RelativeTone = transpose; mptSmp.nLength = length; if(loopLength > 2 && loopStart + loopLength <= length) { mptSmp.uFlags.set(CHN_LOOP); mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopStart + loopLength; } } }; MPT_BINARY_STRUCT(AsylumSampleHeader, 37) static bool ValidateHeader(const AsylumFileHeader &fileHeader) { if(std::memcmp(fileHeader.signature, "ASYLUM Music Format V1.0\0", 25) || fileHeader.numSamples > 64 ) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const AsylumFileHeader &fileHeader) { return 256 + 64 * sizeof(AsylumSampleHeader) + 64 * 4 * 8 * fileHeader.numPatterns; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize) { AsylumFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); AsylumFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_AMF0, 8); SetupMODPanning(true); Order().SetDefaultSpeed(fileHeader.defaultSpeed); Order().SetDefaultTempoInt(fileHeader.defaultTempo); m_nSamples = fileHeader.numSamples; if(fileHeader.restartPos < fileHeader.numOrders) { Order().SetRestartPos(fileHeader.restartPos); } m_modFormat.formatName = UL_("ASYLUM Music Format"); m_modFormat.type = UL_("amf"); m_modFormat.charset = mpt::Charset::CP437; uint8 orders[256]; file.ReadArray(orders); ReadOrderFromArray(Order(), orders, fileHeader.numOrders); // Read Sample Headers for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { AsylumSampleHeader sampleHeader; file.ReadStruct(sampleHeader); sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name); } file.Skip((64 - fileHeader.numSamples) * sizeof(AsylumSampleHeader)); // Read Patterns Patterns.ResizeArray(fileHeader.numPatterns); for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { file.Skip(64 * 4 * 8); continue; } for(auto &m : Patterns[pat]) { const auto [note, instr, command, param] = file.ReadArray(); if(note && note + 12 + NOTE_MIN <= NOTE_MAX) { m.note = note + 12 + NOTE_MIN; } m.instr = instr; ConvertModCommand(m, command, param); #ifdef MODPLUG_TRACKER if(m.command == CMD_PANNING8) { // Convert 7-bit panning to 8-bit m.param = mpt::saturate_cast(m.param * 2u); } #endif } } if(loadFlags & loadSampleData) { // Read Sample Data const SampleIO sampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM); for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { sampleIO.ReadSample(Samples[smp], file); } } return true; } // DSMI AMF magic bytes struct AMFFileSignature { char amf[3]; // "AMF" for regular AMF files, "DMF" for the compact format found in Webfoot games uint8 version; bool IsValidAMF() const { return !std::memcmp(amf, "AMF", 3) && (version == 1 || (version >= 8 && version <= 14)); } bool IsValidDMF() const { // Version checks are only an assumption; All Webfoot games use version 14 files, but we can probably assume // that if there are earlier versions, they differ in exactly the same way from regular AMF as those files do. return !std::memcmp(amf, "DMF", 3) && (version >= 10 && version <= 14); } }; MPT_BINARY_STRUCT(AMFFileSignature, 4) // DSMI AMF File Header struct AMFFileHeader { uint8le numSamples; uint8le numOrders; uint16le numTracks; uint8le numChannels; // v9+ bool IsValid(const uint8 version) const { if(!numSamples || !numOrders || !numTracks) return false; if(version < 9) return true; if(version < 12) return (numChannels >= 1 && numChannels <= 16); return (numChannels >= 1 && numChannels <= 32); } // How much of AMFFileHeader should actually be read static size_t GetHeaderSize(const uint8 version) { return (version >= 9) ? sizeof(AMFFileHeader) : 4u; } }; MPT_BINARY_STRUCT(AMFFileHeader, 5) // DSMI AMF Sample Header (v1-v9) struct AMFSampleHeaderOld { uint8le type; char name[32]; char filename[13]; uint32le index; uint16le length; uint16le sampleRate; uint8le volume; uint16le loopStart; uint16le loopEnd; void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename); mptSmp.nLength = length; mptSmp.nC5Speed = sampleRate; mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4u; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; if(mptSmp.nLoopEnd == uint16_max) mptSmp.nLoopStart = mptSmp.nLoopEnd = 0; else if(type != 0 && mptSmp.nLoopEnd > mptSmp.nLoopStart + 2 && mptSmp.nLoopEnd <= mptSmp.nLength) mptSmp.uFlags.set(CHN_LOOP); } }; MPT_BINARY_STRUCT(AMFSampleHeaderOld, 59) // DSMI AMF Sample Header (v10+) struct AMFSampleHeaderNew { uint8le type; char name[32]; char filename[13]; uint32le index; uint32le length; uint16le sampleRate; uint8le volume; uint32le loopStart; uint32le loopEnd; void ConvertToMPT(ModSample &mptSmp, bool truncated) const { mptSmp.Initialize(); mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename); mptSmp.nLength = length; mptSmp.nC5Speed = sampleRate; mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4u; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; if(truncated && mptSmp.nLoopStart > 0) mptSmp.nLoopEnd = mptSmp.nLength; if(type != 0 && mptSmp.nLoopEnd > mptSmp.nLoopStart + 2 && mptSmp.nLoopEnd <= mptSmp.nLength) mptSmp.uFlags.set(CHN_LOOP); } // Check if sample headers might be truncated bool IsValid(uint8 numSamples) const { return type <= 1 && index <= numSamples && length <= 0x100000 && volume <= 64 && loopStart <= length && loopEnd <= length; } }; MPT_BINARY_STRUCT(AMFSampleHeaderNew, 65) // DSMI DMF ("compact AMF") Sample Header struct AMFSampleHeaderCompact { using uint24le = mpt::uint24le; uint8le type; char leftOverFirstCharOfSampleName; uint32le index; uint32le length; uint16le sampleRate; uint8le volume; uint32le loopStart; uint24le loopEnd; void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.filename = std::string(1, leftOverFirstCharOfSampleName); // Why not :) mptSmp.nLength = length; mptSmp.nC5Speed = sampleRate; mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4u; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd.get(); if(type != 0 && mptSmp.nLoopEnd > mptSmp.nLoopStart + 2 && mptSmp.nLoopEnd <= mptSmp.nLength) mptSmp.uFlags.set(CHN_LOOP); } }; MPT_BINARY_STRUCT(AMFSampleHeaderCompact, 20) // Read a single AMF track (channel) into a pattern. static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &fileChunk) { fileChunk.Rewind(); while(fileChunk.CanRead(3)) { const auto [row, command, value] = fileChunk.ReadArray(); if(row >= pattern.GetNumRows()) { break; } ModCommand &m = *pattern.GetpModCommand(row, chn); if(command < 0x7F) { // Note + Volume if(command == 0 && value == 0) { m.note = NOTE_NOTECUT; } else { m.note = command + NOTE_MIN; if(value != 0xFF) { m.volcmd = VOLCMD_VOLUME; m.vol = value; } } } else if(command == 0x7F) { // Instrument without note retrigger in MOD (no need to do anything here, should be preceded by 0x80 command) } else if(command == 0x80) { // Instrument m.instr = value + 1; } else { // Effect static constexpr EffectCommand effTrans[] = { CMD_NONE, CMD_SPEED, CMD_VOLUMESLIDE, CMD_VOLUME, CMD_PORTAMENTOUP, CMD_NONE, CMD_TONEPORTAMENTO, CMD_TREMOR, CMD_ARPEGGIO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_PATTERNBREAK, CMD_POSITIONJUMP, CMD_NONE, CMD_RETRIG, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_PORTAMENTOUP, CMD_S3MCMDEX, CMD_S3MCMDEX, CMD_TEMPO, CMD_PORTAMENTOUP, CMD_PANNING8, }; uint8 param = value; EffectCommand cmd = CMD_NONE; if(uint8 maskedCmd = command & 0x7F; maskedCmd < std::size(effTrans)) cmd = effTrans[maskedCmd]; // Fix some commands... switch(command & 0x7F) { // 02: Volume Slide // 0A: Tone Porta + Vol Slide // 0B: Vibrato + Vol Slide case 0x02: case 0x0A: case 0x0B: if(param & 0x80) param = (-static_cast(param)) & 0x0F; else param = (param & 0x0F) << 4; break; // 03: Volume case 0x03: param = std::min(param, uint8(64)); if(m.volcmd == VOLCMD_NONE || m.volcmd == VOLCMD_VOLUME) { m.volcmd = VOLCMD_VOLUME; m.vol = param; cmd = CMD_NONE; } break; // 04: Porta Up/Down case 0x04: if(param & 0x80) param = (-static_cast(param)) & 0x7F; else cmd = CMD_PORTAMENTODOWN; break; // 11: Fine Volume Slide case 0x11: if(param) { if(param & 0x80) param = static_cast(0xF0 | ((-static_cast(param)) & 0x0F)); else param = 0x0F | ((param & 0x0F) << 4); } else { cmd = CMD_NONE; } break; // 12: Fine Portamento // 16: Extra Fine Portamento case 0x12: case 0x16: if(param) { cmd = (param & 0x80) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN; if(param & 0x80) { param = ((-static_cast(param)) & 0x0F); } param |= (command == 0x16) ? 0xE0 : 0xF0; } else { cmd = CMD_NONE; } break; // 13: Note Delay case 0x13: param = 0xD0 | (param & 0x0F); break; // 14: Note Cut case 0x14: param = 0xC0 | (param & 0x0F); break; // 17: Panning case 0x17: if(param == 100) { // History lesson intermission: According to Otto Chrons, he remembers that he added support // for 8A4 / XA4 "surround" panning in DMP for MOD and S3M files before any other trackers did, // So DSMI / DMP are most likely the original source of these 7-bit panning + surround commands! param = 0xA4; } else { param = static_cast(std::clamp(static_cast(param) + 64, 0, 128)); if(m.command != CMD_NONE) { // Move to volume column if required if(m.volcmd == VOLCMD_NONE || m.volcmd == VOLCMD_PANNING) { m.volcmd = VOLCMD_PANNING; m.vol = param / 2; } cmd = CMD_NONE; } } break; } if(cmd != CMD_NONE) { m.command = cmd; m.param = param; } } } } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize) { AMFFileSignature fileSignature; if(!file.ReadStruct(fileSignature)) { return CSoundFile::ProbeWantMoreData; } if(fileSignature.IsValidAMF()) { if(!file.Skip(32)) return CSoundFile::ProbeWantMoreData; } else if(!fileSignature.IsValidDMF()) { return ProbeFailure; } AMFFileHeader fileHeader; if(!file.ReadStructPartial(fileHeader, AMFFileHeader::GetHeaderSize(fileSignature.version))) { return ProbeWantMoreData; } if(!fileHeader.IsValid(fileSignature.version)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); AMFFileSignature fileSignature; if(!file.ReadStruct(fileSignature)) return false; char title[32] = {}; bool isDMF = false; if(fileSignature.IsValidAMF() && file.CanRead(sizeof(title))) file.ReadArray(title); else if(fileSignature.IsValidDMF()) isDMF = true; else return false; AMFFileHeader fileHeader; if(!file.ReadStructPartial(fileHeader, AMFFileHeader::GetHeaderSize(fileSignature.version))) return false; if(!fileHeader.IsValid(fileSignature.version)) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_AMF, (fileSignature.version < 9) ? 4 : fileHeader.numChannels); if(isDMF) { m_modFormat.formatName = MPT_UFORMAT("DSMI Advanced Music Format (Compact) v{}")(fileSignature.version); m_modFormat.type = UL_("dmf"); } else { m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, title); m_modFormat.formatName = MPT_UFORMAT("DSMI Advanced Music Format v{}")(fileSignature.version); m_modFormat.type = UL_("amf"); } m_modFormat.charset = mpt::Charset::CP437; m_nSamples = fileHeader.numSamples; if(fileSignature.version < 9) { // Old format revisions are fixed to 4 channels for(CHANNELINDEX chn = 0; chn < 4; chn++) { ChnSettings[chn].nPan = (chn & 1) ? 0xC0 : 0x40; } } // Setup Channel Pan Positions if(fileSignature.version >= 11) { const CHANNELINDEX readChannels = fileSignature.version >= 12 ? 32 : 16; for(auto &chn : ChnSettings) { int8 pan = file.ReadInt8(); if(pan == 100) chn.dwFlags = CHN_SURROUND; else chn.nPan = static_cast(std::clamp((pan + 64) * 2, 0, 256)); } file.Skip(readChannels - GetNumChannels()); } else if(fileSignature.version >= 9) { // Internally, DSMI assigns an Amiga-like LRRL panning scheme to the channels in pre-v11 files, // but channels are stored in LRLR order (0 1 3 2 typically). The channel remap table that follows // would normally undo this mapping, so that the panning is as expected again. // This can be observed by looking at a 4-channel MOD and the converted AMF file: The last two channels are swapped. // We ignore all this mess and simply assume that all AMF files use the standard remap table. file.Skip(16); for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = (chn & 1) ? 0xC0 : 0x40; } } // Get Tempo/Speed if(fileSignature.version >= 13) { auto [tempo, speed] = file.ReadArray(); if(tempo < 32) tempo = 125; Order().SetDefaultTempoInt(tempo); Order().SetDefaultSpeed(speed); } else { Order().SetDefaultTempoInt(125); Order().SetDefaultSpeed(6); } // Setup Order List Order().resize(fileHeader.numOrders); std::vector patternLength; const FileReader::pos_type trackStartPos = file.GetPosition() + (fileSignature.version >= 14 ? 2 : 0); if(fileSignature.version >= 14) { patternLength.resize(fileHeader.numOrders); } for(ORDERINDEX ord = 0; ord < fileHeader.numOrders; ord++) { Order()[ord] = ord; if(fileSignature.version >= 14) { patternLength[ord] = file.ReadUint16LE(); } // Track positions will be read as needed. file.Skip(GetNumChannels() * 2); } // Read Sample Headers bool truncatedSampleHeaders = false; if(fileSignature.version == 10) { // M2AMF 1.3 included with DMP 2.32 wrote new (v10+) sample headers, but using the old struct length. const auto startPos = file.GetPosition(); for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { AMFSampleHeaderNew sample; if(file.ReadStruct(sample) && !sample.IsValid(fileHeader.numSamples)) { truncatedSampleHeaders = true; break; } } file.Seek(startPos); } std::vector sampleMap(GetNumSamples(), 0); for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { if(fileSignature.version < 10) { AMFSampleHeaderOld sample; file.ReadStruct(sample); sample.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sample.name); sampleMap[smp - 1] = sample.index; } else if(isDMF) { AMFSampleHeaderCompact sample; file.ReadStruct(sample); sample.ConvertToMPT(Samples[smp]); m_szNames[smp] = ""; sampleMap[smp - 1] = sample.index; } else { AMFSampleHeaderNew sample; file.ReadStructPartial(sample, truncatedSampleHeaders ? sizeof(AMFSampleHeaderOld) : sizeof(AMFSampleHeaderNew)); sample.ConvertToMPT(Samples[smp], truncatedSampleHeaders); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sample.name); sampleMap[smp - 1] = sample.index; } } // Read Track Mapping Table std::vector trackMap; if(!file.ReadVector(trackMap, fileHeader.numTracks)) { return false; } uint16 trackCount = 0; if(!trackMap.empty()) trackCount = *std::max_element(trackMap.cbegin(), trackMap.cend()); // Read pattern tracks std::vector trackData(trackCount); for(uint16 i = 0; i < trackCount; i++) { // Track size is a 16-Bit value describing the number of byte triplets in this track, followed by a track type byte. uint16 numEvents = file.ReadUint16LE(); file.Skip(1); if(numEvents) trackData[i] = file.ReadChunk(numEvents * 3 + (fileSignature.version == 1 ? 3 : 0)); } if(loadFlags & loadSampleData) { // Read Sample Data const SampleIO sampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, isDMF ? SampleIO::deltaPCM : SampleIO::unsignedPCM); // Note: in theory a sample can be reused by several instruments and appear in a different order in the file // However, M2AMF doesn't take advantage of this and just writes instruments in the order they appear, // without de-duplicating identical sample data. for(SAMPLEINDEX smp = 1; smp <= GetNumSamples() && file.CanRead(1); smp++) { auto startPos = file.GetPosition(); for(SAMPLEINDEX target = 0; target < GetNumSamples(); target++) { if(sampleMap[target] != smp) continue; file.Seek(startPos); ModSample &sample = Samples[target + 1]; sampleIO.ReadSample(sample, file); if(isDMF) { // Unsigned delta samples, how novel! for(auto &v : mpt::as_span(sample.sample8(), sample.nLength)) { v = static_cast(static_cast(v) ^ 0x80u); } } } } } if(!(loadFlags & loadPatternData)) { return true; } // Create the patterns from the list of tracks Patterns.ResizeArray(fileHeader.numOrders); for(PATTERNINDEX pat = 0; pat < fileHeader.numOrders; pat++) { uint16 patLength = pat < patternLength.size() ? patternLength[pat] : 64; if(!Patterns.Insert(pat, patLength)) { continue; } // Get table with per-channel track assignments file.Seek(trackStartPos + pat * (GetNumChannels() * 2 + (fileSignature.version >= 14 ? 2 : 0))); std::vector tracks; if(!file.ReadVector(tracks, GetNumChannels())) { continue; } for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { if(tracks[chn] > 0 && tracks[chn] <= fileHeader.numTracks) { uint16 realTrack = trackMap[tracks[chn] - 1]; if(realTrack > 0 && realTrack <= trackCount) { realTrack--; AMFReadPattern(Patterns[pat], chn, trackData[realTrack]); } } } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/AudioCriticalSection.cpp0000644000175000017500000000307214047666254022662 00000000000000/* * AudioCriticalSection.cpp * ----------- * Purpose: Implementation of OpenMPT's critical section for access to CSoundFile. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "AudioCriticalSection.h" #if defined(MODPLUG_TRACKER) #include "../misc/mptMutex.h" #endif OPENMPT_NAMESPACE_BEGIN #if defined(MODPLUG_TRACKER) #if MPT_COMPILER_MSVC _Acquires_lock_(m_refGlobalMutex.mutex) #endif // MPT_COMPILER_MSVC CriticalSection::CriticalSection() : m_refGlobalMutex(Tracker::GetGlobalMutexRef()) , inSection(false) { Enter(); } CriticalSection::CriticalSection(CriticalSection &&other) noexcept : m_refGlobalMutex(other.m_refGlobalMutex) , inSection(other.inSection) { other.inSection = false; } CriticalSection::CriticalSection(InitialState state) : m_refGlobalMutex(Tracker::GetGlobalMutexRef()) , inSection(false) { if(state == InitialState::Locked) { Enter(); } } #if MPT_COMPILER_MSVC _Acquires_lock_(m_refGlobalMutex.mutex) #endif // MPT_COMPILER_MSVC void CriticalSection::Enter() { if(!inSection) { inSection = true; m_refGlobalMutex.lock(); } } #if MPT_COMPILER_MSVC _Requires_lock_held_(m_refGlobalMutex.mutex) _Releases_lock_(m_refGlobalMutex.mutex) #endif // MPT_COMPILER_MSVC void CriticalSection::Leave() { if(inSection) { inSection = false; m_refGlobalMutex.unlock(); } } CriticalSection::~CriticalSection() { Leave(); } #else MPT_MSVC_WORKAROUND_LNK4221(AudioCriticalSection) #endif OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleNormalize.h0000644000175000017500000000723314657606142021370 00000000000000/* * SampleNormalize.h * ----------------- * Purpose: Functions for normalizing samples. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" OPENMPT_NAMESPACE_BEGIN namespace SC { // SC = _S_ample_C_onversion template struct Normalize; template <> struct Normalize { using input_t = int32; using output_t = int32; using peak_t = uint32; uint32 maxVal; MPT_FORCEINLINE Normalize() : maxVal(0) {} MPT_FORCEINLINE void FindMax(input_t val) { if(val < 0) { if(val == std::numeric_limits::min()) { maxVal = static_cast(-static_cast(std::numeric_limits::min())); return; } val = -val; } if(static_cast(val) > maxVal) { maxVal = static_cast(val); } } MPT_FORCEINLINE bool IsSilent() const { return maxVal == 0; } MPT_FORCEINLINE output_t operator()(input_t val) { return Util::muldivrfloor(val, static_cast(1) << 31, maxVal); } MPT_FORCEINLINE peak_t GetSrcPeak() const { return maxVal; } }; template <> struct Normalize { using input_t = somefloat32; using output_t = somefloat32; using peak_t = somefloat32; float maxVal; float maxValInv; MPT_FORCEINLINE Normalize() : maxVal(0.0f), maxValInv(1.0f) {} MPT_FORCEINLINE void FindMax(input_t val) { float absval = std::fabs(val); if(absval > maxVal) { maxVal = absval; } } MPT_FORCEINLINE bool IsSilent() { if(maxVal == 0.0f) { maxValInv = 1.0f; return true; } else { maxValInv = 1.0f / maxVal; return false; } } MPT_FORCEINLINE output_t operator()(input_t val) { return val * maxValInv; } MPT_FORCEINLINE peak_t GetSrcPeak() const { return maxVal; } }; template <> struct Normalize { using input_t = somefloat64; using output_t = somefloat64; using peak_t = somefloat64; double maxVal; double maxValInv; MPT_FORCEINLINE Normalize() : maxVal(0.0), maxValInv(1.0) {} MPT_FORCEINLINE void FindMax(input_t val) { double absval = std::fabs(val); if(absval > maxVal) { maxVal = absval; } } MPT_FORCEINLINE bool IsSilent() { if(maxVal == 0.0) { maxValInv = 1.0; return true; } else { maxValInv = 1.0 / maxVal; return false; } } MPT_FORCEINLINE output_t operator()(input_t val) { return val * maxValInv; } MPT_FORCEINLINE peak_t GetSrcPeak() const { return maxVal; } }; // Reads sample data with Func1, then normalizes the sample data, and then converts it with Func2. // Func1::output_t and Func2::input_t must be identical. // Func1 can also be the identity decode (DecodeIdentity). // Func2 can also be the identity conversion (Convert). template struct NormalizationChain { using input_t = typename Func1::input_t; using normalize_t = typename Func1::output_t; using peak_t = typename Normalize::peak_t; using output_t = typename Func2::output_t; static constexpr std::size_t input_inc = Func1::input_inc; Func1 func1; Normalize normalize; Func2 func2; MPT_FORCEINLINE void FindMax(const input_t *inBuf) { normalize.FindMax(func1(inBuf)); } MPT_FORCEINLINE bool IsSilent() { return normalize.IsSilent(); } MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { return func2(normalize(func1(inBuf))); } MPT_FORCEINLINE peak_t GetSrcPeak() const { return normalize.GetSrcPeak(); } MPT_FORCEINLINE NormalizationChain(Func2 f2 = Func2(), Func1 f1 = Func1()) : func1(f1) , func2(f2) { return; } }; } // namespace SC OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SoundFilePlayConfig.cpp0000644000175000017500000000756014500065511022452 00000000000000/* * SoundFilePlayConfig.cpp * ----------------------- * Purpose: Configuration of sound levels, pan laws, etc... for various mix configurations. * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "SoundFilePlayConfig.h" #include "Mixer.h" OPENMPT_NAMESPACE_BEGIN CSoundFilePlayConfig::CSoundFilePlayConfig() { setVSTiVolume(1.0f); SetMixLevels(MixLevels::Compatible); } void CSoundFilePlayConfig::SetMixLevels(MixLevels mixLevelType) { switch (mixLevelType) { // Olivier's version gives us floats in [-0.5; 0.5] and slightly saturates VSTis. case MixLevels::Original: setVSTiAttenuation(1.0f); // no attenuation setIntToFloat(1.0f/static_cast(1<<28)); setFloatToInt(static_cast(1<<28)); setGlobalVolumeAppliesToMaster(false); setUseGlobalPreAmp(true); setPanningMode(PanningMode::Undetermined); setDisplayDBValues(false); setNormalSamplePreAmp(256.0f); setNormalVSTiVol(100.0f); setNormalGlobalVol(128.0f); setExtraSampleAttenuation(MIXING_ATTENUATION); break; // Ericus' version gives us floats in [-0.06;0.06] and requires attenuation to // avoid massive VSTi saturation. case MixLevels::v1_17RC1: setVSTiAttenuation(32.0f); setIntToFloat(1.0f/static_cast(0x07FFFFFFF)); setFloatToInt(static_cast(0x07FFFFFFF)); setGlobalVolumeAppliesToMaster(false); setUseGlobalPreAmp(true); setPanningMode(PanningMode::Undetermined); setDisplayDBValues(false); setNormalSamplePreAmp(256.0f); setNormalVSTiVol(100.0f); setNormalGlobalVol(128.0f); setExtraSampleAttenuation(MIXING_ATTENUATION); break; // 1.17RC2 gives us floats in [-1.0; 1.0] and hopefully plays VSTis at // the right volume... but we attenuate by 2x to approx. match sample volume. case MixLevels::v1_17RC2: setVSTiAttenuation(2.0f); setIntToFloat(1.0f/MIXING_SCALEF); setFloatToInt(MIXING_SCALEF); setGlobalVolumeAppliesToMaster(true); setUseGlobalPreAmp(true); setPanningMode(PanningMode::Undetermined); setDisplayDBValues(false); setNormalSamplePreAmp(256.0f); setNormalVSTiVol(100.0f); setNormalGlobalVol(128.0f); setExtraSampleAttenuation(MIXING_ATTENUATION); break; // 1.17RC3 ignores the horrible global, system-specific pre-amp, // treats panning as balance to avoid saturation on loud sample (and because I think it's better :), // and allows display of attenuation in decibels. default: case MixLevels::v1_17RC3: setVSTiAttenuation(1.0f); setIntToFloat(1.0f/MIXING_SCALEF); setFloatToInt(MIXING_SCALEF); setGlobalVolumeAppliesToMaster(true); setUseGlobalPreAmp(false); setPanningMode(PanningMode::SoftPanning); setDisplayDBValues(true); setNormalSamplePreAmp(128.0f); setNormalVSTiVol(128.0f); setNormalGlobalVol(256.0f); setExtraSampleAttenuation(0); break; // A mixmode that is intended to be compatible to legacy trackers (IT/FT2/etc). // This is basically derived from mixmode 1.17 RC3, with panning mode and volume levels changed. // Sample attenuation is the same as in Schism Tracker (more attenuation than with RC3, thus VSTi attenuation is also higher). case MixLevels::Compatible: case MixLevels::CompatibleFT2: setVSTiAttenuation(0.75f); setIntToFloat(1.0f/MIXING_SCALEF); setFloatToInt(MIXING_SCALEF); setGlobalVolumeAppliesToMaster(true); setUseGlobalPreAmp(false); setPanningMode(mixLevelType == MixLevels::Compatible ? PanningMode::NoSoftPanning : PanningMode::FT2Panning); setDisplayDBValues(true); setNormalSamplePreAmp(mixLevelType == MixLevels::Compatible ? 256.0f : 192.0f); setNormalVSTiVol(mixLevelType == MixLevels::Compatible ? 256.0f : 192.0f); setNormalGlobalVol(256.0f); setExtraSampleAttenuation(1); break; } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/InstrumentSynth.h0000644000175000017500000004124615014626253021457 00000000000000/* * InstrumentSynth.h * ----------------- * Purpose: "Script" / "Synth" processor for various file formats (MED, GT2, Puma, His Master's Noise, Face The Music, Future Composer) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" #include OPENMPT_NAMESPACE_BEGIN class CSoundFile; struct ModChannel; struct PlayState; struct InstrumentSynth { struct Event { enum class Type : uint8 { StopScript, // No parameter Jump, // Parameter: Event index (uint16) JumpIfTrue, // Parameter: Event index (uint16) Delay, // Parameter: Number of ticks (uint16) SetStepSpeed, // Parameter: Speed (uint8), update speed now? (bool) JumpMarker, // Parameter: Marker ID (uint16) SampleOffset, // Parameter: Offset (uint32) SampleOffsetAdd, // Parameter: Offset (uint32) SampleOffsetSub, // Parameter: Offset (uint32) SetLoopCounter, // Parameter: Count (uint16), force? (bool) EvaluateLoopCounter, // Parameter: Event index (uint16) NoteCut, // No parameter GTK_KeyOff, // Parameter: Jump target once key is released (uint16) GTK_SetVolume, // Parameter: Volume (uint16) GTK_SetPitch, // Parameter: Pitch (uint16) GTK_SetPanning, // Parameter: Panning (uint16) GTK_SetVolumeStep, // Parameter: Step size (int16) GTK_SetPitchStep, // Parameter: Step size (int16) GTK_SetPanningStep, // Parameter: Step size (int16) GTK_SetSpeed, // Parameter: Speed (uint8) GTK_EnableTremor, // Parameter: Enable (uint8) GTK_SetTremorTime, // Parameter: On time (uint8), off time (uint8) GTK_EnableTremolo, // Parameter: Enable (uint8) GTK_EnableVibrato, // Parameter: Enable (uint8) GTK_SetVibratoParams, // Parameter: Width (uint8), speed (uint8) Puma_SetWaveform, // Parameter: Waveform (uint8), wavestorm step (uint8), number of waveforms to cycle (uint8) Puma_VolumeRamp, // Parameter: Start volume (uint8), end volume (uint8), number of ticks (uint8) Puma_StopVoice, // No parameter Puma_SetPitch, // Parameter: Pitch offset (int8), (uint8), number of ticks (uint8) Puma_PitchRamp, // Parameter: Start pitch offset (int8), end pitch offset (int8), number of ticks (uint8) Mupp_SetWaveform, // Parameter: Source instrument (uint8), waveform (uint8), volume (uint8) MED_DefineArpeggio, // Parameter: Arpeggio note (uint8), arp length or 0 if it's not the first note (uint16) MED_JumpScript, // Parameter: Script index (uint8), jump target (uint16 - JumpMarker ID, not event index!) MED_SetEnvelope, // Parameter: Envelope index (uint8), loop on/off (uint8), is volume envelope (uint8) MED_SetVolume, // Parameter: Volume (uint8) MED_SetWaveform, // Parameter: Waveform (uint8) MED_SetVibratoSpeed, // Parameter: Speed (uint8) MED_SetVibratoDepth, // Parameter: Depth (uint8) MED_SetVolumeStep, // Parameter: Volume step (int16) MED_SetPeriodStep, // Parameter: Period step (int16) MED_HoldDecay, // Parameter: Hold time (uint8), decay point (uint16) FTM_PlaySample, // No parameter FTM_SetPitch, // Parameter: New pitch (uint16) FTM_AddPitch, // Parameter: Pitch amount (int16) FTM_SetDetune, // Parameter: Detune amount (uint16) FTM_AddDetune, // Parameter: Detune amount (int16) FTM_SetVolume, // Parameter: Channel volume (uint8) FTM_AddVolume, // Parameter: Volume amount (int16) FTM_SetSample, // Parameter: New sample (uint8) FTM_SetCondition, // Parameter: Pitch/volume threshold (uint16), condition type (uint8) FTM_SetInterrupt, // Parameter: Jump target (uint16), interrupt type (uint8) FTM_SetSampleStart, // Parameter: Offset (uint16), modification type (uint8) FTM_SetOneshotLength, // Parameter: Length (uint16), modification type (uint8) FTM_SetRepeatLength, // Parameter: Length (uint16), modification type (uint8) FTM_CloneTrack, // Parameter: Track (uint8), properties (uint8) FTM_StartLFO, // Parameter: LFO index (uint8), target/waveform (uint8) FTM_LFOAddSub, // Parameter: LFO/addSub (uint8), speed (uint8), depth (uint8) FTM_SetWorkTrack, // Parameter: Channel index (uint8), is relative? (bool) FTM_SetGlobalVolume, // Parameter: Global volume (uint16) FTM_SetTempo, // Parameter: Tempo (uint16) FTM_SetSpeed, // Parameter: Speed (uint16) FTM_SetPlayPosition, // Parameter: Pattern to play (uint16), row in pattern (uint8) FC_SetWaveform, // Parameter: Command type (uint8), waveform (uint8), sample pack (uint8) FC_SetPitch, // Parameter: Pitch (int8) FC_SetVibrato, // Parameter: Speed (uint8), depth (uint8), delay (uint8) FC_PitchSlide, // Parameter: Speed (uint8), time (uint8) FC_VolumeSlide, // Parameter: Speed (uint8), time (uint8) }; static constexpr Type JumpEvents[] = { Type::Jump, Type::JumpIfTrue, Type::EvaluateLoopCounter, Type::GTK_KeyOff, Type::MED_HoldDecay, Type::FTM_SetInterrupt, }; Type type = Type::StopScript; union { uint8 u8 = 0; int8 i8; }; union { uint16 u16; int16 i16; std::array bytes = {{}}; }; static constexpr Event StopScript() noexcept { return Event{Type::StopScript}; } static constexpr Event Jump(uint16 target) noexcept { return Event{Type::Jump, target}; } static constexpr Event JumpIfTrue(uint16 target) noexcept { return Event{Type::JumpIfTrue, target}; } static constexpr Event Delay(uint16 ticks) noexcept { return Event{Type::Delay, ticks}; } static constexpr Event SetStepSpeed(uint8 speed, bool updateNow) noexcept { return Event{Type::SetStepSpeed, speed, uint8(updateNow ? 1 : 0)}; } static constexpr Event JumpMarker(uint16 data) noexcept { return Event{Type::JumpMarker, data}; } static constexpr Event SampleOffset(uint32 offset) noexcept { return Event24Bit(Type::SampleOffset, offset); } static constexpr Event SampleOffsetAdd(uint32 offset) noexcept { return Event24Bit(Type::SampleOffsetAdd, offset); } static constexpr Event SampleOffsetSub(uint32 offset) noexcept { return Event24Bit(Type::SampleOffsetSub, offset); } static constexpr Event SetLoopCounter(uint16 count, bool force) noexcept { return Event{Type::SetLoopCounter, count, uint8(force ? 1 : 0)}; } static constexpr Event EvaluateLoopCounter(uint16 target) noexcept { return Event{Type::EvaluateLoopCounter, target}; } static constexpr Event NoteCut() noexcept { return Event{Type::NoteCut}; } static constexpr Event GTK_KeyOff(uint16 target) noexcept { return Event{Type::GTK_KeyOff, target}; } static constexpr Event GTK_SetVolume(uint16 volume) noexcept { return Event{Type::GTK_SetVolume, volume}; } static constexpr Event GTK_SetPitch(uint16 pitch) noexcept { return Event{Type::GTK_SetPitch, pitch}; } static constexpr Event GTK_SetPanning(uint16 panning) noexcept { return Event{Type::GTK_SetPanning, panning}; } static constexpr Event GTK_SetVolumeStep(int16 stepSize) noexcept { return Event{Type::GTK_SetVolumeStep, stepSize}; } static constexpr Event GTK_SetPitchStep(int16 stepSize) noexcept { return Event{Type::GTK_SetPitchStep, stepSize}; } static constexpr Event GTK_SetPanningStep(int16 stepSize) noexcept { return Event{Type::GTK_SetPanningStep, stepSize}; } static constexpr Event GTK_SetSpeed(uint8 speed) noexcept { return Event{Type::GTK_SetSpeed, speed}; } static constexpr Event GTK_EnableTremor(uint8 enable) noexcept { return Event{Type::GTK_EnableTremor, enable}; } static constexpr Event GTK_SetTremorTime(uint8 onTime, uint8 offTime) noexcept { return Event{Type::GTK_SetTremorTime, onTime, offTime}; } static constexpr Event GTK_EnableTremolo(uint8 enable) noexcept { return Event{Type::GTK_EnableTremolo, enable}; } static constexpr Event GTK_EnableVibrato(uint8 enable) noexcept { return Event{Type::GTK_EnableVibrato, enable}; } static constexpr Event GTK_SetVibratoParams(uint8 width, uint8 speed) noexcept { return Event{Type::GTK_SetVibratoParams, width, speed}; } static constexpr Event Puma_SetWaveform(uint8 waveform, uint8 step, uint8 count) noexcept { return Event{Type::Puma_SetWaveform, waveform, step, count}; } static constexpr Event Puma_VolumeRamp(uint8 startVol, uint8 endVol, uint8 ticks) noexcept { return Event{Type::Puma_VolumeRamp, startVol, endVol, ticks}; } static constexpr Event Puma_StopVoice() noexcept { return Event{Type::Puma_StopVoice}; } static constexpr Event Puma_SetPitch(int8 pitchOffset, uint8 ticks) noexcept { return Event{Type::Puma_SetPitch, pitchOffset, uint8(0), ticks}; } static constexpr Event Puma_PitchRamp(int8 startPitch, int8 endPitch, uint8 ticks) noexcept { return Event{Type::Puma_PitchRamp, startPitch, endPitch, ticks}; } static constexpr Event Mupp_SetWaveform(uint8 instr, uint8 waveform, uint8 volume) noexcept { return Event{Type::Mupp_SetWaveform, instr, waveform, volume}; } static constexpr Event MED_DefineArpeggio(uint8 note, uint16 noteCount) noexcept { return Event{Type::MED_DefineArpeggio, noteCount, note}; } static constexpr Event MED_JumpScript(uint8 scriptIndex, uint16 target) noexcept { return Event{Type::MED_JumpScript, target, scriptIndex}; } static constexpr Event MED_SetEnvelope(uint8 envelope, bool loop, bool volumeEnv) noexcept { return Event{Type::MED_SetEnvelope, envelope, uint8(loop ? 1 : 0), uint8(volumeEnv ? 1 : 0)}; } static constexpr Event MED_SetVolume(uint8 volume) noexcept { return Event{Type::MED_SetVolume, volume}; } static constexpr Event MED_SetWaveform(uint8 waveform) noexcept { return Event{Type::MED_SetWaveform, waveform}; } static constexpr Event MED_SetVibratoSpeed(uint8 depth) noexcept { return Event{Type::MED_SetVibratoSpeed, depth}; } static constexpr Event MED_SetVibratoDepth(uint8 depth) noexcept { return Event{Type::MED_SetVibratoDepth, depth}; } static constexpr Event MED_SetVolumeStep(int16 volumeStep) noexcept { return Event{Type::MED_SetVolumeStep, volumeStep}; } static constexpr Event MED_SetPeriodStep(int16 periodStep) noexcept { return Event{Type::MED_SetPeriodStep, periodStep}; } static constexpr Event MED_HoldDecay(uint8 hold, uint16 decay) noexcept { return Event{Type::MED_HoldDecay, decay, hold}; } static constexpr Event FTM_SetCondition(uint16 threshold, uint8 condition) noexcept { return Event{Type::FTM_SetCondition, threshold, condition}; } static constexpr Event FTM_SetInterrupt(uint16 target, uint8 type) noexcept { return Event{Type::FTM_SetInterrupt, target, type}; } static constexpr Event FTM_PlaySample() noexcept { return Event{Type::FTM_PlaySample}; } static constexpr Event FTM_SetPitch(uint16 pitch) noexcept { return Event{Type::FTM_SetPitch, pitch}; } static constexpr Event FTM_AddPitch(int16 pitch) noexcept { return Event{Type::FTM_AddPitch, pitch}; } static constexpr Event FTM_SetDetune(uint16 detune) noexcept { return Event{Type::FTM_SetDetune, detune}; } static constexpr Event FTM_AddDetune(int16 detune) noexcept { return Event{Type::FTM_AddDetune, detune}; } static constexpr Event FTM_SetVolume(uint8 volume) noexcept { return Event{Type::FTM_SetVolume, volume}; } static constexpr Event FTM_AddVolume(int16 volume) noexcept { return Event{Type::FTM_AddVolume, volume}; } static constexpr Event FTM_SetSample(uint8 sample) noexcept { return Event{Type::FTM_SetSample, sample}; } static constexpr Event FTM_SetSampleStart(uint16 offset, uint8 type) noexcept { return Event{Type::FTM_SetSampleStart, offset, type}; } static constexpr Event FTM_SetOneshotLength(uint16 length, uint8 type) noexcept { return Event{Type::FTM_SetOneshotLength, length, type}; } static constexpr Event FTM_SetRepeatLength(uint16 length, uint8 type) noexcept { return Event{ Type::FTM_SetRepeatLength, length, type }; } static constexpr Event FTM_CloneTrack(uint8 track, uint8 properties) noexcept { return Event{Type::FTM_CloneTrack, track, properties}; } static constexpr Event FTM_StartLFO(uint8 lfo, uint8 targetWaveform) noexcept { return Event{Type::FTM_StartLFO, lfo, targetWaveform, 0}; } static constexpr Event FTM_LFOAddSub(uint8 lfoAddSub, uint8 speed, uint8 depth) noexcept { return Event{Type::FTM_LFOAddSub, lfoAddSub, speed, depth}; } static constexpr Event FTM_SetWorkTrack(uint8 track, bool relative) noexcept { return Event{ Type::FTM_SetWorkTrack, track, uint8(relative ? 1 : 0), 0}; } static constexpr Event FTM_SetGlobalVolume(uint16 globalVolume) noexcept { return Event{Type::FTM_SetGlobalVolume, globalVolume}; } static constexpr Event FTM_SetTempo(uint16 tempo) noexcept { return Event{Type::FTM_SetTempo, tempo}; } static constexpr Event FTM_SetSpeed(uint16 speed) noexcept { return Event{Type::FTM_SetSpeed, speed}; } static constexpr Event FTM_SetPlayPosition(uint16 pattern, uint8 row) noexcept { return Event{Type::FTM_SetPlayPosition, pattern, row}; } static constexpr Event FC_SetWaveform(uint8 command, uint8 waveform, uint8 samplePack) noexcept { return Event{Type::FC_SetWaveform, command, waveform, samplePack}; } static constexpr Event FC_SetPitch(int8 pitch) noexcept { return Event{Type::FC_SetPitch, pitch}; } static constexpr Event FC_SetVibrato(uint8 speed, uint8 depth, uint8 delay) noexcept { return Event{Type::FC_SetVibrato, speed, depth, delay}; } static constexpr Event FC_PitchSlide(uint8 speed, uint8 time) noexcept { return Event{Type::FC_PitchSlide, speed, time}; } static constexpr Event FC_VolumeSlide(uint8 speed, uint8 time) noexcept { return Event{Type::FC_VolumeSlide, speed, time}; } constexpr Event() noexcept : u8{}, u16{} {} constexpr Event(const Event &other) noexcept = default; constexpr Event(Event &&other) noexcept = default; constexpr Event &operator=(const Event &other) noexcept = default; constexpr Event &operator=(Event &&other) noexcept = default; MPT_CONSTEXPR20_FUN bool IsJumpEvent() const noexcept { return mpt::contains(JumpEvents, type); } template void FixupJumpTarget(TMap &offsetToIndexMap) { if(!IsJumpEvent()) return; if(auto it = offsetToIndexMap.lower_bound(u16); it != offsetToIndexMap.end()) u16 = it->second; else u16 = uint16_max; } constexpr uint8 Byte0() const noexcept { return u8; } constexpr uint8 Byte1() const noexcept { return bytes[0]; } constexpr uint8 Byte2() const noexcept { return bytes[1]; } constexpr uint32 Value24Bit() const noexcept { return Byte0() | (Byte1() << 8) | (Byte2() << 16); } protected: constexpr Event(Type type, uint8 b1, uint8 b2, uint8 b3) noexcept : type{type}, u8{b1}, bytes{b2, b3} {} constexpr Event(Type type, int8 b1, uint8 b2, uint8 b3) noexcept : type{type}, i8{b1}, bytes{b2, b3} {} constexpr Event(Type type, int8 b1, int8 b2, uint8 b3) noexcept : type{type}, i8{b1}, bytes{static_cast(b2), b3} {} constexpr Event(Type type, uint8 b1, uint8 b2) noexcept : type{type}, u8{b1}, bytes{b2, 0} {} constexpr Event(Type type, uint16 u16, uint8 u8) noexcept : type{type}, u8{u8}, u16{u16} {} constexpr Event(Type type, uint16 u16) noexcept : type{type}, u8{0}, u16{u16} {} constexpr Event(Type type, int16 i16) noexcept : type{type}, u8{}, i16{i16} {} constexpr Event(Type type, uint8 u8) noexcept : type{type}, u8{u8}, u16{} {} constexpr Event(Type type, int8 i8) noexcept : type{type}, i8{i8}, u16{} {} explicit constexpr Event(Type type) noexcept : type{type}, u8{}, u16{} {} static constexpr Event Event24Bit(Type type, uint32 value) { value = std::min(value, uint32(0xFFFFFF)); return Event{type, static_cast(value & 0xFF), static_cast(value >> 8), static_cast(value >> 16)}; } }; using Events = std::vector; class States { public: struct State; friend struct State; States(); States(const States &other); States(States &&other) noexcept; virtual ~States(); States& operator=(const States &other); States& operator=(States &&other) noexcept; void Stop(); void NextTick(PlayState &playState, CHANNELINDEX channel, const CSoundFile &sndFile); void ApplyChannelState(ModChannel &chn, int32 &period, const CSoundFile& sndFile); protected: std::vector states; }; std::vector m_scripts; bool HasScripts() const noexcept { return !m_scripts.empty(); } void Clear() { m_scripts.clear(); } void Sanitize(); }; struct GlobalScriptState final : private InstrumentSynth::States { void Initialize(const CSoundFile &sndFile); void NextTick(PlayState &playState, const CSoundFile &sndFile); void ApplyChannelState(PlayState &playState, CHANNELINDEX chn, int32 &period, const CSoundFile &sndFile); }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_dsym.cpp0000644000175000017500000004300314664653442020532 00000000000000/* * Load_dsym.cpp * ------------- * Purpose: Digital Symphony module loader * Notes : Based on information from the DSym_Info file and sigma-delta decompression code from TimPlayer. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "BitReader.h" #include "mpt/endian/int24.hpp" OPENMPT_NAMESPACE_BEGIN struct DSymFileHeader { using uint24le = mpt::uint24le; char magic[8]; uint8le version; // 0 / 1 uint8le numChannels; // 1...8 uint16le numOrders; // 0...4096 uint16le numTracks; // 0...4096 uint24le infoLen; bool Validate() const { return !std::memcmp(magic, "\x02\x01\x13\x13\x14\x12\x01\x0B", 8) && version <= 1 && numChannels >= 1 && numChannels <= 8 && numOrders <= 4096 && numTracks <= 4096; } uint64 GetHeaderMinimumAdditionalSize() const { return 72u; } }; MPT_BINARY_STRUCT(DSymFileHeader, 17) static std::vector DecompressDSymLZW(FileReader &file, uint32 size) { BitReader bitFile(file); const auto startPos = bitFile.GetPosition(); // In the best case, 13 bits decode 8192 bytes, a ratio of approximately 1:5042. // Too much for reserving memory in case of malformed files, just choose an arbitrary but realistic upper limit. std::vector output; output.reserve(std::min(size, std::min(mpt::saturate_cast(file.BytesLeft()), Util::MaxValueOfType(size) / 50u) * 50u)); static constexpr uint16 lzwBits = 13, MaxNodes = 1 << lzwBits; static constexpr uint16 ResetDict = 256, EndOfStream = 257; struct LZWEntry { uint16 prev; std::byte value; }; std::vector dictionary(MaxNodes); std::vector match(MaxNodes); // Initialize dictionary for(int i = 0; i < 256; i++) { dictionary[i].prev = MaxNodes; dictionary[i].value = static_cast(i); } uint8 codeSize = 9; uint16 prevCode = 0; uint16 nextIndex = 257; while(true) { // Read next code const auto newCode = static_cast(bitFile.ReadBits(codeSize)); if(newCode == EndOfStream || newCode > nextIndex || output.size() >= size) break; // Reset dictionary if(newCode == ResetDict) { codeSize = 9; prevCode = 0; nextIndex = 257; continue; } // Output auto code = (newCode < nextIndex) ? newCode : prevCode; auto writeOffset = MaxNodes; do { match[--writeOffset] = dictionary[code].value; code = dictionary[code].prev; } while(code < MaxNodes); output.insert(output.end(), match.begin() + writeOffset, match.end()); // Handling for KwKwK problem if(newCode == nextIndex) output.push_back(match[writeOffset]); // Add to dictionary if(nextIndex < MaxNodes) { // Special case for FULLEFFECT, NARCOSIS and NEWDANCE, which end with a dictionary size of 512 // right before the end-of-stream token, but the code size is expected to be 9 if(output.size() >= size) continue; dictionary[nextIndex].value = match[writeOffset]; dictionary[nextIndex].prev = prevCode; nextIndex++; if(nextIndex != MaxNodes && nextIndex == (1u << codeSize)) codeSize++; } prevCode = newCode; } MPT_ASSERT(output.size() == size); // Align length to 4 bytes file.Seek(startPos + ((bitFile.GetPosition() - startPos + 3u) & ~FileReader::pos_type(3))); // cppcheck false-positive // cppcheck-suppress returnDanglingLifetime return output; } static std::vector DecompressDSymSigmaDelta(FileReader &file, uint32 size) { const uint8 maxRunLength = std::max(file.ReadUint8(), uint8(1)); BitReader bitFile(file); const auto startPos = bitFile.GetPosition(); // In the best case, sigma-delta compression represents each sample point as one bit. // As a result, if we have a file length of n, we know that the sample can be at most n*8 sample points long. LimitMax(size, std::min(mpt::saturate_cast(file.BytesLeft()), Util::MaxValueOfType(size) / 8u) * 8u); std::vector output(size); uint32 pos = 0; uint8 runLength = maxRunLength; uint8 numBits = 8; uint8 accum = static_cast(bitFile.ReadBits(numBits)); output[pos++] = mpt::byte_cast(accum); while(pos < size) { const uint32 value = bitFile.ReadBits(numBits); // Increase bit width if(value == 0) { if(numBits >= 9) break; numBits++; runLength = maxRunLength; continue; } if(value & 1) accum -= static_cast(value >> 1); else accum += static_cast(value >> 1); output[pos++] = mpt::byte_cast(accum); // Reset run length if high bit is set if((value >> (numBits - 1u)) != 0) { runLength = maxRunLength; continue; } // Decrease bit width if(--runLength == 0) { if(numBits > 1) numBits--; runLength = maxRunLength; } } // Align length to 4 bytes file.Seek(startPos + ((bitFile.GetPosition() - startPos + 3u) & ~FileReader::pos_type(3))); return output; } static bool ReadDSymChunk(FileReader &file, std::vector &data, uint32 size) { const uint8 packingType = file.ReadUint8(); if(packingType > 1) return false; if(packingType) { try { data = DecompressDSymLZW(file, size); } catch(const BitReader::eof &) { return false; } } else { if(!file.CanRead(size)) return false; file.ReadVector(data, size); } return data.size() >= size; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDSym(MemoryFileReader file, const uint64 *pfilesize) { DSymFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.Validate()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadDSym(FileReader &file, ModLoadingFlags loadFlags) { DSymFileHeader fileHeader; file.Rewind(); if(!file.ReadStruct(fileHeader) || !fileHeader.Validate()) return false; if(!file.CanRead(mpt::saturate_cast(fileHeader.GetHeaderMinimumAdditionalSize()))) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_MOD, fileHeader.numChannels); m_SongFlags.set(SONG_IMPORTED | SONG_AMIGALIMITS); m_SongFlags.reset(SONG_ISAMIGA); m_nSamples = 63; for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 64 : 192; } uint8 sampleNameLength[64] = {}; for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { Samples[smp].Initialize(MOD_TYPE_MOD); sampleNameLength[smp] = file.ReadUint8(); if(!(sampleNameLength[smp] & 0x80)) Samples[smp].nLength = file.ReadUint24LE() << 1; } file.ReadSizedString(m_songName); const auto allowedCommands = file.ReadArray(); std::vector sequence; if(fileHeader.numOrders) { std::vector sequenceData; const uint32 sequenceSize = fileHeader.numOrders * fileHeader.numChannels * 2u; if(!ReadDSymChunk(file, sequenceData, sequenceSize)) return false; FileReader sequenceChunk = FileReader(mpt::as_span(sequenceData)); sequenceChunk.ReadVector(sequence, sequenceData.size() / 2u); } std::vector trackData; trackData.reserve(fileHeader.numTracks * 256u); // For some reason, patterns are stored in 512K chunks for(uint16 offset = 0; offset < fileHeader.numTracks; offset += 2000) { const uint32 chunkSize = std::min(fileHeader.numTracks - offset, 2000) * 256; std::vector chunk; if(!ReadDSymChunk(file, chunk, chunkSize)) return false; trackData.insert(trackData.end(), chunk.begin(), chunk.end()); } const auto tracks = mpt::byte_cast>(mpt::as_span(trackData)); Order().resize(fileHeader.numOrders); for(ORDERINDEX pat = 0; pat < fileHeader.numOrders; pat++) { Order()[pat] = pat; if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) continue; for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { const uint16 track = sequence[pat * GetNumChannels() + chn]; if(track >= fileHeader.numTracks) continue; ModCommand *m = Patterns[pat].GetpModCommand(0, chn); for(ROWINDEX row = 0; row < 64; row++, m += GetNumChannels()) { const auto data = tracks.subspan(track * 256 + row * 4, 4); m->note = data[0] & 0x3F; if(m->note) m->note += 47 + NOTE_MIN; else m->note = NOTE_NONE; m->instr = (data[0] >> 6) | ((data[1] & 0x0F) << 2); const uint8 command = (data[1] >> 6) | ((data[2] & 0x0F) << 2); const uint16 param = (data[2] >> 4) | (data[3] << 4); if(!(allowedCommands[command >> 3u] & (1u << (command & 7u)))) continue; if(command == 0 && param == 0) continue; m->param = static_cast(param); m->vol = static_cast(param >> 8); switch(command) { case 0x00: // 00 xyz Normal play or Arpeggio + Volume Slide Up case 0x01: // 01 xyy Slide Up + Volume Slide Up case 0x02: // 01 xyy Slide Up + Volume Slide Up case 0x20: // 20 xyz Normal play or Arpeggio + Volume Slide Down case 0x21: // 21 xyy Slide Up + Volume Slide Down case 0x22: // 22 xyy Slide Down + Volume Slide Down ConvertModCommand(*m, command & 0x0F, m->param); if(m->vol) m->volcmd = (command < 0x20) ? VOLCMD_VOLSLIDEUP : VOLCMD_VOLSLIDEDOWN; break; case 0x03: // 03 xyy Tone Portamento case 0x04: // 04 xyz Vibrato case 0x05: // 05 xyz Tone Portamento + Volume Slide case 0x06: // 06 xyz Vibrato + Volume Slide case 0x07: // 07 xyz Tremolo case 0x0C: // 0C xyy Set Volume ConvertModCommand(*m, command, m->param); break; case 0x09: // 09 xxx Set Sample Offset m->command = CMD_OFFSET; m->param = static_cast(param >> 1); if(param >= 0x200) { m->volcmd = VOLCMD_OFFSET; m->vol >>= 1; } break; case 0x0A: // 0A xyz Volume Slide + Fine Slide Up case 0x2A: // 2A xyz Volume Slide + Fine Slide Down if(param < 0xFF) { ConvertModCommand(*m, command & 0x0F, m->param); } else { m->command = CMD_MODCMDEX; m->param = static_cast(((command < 0x20) ? 0x10 : 0x20) | (param >> 8)); if(param & 0xF0) { m->volcmd = VOLCMD_VOLSLIDEUP; m->vol = static_cast((param >> 4) & 0x0F); } else { m->volcmd = VOLCMD_VOLSLIDEDOWN; m->vol = static_cast(param & 0x0F); } } break; case 0x0B: // 0B xxx Position Jump case 0x0F: // 0F xxx Set Speed m->command = (command == 0x0B) ? CMD_POSITIONJUMP : CMD_SPEED; m->param = mpt::saturate_cast(param); break; case 0x0D: // 0D xyy Pattern Break (not BCD-encoded like in MOD) m->command = CMD_PATTERNBREAK; if(m->param > 63) m->param = 0; break; case 0x10: // 10 xxy Filter Control (not implemented in Digital Symphony) case 0x13: // 13 xxy Glissando Control case 0x14: // 14 xxy Set Vibrato Waveform case 0x15: // 15 xxy Set Fine Tune case 0x17: // 17 xxy Set Tremolo Waveform case 0x1F: // 1F xxy Invert Loop m->command = CMD_MODCMDEX; m->param = (command << 4) | (m->param & 0x0F); break; case 0x16: // 16 xxx Jump to Loop case 0x19: // 19 xxx Retrig Note case 0x1C: // 1C xxx Note Cut case 0x1D: // 1D xxx Note Delay case 0x1E: // 1E xxx Pattern Delay m->command = CMD_MODCMDEX; m->param = (command << 4) | static_cast(std::min(param, uint16(0x0F))); break; case 0x11: // 11 xyy Fine Slide Up + Fine Volume Slide Up case 0x12: // 12 xyy Fine Slide Down + Fine Volume Slide Up case 0x1A: // 1A xyy Fine Slide Up + Fine Volume Slide Down case 0x1B: // 1B xyy Fine Slide Down + Fine Volume Slide Down m->command = CMD_MODCMDEX; if(m->param & 0xFF) { m->param = static_cast(((command == 0x11 || command == 0x1A) ? 0x10 : 0x20) | (param & 0x0F)); if(param & 0xF00) m->volcmd = (command >= 0x1A) ? VOLCMD_FINEVOLDOWN : VOLCMD_FINEVOLUP; } else { m->param = static_cast(((command >= 0x1A) ? 0xB0 : 0xA0) | (param >> 8)); } break; case 0x2F: // 2F xxx Set Tempo if(param > 0) { m->command = CMD_TEMPO; m->param = mpt::saturate_cast(std::max(8, param + 4) / 8); #ifdef MODPLUG_TRACKER m->param = std::max(m->param, ModCommand::PARAM(0x20)); #endif } else { m->command = CMD_NONE; } break; case 0x2B: // 2B xyy Line Jump m->command = CMD_PATTERNBREAK; for(CHANNELINDEX brkChn = 0; brkChn < GetNumChannels(); brkChn++) { ModCommand &cmd = *(m - chn + brkChn); if(cmd.command != CMD_NONE) continue; cmd.command = CMD_POSITIONJUMP; cmd.param = mpt::saturate_cast(pat); } break; case 0x30: // 30 xxy Set Stereo m->command = CMD_PANNING8; if(param & 7) { static constexpr uint8 panning[8] = {0x00, 0x00, 0x2B, 0x56, 0x80, 0xAA, 0xD4, 0xFF}; m->param = panning[param & 7]; } else if((param >> 4) != 0x80) { m->param = static_cast(param >> 4); if(m->param < 0x80) m->param += 0x80; else m->param = 0xFF - m->param; } else { m->command = CMD_NONE; } break; case 0x32: // 32 xxx Unset Sample Repeat m->command = CMD_NONE; m->param = 0; if(m->note == NOTE_NONE) m->note = NOTE_KEYOFF; else m->command = CMD_KEYOFF; break; case 0x31: // 31 xxx Song Upcall default: m->command = CMD_NONE; break; } } } } for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { file.ReadString(m_szNames[smp], sampleNameLength[smp] & 0x3F); if(sampleNameLength[smp] & 0x80) continue; ModSample &mptSmp = Samples[smp]; mptSmp.nSustainStart = file.ReadUint24LE() << 1; if(const auto loopLen = file.ReadUint24LE() << 1; loopLen > 2) { mptSmp.nSustainEnd = mptSmp.nSustainStart + loopLen; mptSmp.uFlags.set(CHN_SUSTAINLOOP); } mptSmp.nVolume = std::min(file.ReadUint8(), uint8(64)) * 4u; mptSmp.nFineTune = MOD2XMFineTune(file.ReadUint8()); mptSmp.Set16BitCuePoints(); if(!mptSmp.nLength) continue; const uint8 packingType = file.ReadUint8(); switch(packingType) { case 0: // Modified u-Law if(loadFlags & loadSampleData) { std::vector sampleData; if(!file.CanRead(mptSmp.nLength)) return false; file.ReadVector(sampleData, mptSmp.nLength); for(auto &b : sampleData) { uint8 v = mpt::byte_cast(b); v = (v << 7) | (static_cast(~v) >> 1); b = mpt::byte_cast(v); } FileReader sampleDataFile = FileReader(mpt::as_span(sampleData)); SampleIO( SampleIO::_16bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::uLaw) .ReadSample(mptSmp, sampleDataFile); } else { file.Skip(mptSmp.nLength); } break; case 1: // 13-bit LZW applied to linear sample data differences { std::vector sampleData; try { sampleData = DecompressDSymLZW(file, mptSmp.nLength); } catch(const BitReader::eof &) { return false; } if(!(loadFlags & loadSampleData)) break; FileReader sampleDataFile = FileReader(mpt::as_span(sampleData)); SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::deltaPCM) .ReadSample(mptSmp, sampleDataFile); } break; case 2: // 8-bit signed case 3: // 16-bit signed if(loadFlags & loadSampleData) { SampleIO( (packingType == 2) ? SampleIO::_8bit : SampleIO::_16bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(mptSmp, file); } else { file.Skip(mptSmp.nLength * (packingType - 1)); } break; case 4: // Sigma-Delta compression applied to linear sample differences case 5: // Sigma-Delta compression applied to logarithmic sample differences { std::vector sampleData; try { sampleData = DecompressDSymSigmaDelta(file, mptSmp.nLength); } catch(const BitReader::eof &) { return false; } if(!(loadFlags & loadSampleData)) break; if(packingType == 5) { static constexpr uint8 xorMask[] = {0x00, 0x7F}; for(auto &b : sampleData) { uint8 v = mpt::byte_cast(b); v ^= xorMask[v >> 7]; b = mpt::byte_cast(v); } } FileReader sampleDataFile = FileReader(mpt::as_span(sampleData)); SampleIO( (packingType == 5) ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, (packingType == 5) ? SampleIO::uLaw : SampleIO::unsignedPCM) .ReadSample(mptSmp, sampleDataFile); } break; default: return false; } } if(const uint32 infoLen = fileHeader.infoLen.get(); infoLen > 0) { std::vector infoData; if(!ReadDSymChunk(file, infoData, infoLen)) return false; FileReader infoChunk = FileReader(mpt::as_span(infoData)); m_songMessage.Read(infoChunk, infoLen, SongMessage::leLF); } m_modFormat.formatName = MPT_UFORMAT("Digital Symphony v{}")(fileHeader.version); m_modFormat.type = UL_("dsym"); // RISC OS doesn't use file extensions but this is a common abbreviation used for this tracker m_modFormat.madeWithTracker = UL_("Digital Symphony"); m_modFormat.charset = mpt::Charset::RISC_OS; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_sfx.cpp0000644000175000017500000002652514654245444020366 00000000000000/* * Load_sfx.cpp * ------------ * Purpose: SFX / MMS (SoundFX / MultiMedia Sound) module loader * Notes : Mostly based on the Soundtracker loader, some effect behavior is based on Flod's implementation. * Authors: Devin Acker * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "Tables.h" OPENMPT_NAMESPACE_BEGIN // File Header struct SFXFileHeader { char magic[4]; uint16be speed; char unknown[14]; // Just NUL bytes most of the time, sometimes appears to contain leftovers from other data structures bool IsValid(const uint8 expectedNumSamples) const noexcept { if(expectedNumSamples == 15 && memcmp(magic, "SONG", 4)) return false; if(expectedNumSamples == 31 && memcmp(magic, "SO31", 4)) return false; return speed >= 178; } }; MPT_BINARY_STRUCT(SFXFileHeader, 20) // Order List struct SFXOrderHeader { uint8 numOrders; uint8 restartPos; uint8 orderList[128]; bool IsValid() const noexcept { return numOrders <= 128; } }; MPT_BINARY_STRUCT(SFXOrderHeader, 130) // Sample Header struct SFXSampleHeader { char name[22]; uint16be oneshotLength; // For unlooped samples, this is quite frequently 2 bytes shorter than the sample data length (and the last two samples would cause a click to be heard) uint8be finetune; uint8be volume; uint16be loopStart; uint16be loopLength; // Convert an SFX sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp, uint32 length) const { mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.nLength = (loopLength > 1) ? length : (oneshotLength * 2u); mptSmp.nFineTune = MOD2XMFineTune(finetune); mptSmp.nVolume = 4u * std::min(volume.get(), uint8(64)); SmpLength lStart = loopStart; SmpLength lLength = loopLength * 2u; if(mptSmp.nLength) { mptSmp.nLoopStart = lStart; mptSmp.nLoopEnd = lStart + lLength; if(mptSmp.nLoopStart >= mptSmp.nLength) { mptSmp.nLoopStart = mptSmp.nLength - 1; } if(mptSmp.nLoopEnd > mptSmp.nLength) { mptSmp.nLoopEnd = mptSmp.nLength; } if(mptSmp.nLoopStart > mptSmp.nLoopEnd || mptSmp.nLoopEnd < 4 || mptSmp.nLoopEnd - mptSmp.nLoopStart < 4) { mptSmp.nLoopStart = 0; mptSmp.nLoopEnd = 0; } if(mptSmp.nLoopEnd > mptSmp.nLoopStart) { mptSmp.uFlags.set(CHN_LOOP); } } } }; MPT_BINARY_STRUCT(SFXSampleHeader, 30) static uint8 ClampSlideParam(uint8 value, uint8 lowNote, uint8 highNote) { uint16 lowPeriod, highPeriod; if(lowNote < highNote && lowNote >= 24 + NOTE_MIN && highNote >= 24 + NOTE_MIN && lowNote < std::size(ProTrackerPeriodTable) + 24 + NOTE_MIN && highNote < std::size(ProTrackerPeriodTable) + 24 + NOTE_MIN) { lowPeriod = ProTrackerPeriodTable[lowNote - 24 - NOTE_MIN]; highPeriod = ProTrackerPeriodTable[highNote - 24 - NOTE_MIN]; // with a fixed speed of 6 ticks/row, and excluding the first row, // 1xx/2xx param has a max value of (low-high)/5 to avoid sliding too far return std::min(value, static_cast((lowPeriod - highPeriod) / 5)); } return 0; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize) { SAMPLEINDEX numSamples = 0; SFXFileHeader fileHeader; if(!file.LengthIsAtLeast(0x3C + sizeof(SFXFileHeader))) return ProbeWantMoreData; if(file.Seek(0x3C) && file.ReadStruct(fileHeader) && fileHeader.IsValid(15)) { numSamples = 15; } else { if(!file.LengthIsAtLeast(0x7C + sizeof(SFXFileHeader))) return ProbeWantMoreData; if(file.Seek(0x7C) && file.ReadStruct(fileHeader) && fileHeader.IsValid(31)) numSamples = 31; else return ProbeFailure; } file.Rewind(); for(SAMPLEINDEX smp = 0; smp < numSamples; smp++) { if(file.ReadUint32BE() > 131072) return ProbeFailure; } if(!file.Skip(sizeof(SFXFileHeader) + sizeof(SFXSampleHeader) * numSamples)) return ProbeWantMoreData; SFXOrderHeader orderHeader; if(!file.ReadStruct(orderHeader)) return ProbeWantMoreData; if(!orderHeader.IsValid()) return ProbeFailure; MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) { SFXFileHeader fileHeader; if(file.Seek(0x3C) && file.ReadStruct(fileHeader) && fileHeader.IsValid(15)) { InitializeGlobals(MOD_TYPE_SFX, 4); m_nSamples = 15; } else if(file.Seek(0x7C) && file.ReadStruct(fileHeader) && fileHeader.IsValid(31)) { InitializeGlobals(MOD_TYPE_SFX, 4); m_nSamples = 31; } else { return false; } uint32 sampleLen[31]; file.Rewind(); for(SAMPLEINDEX smp = 0; smp < m_nSamples; smp++) { sampleLen[smp] = file.ReadUint32BE(); if(sampleLen[smp] > 131072) return false; } file.Skip(sizeof(SFXFileHeader)); m_nInstruments = 0; Order().SetDefaultTempo(TEMPO((14565.0 * 122.0) / fileHeader.speed)); Order().SetDefaultSpeed(6); m_nMinPeriod = 14 * 4; m_nMaxPeriod = 3424 * 4; m_nSamplePreAmp = 64; // Setup channel pan positions and volume SetupMODPanning(true); uint32 invalidChars = 0; for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { SFXSampleHeader sampleHeader; file.ReadStruct(sampleHeader); // cppcheck false-positive // cppcheck-suppress uninitvar sampleHeader.ConvertToMPT(Samples[smp], sampleLen[smp - 1]); // Get rid of weird characters in sample names. for(char &c : sampleHeader.name) { if(c > 0 && c < ' ') { c = ' '; invalidChars++; } } if(invalidChars >= 128) return false; m_szNames[smp] = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); } // Broken conversions of the "Operation Stealth" soundtrack (BOND23 / BOND32) // There is a converter that shifts all note values except FFFD (empty note) to the left by 1 bit, // but it should not do that for FFFE (STP) notes - as a consequence, they turn into pattern breaks (FFFC). const bool fixPatternBreaks = (m_szNames[1] == "BASSE2.AMI") || (m_szNames[1] == "PRA1.AMI"); SFXOrderHeader orderHeader; if(!file.ReadStruct(orderHeader) || !orderHeader.IsValid()) return false; else if(loadFlags == onlyVerifyHeader) return true; PATTERNINDEX numPatterns = 0; for(ORDERINDEX ord = 0; ord < orderHeader.numOrders; ord++) { numPatterns = std::max(numPatterns, static_cast(orderHeader.orderList[ord] + 1)); } if(orderHeader.restartPos < orderHeader.numOrders) Order().SetRestartPos(orderHeader.restartPos); else Order().SetRestartPos(0); ReadOrderFromArray(Order(), orderHeader.orderList, orderHeader.numOrders); // SFX v2 / MMS modules have 4 extra bytes here for some reason if(m_nSamples == 31) file.Skip(4); uint8 lastNote[4] = {0}; uint8 slideTo[4] = {0}; uint8 slideRate[4] = {0}; uint8 version = 0; // Reading patterns if(loadFlags & loadPatternData) Patterns.ResizeArray(numPatterns); for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { file.Skip(64 * 4 * 4); continue; } for(ROWINDEX row = 0; row < 64; row++) { auto rowBase = Patterns[pat].GetRow(row); for(CHANNELINDEX chn = 0; chn < 4; chn++) { ModCommand &m = rowBase[chn]; auto data = file.ReadArray(); if(data[0] == 0xFF) { lastNote[chn] = slideRate[chn] = 0; if(fixPatternBreaks && data[1] == 0xFC) data[1] = 0xFE; switch(data[1]) { case 0xFE: // STP (note cut) m.command = CMD_VOLUME; continue; case 0xFD: // PIC (null) continue; case 0xFC: // BRK (pattern break) m.command = CMD_PATTERNBREAK; version = 9; continue; } } const auto [command, param] = ReadMODPatternEntry(data, m); if(m.note != NOTE_NONE) { lastNote[chn] = m.note; slideRate[chn] = 0; if(m.note < NOTE_MIDDLEC - 12) { version = std::max(version, uint8(8)); } } if(command || param) { m.param = param; switch(command) { case 0x1: // Arpeggio m.command = CMD_ARPEGGIO; break; case 0x2: // Portamento (like Ultimate Soundtracker) if(m.param & 0xF0) { m.command = CMD_PORTAMENTODOWN; m.param >>= 4; } else if(m.param & 0xF) { m.command = CMD_PORTAMENTOUP; m.param &= 0x0F; } else { m.command = CMD_NONE; } break; case 0x3: // Enable LED filter // Give precedence to 7xy/8xy slides if(slideRate[chn]) { m.command = CMD_NONE; break; } m.SetEffectCommand(CMD_MODCMDEX, 0x00); break; case 0x4: // Disable LED filter // Give precedence to 7xy/8xy slides if(slideRate[chn]) { m.command = CMD_NONE; break; } m.SetEffectCommand(CMD_MODCMDEX, 0x01); break; case 0x5: // Increase volume if(m.instr) { m.SetEffectCommand(CMD_VOLUME, std::min(ModCommand::PARAM(0x3F), static_cast((Samples[m.instr].nVolume / 4u) + m.param))); // Give precedence to 7xy/8xy slides (and move this to the volume column) if(slideRate[chn]) { m.SetVolumeCommand(VOLCMD_VOLUME, m.param); m.command = CMD_NONE; break; } } else { m.command = CMD_NONE; } break; case 0x6: // Decrease volume if(m.instr) { m.command = CMD_VOLUME; if((Samples[m.instr].nVolume / 4u) >= m.param) m.param = static_cast(Samples[m.instr].nVolume / 4u) - m.param; else m.param = 0; // Give precedence to 7xy/8xy slides (and move this to the volume column) if(slideRate[chn]) { m.SetVolumeCommand(VOLCMD_VOLUME, m.param); m.command = CMD_NONE; break; } } else { m.command = CMD_NONE; } break; case 0x7: // 7xy: Slide down x semitones at speed y slideTo[chn] = lastNote[chn] - (m.param >> 4); slideRate[chn] = m.param & 0xF; m.SetEffectCommand(CMD_PORTAMENTODOWN, ClampSlideParam(slideRate[chn], slideTo[chn], lastNote[chn])); break; case 0x8: // 8xy: Slide up x semitones at speed y slideTo[chn] = lastNote[chn] + (m.param >> 4); slideRate[chn] = m.param & 0xF; m.SetEffectCommand(CMD_PORTAMENTOUP, ClampSlideParam(slideRate[chn], lastNote[chn], slideTo[chn])); break; case 0x9: // 9xy: Auto slide version = std::max(version, uint8(8)); [[fallthrough]]; default: m.command = CMD_NONE; break; } } // Continue 7xy/8xy slides if needed if(m.command == CMD_NONE && slideRate[chn]) { if(slideTo[chn]) { m.note = lastNote[chn] = slideTo[chn]; m.param = slideRate[chn]; slideTo[chn] = 0; } m.command = CMD_TONEPORTAMENTO; } } } } // Reading samples if(loadFlags & loadSampleData) { for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { if(!sampleLen[smp - 1]) continue; FileReader chunk = file.ReadChunk(sampleLen[smp - 1]); SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(Samples[smp], chunk); } } m_modFormat.formatName = m_nSamples == 15 ? MPT_UFORMAT("SoundFX 1.{}")(version) : UL_("SoundFX 2.0 / MultiMedia Sound"); m_modFormat.type = m_nSamples == 15 ? UL_("sfx") : UL_("sfx2"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MixerLoops.cpp0000644000175000017500000000776414362717125020730 00000000000000/* * MixerLoops.cpp * -------------- * Purpose: Utility inner loops for mixer-related functionality. * Notes : This file contains performance-critical loops. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "MixerLoops.h" #include "Snd_defs.h" #include "ModChannel.h" OPENMPT_NAMESPACE_BEGIN void FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *pOut, uint32 nCount, const float _f2ic) { for(uint32 i=0; i(*pIn1++ * _f2ic); *pOut++ = static_cast(*pIn2++ * _f2ic); } } void StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, uint32 nCount, const float _i2fc) { for(uint32 i=0; i(*pSrc++) * _i2fc; *pOut2++ = static_cast(*pSrc++) * _i2fc; } } void InitMixBuffer(mixsample_t *pBuffer, uint32 nSamples) { std::memset(pBuffer, 0, nSamples * sizeof(mixsample_t)); } void InterleaveFrontRear(mixsample_t *pFrontBuf, mixsample_t *pRearBuf, uint32 nFrames) { // copy backwards as we are writing back into FrontBuf for(int i=nFrames-1; i>=0; i--) { pFrontBuf[i*4+3] = pRearBuf[i*2+1]; pFrontBuf[i*4+2] = pRearBuf[i*2+0]; pFrontBuf[i*4+1] = pFrontBuf[i*2+1]; pFrontBuf[i*4+0] = pFrontBuf[i*2+0]; } } void MonoFromStereo(mixsample_t *pMixBuf, uint32 nSamples) { for(uint32 i=0; i(1.0 / (1 << 20)) // Decay threshold for floating point mixer void StereoFill(mixsample_t *pBuffer, uint32 nSamples, mixsample_t &rofs, mixsample_t &lofs) { if((!rofs) && (!lofs)) { InitMixBuffer(pBuffer, nSamples*2); return; } for(uint32 i=0; i 0 ? 255 : -255)) / 256; const mixsample_t x_r = mpt::rshift_signed(rofs + (mpt::rshift_signed(-rofs, sizeof(mixsample_t) * 8 - 1) & OFSDECAYMASK), OFSDECAYSHIFT); const mixsample_t x_l = mpt::rshift_signed(lofs + (mpt::rshift_signed(-lofs, sizeof(mixsample_t) * 8 - 1) & OFSDECAYMASK), OFSDECAYSHIFT); #else const mixsample_t x_r = rofs * (1.0f / (1 << OFSDECAYSHIFT)); const mixsample_t x_l = lofs * (1.0f / (1 << OFSDECAYSHIFT)); #endif rofs -= x_r; lofs -= x_l; pBuffer[i*2] = rofs; pBuffer[i*2+1] = lofs; } #ifndef MPT_INTMIXER if(fabs(rofs) < OFSTHRESHOLD) rofs = 0; if(fabs(lofs) < OFSTHRESHOLD) lofs = 0; #endif } void EndChannelOfs(ModChannel &chn, mixsample_t *pBuffer, uint32 nSamples) { mixsample_t rofs = chn.nROfs; mixsample_t lofs = chn.nLOfs; if((!rofs) && (!lofs)) { return; } for(uint32 i=0; im_playBehaviour[kPeriodsAreHertz] ? LinearSlideDownTable[i] : LinearSlideUpTable[i]; } static uint32 GetLinearSlideUpTable (const CSoundFile *sndFile, uint32 i) { MPT_ASSERT(i < std::size(LinearSlideDownTable)); return sndFile->m_playBehaviour[kPeriodsAreHertz] ? LinearSlideUpTable[i] : LinearSlideDownTable[i]; } static uint32 GetFineLinearSlideDownTable(const CSoundFile *sndFile, uint32 i) { MPT_ASSERT(i < std::size(FineLinearSlideDownTable)); return sndFile->m_playBehaviour[kPeriodsAreHertz] ? FineLinearSlideDownTable[i] : FineLinearSlideUpTable[i]; } static uint32 GetFineLinearSlideUpTable (const CSoundFile *sndFile, uint32 i) { MPT_ASSERT(i < std::size(FineLinearSlideDownTable)); return sndFile->m_playBehaviour[kPeriodsAreHertz] ? FineLinearSlideUpTable[i] : FineLinearSlideDownTable[i]; } // Minimum parameter of tempo command that is considered to be a BPM rather than a tempo slide static constexpr TEMPO GetMinimumTempoParam(MODTYPE modType) { return (modType & (MOD_TYPE_MDL | MOD_TYPE_MED | MOD_TYPE_XM | MOD_TYPE_MOD)) ? TEMPO(1, 0) : TEMPO(32, 0); } //////////////////////////////////////////////////////////// // Length // Memory class for GetLength() code class GetLengthMemory { protected: const CSoundFile &sndFile; public: std::unique_ptr state; struct ChnSettings { uint32 ticksToRender = 0; // When using sample sync, we still need to render this many ticks bool incChanged = false; // When using sample sync, note frequency has changed uint8 vol = 0xFF; }; std::vector chnSettings; double elapsedTime; const SEQUENCEINDEX m_sequence; static constexpr uint32 IGNORE_CHANNEL = uint32_max; GetLengthMemory(const CSoundFile &sf, SEQUENCEINDEX sequence) : sndFile{sf} , state{std::make_unique(sf.m_PlayState)} , m_sequence{sequence} { Reset(); } void Reset() { if(state->m_midiMacroEvaluationResults) state->m_midiMacroEvaluationResults.emplace(); elapsedTime = 0.0; state->m_lTotalSampleCount = 0; state->m_nMusicSpeed = sndFile.Order(m_sequence).GetDefaultSpeed(); state->m_nMusicTempo = sndFile.Order(m_sequence).GetDefaultTempo(); state->m_ppqPosFract = 0.0; state->m_ppqPosBeat = 0; state->m_nGlobalVolume = sndFile.m_nDefaultGlobalVolume; state->m_globalScriptState.Initialize(sndFile); chnSettings.assign(sndFile.GetNumChannels(), {}); const auto muteFlag = CSoundFile::GetChannelMuteFlag(); for(CHANNELINDEX chn = 0; chn < sndFile.GetNumChannels(); chn++) { state->Chn[chn].Reset(ModChannel::resetTotal, sndFile, chn, muteFlag); state->Chn[chn].nOldGlobalVolSlide = 0; state->Chn[chn].nOldChnVolSlide = 0; state->Chn[chn].nLastNote = NOTE_NONE; } } // Increment playback position of sample and envelopes on a channel void RenderChannel(CHANNELINDEX channel, uint32 tickDuration, uint32 portaStart = uint32_max) { ModChannel &chn = state->Chn[channel]; uint32 numTicks = chnSettings[channel].ticksToRender; if(numTicks == IGNORE_CHANNEL || numTicks == 0 || (!chn.IsSamplePlaying() && !chnSettings[channel].incChanged) || chn.pModSample == nullptr) { return; } const SamplePosition loopStart(chn.dwFlags[CHN_LOOP] ? chn.nLoopStart : 0u, 0); const SamplePosition sampleEnd(chn.dwFlags[CHN_LOOP] ? chn.nLoopEnd : chn.nLength, 0); const SmpLength loopLength = chn.nLoopEnd - chn.nLoopStart; const bool itEnvMode = sndFile.m_playBehaviour[kITEnvelopePositionHandling]; const bool updatePitchEnv = (chn.PitchEnv.flags & (ENV_ENABLED | ENV_FILTER)) == ENV_ENABLED; bool stopNote = false; SamplePosition inc = chn.increment * tickDuration; if(chn.dwFlags[CHN_PINGPONGFLAG]) inc.Negate(); for(uint32 i = 0; i < numTicks; i++) { bool updateInc = (chn.PitchEnv.flags & (ENV_ENABLED | ENV_FILTER)) == ENV_ENABLED; if(i >= portaStart) { state->m_nTickCount = i - portaStart; chn.isFirstTick = (i == portaStart); const ModCommand &m = *sndFile.Patterns[state->m_nPattern].GetpModCommand(state->m_nRow, channel); auto command = m.command; switch(m.volcmd) { case VOLCMD_TONEPORTAMENTO: { const auto [porta, clearEffectCommand] = sndFile.GetVolCmdTonePorta(m, 0); sndFile.TonePortamento(*state, channel, porta); if(clearEffectCommand) command = CMD_NONE; } break; case VOLCMD_PORTAUP: sndFile.PortamentoUp(*state, channel, static_cast(m.vol << 2), sndFile.m_playBehaviour[kITVolColFinePortamento]); break; case VOLCMD_PORTADOWN: sndFile.PortamentoDown(*state, channel, static_cast(m.vol << 2), sndFile.m_playBehaviour[kITVolColFinePortamento]); break; default: break; } switch(command) { case CMD_TONEPORTAMENTO: sndFile.TonePortamento(*state, channel, m.param); break; case CMD_TONEPORTAVOL: sndFile.TonePortamento(*state, channel, 0); break; case CMD_PORTAMENTOUP: if(m.param || !(sndFile.GetType() & MOD_TYPE_MOD)) sndFile.PortamentoUp(*state, channel, m.param, false); break; case CMD_PORTAMENTODOWN: if(m.param || !(sndFile.GetType() & MOD_TYPE_MOD)) sndFile.PortamentoDown(*state, channel, m.param, false); break; case CMD_MODCMDEX: if(!(m.param & 0x0F) && !(sndFile.GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) break; if((m.param & 0xF0) == 0x10) sndFile.FinePortamentoUp(chn, m.param & 0x0F); else if((m.param & 0xF0) == 0x20) sndFile.FinePortamentoDown(chn, m.param & 0x0F); break; case CMD_XFINEPORTAUPDOWN: if((m.param & 0xF0) == 0x10) sndFile.ExtraFinePortamentoUp(chn, m.param & 0x0F); else if((m.param & 0xF0) == 0x20) sndFile.ExtraFinePortamentoDown(chn, m.param & 0x0F); break; case CMD_NOTESLIDEUP: case CMD_NOTESLIDEDOWN: case CMD_NOTESLIDEUPRETRIG: case CMD_NOTESLIDEDOWNRETRIG: sndFile.NoteSlide(chn, m.param, command == CMD_NOTESLIDEUP || command == CMD_NOTESLIDEUPRETRIG, command == CMD_NOTESLIDEUPRETRIG || command == CMD_NOTESLIDEDOWNRETRIG); break; default: break; } if(chn.autoSlide.IsActive(AutoSlideCommand::TonePortamento) && !chn.rowCommand.IsTonePortamento()) sndFile.TonePortamento(*state, channel, chn.portamentoSlide); else if(chn.autoSlide.IsActive(AutoSlideCommand::TonePortamentoWithDuration)) sndFile.TonePortamentoWithDuration(chn, 0); if(chn.autoSlide.IsActive(AutoSlideCommand::PortamentoUp)) sndFile.PortamentoUp(*state, channel, chn.nOldPortaUp, true); else if(chn.autoSlide.IsActive(AutoSlideCommand::PortamentoDown)) sndFile.PortamentoDown(*state, channel, chn.nOldPortaDown, true); else if(chn.autoSlide.IsActive(AutoSlideCommand::FinePortamentoUp)) sndFile.FinePortamentoUp(chn, chn.nOldFinePortaUpDown); else if(chn.autoSlide.IsActive(AutoSlideCommand::FinePortamentoDown)) sndFile.FinePortamentoDown(chn, chn.nOldFinePortaUpDown); if(chn.autoSlide.IsActive(AutoSlideCommand::PortamentoFC)) sndFile.PortamentoFC(chn); updateInc = true; } int32 period = chn.nPeriod; if(itEnvMode) sndFile.IncrementEnvelopePositions(chn); if(updatePitchEnv) { sndFile.ProcessPitchFilterEnvelope(chn, period); updateInc = true; } if(!itEnvMode) sndFile.IncrementEnvelopePositions(chn); int vol = 0; sndFile.ProcessInstrumentFade(chn, vol); if(chn.dwFlags[CHN_ADLIB]) continue; if(updateInc || chnSettings[channel].incChanged) { if(chn.m_CalculateFreq || chn.m_ReCalculateFreqOnFirstTick) { chn.RecalcTuningFreq(1, 0, sndFile); if(!chn.m_CalculateFreq) chn.m_ReCalculateFreqOnFirstTick = false; else chn.m_CalculateFreq = false; } chn.increment = sndFile.GetChannelIncrement(chn, period, 0).first; chnSettings[channel].incChanged = false; inc = chn.increment * tickDuration; if(chn.dwFlags[CHN_PINGPONGFLAG]) inc.Negate(); } chn.position += inc; if(chn.position >= sampleEnd || (chn.position < loopStart && inc.IsNegative())) { if(!chn.dwFlags[CHN_LOOP] || !loopLength) { // Past sample end. stopNote = true; break; } // We exceeded the sample loop, go back to loop start. if(chn.dwFlags[CHN_PINGPONGLOOP]) { if(chn.position < loopStart) { chn.position = SamplePosition(chn.nLoopStart + chn.nLoopStart, 0) - chn.position; chn.dwFlags.flip(CHN_PINGPONGFLAG); inc.Negate(); } SmpLength posInt = chn.position.GetUInt() - chn.nLoopStart; SmpLength pingpongLength = loopLength * 2; if(sndFile.m_playBehaviour[kITPingPongMode]) pingpongLength--; posInt %= pingpongLength; bool forward = (posInt < loopLength); if(forward) chn.position.SetInt(chn.nLoopStart + posInt); else chn.position.SetInt(chn.nLoopEnd - (posInt - loopLength)); if(forward == chn.dwFlags[CHN_PINGPONGFLAG]) { chn.dwFlags.flip(CHN_PINGPONGFLAG); inc.Negate(); } } else { SmpLength posInt = chn.position.GetUInt(); if(posInt >= chn.nLoopEnd + loopLength) { const SmpLength overshoot = posInt - chn.nLoopEnd; posInt -= (overshoot / loopLength) * loopLength; } while(posInt >= chn.nLoopEnd) { posInt -= loopLength; } chn.position.SetInt(posInt); } } } state->m_nTickCount = 0; if(stopNote) { chn.Stop(); chn.nPortamentoDest = 0; } chnSettings[channel].ticksToRender = 0; } void GlobalVolSlide(ModChannel &chn, ModCommand::PARAM param, uint32 nonRowTicks) { if(sndFile.m_SongFlags[SONG_AUTO_GLOBALVOL]) chn.autoSlide.SetActive(AutoSlideCommand::GlobalVolumeSlide, param != 0); if(param) chn.nOldGlobalVolSlide = param; else param = chn.nOldGlobalVolSlide; if((param & 0x0F) == 0x0F && (param & 0xF0)) { param >>= 4; if(!(sndFile.GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1; state->m_nGlobalVolume += param << 1; } else if((param & 0xF0) == 0xF0 && (param & 0x0F)) { param = (param & 0x0F) << 1; if(!(sndFile.GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1; state->m_nGlobalVolume -= param; } else if(param & 0xF0) { param >>= 4; param <<= 1; if(!(sndFile.GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1; state->m_nGlobalVolume += param * nonRowTicks; } else { param = (param & 0x0F) << 1; if(!(sndFile.GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1; state->m_nGlobalVolume -= param * nonRowTicks; } Limit(state->m_nGlobalVolume, 0, 256); } }; // Get mod length in various cases. Parameters: // [in] adjustMode: See enmGetLengthResetMode for possible adjust modes. // [in] target: Time or position target which should be reached, or no target to get length of the first sub song. Use GetLengthTarget::StartPos to also specify a position from where the seeking should begin. // [out] See definition of type GetLengthType for the returned values. std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMode, GetLengthTarget target) { std::vector results; GetLengthType retval; // Are we trying to reach a certain pattern position? const bool hasSearchTarget = target.mode != GetLengthTarget::NoTarget && target.mode != GetLengthTarget::GetAllSubsongs; const bool adjustSamplePos = (adjustMode & eAdjustSamplePositions) == eAdjustSamplePositions; SEQUENCEINDEX sequence = target.sequence; if(sequence >= Order.GetNumSequences()) sequence = Order.GetCurrentSequenceIndex(); const ModSequence &orderList = Order(sequence); GetLengthMemory memory(*this, sequence); PlayState &playState = *memory.state; // Temporary visited rows vector (so that GetLength() won't interfere with the player code if the module is playing at the same time) RowVisitor visitedRows(*this, sequence); ROWINDEX allowedPatternLoopComplexity = 32768; // If sequence starts with some non-existent patterns, find a better start while(target.startOrder < orderList.size() && !orderList.IsValidPat(target.startOrder)) { target.startOrder++; target.startRow = 0; } retval.startRow = playState.m_nNextRow = playState.m_nRow = target.startRow; retval.startOrder = playState.m_nNextOrder = playState.m_nCurrentOrder = target.startOrder; // Fast LUTs for commands that are too weird / complicated / whatever to emulate in sample position adjust mode. std::bitset forbiddenCommands; if(adjustSamplePos) { forbiddenCommands.set(CMD_ARPEGGIO); if(target.mode == GetLengthTarget::SeekPosition && target.pos.order < orderList.size()) { // If we know where to seek, we can directly rule out any channels on which a new note would be triggered right at the start. const PATTERNINDEX seekPat = orderList[target.pos.order]; if(Patterns.IsValidPat(seekPat) && Patterns[seekPat].IsValidRow(target.pos.row)) { const ModCommand *m = Patterns[seekPat].GetpModCommand(target.pos.row, 0); for(CHANNELINDEX i = 0; i < GetNumChannels(); i++, m++) { if(m->note == NOTE_NOTECUT || m->note == NOTE_KEYOFF || (m->note == NOTE_FADE && GetNumInstruments()) || (m->IsNote() && m->instr && !m->IsTonePortamento())) { memory.chnSettings[i].ticksToRender = GetLengthMemory::IGNORE_CHANNEL; } } } } } if(adjustMode & eAdjust) playState.m_midiMacroEvaluationResults.emplace(); // If samples are being synced, force them to resync if tick duration changes uint32 oldTickDuration = 0; bool breakToRow = false; for (;;) { const bool ignoreRow = NextRow(playState, breakToRow).first; // Time target reached. if(target.mode == GetLengthTarget::SeekSeconds && memory.elapsedTime >= target.time) { retval.targetReached = true; break; } // Check if pattern is valid playState.m_nPattern = playState.m_nCurrentOrder < orderList.size() ? orderList[playState.m_nCurrentOrder] : PATTERNINDEX_INVALID; playState.m_nTickCount = 0; if(!Patterns.IsValidPat(playState.m_nPattern) && playState.m_nPattern != PATTERNINDEX_INVALID && target.mode == GetLengthTarget::SeekPosition && playState.m_nCurrentOrder == target.pos.order) { // Early test: Target is inside +++ or non-existing pattern retval.targetReached = true; break; } while(playState.m_nPattern >= Patterns.Size()) { // End of song? if((playState.m_nPattern == PATTERNINDEX_INVALID) || (playState.m_nCurrentOrder >= orderList.size())) { if(playState.m_nCurrentOrder == orderList.GetRestartPos()) break; else playState.m_nCurrentOrder = orderList.GetRestartPos(); } else { playState.m_nCurrentOrder++; } playState.m_nPattern = (playState.m_nCurrentOrder < orderList.size()) ? orderList[playState.m_nCurrentOrder] : PATTERNINDEX_INVALID; playState.m_nNextOrder = playState.m_nCurrentOrder; if((!Patterns.IsValidPat(playState.m_nPattern)) && visitedRows.Visit(playState.m_nCurrentOrder, 0, playState.Chn, ignoreRow)) { if(!hasSearchTarget) { retval.restartOrder = playState.m_nCurrentOrder; retval.restartRow = 0; } if(target.mode == GetLengthTarget::NoTarget || !visitedRows.GetFirstUnvisitedRow(playState.m_nNextOrder, playState.m_nRow, true)) { // We aren't searching for a specific row, or we couldn't find any more unvisited rows. break; } else { // We haven't found the target row yet, but we found some other unplayed row... continue searching from here. retval.duration = memory.elapsedTime; results.push_back(retval); retval.startRow = playState.m_nRow; retval.startOrder = playState.m_nNextOrder; memory.Reset(); playState.m_nCurrentOrder = playState.m_nNextOrder; playState.m_nPattern = orderList[playState.m_nCurrentOrder]; playState.m_nNextRow = playState.m_nRow; break; } } } if(playState.m_nNextOrder == ORDERINDEX_INVALID) { // GetFirstUnvisitedRow failed, so there is nothing more to play break; } // Skip non-existing patterns if(!Patterns.IsValidPat(playState.m_nPattern)) { // If there isn't even a tune, we should probably stop here. if(playState.m_nCurrentOrder == orderList.GetRestartPos()) { if(target.mode == GetLengthTarget::NoTarget || !visitedRows.GetFirstUnvisitedRow(playState.m_nNextOrder, playState.m_nRow, true)) { // We aren't searching for a specific row, or we couldn't find any more unvisited rows. break; } else { // We haven't found the target row yet, but we found some other unplayed row... continue searching from here. retval.duration = memory.elapsedTime; results.push_back(retval); retval.startRow = playState.m_nRow; retval.startOrder = playState.m_nNextOrder; memory.Reset(); playState.m_nNextRow = playState.m_nRow; continue; } } playState.m_nNextOrder = playState.m_nCurrentOrder + 1; continue; } // Should never happen if(playState.m_nRow >= Patterns[playState.m_nPattern].GetNumRows()) playState.m_nRow = 0; // Check whether target was reached. if(target.mode == GetLengthTarget::SeekPosition && playState.m_nCurrentOrder == target.pos.order && playState.m_nRow == target.pos.row) { retval.targetReached = true; break; } // If pattern loops are nested too deeply, they can cause an effectively infinite amount of loop evalations to be generated. // As we don't want the user to wait forever, we bail out if the pattern loops are too complex. const bool moduleTooComplex = target.mode != GetLengthTarget::SeekSeconds && visitedRows.ModuleTooComplex(allowedPatternLoopComplexity); if(moduleTooComplex) { memory.elapsedTime = std::numeric_limits::infinity(); // Decrease allowed complexity with each subsong, as this seems to be a malicious module if(allowedPatternLoopComplexity > 256) allowedPatternLoopComplexity /= 2; visitedRows.ResetComplexity(); } if(visitedRows.Visit(playState.m_nCurrentOrder, playState.m_nRow, playState.Chn, ignoreRow) || moduleTooComplex) { if(!hasSearchTarget) { retval.restartOrder = playState.m_nCurrentOrder; retval.restartRow = playState.m_nRow; } if(target.mode == GetLengthTarget::NoTarget || !visitedRows.GetFirstUnvisitedRow(playState.m_nNextOrder, playState.m_nRow, true)) { // We aren't searching for a specific row, or we couldn't find any more unvisited rows. break; } else { // We haven't found the target row yet, but we found some other unplayed row... continue searching from here. retval.duration = memory.elapsedTime; results.push_back(retval); retval.startRow = playState.m_nRow; retval.startOrder = playState.m_nNextOrder; memory.Reset(); playState.m_nNextRow = playState.m_nRow; continue; } } retval.endOrder = playState.m_nCurrentOrder; retval.endRow = playState.m_nRow; // Update next position SetupNextRow(playState, false); // Jumped to invalid pattern row? if(playState.m_nRow >= Patterns[playState.m_nPattern].GetNumRows()) { playState.m_nRow = 0; } playState.UpdatePPQ(breakToRow); playState.UpdateTimeSignature(*this); if(ignoreRow) continue; // For various effects, we need to know first how many ticks there are in this row. const ModCommand *p = Patterns[playState.m_nPattern].GetpModCommand(playState.m_nRow, 0); const bool ignoreMutedChn = m_playBehaviour[kST3NoMutedChannels]; for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++, p++) { ModChannel &chn = playState.Chn[nChn]; chn.isFirstTick = true; if(p->IsEmpty() || (ignoreMutedChn && ChnSettings[nChn].dwFlags[CHN_MUTE])) // not even effects are processed on muted S3M channels { chn.rowCommand.Clear(); continue; } if(p->IsPcNote()) { #ifndef NO_PLUGINS if(playState.m_midiMacroEvaluationResults && p->instr > 0 && p->instr <= MAX_MIXPLUGINS) { playState.m_midiMacroEvaluationResults->pluginParameter[{static_cast(p->instr - 1), p->GetValueVolCol()}] = p->GetValueEffectCol() / PlugParamValue(ModCommand::maxColumnValue); } #endif // NO_PLUGINS chn.rowCommand.Clear(); continue; } if(p->IsNote()) chn.nNewNote = chn.nLastNote = p->note; else if(p->note > NOTE_MAX && m_playBehaviour[kITClearOldNoteAfterCut]) chn.nNewNote = NOTE_NONE; if(m_playBehaviour[kITEmptyNoteMapSlotIgnoreCell] && p->instr > 0 && p->instr <= GetNumInstruments() && Instruments[p->instr] != nullptr && !Instruments[p->instr]->HasValidMIDIChannel()) { auto note = (chn.rowCommand.note != NOTE_NONE) ? p->note : chn.nNewNote; if (ModCommand::IsNote(note) && Instruments[p->instr]->Keyboard[note - NOTE_MIN] == 0) { chn.nNewNote = chn.nLastNote = note; chn.nNewIns = p->instr; chn.rowCommand.Clear(); continue; } } chn.rowCommand = *p; switch(p->command) { case CMD_SPEED: SetSpeed(playState, p->param); break; case CMD_TEMPO: if(m_playBehaviour[kMODVBlankTiming]) { // ProTracker MODs with VBlank timing: All Fxx parameters set the tick count. if(p->param != 0) SetSpeed(playState, p->param); } // Regular tempo handled below break; case CMD_S3MCMDEX: if(!chn.rowCommand.param && (GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT))) chn.rowCommand.param = chn.nOldCmdEx; else chn.nOldCmdEx = static_cast(chn.rowCommand.param); if((p->param & 0xF0) == 0x60) { // Fine Pattern Delay playState.m_nFrameDelay += (p->param & 0x0F); } else if((p->param & 0xF0) == 0xE0 && !playState.m_nPatternDelay) { // Pattern Delay if(!(GetType() & MOD_TYPE_S3M) || (p->param & 0x0F) != 0) { // While Impulse Tracker *does* count S60 as a valid row delay (and thus ignores any other row delay commands on the right), // Scream Tracker 3 simply ignores such commands. playState.m_nPatternDelay = 1 + (p->param & 0x0F); } } break; case CMD_MODCMDEX: if((p->param & 0xF0) == 0xE0) { // Pattern Delay playState.m_nPatternDelay = 1 + (p->param & 0x0F); } break; default: break; } } // This may change speed/tempo/global volume/next row playState.m_globalScriptState.NextTick(playState, *this); const uint32 numTicks = playState.TicksOnRow(); const uint32 nonRowTicks = numTicks - std::max(playState.m_nPatternDelay, uint32(1)); playState.m_patLoopRow = ROWINDEX_INVALID; playState.m_breakRow = ROWINDEX_INVALID; playState.m_posJump = ORDERINDEX_INVALID; for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++) { ModChannel &chn = playState.Chn[nChn]; if(chn.rowCommand.IsEmpty() && !chn.autoSlide.AnyActive()) continue; ModCommand::COMMAND command = chn.rowCommand.command; ModCommand::PARAM param = chn.rowCommand.param; ModCommand::NOTE note = chn.rowCommand.note; if((adjustMode & eAdjust) && !chn.rowCommand.IsEmpty()) { if(chn.rowCommand.instr) { chn.swapSampleIndex = chn.nNewIns = chn.rowCommand.instr; memory.chnSettings[nChn].vol = 0xFF; } if(chn.rowCommand.IsNote()) { chn.RestorePanAndFilter(); if(!adjustSamplePos || memory.chnSettings[nChn].ticksToRender == GetLengthMemory::IGNORE_CHANNEL) { // Even if we don't intend to render anything on this channel, update instrument cutoff/resonance because it might override a Zxx effect evaluated earlier. const ModInstrument *instr = chn.pModInstrument; if(chn.nNewIns && chn.nNewIns <= GetNumInstruments()) instr = Instruments[chn.nNewIns]; if(instr != nullptr) { if(instr->IsCutoffEnabled()) chn.nCutOff = instr->GetCutoff(); if(instr->IsResonanceEnabled()) chn.nResonance = instr->GetResonance(); } const bool wasGlobalSlideRunning = chn.autoSlide.IsActive(AutoSlideCommand::GlobalVolumeSlide); chn.autoSlide.Reset(); chn.autoSlide.SetActive(AutoSlideCommand::GlobalVolumeSlide, wasGlobalSlideRunning); } } // Update channel panning if(chn.rowCommand.IsNote() || chn.rowCommand.instr) { ModInstrument *pIns; if(chn.nNewIns > 0 && chn.nNewIns <= GetNumInstruments() && (pIns = Instruments[chn.nNewIns]) != nullptr) { if(pIns->dwFlags[INS_SETPANNING]) chn.SetInstrumentPan(pIns->nPan, *this); } const SAMPLEINDEX smp = GetSampleIndex(note, chn.nNewIns); if(smp > 0) { if(Samples[smp].uFlags[CHN_PANNING]) chn.SetInstrumentPan(Samples[smp].nPan, *this); } } switch(chn.rowCommand.volcmd) { case VOLCMD_VOLUME: memory.chnSettings[nChn].vol = chn.rowCommand.vol; break; case VOLCMD_VOLSLIDEUP: case VOLCMD_VOLSLIDEDOWN: if(chn.rowCommand.vol != 0) chn.nOldVolParam = chn.rowCommand.vol; break; case VOLCMD_TONEPORTAMENTO: if(chn.rowCommand.vol) { const auto [porta, clearEffectCommand] = GetVolCmdTonePorta(chn.rowCommand, 0); chn.portamentoSlide = porta; if(clearEffectCommand) command = CMD_NONE; } break; default: break; } } switch(command) { // Position Jump case CMD_POSITIONJUMP: PositionJump(playState, nChn); break; // Pattern Break case CMD_PATTERNBREAK: if(ROWINDEX row = PatternBreak(playState, nChn, param); row != ROWINDEX_INVALID) playState.m_breakRow = row; break; // Set Tempo case CMD_TEMPO: if(!m_playBehaviour[kMODVBlankTiming]) { TEMPO tempo(CalculateXParam(playState.m_nPattern, playState.m_nRow, nChn), 0); if(GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)) { if (tempo.GetInt()) chn.nOldTempo = static_cast(tempo.GetInt()); else tempo.Set(chn.nOldTempo); } if(tempo >= GetMinimumTempoParam(GetType())) { playState.m_flags.set(SONG_FIRSTTICK, !m_playBehaviour[kMODTempoOnSecondTick]); SetTempo(playState, tempo, false); } else { // Tempo Slide playState.m_flags.reset(SONG_FIRSTTICK); for(uint32 i = 0; i < nonRowTicks; i++) { SetTempo(playState, tempo, false); } } } break; case CMD_S3MCMDEX: switch(param & 0xF0) { case 0xB0: // Pattern Loop PatternLoop(playState, nChn, param & 0x0F); break; } break; case CMD_MODCMDEX: switch(param & 0xF0) { case 0x60: // Pattern Loop PatternLoop(playState, nChn, param & 0x0F); break; } break; default: break; } // The following calculations are not interesting if we just want to get the song length... // ...unless we're playing a Face The Music module with scripts that may modify the speed or tempo based on some volume or pitch variable (see schlendering.ftm) if(!(adjustMode & eAdjust) && m_globalScript.empty()) continue; ResetAutoSlides(chn); switch(command) { // Portamento Up/Down case CMD_PORTAMENTOUP: if(param) { // FT2 compatibility: Separate effect memory for all portamento commands // Test case: Porta-LinkMem.xm if(!m_playBehaviour[kFT2PortaUpDownMemory]) chn.nOldPortaDown = param; chn.nOldPortaUp = param; } break; case CMD_PORTAMENTODOWN: if(param) { // FT2 compatibility: Separate effect memory for all portamento commands // Test case: Porta-LinkMem.xm if(!m_playBehaviour[kFT2PortaUpDownMemory]) chn.nOldPortaUp = param; chn.nOldPortaDown = param; } break; // Tone-Portamento case CMD_TONEPORTAMENTO: if (param) chn.portamentoSlide = param; break; // Offset case CMD_OFFSET: if(param) chn.oldOffset = param << 8; break; // Volume Slide case CMD_VOLUMESLIDE: case CMD_TONEPORTAVOL: if (param) chn.nOldVolumeSlide = param; break; case CMD_AUTO_VOLUMESLIDE: AutoVolumeSlide(chn, param); break; case CMD_VOLUMEDOWN_ETX: VolumeDownETX(playState, chn, param); break; // Set Volume case CMD_VOLUME: memory.chnSettings[nChn].vol = param; break; case CMD_VOLUME8: memory.chnSettings[nChn].vol = static_cast((param + 3u) / 4u); break; // Global Volume case CMD_GLOBALVOLUME: if(!(GetType() & GLOBALVOL_7BIT_FORMATS) && param < 128) param *= 2; // IT compatibility 16. ST3 and IT ignore out-of-range values if(param <= 128) { playState.m_nGlobalVolume = param * 2; } else if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_S3M))) { playState.m_nGlobalVolume = 256; } playState.Chn[m_playBehaviour[kPerChannelGlobalVolSlide] ? nChn : 0].autoSlide.SetActive(AutoSlideCommand::GlobalVolumeSlide, false); break; // Global Volume Slide case CMD_GLOBALVOLSLIDE: memory.GlobalVolSlide(playState.Chn[m_playBehaviour[kPerChannelGlobalVolSlide] ? nChn : 0], param, nonRowTicks); break; case CMD_CHANNELVOLUME: if (param <= 64) chn.nGlobalVol = param; break; case CMD_CHANNELVOLSLIDE: { if (param) chn.nOldChnVolSlide = param; else param = chn.nOldChnVolSlide; int32 volume = chn.nGlobalVol; if((param & 0x0F) == 0x0F && (param & 0xF0)) volume += (param >> 4); // Fine Up else if((param & 0xF0) == 0xF0 && (param & 0x0F)) volume -= (param & 0x0F); // Fine Down else if(param & 0x0F) // Down volume -= (param & 0x0F) * nonRowTicks; else // Up volume += ((param & 0xF0) >> 4) * nonRowTicks; Limit(volume, 0, 64); chn.nGlobalVol = static_cast(volume); } break; case CMD_VOLUMEDOWN_DURATION: ChannelVolumeDownWithDuration(chn, param); break; case CMD_PANNING8: Panning(chn, param, Pan8bit); break; case CMD_MODCMDEX: switch(param & 0xF0) { case 0x00: // LED filter for(CHANNELINDEX channel = 0; channel < GetNumChannels(); channel++) { playState.Chn[channel].dwFlags.set(CHN_AMIGAFILTER, !(param & 1)); } break; case 0x80: // Panning Panning(chn, (param & 0x0F), Pan4bit); break; case 0xF0: // Active macro chn.nActiveMacro = param & 0x0F; break; } break; case CMD_S3MCMDEX: switch(param & 0xF0) { case 0x80: // Panning Panning(chn, (param & 0x0F), Pan4bit); break; case 0x90: // Extended channel effects // Change play direction is handled in adjustSamplePos case if (param < 0x9E) ExtendedChannelEffect(chn, param, playState); break; case 0xA0: // High sample offset chn.nOldHiOffset = param & 0x0F; break; case 0xF0: // Active macro chn.nActiveMacro = param & 0x0F; break; } break; case CMD_XFINEPORTAUPDOWN: // ignore high offset in compatible mode if (((param & 0xF0) == 0xA0) && !m_playBehaviour[kFT2RestrictXCommand]) chn.nOldHiOffset = param & 0x0F; break; case CMD_VIBRATOVOL: if (param) chn.nOldVolumeSlide = param; param = 0; [[fallthrough]]; case CMD_VIBRATO: Vibrato(chn, param); break; case CMD_FINEVIBRATO: FineVibrato(chn, param); break; case CMD_TREMOLO: Tremolo(chn, param); break; case CMD_PANBRELLO: Panbrello(chn, param); // Panbrello effect is permanent in compatible mode, so actually apply panbrello for the last tick of this row chn.nPanbrelloPos += static_cast(chn.nPanbrelloSpeed * nonRowTicks); ProcessPanbrello(chn); break; case CMD_MIDI: case CMD_SMOOTHMIDI: if(param < 0x80) ProcessMIDIMacro(playState, nChn, false, m_MidiCfg.SFx[chn.nActiveMacro], chn.rowCommand.param, 0); else ProcessMIDIMacro(playState, nChn, false, m_MidiCfg.Zxx[param & 0x7F], chn.rowCommand.param, 0); break; default: break; } switch(chn.rowCommand.volcmd) { case VOLCMD_PANNING: Panning(chn, chn.rowCommand.vol, Pan6bit); break; case VOLCMD_VIBRATOSPEED: // FT2 does not automatically enable vibrato with the "set vibrato speed" command if(m_playBehaviour[kFT2VolColVibrato]) chn.nVibratoSpeed = chn.rowCommand.vol & 0x0F; else Vibrato(chn, chn.rowCommand.vol << 4); break; case VOLCMD_VIBRATODEPTH: Vibrato(chn, chn.rowCommand.vol); break; default: break; } chn.isFirstTick = true; if(chn.autoSlide.IsActive(AutoSlideCommand::FineVolumeSlideUp) && command != CMD_AUTO_VOLUMESLIDE) FineVolumeUp(chn, 0, false); if(chn.autoSlide.IsActive(AutoSlideCommand::FineVolumeSlideDown) && command != CMD_AUTO_VOLUMESLIDE) FineVolumeDown(chn, 0, false); if(chn.autoSlide.IsActive(AutoSlideCommand::VolumeSlideSTK)) { for(uint32 i = 0; i < numTicks; i++) { chn.isFirstTick = (i == 0); VolumeSlide(chn, 0); } } if(chn.autoSlide.IsActive(AutoSlideCommand::VolumeDownWithDuration)) { chn.volSlideDownRemain -= std::min(chn.volSlideDownRemain, mpt::saturate_cast(numTicks - 1)); ChannelVolumeDownWithDuration(chn); } if(chn.autoSlide.IsActive(AutoSlideCommand::GlobalVolumeSlide) && command != CMD_GLOBALVOLSLIDE) memory.GlobalVolSlide(chn, chn.nOldGlobalVolSlide, nonRowTicks); if(command == CMD_VIBRATO || command == CMD_FINEVIBRATO || command == CMD_VIBRATOVOL || chn.autoSlide.IsActive(AutoSlideCommand::Vibrato)) { uint32 vibTicks = ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]) ? numTicks : nonRowTicks; uint32 inc = chn.nVibratoSpeed * vibTicks; if(m_playBehaviour[kITVibratoTremoloPanbrello]) inc *= 4; chn.nVibratoPos += static_cast(inc); } if(command == CMD_TREMOLO || chn.autoSlide.IsActive(AutoSlideCommand::Tremolo)) { uint32 tremTicks = ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]) ? numTicks : nonRowTicks; uint32 inc = chn.nTremoloSpeed * tremTicks; if(m_playBehaviour[kITVibratoTremoloPanbrello]) inc *= 4; chn.nTremoloPos += static_cast(inc); } if(m_playBehaviour[kST3EffectMemory] && command != CMD_NONE && param != 0) { UpdateS3MEffectMemory(chn, param); } } if(!m_globalScript.empty()) { for(playState.m_nTickCount = 1; playState.m_nTickCount < numTicks; playState.m_nTickCount++) { playState.m_globalScriptState.NextTick(playState, *this); } } // Interpret F00 effect in XM files as "stop song" if(GetType() == MOD_TYPE_XM && playState.m_nMusicSpeed == uint16_max) { playState.m_nNextRow = playState.m_nRow; playState.m_nNextOrder = playState.m_nCurrentOrder; continue; } const uint32 tickDuration = GetTickDuration(playState); const uint32 rowDuration = tickDuration * numTicks; memory.elapsedTime += static_cast(rowDuration) / static_cast(m_MixerSettings.gdwMixingFreq); playState.m_lTotalSampleCount += rowDuration; const ROWINDEX rowsPerBeat = playState.m_nCurrentRowsPerBeat ? playState.m_nCurrentRowsPerBeat : DEFAULT_ROWS_PER_BEAT; playState.m_ppqPosFract += 1.0 / rowsPerBeat; if(adjustSamplePos) { // Super experimental and dirty sample seeking for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++) { if(memory.chnSettings[nChn].ticksToRender == GetLengthMemory::IGNORE_CHANNEL) continue; ModChannel &chn = playState.Chn[nChn]; const ModCommand &m = chn.rowCommand; if(!chn.nPeriod && m.IsEmpty()) continue; uint32 paramHi = m.param >> 4, paramLo = m.param & 0x0F; uint32 startTick = 0; const bool porta = m.IsTonePortamento(); bool stopNote = false; if(m.instr) chn.prevNoteOffset = 0; if(m.IsNote()) { if(porta && memory.chnSettings[nChn].incChanged) { // If there's a portamento, the current channel increment mustn't be 0 in NoteChange() chn.increment = GetChannelIncrement(chn, chn.nPeriod, 0).first; } int32 setPan = chn.nPan; if(chn.nNewIns != 0) InstrumentChange(chn, chn.nNewIns, porta); NoteChange(chn, m.note, porta); HandleNoteChangeFilter(chn); HandleDigiSamplePlayDirection(playState, nChn); memory.chnSettings[nChn].incChanged = true; if((m.command == CMD_MODCMDEX || m.command == CMD_S3MCMDEX) && (m.param & 0xF0) == 0xD0 && paramLo < numTicks) { startTick = paramLo; } else if(m.command == CMD_DELAYCUT && paramHi < numTicks) { startTick = paramHi; } if(playState.m_nPatternDelay > 1 && startTick != 0 && (GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT))) { startTick += (playState.m_nMusicSpeed + playState.m_nFrameDelay) * (playState.m_nPatternDelay - 1); } if(!porta) memory.chnSettings[nChn].ticksToRender = 0; // Panning commands have to be re-applied after a note change with potential pan change. if(m.command == CMD_PANNING8 || ((m.command == CMD_MODCMDEX || m.command == CMD_S3MCMDEX) && paramHi == 0x8) || m.volcmd == VOLCMD_PANNING) { chn.nPan = setPan; } } if(m.IsNote() || m_playBehaviour[kApplyOffsetWithoutNote]) { if(m.command == CMD_OFFSET) { if(!porta || !(GetType() & (MOD_TYPE_XM | MOD_TYPE_DBM))) ProcessSampleOffset(chn, nChn, playState); } else if(m.command == CMD_OFFSETPERCENTAGE) { SampleOffset(chn, Util::muldiv_unsigned(chn.nLength, m.param, 256)); } else if(m.command == CMD_REVERSEOFFSET && chn.pModSample != nullptr) { memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far ReverseSampleOffset(chn, m.param); startTick = playState.m_nMusicSpeed - 1; } else if(m.volcmd == VOLCMD_OFFSET) { if(chn.pModSample != nullptr && !chn.pModSample->uFlags[CHN_ADLIB] && m.vol <= std::size(chn.pModSample->cues)) { SmpLength offset; if(m.vol == 0) offset = chn.oldOffset; else offset = chn.oldOffset = chn.pModSample->cues[m.vol - 1]; SampleOffset(chn, offset); } } } if(m.note == NOTE_KEYOFF || m.note == NOTE_NOTECUT || (m.note == NOTE_FADE && GetNumInstruments()) || ((m.command == CMD_MODCMDEX || m.command == CMD_S3MCMDEX) && (m.param & 0xF0) == 0xC0 && paramLo < numTicks) || (m.command == CMD_DELAYCUT && paramLo != 0 && startTick + paramLo < numTicks) || m.command == CMD_KEYOFF) { stopNote = true; } if(m.command == CMD_VOLUME) chn.nVolume = m.param * 4u; else if(m.command == CMD_VOLUME8) chn.nVolume = m.param; else if(m.volcmd == VOLCMD_VOLUME) chn.nVolume = m.vol * 4u; if(chn.pModSample && !stopNote) { // Check if we don't want to emulate some effect and thus stop processing. if(m.command < MAX_EFFECTS) { if(forbiddenCommands[m.command]) { stopNote = true; } else if(m.command == CMD_MODCMDEX) { // Special case: Slides using extended commands switch(m.param & 0xF0) { case 0x10: case 0x20: stopNote = true; } } } } if(stopNote) { chn.Stop(); memory.chnSettings[nChn].ticksToRender = 0; } else { if(oldTickDuration != tickDuration && oldTickDuration != 0) { memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far } switch(m.command) { case CMD_TONEPORTAVOL: case CMD_VOLUMESLIDE: case CMD_VIBRATOVOL: if(m.param || (GetType() != MOD_TYPE_MOD)) { // ST3 compatibility: Do not run combined slides (Kxy / Lxy) on first tick // Test cases: NoCombinedSlidesOnFirstTick-Normal.s3m, NoCombinedSlidesOnFirstTick-Fast.s3m for(uint32 i = (m_playBehaviour[kS3MIgnoreCombinedFineSlides] ? 1 : 0); i < numTicks; i++) { chn.isFirstTick = (i == 0); VolumeSlide(chn, m.param); } } break; case CMD_MODCMDEX: if((m.param & 0x0F) || (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) { chn.isFirstTick = true; switch(m.param & 0xF0) { case 0xA0: FineVolumeUp(chn, m.param & 0x0F, false); break; case 0xB0: FineVolumeDown(chn, m.param & 0x0F, false); break; } } break; case CMD_S3MCMDEX: if((m.param & 0xF0) == 0x90) { // Change play direction - other cases already handled above if(m.param == 0x9E || m.param == 0x9F) { memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far ExtendedChannelEffect(chn, m.param, playState); } } else if((m.param & 0xF0) == 0x70) { if(m.param >= 0x73) chn.InstrumentControl(m.param, *this); } break; case CMD_DIGIREVERSESAMPLE: DigiBoosterSampleReverse(chn, m.param); break; case CMD_FINETUNE: case CMD_FINETUNE_SMOOTH: memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far chn.microTuning = CalculateFinetuneTarget(playState.m_nPattern, playState.m_nRow, nChn); // TODO should render each tick individually for CMD_FINETUNE_SMOOTH for higher sync accuracy break; // Auto portamentos case CMD_AUTO_PORTAUP: chn.autoSlide.SetActive(AutoSlideCommand::PortamentoUp, m.param != 0); chn.nOldPortaUp = m.param; break; case CMD_AUTO_PORTADOWN: chn.autoSlide.SetActive(AutoSlideCommand::PortamentoDown, m.param != 0); chn.nOldPortaDown = m.param; break; case CMD_AUTO_PORTAUP_FINE: chn.autoSlide.SetActive(AutoSlideCommand::FinePortamentoUp, m.param != 0); chn.nOldFinePortaUpDown = m.param; break; case CMD_AUTO_PORTADOWN_FINE: chn.autoSlide.SetActive(AutoSlideCommand::FinePortamentoDown, m.param != 0); chn.nOldFinePortaUpDown = m.param; break; case CMD_AUTO_PORTAMENTO_FC: chn.autoSlide.SetActive(AutoSlideCommand::PortamentoFC, m.param != 0); chn.nOldPortaUp = chn.nOldPortaDown = m.param; break; case CMD_TONEPORTA_DURATION: if(chn.rowCommand.IsNote()) TonePortamentoWithDuration(chn, m.param); break; default: break; } chn.isFirstTick = true; switch(m.volcmd) { case VOLCMD_FINEVOLUP: FineVolumeUp(chn, m.vol, m_playBehaviour[kITVolColMemory]); break; case VOLCMD_FINEVOLDOWN: FineVolumeDown(chn, m.vol, m_playBehaviour[kITVolColMemory]); break; case VOLCMD_VOLSLIDEUP: case VOLCMD_VOLSLIDEDOWN: { // IT Compatibility: Volume column volume slides have their own memory // Test case: VolColMemory.it ModCommand::VOL vol = m.vol; if(vol == 0 && m_playBehaviour[kITVolColMemory]) { vol = chn.nOldVolParam; if(vol == 0) break; } if(m.volcmd == VOLCMD_VOLSLIDEUP) vol <<= 4; for(uint32 i = 0; i < numTicks; i++) { chn.isFirstTick = (i == 0); VolumeSlide(chn, vol); } } break; case VOLCMD_PLAYCONTROL: if(m.vol >= 2 && m.vol <= 4) memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far chn.PlayControl(m.vol); break; default: break; } if(chn.isPaused) continue; if(m.IsAnyPitchSlide() || chn.autoSlide.AnyPitchSlideActive()) { // Portamento needs immediate syncing, as the pitch changes on each tick uint32 portaTick = memory.chnSettings[nChn].ticksToRender + startTick; memory.chnSettings[nChn].ticksToRender += numTicks; memory.RenderChannel(nChn, tickDuration, portaTick); } else { memory.chnSettings[nChn].ticksToRender += (numTicks - startTick); } } } } oldTickDuration = tickDuration; breakToRow = HandleNextRow(playState, orderList, false); } // Now advance the sample positions for sample seeking on channels that are still playing if(adjustSamplePos) { for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++) { if(memory.chnSettings[nChn].ticksToRender != GetLengthMemory::IGNORE_CHANNEL) { memory.RenderChannel(nChn, oldTickDuration); } } } if(retval.targetReached) { retval.restartOrder = playState.m_nCurrentOrder; retval.restartRow = playState.m_nRow; } retval.duration = memory.elapsedTime; results.push_back(retval); // Store final variables if(adjustMode & eAdjust) { if(retval.targetReached || target.mode == GetLengthTarget::NoTarget) { const auto midiMacroEvaluationResults = std::move(playState.m_midiMacroEvaluationResults); playState.m_midiMacroEvaluationResults.reset(); // Target found, or there is no target (i.e. play whole song)... m_PlayState = std::move(playState); m_PlayState.ResetGlobalVolumeRamping(); m_PlayState.m_nNextRow = m_PlayState.m_nRow; m_PlayState.m_nFrameDelay = m_PlayState.m_nPatternDelay = 0; m_PlayState.m_nTickCount = TICKS_ROW_FINISHED; m_PlayState.m_flags.set(SONG_POSITIONCHANGED); if(m_opl != nullptr) m_opl->Reset(); for(CHANNELINDEX n = 0; n < GetNumChannels(); n++) { auto &chn = m_PlayState.Chn[n]; if(memory.chnSettings[n].vol != 0xFF && !adjustSamplePos) { chn.nVolume = std::min(memory.chnSettings[n].vol, uint8(64)) * 4; } if(!chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE] && chn.pModSample != nullptr && chn.pModSample->uFlags[CHN_ADLIB] && m_opl) { m_opl->Patch(n, chn.pModSample->adlib); m_opl->NoteCut(n); } chn.pCurrentSample = nullptr; } #ifndef NO_PLUGINS // If there were any PC events or MIDI macros updating plugin parameters, update plugin parameters to their latest value. std::bitset plugSetProgram; for(const auto &[plugParam, value] : midiMacroEvaluationResults->pluginParameter) { PLUGINDEX plug = plugParam.first; IMixPlugin *plugin = m_MixPlugins[plug].pMixPlugin; if(plugin != nullptr) { if(!plugSetProgram[plug]) { // Used for bridged plugins to avoid sending out individual messages for each parameter. plugSetProgram.set(plug); plugin->BeginSetProgram(); } plugin->SetParameter(plugParam.second, value); } } if(plugSetProgram.any()) { for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++) { if(plugSetProgram[i]) { m_MixPlugins[i].pMixPlugin->EndSetProgram(); } } } // Do the same for dry/wet ratios for(const auto &[plug, dryWetRatio] : midiMacroEvaluationResults->pluginDryWetRatio) { m_MixPlugins[plug].fDryRatio = dryWetRatio; } UpdatePluginPositions(); #endif // NO_PLUGINS } else if(adjustMode != eAdjustOnSuccess) { // Target not found (e.g. when jumping to a hidden sub song), reset global variables... m_PlayState.m_nMusicSpeed = Order(sequence).GetDefaultSpeed(); m_PlayState.m_nMusicTempo = Order(sequence).GetDefaultTempo(); m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume; } // When adjusting the playback status, we will also want to update the visited rows vector according to the current position. if(sequence != Order.GetCurrentSequenceIndex()) { Order.SetSequence(sequence); } } if(adjustMode & (eAdjust | eAdjustOnlyVisitedRows)) m_visitedRows.MoveVisitedRowsFrom(visitedRows); return results; } ////////////////////////////////////////////////////////////////////////////////////////////////// // Effects // Change sample or instrument number. void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bool bUpdVol, bool bResetEnv) const { const ModInstrument *pIns = instr <= GetNumInstruments() ? Instruments[instr] : nullptr; const ModSample *pSmp = &Samples[instr <= GetNumSamples() ? instr : 0]; const auto oldInsVol = chn.nInsVol; ModCommand::NOTE note = chn.nNewNote; if(note == NOTE_NONE && m_playBehaviour[kITInstrWithoutNote]) return; if(pIns != nullptr && ModCommand::IsNote(note)) { // Impulse Tracker ignores empty slots. // We won't ignore them if a plugin is assigned to this slot, so that VSTis still work as intended. // Test case: emptyslot.it, PortaInsNum.it, gxsmp.it, gxsmp2.it if(pIns->Keyboard[note - NOTE_MIN] == 0 && m_playBehaviour[kITEmptyNoteMapSlot] && !pIns->HasValidMIDIChannel()) { chn.pModInstrument = pIns; return; } if(pIns->NoteMap[note - NOTE_MIN] > NOTE_MAX) return; uint32 n = pIns->Keyboard[note - NOTE_MIN]; if(n) pSmp = (n <= GetNumSamples()) ? &Samples[n] : &Samples[0]; else pSmp = nullptr; } else if(GetNumInstruments()) { // No valid instrument, or not a valid note. if (note >= NOTE_MIN_SPECIAL) return; if(m_playBehaviour[kITEmptyNoteMapSlot] && (pIns == nullptr || !pIns->HasValidMIDIChannel())) { // Impulse Tracker ignores empty slots. // We won't ignore them if a plugin is assigned to this slot, so that VSTis still work as intended. // Test case: emptyslot.it, PortaInsNum.it, gxsmp.it, gxsmp2.it chn.pModInstrument = nullptr; chn.swapSampleIndex = chn.nNewIns = 0; return; } pSmp = nullptr; } bool returnAfterVolumeAdjust = false; // instrumentChanged is used for IT carry-on env option bool instrumentChanged = (pIns != chn.pModInstrument); const bool sampleChanged = (chn.pModSample != nullptr) && (pSmp != chn.pModSample); const bool newTuning = (GetType() == MOD_TYPE_MPT && pIns && pIns->pTuning); if(!bPorta || instrumentChanged || sampleChanged) chn.microTuning = 0; // Playback behavior change for MPT: With portamento don't change sample if it is in // the same instrument as previous sample. if(bPorta && newTuning && pIns == chn.pModInstrument && sampleChanged) return; if(sampleChanged && bPorta) { // IT compatibility: No sample change (also within multi-sample instruments) during portamento when using Compatible Gxx. // Test case: PortaInsNumCompat.it, PortaSampleCompat.it, PortaCutCompat.it if(m_playBehaviour[kITPortamentoInstrument] && m_SongFlags[SONG_ITCOMPATGXX] && !chn.increment.IsZero()) { pSmp = chn.pModSample; } // Special XM hack (also applies to MOD / S3M, except when playing IT-style S3Ms, such as k_vision.s3m) // Test case: PortaSmpChange.mod, PortaSmpChange.s3m, PortaSwap.s3m if((!instrumentChanged && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)) && pIns) || (GetType() == MOD_TYPE_PLM) || (GetType() == MOD_TYPE_MOD && chn.IsSamplePlaying()) || (m_playBehaviour[kST3PortaSampleChange] && chn.IsSamplePlaying())) { // FT2 doesn't change the sample in this case, // but still uses the sample info from the old one (bug?) returnAfterVolumeAdjust = true; } // IT compatibility: Reset filter if portamento results in sample change // Test case: FilterPortaSmpChange.it, FilterPortaSmpChange-InsMode.it if(m_playBehaviour[kITResetFilterOnPortaSmpChange] && !m_nInstruments) chn.triggerNote = true; } // IT compatibility: A lone instrument number should only reset sample properties to those of the corresponding sample in instrument mode. // C#5 01 ... <-- sample 1 // C-5 .. g02 <-- sample 2 // ... 01 ... <-- still sample 1, but with properties of sample 2 // In the above example, no sample change happens on the second row. In the third row, sample 1 keeps playing but with the // volume and panning properties of sample 2. // Test case: InstrAfterMultisamplePorta.it if(m_nInstruments && !instrumentChanged && sampleChanged && chn.pCurrentSample != nullptr && m_playBehaviour[kITMultiSampleInstrumentNumber] && !chn.rowCommand.IsNote()) { returnAfterVolumeAdjust = true; } // IT Compatibility: Envelope pickup after SCx cut (but don't do this when working with plugins, or else envelope carry stops working) // Test case: cut-carry.it if(!chn.IsSamplePlaying() && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (!pIns || !pIns->HasValidMIDIChannel())) { instrumentChanged = true; } // FT2 compatibility: new instrument + portamento = ignore new instrument number, but reload old instrument settings (the world of XM is upside down...) // And this does *not* happen if volume column portamento is used together with note delay... (handled in ProcessEffects(), where all the other note delay stuff is.) // Test case: porta-delay.xm, SamplePortaInInstrument.xm if((instrumentChanged || sampleChanged) && bPorta && m_playBehaviour[kFT2PortaIgnoreInstr] && (chn.pModInstrument != nullptr || chn.pModSample != nullptr)) { pIns = chn.pModInstrument; pSmp = chn.pModSample; instrumentChanged = false; } else { chn.pModInstrument = pIns; } // Update Volume if (bUpdVol && (!(GetType() & (MOD_TYPE_MOD | MOD_TYPE_S3M)) || ((pSmp != nullptr && pSmp->HasSampleData()) || chn.HasMIDIOutput()))) { if(pSmp) { if(!pSmp->uFlags[SMP_NODEFAULTVOLUME]) chn.nVolume = pSmp->nVolume; } else if(pIns && pIns->nMixPlug) { chn.nVolume = chn.GetVSTVolume(); } else { chn.nVolume = 0; } } if(returnAfterVolumeAdjust && sampleChanged && pSmp != nullptr) { // ProTracker applies new instrument's finetune but keeps the old sample playing. // Test case: PortaSwapPT.mod if(m_playBehaviour[kMODSampleSwap]) chn.nFineTune = pSmp->nFineTune; // ST3 does it similarly for middle-C speed. // Test case: PortaSwap.s3m, SampleSwap.s3m if(GetType() == MOD_TYPE_S3M && pSmp->HasSampleData()) chn.nC5Speed = pSmp->nC5Speed; } if(returnAfterVolumeAdjust) return; // Instrument adjust chn.swapSampleIndex = chn.nNewIns = 0; // IT Compatiblity: NNA is reset on every note change, not every instrument change (fixes s7xinsnum.it). if (pIns && ((!m_playBehaviour[kITNNAReset] && pSmp) || pIns->nMixPlug || instrumentChanged)) chn.nNNA = pIns->nNNA; // Update volume chn.UpdateInstrumentVolume(pSmp, pIns); // Update panning // FT2 compatibility: Only reset panning on instrument numbers, not notes (bUpdVol condition) // Test case: PanMemory.xm // IT compatibility: Sample and instrument panning is only applied on note change, not instrument change // Test case: PanReset.it if((bUpdVol || !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) && !m_playBehaviour[kITPanningReset]) { ApplyInstrumentPanning(chn, pIns, pSmp); } // Reset envelopes if(bResetEnv) { // Blurb by Storlek (from the SchismTracker code): // Conditions experimentally determined to cause envelope reset in Impulse Tracker: // - no note currently playing (of course) // - note given, no portamento // - instrument number given, portamento, compat gxx enabled // - instrument number given, no portamento, after keyoff, old effects enabled // If someone can enlighten me to what the logic really is here, I'd appreciate it. // Seems like it's just a total mess though, probably to get XMs to play right. bool reset, resetAlways; // IT Compatibility: Envelope reset // Test case: EnvReset.it if(m_playBehaviour[kITEnvelopeReset]) { const bool insNumber = (instr != 0); reset = (!chn.nLength || (insNumber && bPorta && m_SongFlags[SONG_ITCOMPATGXX]) || (insNumber && !bPorta && chn.dwFlags[CHN_NOTEFADE | CHN_KEYOFF] && m_SongFlags[SONG_ITOLDEFFECTS])); // NOTE: Carry behaviour is not consistent between IT drivers. // If NNA is set to "Note Cut", carry only works if the driver uses volume ramping on cut notes. // This means that the normal SB and GUS drivers behave differently than what is implemented here. // We emulate IT's WAV writer and SB16 MMX driver instead. // Test case: CarryNNA.it resetAlways = !chn.nFadeOutVol || instrumentChanged || (m_playBehaviour[kITCarryAfterNoteOff] ? !chn.rowCommand.IsNote() : chn.dwFlags[CHN_KEYOFF]); } else { reset = (!bPorta || !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_DBM)) || m_SongFlags[SONG_ITCOMPATGXX] || !chn.nLength || (chn.dwFlags[CHN_NOTEFADE] && !chn.nFadeOutVol)); resetAlways = !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_DBM)) || instrumentChanged || pIns == nullptr || chn.dwFlags[CHN_KEYOFF | CHN_NOTEFADE]; } if(reset) { chn.dwFlags.set(CHN_FASTVOLRAMP); if(pIns != nullptr) { if(resetAlways) { chn.ResetEnvelopes(); } else { if(!pIns->VolEnv.dwFlags[ENV_CARRY]) chn.VolEnv.Reset(); if(!pIns->PanEnv.dwFlags[ENV_CARRY]) chn.PanEnv.Reset(); if(!pIns->PitchEnv.dwFlags[ENV_CARRY]) chn.PitchEnv.Reset(); } } // IT Compatibility: Autovibrato reset if(!m_playBehaviour[kITVibratoTremoloPanbrello]) { chn.nAutoVibDepth = 0; chn.nAutoVibPos = 0; } } else if(pIns != nullptr && !pIns->VolEnv.dwFlags[ENV_ENABLED]) { if(m_playBehaviour[kITPortamentoInstrument]) { chn.VolEnv.Reset(); } else { chn.ResetEnvelopes(); } } } // Invalid sample ? if(pSmp == nullptr && (pIns == nullptr || !pIns->HasValidMIDIChannel())) { chn.pModSample = nullptr; chn.nInsVol = 0; return; } const bool wasKeyOff = chn.dwFlags[CHN_KEYOFF]; // Tone-Portamento doesn't reset the pingpong direction flag if(bPorta && pSmp == chn.pModSample && pSmp != nullptr) { // IT compatibility: Instrument change but sample stays the same: still reset the key-off flags // Test case: SampleSustainAfterPortaInstrMode.it if(instrumentChanged && pIns && m_playBehaviour[kITNoSustainOnPortamento]) chn.dwFlags.reset(CHN_KEYOFF | CHN_NOTEFADE); // If channel length is 0, we cut a previous sample using SCx. In that case, we have to update sample length, loop points, etc... if(GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT) && chn.nLength != 0) return; // FT2 compatibility: Do not reset key-off status on portamento without instrument number // Test case: Off-Porta.xm if(GetType() != MOD_TYPE_XM || !m_playBehaviour[kITFT2DontResetNoteOffOnPorta] || chn.rowCommand.instr != 0) chn.dwFlags.reset(CHN_KEYOFF | CHN_NOTEFADE); chn.dwFlags = (chn.dwFlags & (CHN_CHANNELFLAGS | CHN_PINGPONGFLAG)); } else //if(!instrumentChanged || chn.rowCommand.instr != 0 || !IsCompatibleMode(TRK_FASTTRACKER2)) // SampleChange.xm? { chn.dwFlags.reset(CHN_KEYOFF | CHN_NOTEFADE); // IT compatibility: Don't change bidi loop direction when no sample nor instrument is changed. if((m_playBehaviour[kITPingPongNoReset] || !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) && pSmp == chn.pModSample && !instrumentChanged) chn.dwFlags = (chn.dwFlags & (CHN_CHANNELFLAGS | CHN_PINGPONGFLAG)); else chn.dwFlags = (chn.dwFlags & CHN_CHANNELFLAGS); if(pIns) { // Copy envelope flags (we actually only need the "enabled" and "pitch" flag) chn.VolEnv.flags = pIns->VolEnv.dwFlags; chn.PanEnv.flags = pIns->PanEnv.dwFlags; chn.PitchEnv.flags = pIns->PitchEnv.dwFlags; // A cutoff frequency of 0 should not be reset just because the filter envelope is enabled. // Test case: FilterEnvReset.it if((pIns->PitchEnv.dwFlags & (ENV_ENABLED | ENV_FILTER)) == (ENV_ENABLED | ENV_FILTER) && !m_playBehaviour[kITFilterBehaviour]) { if(!chn.nCutOff) chn.nCutOff = 0x7F; } if(pIns->IsCutoffEnabled()) chn.nCutOff = pIns->GetCutoff(); if(pIns->IsResonanceEnabled()) chn.nResonance = pIns->GetResonance(); } } if(pSmp == nullptr) { chn.pModSample = nullptr; chn.nLength = 0; return; } if(bPorta && chn.nLength == 0 && (m_playBehaviour[kFT2PortaNoNote] || m_playBehaviour[kITPortaNoNote])) { // IT/FT2 compatibility: If the note just stopped on the previous tick, prevent it from restarting. // Test cases: PortaJustStoppedNote.xm, PortaJustStoppedNote.it chn.increment.Set(0); } // IT compatibility: Note-off with instrument number + Old Effects retriggers envelopes. // If the instrument changes, keep playing the previous sample, but load the new instrument's envelopes. // Test case: ResetEnvNoteOffOldFx.it if(chn.rowCommand.note == NOTE_KEYOFF && m_playBehaviour[kITInstrWithNoteOffOldEffects] && m_SongFlags[SONG_ITOLDEFFECTS] && sampleChanged) { if(chn.pModSample) { chn.dwFlags |= (chn.pModSample->uFlags & CHN_SAMPLEFLAGS); } chn.nInsVol = oldInsVol; chn.nVolume = pSmp->nVolume; if(pSmp->uFlags[CHN_PANNING]) chn.SetInstrumentPan(pSmp->nPan, *this); return; } chn.pModSample = pSmp; chn.nLength = pSmp->nLength; chn.nLoopStart = pSmp->nLoopStart; chn.nLoopEnd = pSmp->nLoopEnd; // ProTracker "oneshot" loops (if loop start is 0, play the whole sample once and then repeat until loop end) if(m_playBehaviour[kMODOneShotLoops] && chn.nLoopStart == 0) chn.nLoopEnd = pSmp->nLength; chn.dwFlags |= (pSmp->uFlags & CHN_SAMPLEFLAGS); // IT Compatibility: Autovibrato reset if(m_playBehaviour[kITVibratoTremoloPanbrello]) { chn.nAutoVibDepth = 0; chn.nAutoVibPos = 0; } if(newTuning) { chn.nC5Speed = pSmp->nC5Speed; chn.m_CalculateFreq = true; chn.nFineTune = 0; } else if(!bPorta || sampleChanged || !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) { // Don't reset finetune changed by "set finetune" command. // Test case: finetune.xm, finetune.mod // But *do* change the finetune if we switch to a different sample, to fix // Miranda`s axe by Jamson (jam007.xm). chn.nC5Speed = pSmp->nC5Speed; chn.nFineTune = pSmp->nFineTune; } chn.nTranspose = UseFinetuneAndTranspose() ? pSmp->RelativeTone : 0; // FT2 compatibility: Don't reset portamento target with new instrument numbers. // Test case: Porta-Pickup.xm // ProTracker does the same. // Test case: PortaTarget.mod if(!m_playBehaviour[kFT2PortaTargetNoReset] && GetType() != MOD_TYPE_MOD) { chn.nPortamentoDest = 0; } chn.m_PortamentoFineSteps = 0; // IT compatibility: Do not reset sustain loop status when using portamento after key-off // Test case: SampleSustainAfterPorta.it, SampleSustainAfterPortaCompatGxx.it, SampleSustainAfterPortaInstrMode.it if(chn.dwFlags[CHN_SUSTAINLOOP] && (!m_playBehaviour[kITNoSustainOnPortamento] || !bPorta || (pIns && !wasKeyOff))) { chn.nLoopStart = pSmp->nSustainStart; chn.nLoopEnd = pSmp->nSustainEnd; if(chn.dwFlags[CHN_PINGPONGSUSTAIN]) chn.dwFlags.set(CHN_PINGPONGLOOP); chn.dwFlags.set(CHN_LOOP); } if(chn.dwFlags[CHN_LOOP] && chn.nLoopEnd < chn.nLength) chn.nLength = chn.nLoopEnd; // Fix sample position on instrument change. This is needed for IT "on the fly" sample change. // XXX is this actually called? In ProcessEffects(), a note-on effect is emulated if there's an on the fly sample change! if(chn.position.GetUInt() >= chn.nLength) { if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) { chn.position.Set(0); } } } void CSoundFile::NoteChange(ModChannel &chn, int note, bool bPorta, bool bResetEnv, bool bManual, CHANNELINDEX channelHint) const { if(note < NOTE_MIN) return; const int origNote = note; const ModSample *pSmp = chn.pModSample; const ModInstrument *pIns = chn.pModInstrument; const bool newTuning = (GetType() == MOD_TYPE_MPT && pIns != nullptr && pIns->pTuning); // save the note that's actually used, as it's necessary to properly calculate PPS and stuff const int realnote = note; if((pIns) && (note - NOTE_MIN < (int)std::size(pIns->Keyboard))) { uint32 n = pIns->Keyboard[note - NOTE_MIN]; if(n > 0) { pSmp = &Samples[(n <= GetNumSamples()) ? n : 0]; } else if(m_playBehaviour[kITEmptyNoteMapSlot] && !chn.HasMIDIOutput()) { // Impulse Tracker ignores empty slots. // We won't ignore them if a plugin is assigned to this slot, so that VSTis still work as intended. // Test case: emptyslot.it, PortaInsNum.it, gxsmp.it, gxsmp2.it return; } note = pIns->NoteMap[note - NOTE_MIN]; } // Key Off if(note > NOTE_MAX) { // Key Off (+ Invalid Note for XM - TODO is this correct?) if(note == NOTE_KEYOFF || !(GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT))) { KeyOff(chn); // IT compatibility: Note-off + instrument releases sample sustain but does not release envelopes or fade the instrument // Test case: noteoff3.it, ResetEnvNoteOffOldFx2.it if(!bPorta && m_playBehaviour[kITInstrWithNoteOffOldEffects] && m_SongFlags[SONG_ITOLDEFFECTS] && chn.rowCommand.instr) chn.dwFlags.reset(CHN_NOTEFADE | CHN_KEYOFF); } else // Invalid Note -> Note Fade { if(/*note == NOTE_FADE && */ GetNumInstruments()) chn.dwFlags.set(CHN_NOTEFADE); } // Note Cut if (note == NOTE_NOTECUT) { if(chn.dwFlags[CHN_ADLIB] && GetType() == MOD_TYPE_S3M) { // OPL voices are not cut but enter the release portion of their envelope // In S3M we can still modify the volume after note-off, in legacy MPTM mode we can't chn.dwFlags.set(CHN_KEYOFF); } else { chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP); // IT compatibility: Stopping sample playback by setting sample increment to 0 rather than volume // Test case: NoteOffInstr.it if ((!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) || (m_nInstruments != 0 && !m_playBehaviour[kITInstrWithNoteOff])) chn.nVolume = 0; if (m_playBehaviour[kITInstrWithNoteOff]) chn.increment.Set(0); chn.nFadeOutVol = 0; } } // IT compatibility tentative fix: Clear channel note memory (TRANCE_N.IT by A3F). if(m_playBehaviour[kITClearOldNoteAfterCut]) { chn.nNote = chn.nNewNote = NOTE_NONE; } return; } if(newTuning) { if(!bPorta || chn.nNote == NOTE_NONE) chn.nPortamentoDest = 0; else { chn.nPortamentoDest = pIns->pTuning->GetStepDistance(chn.nNote, chn.m_PortamentoFineSteps, static_cast(note), 0); //Here chn.nPortamentoDest means 'steps to slide'. chn.m_PortamentoFineSteps = -chn.nPortamentoDest; } } if(!bPorta && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MED | MOD_TYPE_MT2))) { if(pSmp) { chn.nTranspose = pSmp->RelativeTone; chn.nFineTune = pSmp->nFineTune; } } // IT Compatibility: Update multisample instruments frequency even if instrument is not specified (fixes the guitars in spx-shuttledeparture.it) // Test case: freqreset-noins.it if(!bPorta && pSmp && m_playBehaviour[kITMultiSampleBehaviour]) chn.nC5Speed = pSmp->nC5Speed; if(bPorta && !chn.IsSamplePlaying()) { if(m_playBehaviour[kFT2PortaNoNote] && (!chn.HasMIDIOutput() || m_playBehaviour[kPluginIgnoreTonePortamento])) { // FT2 Compatibility: Ignore notes with portamento if there was no note playing. // Test case: 3xx-no-old-samp.xm chn.nPeriod = 0; return; } else if(m_playBehaviour[kITPortaNoNote]) { // IT Compatibility: Ignore portamento command if no note was playing (e.g. if a previous note has faded out). // Test case: Fade-Porta.it bPorta = false; } } if(UseFinetuneAndTranspose()) { note += chn.nTranspose; // RealNote = PatternNote + RelativeTone; (0..118, 0 = C-0, 118 = A#9) Limit(note, NOTE_MIN + 11, NOTE_MIN + 130); // 119 possible notes } else { Limit(note, NOTE_MIN, NOTE_MAX); } if(m_playBehaviour[kITRealNoteMapping]) { // need to memorize the original note for various effects (e.g. PPS) chn.nNote = static_cast(Clamp(realnote, NOTE_MIN, NOTE_MAX)); } else { chn.nNote = static_cast(note); } chn.m_CalculateFreq = true; chn.isPaused = false; if ((!bPorta) || (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT))) chn.swapSampleIndex = chn.nNewIns = 0; uint32 period = GetPeriodFromNote(note, chn.nFineTune, chn.nC5Speed); chn.nPanbrelloOffset = 0; // IT compatibility: Sample and instrument panning is only applied on note change, not instrument change // Test case: PanReset.it if(m_playBehaviour[kITPanningReset]) ApplyInstrumentPanning(chn, pIns, pSmp); // IT compatibility: Pitch/Pan Separation can be overriden by panning commands, and shouldn't be affected by note-off commands // Test case: PitchPanReset.it if(m_playBehaviour[kITPitchPanSeparation] && pIns && pIns->nPPS) { if(!chn.nRestorePanOnNewNote) chn.nRestorePanOnNewNote = static_cast(chn.nPan + 1); ProcessPitchPanSeparation(chn.nPan, origNote, *pIns); } if(bResetEnv && !bPorta) { chn.nVolSwing = chn.nPanSwing = 0; chn.nResSwing = chn.nCutSwing = 0; if(pIns) { // IT Compatiblity: NNA is reset on every note change, not every instrument change (fixes spx-farspacedance.it). if(m_playBehaviour[kITNNAReset]) chn.nNNA = pIns->nNNA; if(!pIns->VolEnv.dwFlags[ENV_CARRY]) chn.VolEnv.Reset(); if(!pIns->PanEnv.dwFlags[ENV_CARRY]) chn.PanEnv.Reset(); if(!pIns->PitchEnv.dwFlags[ENV_CARRY]) chn.PitchEnv.Reset(); // Volume Swing if(pIns->nVolSwing) { chn.nVolSwing = static_cast(((mpt::random(AccessPRNG()) * pIns->nVolSwing) / 64 + 1) * (m_playBehaviour[kITSwingBehaviour] ? chn.nInsVol : ((chn.nVolume + 1) / 2)) / 199); } // Pan Swing if(pIns->nPanSwing) { chn.nPanSwing = static_cast(((mpt::random(AccessPRNG()) * pIns->nPanSwing * 4) / 128)); if(!m_playBehaviour[kITSwingBehaviour] && chn.nRestorePanOnNewNote == 0) { chn.nRestorePanOnNewNote = static_cast(chn.nPan + 1); } } // Cutoff Swing if(pIns->nCutSwing) { int32 d = ((int32)pIns->nCutSwing * (int32)(static_cast(mpt::random(AccessPRNG())) + 1)) / 128; chn.nCutSwing = static_cast((d * chn.nCutOff + 1) / 128); chn.nRestoreCutoffOnNewNote = chn.nCutOff + 1; } // Resonance Swing if(pIns->nResSwing) { int32 d = ((int32)pIns->nResSwing * (int32)(static_cast(mpt::random(AccessPRNG())) + 1)) / 128; chn.nResSwing = static_cast((d * chn.nResonance + 1) / 128); chn.nRestoreResonanceOnNewNote = chn.nResonance + 1; } } } if(!pSmp) return; if(period) { if((!bPorta) || (!chn.nPeriod)) chn.nPeriod = period; if(!newTuning) { // FT2 compatibility: Don't reset portamento target with new notes. // Test case: Porta-Pickup.xm // ProTracker does the same. // Test case: PortaTarget.mod // IT compatibility: Portamento target is completely cleared with new notes. // Test case: PortaReset.it if(bPorta || !(m_playBehaviour[kFT2PortaTargetNoReset] || m_playBehaviour[kITClearPortaTarget] || GetType() == MOD_TYPE_MOD)) { chn.nPortamentoDest = period; chn.portaTargetReached = false; } } if(!bPorta || (!chn.nLength && !(GetType() & MOD_TYPE_S3M))) { chn.pModSample = pSmp; chn.nLength = pSmp->nLength; chn.nLoopEnd = pSmp->nLength; chn.nLoopStart = 0; chn.position.Set(0); if((m_SongFlags[SONG_PT_MODE] || m_playBehaviour[kST3OffsetWithoutInstrument] || GetType() == MOD_TYPE_MED) && !chn.rowCommand.instr) { chn.position.SetInt(std::min(chn.prevNoteOffset, chn.nLength - SmpLength(1))); } else { chn.prevNoteOffset = 0; } chn.dwFlags = (chn.dwFlags & CHN_CHANNELFLAGS) | (pSmp->uFlags & CHN_SAMPLEFLAGS); chn.dwFlags.reset(CHN_PORTAMENTO); if(chn.dwFlags[CHN_SUSTAINLOOP]) { chn.nLoopStart = pSmp->nSustainStart; chn.nLoopEnd = pSmp->nSustainEnd; chn.dwFlags.set(CHN_PINGPONGLOOP, chn.dwFlags[CHN_PINGPONGSUSTAIN]); chn.dwFlags.set(CHN_LOOP); if (chn.nLength > chn.nLoopEnd) chn.nLength = chn.nLoopEnd; } else if(chn.dwFlags[CHN_LOOP]) { chn.nLoopStart = pSmp->nLoopStart; chn.nLoopEnd = pSmp->nLoopEnd; if (chn.nLength > chn.nLoopEnd) chn.nLength = chn.nLoopEnd; } // ProTracker "oneshot" loops (if loop start is 0, play the whole sample once and then repeat until loop end) if(m_playBehaviour[kMODOneShotLoops] && chn.nLoopStart == 0) chn.nLoopEnd = chn.nLength = pSmp->nLength; if(chn.dwFlags[CHN_REVERSE] && chn.nLength > 0) { chn.dwFlags.set(CHN_PINGPONGFLAG); chn.position.SetInt(chn.nLength - 1); } // Handle "retrigger" waveform type if(chn.nVibratoType < 4) { // IT Compatibilty: Slightly different waveform offsets (why does MPT have two different offsets here with IT old effects enabled and disabled?) if(!m_playBehaviour[kITVibratoTremoloPanbrello] && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]) chn.nVibratoPos = 0x10; else if(GetType() == MOD_TYPE_MTM) chn.nVibratoPos = 0x20; else if(!(GetType() & (MOD_TYPE_DIGI | MOD_TYPE_DBM))) chn.nVibratoPos = 0; } // IT Compatibility: No "retrigger" waveform here if(!m_playBehaviour[kITVibratoTremoloPanbrello] && chn.nTremoloType < 4) { chn.nTremoloPos = 0; } } if(chn.position.GetUInt() >= chn.nLength) chn.position.SetInt(chn.nLoopStart); } else { bPorta = false; } if (!bPorta || (!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_DBM))) || (chn.dwFlags[CHN_NOTEFADE] && !chn.nFadeOutVol) || (m_SongFlags[SONG_ITCOMPATGXX] && chn.rowCommand.instr != 0)) { if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_DBM)) && chn.dwFlags[CHN_NOTEFADE] && !chn.nFadeOutVol) { chn.ResetEnvelopes(); // IT Compatibility: Autovibrato reset if(!m_playBehaviour[kITVibratoTremoloPanbrello]) { chn.nAutoVibDepth = 0; chn.nAutoVibPos = 0; } chn.dwFlags.reset(CHN_NOTEFADE); chn.nFadeOutVol = 65536; } if ((!bPorta) || (!m_SongFlags[SONG_ITCOMPATGXX]) || (chn.rowCommand.instr)) { if ((!(GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) || (chn.rowCommand.instr)) { chn.dwFlags.reset(CHN_NOTEFADE); chn.nFadeOutVol = 65536; } } } // IT compatibility: Don't reset key-off flag on porta notes unless Compat Gxx is enabled. // Test case: Off-Porta.it, Off-Porta-CompatGxx.it, Off-Porta.xm if(m_playBehaviour[kITFT2DontResetNoteOffOnPorta] && bPorta && (!m_SongFlags[SONG_ITCOMPATGXX] || chn.rowCommand.instr == 0)) chn.dwFlags.reset(CHN_EXTRALOUD); else chn.dwFlags.reset(CHN_EXTRALOUD | CHN_KEYOFF); // Enable Ramping if(!bPorta) { chn.triggerNote = true; chn.nLeftVU = chn.nRightVU = 0xFF; chn.dwFlags.reset(CHN_FILTER); chn.dwFlags.set(CHN_FASTVOLRAMP); // IT compatibility 15. Retrigger is reset in RetrigNote (Tremor doesn't store anything here, so we just don't reset this as well) if(!m_playBehaviour[kITRetrigger] && !m_playBehaviour[kITTremor]) { // FT2 compatibility: Retrigger is reset in RetrigNote, tremor in ProcessEffects if(!m_playBehaviour[kFT2Retrigger] && !m_playBehaviour[kFT2Tremor]) { chn.nRetrigCount = 0; chn.nTremorCount = 0; } } if(bResetEnv) { chn.nAutoVibDepth = 0; chn.nAutoVibPos = 0; } chn.rightVol = chn.leftVol = 0; if(chn.dwFlags[CHN_ADLIB] && m_opl && channelHint != CHANNELINDEX_INVALID) { // Test case: AdlibZeroVolumeNote.s3m if(m_playBehaviour[kOPLNoteOffOnNoteChange]) m_opl->NoteOff(channelHint); else if(m_playBehaviour[kOPLNoteStopWith0Hz]) m_opl->Frequency(channelHint, 0, true, false); } } // Special case for MPT if (bManual) chn.dwFlags.reset(CHN_MUTE); if((chn.dwFlags[CHN_MUTE] && (m_MixerSettings.MixerFlags & SNDMIX_MUTECHNMODE)) || (chn.pModSample != nullptr && chn.pModSample->uFlags[CHN_MUTE] && !bManual) || (chn.pModInstrument != nullptr && chn.pModInstrument->dwFlags[INS_MUTE] && !bManual)) { if (!bManual) chn.nPeriod = 0; } // Reset the Amiga resampler for this channel if(!bPorta) { chn.paulaState.Reset(); } const bool wasGlobalSlideRunning = chn.autoSlide.IsActive(AutoSlideCommand::GlobalVolumeSlide); const bool wasChannelVolSlideRunning = chn.autoSlide.IsActive(AutoSlideCommand::VolumeDownWithDuration); chn.autoSlide.Reset(); chn.autoSlide.SetActive(AutoSlideCommand::GlobalVolumeSlide, wasGlobalSlideRunning); chn.autoSlide.SetActive(AutoSlideCommand::VolumeDownWithDuration, wasChannelVolSlideRunning); } // Apply sample or instrument panning void CSoundFile::ApplyInstrumentPanning(ModChannel &chn, const ModInstrument *instr, const ModSample *smp) const { int32 newPan = int32_min; // Default instrument panning if(instr != nullptr && instr->dwFlags[INS_SETPANNING]) newPan = instr->nPan; // Default sample panning if(smp != nullptr && smp->uFlags[CHN_PANNING]) newPan = smp->nPan; if(newPan != int32_min) { chn.SetInstrumentPan(newPan, *this); // IT compatibility: Sample and instrument panning overrides channel surround status. // Test case: SmpInsPanSurround.it if(m_playBehaviour[kPanOverride] && !m_PlayState.m_flags[SONG_SURROUNDPAN]) { chn.dwFlags.reset(CHN_SURROUND); } } } CHANNELINDEX CSoundFile::GetNNAChannel(CHANNELINDEX nChn) const { // Check for empty channel for(CHANNELINDEX i = GetNumChannels(); i < m_PlayState.Chn.size(); i++) { const ModChannel &c = m_PlayState.Chn[i]; // Sample playing? if(c.nLength) continue; // Can a plugin potentially be playing? if(!c.HasMIDIOutput()) return i; // Has the plugin note already been released? (note: lastMidiNoteWithoutArp is set from within IMixPlugin, so this implies that there is a valid plugin assignment) if(c.dwFlags[CHN_KEYOFF | CHN_NOTEFADE] || c.lastMidiNoteWithoutArp == NOTE_NONE) return i; } int32 vol = 0x800100; if(nChn < m_PlayState.Chn.size()) { const ModChannel &srcChn = m_PlayState.Chn[nChn]; if(!srcChn.nFadeOutVol && srcChn.nLength) return CHANNELINDEX_INVALID; vol = (srcChn.nRealVolume << 9) | srcChn.nVolume; } // All channels are used: check for lowest volume CHANNELINDEX result = CHANNELINDEX_INVALID; uint32 envpos = 0; for(CHANNELINDEX i = GetNumChannels(); i < m_PlayState.Chn.size(); i++) { const ModChannel &c = m_PlayState.Chn[i]; // Stopped OPL channel if(c.dwFlags[CHN_ADLIB] && (!m_opl || !m_opl->IsActive(i))) return i; if(c.nLength && !c.nFadeOutVol) return i; // Use a combination of real volume [14 bit] (which includes volume envelopes, but also potentially global volume) and note volume [9 bit]. // Rationale: We need volume envelopes in case e.g. all NNA channels are playing at full volume but are looping on a 0-volume envelope node. // But if global volume is not applied to master and the global volume temporarily drops to 0, we would kill arbitrary channels. Hence, add the note volume as well. int32 v = (c.nRealVolume << 9) | c.nVolume; // Less priority to looped samples if(c.dwFlags[CHN_LOOP]) v /= 2; // Less priority for channels potentially held for plugin notes with NNA=continue the older they get if(!c.nLength && c.nMasterChn) v -= std::min(static_cast(c.nnaChannelAge) * c.nnaChannelAge, static_cast(int32_max / 16)) * 16; if((v < vol) || ((v == vol) && (c.VolEnv.nEnvPosition > envpos || !c.VolEnv.flags[ENV_ENABLED]))) { envpos = c.VolEnv.nEnvPosition; vol = v; result = i; } } return result; } CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, bool forceCut) { ModChannel &srcChn = m_PlayState.Chn[nChn]; const ModInstrument *pIns = nullptr; if(!ModCommand::IsNote(static_cast(note))) return CHANNELINDEX_INVALID; // Do we need to apply New/Duplicate Note Action to an instrument plugin? #ifndef NO_PLUGINS IMixPlugin *pPlugin = nullptr; if(srcChn.HasMIDIOutput() && ModCommand::IsNote(srcChn.nNote)) // Instrument has MIDI channel assigned (but not necessarily a plugin) { const PLUGINDEX plugin = GetBestPlugin(m_PlayState.Chn[nChn], nChn, PrioritiseInstrument, RespectMutes); if(plugin > 0 && plugin <= MAX_MIXPLUGINS) pPlugin = m_MixPlugins[plugin - 1].pMixPlugin; } // apply NNA to this plugin iff it is currently playing a note on this tracker channel // (and if it is playing a note, we know that would be the last note played on this chan). const bool applyNNAtoPlug = pPlugin && (srcChn.lastMidiNoteWithoutArp != NOTE_NONE) && pPlugin->IsNotePlaying(srcChn.lastMidiNoteWithoutArp, nChn); #else const bool applyNNAtoPlug = false; #endif // NO_PLUGINS // Always NNA cut if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_MT2)) || !m_nInstruments || forceCut) { if(!srcChn.nLength || srcChn.dwFlags[CHN_MUTE] || !(srcChn.rightVol | srcChn.leftVol)) return CHANNELINDEX_INVALID; #ifndef NO_PLUGINS if(applyNNAtoPlug) SendMIDINote(nChn, NOTE_KEYOFF, 0, m_playBehaviour[kMIDINotesFromChannelPlugin] ? pPlugin : nullptr); #endif // NO_PLUGINS if(srcChn.dwFlags[CHN_ADLIB] && m_opl) { m_opl->NoteCut(nChn, false); return CHANNELINDEX_INVALID; } const CHANNELINDEX nnaChn = GetNNAChannel(nChn); if(nnaChn == CHANNELINDEX_INVALID) return CHANNELINDEX_INVALID; ModChannel &chn = m_PlayState.Chn[nnaChn]; StopOldNNA(chn, nnaChn); // Copy Channel chn = srcChn; chn.dwFlags.reset(CHN_VIBRATO | CHN_TREMOLO | CHN_MUTE | CHN_PORTAMENTO); chn.nPanbrelloOffset = 0; chn.nMasterChn = nChn + 1; chn.nCommand = CMD_NONE; chn.rowCommand.Clear(); // Cut the note chn.nFadeOutVol = 0; chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP); chn.nnaChannelAge = 0; chn.nnaGeneration = ++srcChn.nnaGeneration; // Stop this channel srcChn.nLength = 0; srcChn.position.Set(0); srcChn.nROfs = srcChn.nLOfs = 0; srcChn.rightVol = srcChn.leftVol = 0; return nnaChn; } if(instr > GetNumInstruments()) instr = 0; const ModSample *pSample = srcChn.pModSample; // If no instrument is given, assume previous instrument to still be valid. // Test case: DNA-NoInstr.it pIns = instr > 0 ? Instruments[instr] : srcChn.pModInstrument; auto dnaNote = note; if(pIns != nullptr) { auto smp = pIns->Keyboard[note - NOTE_MIN]; // IT compatibility: DCT = note uses pattern notes for comparison // Note: This is not applied in case kITRealNoteMapping is not set to keep playback of legacy modules simple (chn.nNote is translated note in that case) // Test case: dct_smp_note_test.it if(!m_playBehaviour[kITDCTBehaviour] || !m_playBehaviour[kITRealNoteMapping]) dnaNote = pIns->NoteMap[note - NOTE_MIN]; if(smp > 0) { pSample = &Samples[(smp <= GetNumSamples()) ? smp : 0]; } else if(m_playBehaviour[kITEmptyNoteMapSlot] && !pIns->HasValidMIDIChannel()) { // Impulse Tracker ignores empty slots. // We won't ignore them if a plugin is assigned to this slot, so that VSTis still work as intended. // Test case: emptyslot.it, PortaInsNum.it, gxsmp.it, gxsmp2.it return CHANNELINDEX_INVALID; } } if(srcChn.dwFlags[CHN_MUTE]) return CHANNELINDEX_INVALID; for(CHANNELINDEX i = nChn; i < m_PlayState.Chn.size(); i++) { // Only apply to background channels, or the same pattern channel if(i < GetNumChannels() && i != nChn) continue; ModChannel &chn = m_PlayState.Chn[i]; bool applyDNAtoPlug = false; if((chn.nMasterChn == nChn + 1 || i == nChn) && chn.pModInstrument != nullptr) { bool applyDNA = false; // Duplicate Check Type switch(chn.pModInstrument->nDCT) { case DuplicateCheckType::None: break; // Note case DuplicateCheckType::Note: if(dnaNote != NOTE_NONE && chn.nNote == dnaNote && pIns == chn.pModInstrument) applyDNA = true; if(pIns && pIns->nMixPlug) applyDNAtoPlug = true; break; // Sample case DuplicateCheckType::Sample: // IT compatibility: DCT = sample only applies to same instrument // Test case: dct_smp_note_test.it if(pSample != nullptr && pSample == chn.pModSample && (pIns == chn.pModInstrument || !m_playBehaviour[kITDCTBehaviour])) applyDNA = true; break; // Instrument case DuplicateCheckType::Instrument: if(pIns == chn.pModInstrument) applyDNA = true; if(pIns && pIns->nMixPlug) applyDNAtoPlug = true; break; // Plugin case DuplicateCheckType::Plugin: if(pIns && (pIns->nMixPlug) && (pIns->nMixPlug == chn.pModInstrument->nMixPlug)) { applyDNAtoPlug = true; applyDNA = true; } break; } // Duplicate Note Action if(applyDNA) { #ifndef NO_PLUGINS if(applyDNAtoPlug && chn.nNote != NOTE_NONE) { switch(chn.pModInstrument->nDNA) { case DuplicateNoteAction::NoteCut: case DuplicateNoteAction::NoteOff: case DuplicateNoteAction::NoteFade: // Switch off duplicated note played on this plugin if(chn.lastMidiNoteWithoutArp != NOTE_NONE) { SendMIDINote(i, chn.lastMidiNoteWithoutArp | IMixPlugin::MIDI_NOTE_OFF, 0); chn.lastMidiNoteWithoutArp = NOTE_NONE; } break; } } #endif // NO_PLUGINS switch(chn.pModInstrument->nDNA) { // Cut case DuplicateNoteAction::NoteCut: KeyOff(chn); chn.nVolume = 0; if(chn.dwFlags[CHN_ADLIB] && m_opl) m_opl->NoteCut(i); break; // Note Off case DuplicateNoteAction::NoteOff: KeyOff(chn); if(chn.dwFlags[CHN_ADLIB] && m_opl) m_opl->NoteOff(i); break; // Note Fade case DuplicateNoteAction::NoteFade: chn.dwFlags.set(CHN_NOTEFADE); if(chn.dwFlags[CHN_ADLIB] && m_opl && !m_playBehaviour[kOPLwithNNA]) m_opl->NoteOff(i); break; } if(!chn.nVolume) { chn.nFadeOutVol = 0; chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP); } } } } // New Note Action if(!srcChn.IsSamplePlaying() && !applyNNAtoPlug) return CHANNELINDEX_INVALID; const CHANNELINDEX nnaChn = GetNNAChannel(nChn); #ifndef NO_PLUGINS if(applyNNAtoPlug) { switch(srcChn.nNNA) { case NewNoteAction::NoteOff: case NewNoteAction::NoteCut: case NewNoteAction::NoteFade: // Switch off note played on this plugin, on this tracker channel and midi channel SendMIDINote(nChn, NOTE_KEYOFF, 0, m_playBehaviour[kMIDINotesFromChannelPlugin] ? pPlugin : nullptr); srcChn.nArpeggioLastNote = NOTE_NONE; srcChn.lastMidiNoteWithoutArp = NOTE_NONE; break; case NewNoteAction::Continue: // If there's no NNA channels available, avoid the note lingering on forever if(nnaChn == CHANNELINDEX_INVALID) SendMIDINote(nChn, NOTE_KEYOFF, 0, m_playBehaviour[kMIDINotesFromChannelPlugin] ? pPlugin : nullptr); else if(!m_playBehaviour[kLegacyPluginNNABehaviour]) pPlugin->MoveChannel(nChn, nnaChn); break; } } #endif // NO_PLUGINS if(nnaChn == CHANNELINDEX_INVALID) return CHANNELINDEX_INVALID; ModChannel &chn = m_PlayState.Chn[nnaChn]; StopOldNNA(chn, nnaChn); // Copy Channel chn = srcChn; chn.dwFlags.reset(CHN_VIBRATO | CHN_TREMOLO | CHN_PORTAMENTO); chn.nPanbrelloOffset = 0; chn.nMasterChn = nChn < GetNumChannels() ? nChn + 1 : 0; chn.nCommand = CMD_NONE; chn.nnaChannelAge = 0; chn.nnaGeneration = ++srcChn.nnaGeneration; // Key Off the note switch(srcChn.nNNA) { case NewNoteAction::NoteOff: KeyOff(chn); if(chn.dwFlags[CHN_ADLIB] && m_opl) { if(m_playBehaviour[kOPLwithNNA]) { m_opl->MoveChannel(nChn, nnaChn); m_opl->NoteOff(nnaChn); // This needs to be done on the NNA channel so that our PlaybackTest implementation knows that it belongs to the "old" note, not to the "new" note } else { m_opl->NoteOff(nChn); } } break; case NewNoteAction::NoteCut: chn.nFadeOutVol = 0; chn.dwFlags.set(CHN_NOTEFADE); if(chn.dwFlags[CHN_ADLIB] && m_opl) m_opl->NoteCut(nChn); break; case NewNoteAction::NoteFade: chn.dwFlags.set(CHN_NOTEFADE); if(chn.dwFlags[CHN_ADLIB] && m_opl) { if(m_playBehaviour[kOPLwithNNA]) m_opl->MoveChannel(nChn, nnaChn); else m_opl->NoteOff(nChn); } break; case NewNoteAction::Continue: if(chn.dwFlags[CHN_ADLIB] && m_opl) m_opl->MoveChannel(nChn, nnaChn); break; } if(!chn.nVolume) { chn.nFadeOutVol = 0; chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP); } // Stop this channel srcChn.nLength = 0; srcChn.position.Set(0); srcChn.nROfs = srcChn.nLOfs = 0; return nnaChn; } void CSoundFile::StopOldNNA(ModChannel &chn, CHANNELINDEX channel) { if(chn.dwFlags[CHN_ADLIB] && m_opl) m_opl->NoteCut(channel); #ifndef NO_PLUGINS // Is a plugin note still associated with this old NNA channel? Stop it first. if(chn.HasMIDIOutput() && ModCommand::IsNote(chn.nNote) && !chn.dwFlags[CHN_KEYOFF] && chn.lastMidiNoteWithoutArp != NOTE_NONE) { const PLUGINDEX plugin = GetBestPlugin(m_PlayState.Chn[channel], channel, PrioritiseInstrument, RespectMutes); if(plugin > 0 && plugin <= MAX_MIXPLUGINS) { IMixPlugin *nnaPlugin = m_MixPlugins[plugin - 1].pMixPlugin; // apply NNA to this plugin iff it is currently playing a note on this tracker channel // (and if it is playing a note, we know that would be the last note played on this chan). if(nnaPlugin && (chn.lastMidiNoteWithoutArp != NOTE_NONE) && nnaPlugin->IsNotePlaying(chn.lastMidiNoteWithoutArp, channel)) { SendMIDINote(channel, chn.lastMidiNoteWithoutArp | IMixPlugin::MIDI_NOTE_OFF, 0, m_playBehaviour[kMIDINotesFromChannelPlugin] ? nnaPlugin : nullptr); } } } #endif // NO_PLUGINS } bool CSoundFile::ProcessEffects() { m_PlayState.m_breakRow = ROWINDEX_INVALID; // Is changed if a break to row command is encountered m_PlayState.m_patLoopRow = ROWINDEX_INVALID; // Is changed if a pattern loop jump-back is executed m_PlayState.m_posJump = ORDERINDEX_INVALID; for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++) { ModChannel &chn = m_PlayState.Chn[nChn]; const uint32 tickCount = m_PlayState.m_nTickCount % (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay); uint32 instr = chn.rowCommand.instr; ModCommand::VOLCMD volcmd = chn.rowCommand.volcmd; ModCommand::VOL vol = chn.rowCommand.vol; ModCommand::COMMAND cmd = chn.rowCommand.command; uint32 param = chn.rowCommand.param; bool bPorta = chn.rowCommand.IsTonePortamento(); uint32 nStartTick = 0; chn.isFirstTick = m_PlayState.m_flags[SONG_FIRSTTICK]; // Process parameter control note. if(chn.rowCommand.note == NOTE_PC) { #ifndef NO_PLUGINS const PLUGINDEX plug = chn.rowCommand.instr; const PlugParamIndex plugparam = chn.rowCommand.GetValueVolCol(); const PlugParamValue value = chn.rowCommand.GetValueEffectCol() / PlugParamValue(ModCommand::maxColumnValue); if(plug > 0 && plug <= MAX_MIXPLUGINS && m_MixPlugins[plug - 1].pMixPlugin) m_MixPlugins[plug-1].pMixPlugin->SetParameter(plugparam, value, &m_PlayState, nChn); #endif // NO_PLUGINS } // Process continuous parameter control note. // Row data is cleared after first tick so on following // ticks using channels m_nPlugParamValueStep to identify // the need for parameter control. The condition cmd == 0 // is to make sure that m_nPlugParamValueStep != 0 because // of NOTE_PCS, not because of macro. if(chn.rowCommand.note == NOTE_PCS || (cmd == CMD_NONE && chn.m_plugParamValueStep != 0)) { #ifndef NO_PLUGINS const bool isFirstTick = m_PlayState.m_flags[SONG_FIRSTTICK]; if(isFirstTick) chn.m_RowPlug = chn.rowCommand.instr; const PLUGINDEX plugin = chn.m_RowPlug; const bool hasValidPlug = (plugin > 0 && plugin <= MAX_MIXPLUGINS && m_MixPlugins[plugin - 1].pMixPlugin); if(hasValidPlug) { if(isFirstTick) chn.m_RowPlugParam = ModCommand::GetValueVolCol(chn.rowCommand.volcmd, chn.rowCommand.vol); const PlugParamIndex plugparam = chn.m_RowPlugParam; if(isFirstTick) { PlugParamValue targetvalue = ModCommand::GetValueEffectCol(chn.rowCommand.command, chn.rowCommand.param) / PlugParamValue(ModCommand::maxColumnValue); chn.m_plugParamTargetValue = targetvalue; chn.m_plugParamValueStep = (targetvalue - m_MixPlugins[plugin - 1].pMixPlugin->GetParameter(plugparam)) / PlugParamValue(m_PlayState.TicksOnRow()); } if(m_PlayState.m_nTickCount + 1 == m_PlayState.TicksOnRow()) { // On last tick, set parameter exactly to target value. m_MixPlugins[plugin - 1].pMixPlugin->SetParameter(plugparam, chn.m_plugParamTargetValue, &m_PlayState, nChn); } else m_MixPlugins[plugin - 1].pMixPlugin->ModifyParameter(plugparam, chn.m_plugParamValueStep, m_PlayState, nChn); } #endif // NO_PLUGINS } // Apart from changing parameters, parameter control notes are intended to be 'invisible'. // To achieve this, clearing the note data so that rest of the process sees the row as empty row. if(ModCommand::IsPcNote(chn.rowCommand.note)) { chn.rowCommand.Clear(); instr = 0; volcmd = VOLCMD_NONE; vol = 0; cmd = CMD_NONE; param = 0; bPorta = false; } // IT compatibility: Empty sample mapping // This is probably the single biggest WTF replayer bug in Impulse Tracker. // In instrument mode, when an note + instrument is triggered that does not map to any sample, the entire cell (including potentially present global effects!) // is ignored. Even better, if on a following row another instrument number (this time without a note) is encountered, we end up in the same situation! // Test cases: NoMap.it, NoMapEffects.it if(m_playBehaviour[kITEmptyNoteMapSlotIgnoreCell] && instr > 0 && instr <= GetNumInstruments() && Instruments[instr] != nullptr && !Instruments[instr]->HasValidMIDIChannel()) { auto note = (chn.rowCommand.note != NOTE_NONE) ? chn.rowCommand.note : chn.nNewNote; if(ModCommand::IsNote(note) && Instruments[instr]->Keyboard[note - NOTE_MIN] == 0) { chn.nNewNote = chn.nLastNote = note; chn.nNewIns = static_cast(instr); chn.rowCommand.Clear(); continue; } } const bool continueNote = !bPorta && m_playBehaviour[kContinueSampleWithoutInstr] && !chn.rowCommand.instr && chn.dwFlags[CHN_LOOP] && chn.pCurrentSample; if(continueNote) bPorta = true; // Process Invert Loop (MOD Effect, called every row if it's active) if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { InvertLoop(m_PlayState.Chn[nChn]); } else { if(instr) m_PlayState.Chn[nChn].nEFxOffset = 0; } // Process special effects (note delay, pattern delay, pattern loop) if (cmd == CMD_DELAYCUT) { //:xy --> note delay until tick x, note cut at tick x+y nStartTick = (param & 0xF0) >> 4; const uint32 cutAtTick = nStartTick + (param & 0x0F); NoteCut(nChn, cutAtTick, m_playBehaviour[kITSCxStopsSample]); } else if ((cmd == CMD_MODCMDEX) || (cmd == CMD_S3MCMDEX)) { if ((!param) && (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT))) param = chn.nOldCmdEx; else chn.nOldCmdEx = static_cast(param); // Note Delay ? if ((param & 0xF0) == 0xD0) { nStartTick = param & 0x0F; if(nStartTick == 0) { //IT compatibility 22. SD0 == SD1 if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) nStartTick = 1; //ST3 ignores notes with SD0 completely else if(GetType() == MOD_TYPE_S3M) continue; } else if(nStartTick >= (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay) && m_playBehaviour[kITOutOfRangeDelay]) { // IT compatibility 08. Handling of out-of-range delay command. // Additional test case: tickdelay.it if(instr) { chn.nNewIns = static_cast(instr); } continue; } } else if(m_PlayState.m_flags[SONG_FIRSTTICK]) { // Pattern Loop ? if((param & 0xF0) == 0xE0) { // Pattern Delay // In Scream Tracker 3 / Impulse Tracker, only the first delay command on this row is considered. // Test cases: PatternDelays.it, PatternDelays.s3m, PatternDelays.xm // XXX In Scream Tracker 3, the "left" channels are evaluated before the "right" channels, which is not emulated here! if(!(GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)) || !m_PlayState.m_nPatternDelay) { if(!(GetType() & (MOD_TYPE_S3M)) || (param & 0x0F) != 0) { // While Impulse Tracker *does* count S60 as a valid row delay (and thus ignores any other row delay commands on the right), // Scream Tracker 3 simply ignores such commands. m_PlayState.m_nPatternDelay = 1 + (param & 0x0F); } } } } } if(GetType() == MOD_TYPE_MTM && cmd == CMD_MODCMDEX && (param & 0xF0) == 0xD0) { // Apparently, retrigger and note delay have the same behaviour in MultiTracker: // They both restart the note at tick x, and if there is a note on the same row, // this note is started on the first tick. nStartTick = 0; param = 0x90 | (param & 0x0F); } if(nStartTick != 0 && chn.rowCommand.note == NOTE_KEYOFF && chn.rowCommand.volcmd == VOLCMD_PANNING && m_playBehaviour[kFT2PanWithDelayedNoteOff]) { // FT2 compatibility: If there's a delayed note off, panning commands are ignored. WTF! // Test case: PanOff.xm chn.rowCommand.volcmd = VOLCMD_NONE; } bool triggerNote = (m_PlayState.m_nTickCount == nStartTick); // Can be delayed by a note delay effect if(m_playBehaviour[kFT2OutOfRangeDelay] && nStartTick >= m_PlayState.m_nMusicSpeed) { // FT2 compatibility: Note delays greater than the song speed should be ignored. // However, EEx pattern delay is *not* considered at all. // Test case: DelayCombination.xm, PortaDelay.xm triggerNote = false; } else if(m_playBehaviour[kRowDelayWithNoteDelay] && nStartTick > 0 && tickCount == nStartTick) { // IT compatibility: Delayed notes (using SDx) that are on the same row as a Row Delay effect are retriggered. // ProTracker / Scream Tracker 3 / FastTracker 2 do the same. // Test case: PatternDelay-NoteDelay.it, PatternDelay-NoteDelay.xm, PatternDelaysRetrig.mod triggerNote = true; } // IT compatibility: Tick-0 vs non-tick-0 effect distinction is always based on tick delay. // Test case: SlideDelay.it if(m_playBehaviour[kITFirstTickHandling]) { chn.isFirstTick = tickCount == nStartTick; } chn.triggerNote = false; // FT2 compatibility: Note + portamento + note delay = no portamento // Test case: PortaDelay.xm if(m_playBehaviour[kFT2PortaDelay] && nStartTick != 0) { bPorta = false; } if(m_SongFlags[SONG_PT_MODE] && instr && !m_PlayState.m_nTickCount) { // Instrument number resets the stacked ProTracker offset. // Test case: ptoffset.mod chn.prevNoteOffset = 0; // ProTracker compatibility: Sample properties are always loaded on the first tick, even when there is a note delay. // Test case: InstrDelay.mod if(!triggerNote && chn.IsSamplePlaying()) { chn.nNewIns = static_cast(instr); chn.swapSampleIndex = GetSampleIndex(chn.nLastNote, instr); if(instr <= GetNumSamples()) { chn.nVolume = Samples[instr].nVolume; chn.nFineTune = Samples[instr].nFineTune; } } } // Handles note/instrument/volume changes if(triggerNote) { ModCommand::NOTE note = chn.rowCommand.note; if(instr) { chn.nNewIns = static_cast(instr); chn.swapSampleIndex = GetSampleIndex(ModCommand::IsNote(note) ? note : chn.nLastNote, instr); } if(ModCommand::IsNote(note) && m_playBehaviour[kFT2Transpose]) { // Notes that exceed FT2's limit are completely ignored. // Test case: NoteLimit.xm int transpose = chn.nTranspose; if(instr && !bPorta) { // Refresh transpose // Test case: NoteLimit2.xm const SAMPLEINDEX sample = GetSampleIndex(note, instr); if(sample > 0) transpose = GetSample(sample).RelativeTone; } const int computedNote = note + transpose; if((computedNote < NOTE_MIN + 11 || computedNote > NOTE_MIN + 130)) { note = NOTE_NONE; } } else if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_J2B)) && GetNumInstruments() != 0 && ModCommand::IsNoteOrEmpty(static_cast(note))) { // IT compatibility: Invalid instrument numbers do nothing, but they are remembered for upcoming notes and do not trigger a note in that case. // Test case: InstrumentNumberChange.it INSTRUMENTINDEX instrToCheck = static_cast((instr != 0) ? instr : chn.nOldIns); if(instrToCheck != 0 && (instrToCheck > GetNumInstruments() || Instruments[instrToCheck] == nullptr)) { note = NOTE_NONE; instr = 0; } } // XM: FT2 ignores a note next to a K00 effect, and a fade-out seems to be done when no volume envelope is present (not exactly the Kxx behaviour) if(cmd == CMD_KEYOFF && param == 0 && m_playBehaviour[kFT2KeyOff]) { note = NOTE_NONE; instr = 0; } bool retrigEnv = note == NOTE_NONE && instr != 0; // Apparently, any note number in a pattern causes instruments to recall their original volume settings - no matter if there's a Note Off next to it or whatever. // Test cases: keyoff+instr.xm, delay.xm bool reloadSampleSettings = (m_playBehaviour[kFT2ReloadSampleSettings] && instr != 0); bool keepInstr = (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) || m_playBehaviour[kST3SampleSwap]; if(m_playBehaviour[kMODSampleSwap]) { // ProTracker Compatibility: If a sample was stopped before, lone instrument numbers can retrigger it // Test cases: PTSwapEmpty.mod, PTInstrVolume.mod, PTStoppedSwap.mod if(!chn.IsSamplePlaying() && instr <= GetNumSamples() && Samples[instr].uFlags[CHN_LOOP]) keepInstr = true; } // Now it's time for some FT2 crap... if (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)) { // XM: Key-Off + Sample == Note Cut (BUT: Only if no instr number or volume effect is present!) // Test case: NoteOffVolume.xm if(note == NOTE_KEYOFF && ((!instr && volcmd != VOLCMD_VOLUME && cmd != CMD_VOLUME) || !m_playBehaviour[kFT2KeyOff]) && (chn.pModInstrument == nullptr || !chn.pModInstrument->VolEnv.dwFlags[ENV_ENABLED])) { chn.dwFlags.set(CHN_FASTVOLRAMP); chn.nVolume = 0; note = NOTE_NONE; instr = 0; retrigEnv = false; // FT2 Compatibility: Start fading the note for notes with no delay. Only relevant when a volume command is encountered after the note-off. // Test case: NoteOffFadeNoEnv.xm if(m_PlayState.m_flags[SONG_FIRSTTICK] && m_playBehaviour[kFT2NoteOffFlags]) chn.dwFlags.set(CHN_NOTEFADE); } else if(m_playBehaviour[kFT2RetrigWithNoteDelay] && !m_PlayState.m_flags[SONG_FIRSTTICK]) { // FT2 Compatibility: Some special hacks for rogue note delays... (EDx with x > 0) // Apparently anything that is next to a note delay behaves totally unpredictable in FT2. Swedish tracker logic. :) retrigEnv = true; // Portamento + Note Delay = No Portamento // Test case: porta-delay.xm bPorta = false; if(note == NOTE_NONE) { // If there's a note delay but no real note, retrig the last note. // Test case: delay2.xm, delay3.xm note = static_cast(chn.nNote - chn.nTranspose); } else if(note >= NOTE_MIN_SPECIAL) { // Gah! Even Note Off + Note Delay will cause envelopes to *retrigger*! How stupid is that? // ... Well, and that is actually all it does if there's an envelope. No fade out, no nothing. *sigh* // Test case: OffDelay.xm note = NOTE_NONE; keepInstr = false; reloadSampleSettings = true; } else if(instr || !m_playBehaviour[kFT2NoteDelayWithoutInstr]) { // Normal note (only if there is an instrument, test case: DelayVolume.xm) keepInstr = true; reloadSampleSettings = true; } } } if((retrigEnv && !m_playBehaviour[kFT2ReloadSampleSettings]) || reloadSampleSettings) { const ModSample *oldSample = nullptr; // Reset default volume when retriggering envelopes if(GetNumInstruments()) { oldSample = chn.pModSample; } else if (instr <= GetNumSamples()) { // Case: Only samples are used; no instruments. oldSample = &Samples[instr]; } if(oldSample != nullptr) { if(!oldSample->uFlags[SMP_NODEFAULTVOLUME] && (GetType() != MOD_TYPE_S3M || oldSample->HasSampleData())) { chn.nVolume = oldSample->nVolume; chn.dwFlags.set(CHN_FASTVOLRAMP); } if(reloadSampleSettings) { // Also reload panning chn.SetInstrumentPan(oldSample->nPan, *this); } } } // FT2 compatibility: Instrument number disables tremor effect // Test case: TremorInstr.xm, TremoRecover.xm if(m_playBehaviour[kFT2Tremor] && instr != 0) { chn.nTremorCount = 0x20; } // IT compatibility: Envelope retriggering with instrument number based on Old Effects and Compatible Gxx flags: // OldFX CompatGxx Env Behaviour // ----- --------- ------------- // off off never reset // on off reset on instrument without portamento // off on reset on instrument with portamento // on on always reset // Test case: ins-xx.it, ins-ox.it, ins-oc.it, ins-xc.it, ResetEnvNoteOffOldFx.it, ResetEnvNoteOffOldFx2.it, noteoff3.it if(GetNumInstruments() && m_playBehaviour[kITInstrWithNoteOffOldEffects] && instr && !ModCommand::IsNote(note)) { if((bPorta && m_SongFlags[SONG_ITCOMPATGXX]) || (!bPorta && m_SongFlags[SONG_ITOLDEFFECTS])) { chn.ResetEnvelopes(); chn.dwFlags.set(CHN_FASTVOLRAMP); chn.nFadeOutVol = 65536; } } if(retrigEnv) //Case: instrument with no note data. { //IT compatibility: Instrument with no note. if(m_playBehaviour[kITInstrWithoutNote] || GetType() == MOD_TYPE_PLM) { // IT compatibility: Completely retrigger note after sample end to also reset portamento. // Test case: PortaResetAfterRetrigger.it bool triggerAfterSmpEnd = m_playBehaviour[kITMultiSampleInstrumentNumber] && !chn.IsSamplePlaying(); if(GetNumInstruments()) { // Instrument mode if(instr <= GetNumInstruments() && (chn.pModInstrument != Instruments[instr] || triggerAfterSmpEnd)) note = chn.nNote; } else { // Sample mode if(instr < MAX_SAMPLES && (chn.pModSample != &Samples[instr] || triggerAfterSmpEnd)) note = chn.nNote; } } if(GetNumInstruments() && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED))) { chn.ResetEnvelopes(); chn.dwFlags.set(CHN_FASTVOLRAMP); chn.dwFlags.reset(CHN_NOTEFADE); chn.nAutoVibDepth = 0; chn.nAutoVibPos = 0; chn.nFadeOutVol = 65536; // FT2 Compatibility: Reset key-off status with instrument number // Test case: NoteOffInstrChange.xm if(m_playBehaviour[kFT2NoteOffFlags]) chn.dwFlags.reset(CHN_KEYOFF); } if (!keepInstr) instr = 0; } // Note Cut/Off/Fade => ignore instrument if (note >= NOTE_MIN_SPECIAL) { // IT compatibility: Default volume of sample is recalled if instrument number is next to a note-off. // Test case: NoteOffInstr.it, noteoff2.it if(m_playBehaviour[kITInstrWithNoteOff] && instr) { const SAMPLEINDEX smp = GetSampleIndex(chn.nLastNote, instr); if(smp > 0 && !Samples[smp].uFlags[SMP_NODEFAULTVOLUME]) chn.nVolume = Samples[smp].nVolume; } // IT compatibility: Note-off with instrument number + Old Effects retriggers envelopes. // Test case: ResetEnvNoteOffOldFx.it if(!m_playBehaviour[kITInstrWithNoteOffOldEffects] || !m_SongFlags[SONG_ITOLDEFFECTS]) instr = 0; } const auto previousNewNote = chn.nNewNote; if(ModCommand::IsNote(note)) { chn.nNewNote = chn.nLastNote = note; // New Note Action ? if(!bPorta) { CheckNNA(nChn, instr, note, false); } chn.RestorePanAndFilter(); } // Instrument Change ? if(instr) { const ModSample *oldSample = chn.pModSample; //const ModInstrument *oldInstrument = chn.pModInstrument; InstrumentChange(chn, instr, bPorta, true); if(!chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE] && chn.pModSample != nullptr && chn.pModSample->uFlags[CHN_ADLIB] && m_opl) { m_opl->Patch(nChn, chn.pModSample->adlib); } // IT compatibility: Keep new instrument number for next instrument-less note even if sample playback is stopped // Test case: StoppedInstrSwap.it if(GetType() == MOD_TYPE_MOD) { // Test case: PortaSwapPT.mod if(!bPorta || !m_playBehaviour[kMODSampleSwap]) chn.nNewIns = 0; } else { if(!m_playBehaviour[kITInstrWithNoteOff] || ModCommand::IsNote(note)) chn.nNewIns = 0; } // When swapping samples without explicit note change (e.g. during portamento), avoid clicks at end of sample (as there won't be an NNA channel to fade the sample out) if(oldSample != nullptr && oldSample != chn.pModSample) { m_dryLOfsVol += chn.nLOfs; m_dryROfsVol += chn.nROfs; chn.nLOfs = 0; chn.nROfs = 0; } if(m_playBehaviour[kITPortamentoSwapResetsPos]) { // Test cases: PortaInsNum.it, PortaSample.it if(ModCommand::IsNote(note) && oldSample != chn.pModSample) { //const bool newInstrument = oldInstrument != chn.pModInstrument && chn.pModInstrument->Keyboard[chn.nNewNote - NOTE_MIN] != 0; chn.position.Set(0); } } else if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && oldSample != chn.pModSample && ModCommand::IsNote(note)) { // Special IT case: portamento+note causes sample change -> ignore portamento bPorta = false; } else if(m_playBehaviour[kST3SampleSwap] && oldSample != chn.pModSample && (bPorta || !ModCommand::IsNote(note)) && chn.position.GetUInt() > chn.nLength) { // ST3 with SoundBlaster does sample swapping and continues playing the new sample where the old sample was stopped. // If the new sample is shorter than that, it is stopped, even if it could be looped. // This also applies to portamento between different samples. // Test case: SampleSwap.s3m chn.nLength = 0; } else if(m_playBehaviour[kMODSampleSwap] && !chn.IsSamplePlaying()) { // If channel was paused and is resurrected by a lone instrument number, reset the sample position. // Test case: PTSwapEmpty.mod chn.position.Set(0); } } // New Note ? if (note != NOTE_NONE) { const bool instrChange = (!instr) && (chn.nNewIns) && ModCommand::IsNote(note); if(instrChange) { // If we change to a new instrument, we need to do so based on whatever previous note would have played // - so that we trigger the correct sample in a multisampled instrument (based on the previous note, not the new note). // Test case: InitialNoteMemoryInstrMode.it if(m_playBehaviour[kITEmptyNoteMapSlotIgnoreCell] && ModCommand::IsNote(previousNewNote)) chn.nNewNote = previousNewNote; InstrumentChange(chn, chn.nNewIns, bPorta, chn.pModSample == nullptr && chn.pModInstrument == nullptr, !(GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))); chn.nNewNote = note; chn.swapSampleIndex = chn.nNewIns = 0; } if(!chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE] && chn.pModSample != nullptr && chn.pModSample->uFlags[CHN_ADLIB] && m_opl && (instrChange || !m_opl->IsActive(nChn))) { m_opl->Patch(nChn, chn.pModSample->adlib); } NoteChange(chn, note, bPorta, !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)), false, nChn); if(continueNote) chn.nPeriod = chn.nPortamentoDest; if(ModCommand::IsNote(note)) HandleDigiSamplePlayDirection(m_PlayState, nChn); if ((bPorta) && (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2)) && (instr)) { chn.dwFlags.set(CHN_FASTVOLRAMP); chn.ResetEnvelopes(); chn.nAutoVibDepth = 0; chn.nAutoVibPos = 0; } if(chn.dwFlags[CHN_ADLIB] && m_opl && ((note == NOTE_NOTECUT || note == NOTE_KEYOFF) || (note == NOTE_FADE && !m_playBehaviour[kOPLFlexibleNoteOff]))) { if(m_playBehaviour[kOPLNoteStopWith0Hz]) m_opl->Frequency(nChn, 0, true, false); m_opl->NoteOff(nChn); } } // Tick-0 only volume commands if (volcmd == VOLCMD_VOLUME) { if (vol > 64) vol = 64; chn.nVolume = vol << 2; chn.dwFlags.set(CHN_FASTVOLRAMP); } else if (volcmd == VOLCMD_PANNING) { Panning(chn, vol, Pan6bit); } #ifndef NO_PLUGINS if (m_nInstruments) ProcessMidiOut(nChn); #endif // NO_PLUGINS } if(m_playBehaviour[kST3NoMutedChannels] && ChnSettings[nChn].dwFlags[CHN_MUTE]) // not even effects are processed on muted S3M channels continue; if(!m_PlayState.m_nTickCount) ResetAutoSlides(chn); // Volume Column Effect (except volume & panning) /* A few notes, paraphrased from ITTECH.TXT by Storlek (creator of schismtracker): Ex/Fx/Gx are shared with Exx/Fxx/Gxx; Ex/Fx are 4x the 'normal' slide value Gx is linked with Ex/Fx if Compat Gxx is off, just like Gxx is with Exx/Fxx Gx values: 1, 4, 8, 16, 32, 64, 96, 128, 255 Ax/Bx/Cx/Dx values are used directly (i.e. D9 == D09), and are NOT shared with Dxx (value is stored into nOldVolParam and used by A0/B0/C0/D0) Hx uses the same value as Hxx and Uxx, and affects the *depth* so... hxx = (hx | (oldhxx & 0xf0)) ??? TODO is this done correctly? */ bool doVolumeColumn = m_PlayState.m_nTickCount >= nStartTick; // FT2 compatibility: If there's a note delay, volume column effects are NOT executed // on the first tick and, if there's an instrument number, on the delayed tick. // Test case: VolColDelay.xm, PortaDelay.xm if(m_playBehaviour[kFT2VolColDelay] && nStartTick != 0) { doVolumeColumn = m_PlayState.m_nTickCount != 0 && (m_PlayState.m_nTickCount != nStartTick || (chn.rowCommand.instr == 0 && volcmd != VOLCMD_TONEPORTAMENTO)); } // IT compatibility: Various mind-boggling behaviours when combining volume colum and effect column portamentos // The most crucial thing here is to initialize effect memory in the exact right order. // Test cases: DoubleSlide.it, DoubleSlideCompatGxx.it if(m_playBehaviour[kITDoublePortamentoSlides] && chn.isFirstTick) { const bool effectColumnTonePorta = (cmd == CMD_TONEPORTAMENTO || cmd == CMD_TONEPORTAVOL); if(effectColumnTonePorta) InitTonePortamento(chn, static_cast(cmd == CMD_TONEPORTAVOL ? 0 : param)); if(volcmd == VOLCMD_TONEPORTAMENTO) InitTonePortamento(chn, GetVolCmdTonePorta(chn.rowCommand, nStartTick).first); if(vol && (volcmd == VOLCMD_PORTAUP || volcmd == VOLCMD_PORTADOWN)) { chn.nOldPortaUp = chn.nOldPortaDown = vol << 2; if(!effectColumnTonePorta && TonePortamentoSharesEffectMemory()) chn.portamentoSlide = vol << 2; } if(param && (cmd == CMD_PORTAMENTOUP || cmd == CMD_PORTAMENTODOWN)) { chn.nOldPortaUp = chn.nOldPortaDown = static_cast(param); if(TonePortamentoSharesEffectMemory()) chn.portamentoSlide = static_cast(param); } } if(volcmd > VOLCMD_PANNING && doVolumeColumn) { if(volcmd == VOLCMD_TONEPORTAMENTO) { const auto [porta, clearEffectCommand] = GetVolCmdTonePorta(chn.rowCommand, nStartTick); if(clearEffectCommand) cmd = CMD_NONE; TonePortamento(nChn, porta); } else { // FT2 Compatibility: FT2 ignores some volume commands with parameter = 0. if(m_playBehaviour[kFT2VolColMemory] && vol == 0) { switch(volcmd) { case VOLCMD_VOLUME: case VOLCMD_PANNING: case VOLCMD_VIBRATODEPTH: break; case VOLCMD_PANSLIDELEFT: // FT2 Compatibility: Pan slide left with zero parameter causes panning to be set to full left on every non-row tick. // Test case: PanSlideZero.xm if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { chn.nPan = 0; } [[fallthrough]]; default: // no memory here. volcmd = VOLCMD_NONE; } } else if(!m_playBehaviour[kITVolColMemory] && volcmd != VOLCMD_PLAYCONTROL) { // IT Compatibility: Effects in the volume column don't have an unified memory. // Test case: VolColMemory.it if(vol) chn.nOldVolParam = vol; else vol = chn.nOldVolParam; } switch(volcmd) { case VOLCMD_VOLSLIDEUP: case VOLCMD_VOLSLIDEDOWN: // IT Compatibility: Volume column volume slides have their own memory // Test case: VolColMemory.it if(vol == 0 && m_playBehaviour[kITVolColMemory]) { vol = chn.nOldVolParam; if(vol == 0) break; } else { chn.nOldVolParam = vol; } VolumeSlide(chn, static_cast(volcmd == VOLCMD_VOLSLIDEUP ? (vol << 4) : vol)); break; case VOLCMD_FINEVOLUP: // IT Compatibility: Fine volume slides in the volume column are only executed on the first tick, not on multiples of the first tick in case of pattern delay // Test case: FineVolColSlide.it if(m_PlayState.m_nTickCount == nStartTick || !m_playBehaviour[kITVolColMemory]) { // IT Compatibility: Volume column volume slides have their own memory // Test case: VolColMemory.it FineVolumeUp(chn, vol, m_playBehaviour[kITVolColMemory]); } break; case VOLCMD_FINEVOLDOWN: // IT Compatibility: Fine volume slides in the volume column are only executed on the first tick, not on multiples of the first tick in case of pattern delay // Test case: FineVolColSlide.it if(m_PlayState.m_nTickCount == nStartTick || !m_playBehaviour[kITVolColMemory]) { // IT Compatibility: Volume column volume slides have their own memory // Test case: VolColMemory.it FineVolumeDown(chn, vol, m_playBehaviour[kITVolColMemory]); } break; case VOLCMD_VIBRATOSPEED: // FT2 does not automatically enable vibrato with the "set vibrato speed" command if(m_playBehaviour[kFT2VolColVibrato]) chn.nVibratoSpeed = vol & 0x0F; else Vibrato(chn, vol << 4); break; case VOLCMD_VIBRATODEPTH: Vibrato(chn, vol); break; case VOLCMD_PANSLIDELEFT: PanningSlide(chn, vol, !m_playBehaviour[kFT2VolColMemory]); break; case VOLCMD_PANSLIDERIGHT: PanningSlide(chn, static_cast(vol << 4), !m_playBehaviour[kFT2VolColMemory]); break; case VOLCMD_PORTAUP: // IT compatibility (one of the first testcases - link effect memory) PortamentoUp(nChn, static_cast(vol << 2), m_playBehaviour[kITVolColFinePortamento]); break; case VOLCMD_PORTADOWN: // IT compatibility (one of the first testcases - link effect memory) PortamentoDown(nChn, static_cast(vol << 2), m_playBehaviour[kITVolColFinePortamento]); break; case VOLCMD_OFFSET: if(triggerNote && chn.pModSample && !chn.pModSample->uFlags[CHN_ADLIB] && vol <= std::size(chn.pModSample->cues)) { SmpLength offset; if(vol == 0) offset = chn.oldOffset; else offset = chn.oldOffset = chn.pModSample->cues[vol - 1]; SampleOffset(chn, offset); } break; case VOLCMD_PLAYCONTROL: if(chn.isFirstTick) chn.PlayControl(vol); break; default: break; } } } // Effects if(cmd != CMD_NONE) switch (cmd) { // Set Volume case CMD_VOLUME: if(m_PlayState.m_flags[SONG_FIRSTTICK]) { chn.nVolume = (param < 64) ? param * 4 : 256; chn.dwFlags.set(CHN_FASTVOLRAMP); } break; case CMD_VOLUME8: if(m_PlayState.m_flags[SONG_FIRSTTICK]) { chn.nVolume = param; chn.dwFlags.set(CHN_FASTVOLRAMP); } break; // Portamento Up case CMD_PORTAMENTOUP: if(param || !(GetType() & MOD_TYPE_MOD)) PortamentoUp(nChn, static_cast(param), false); break; // Portamento Down case CMD_PORTAMENTODOWN: if(param || !(GetType() & MOD_TYPE_MOD)) PortamentoDown(nChn, static_cast(param), false); break; // Auto portamentos case CMD_AUTO_PORTAUP: chn.autoSlide.SetActive(AutoSlideCommand::PortamentoUp, param != 0); chn.nOldPortaUp = static_cast(param); break; case CMD_AUTO_PORTADOWN: chn.autoSlide.SetActive(AutoSlideCommand::PortamentoDown, param != 0); chn.nOldPortaDown = static_cast(param); break; case CMD_AUTO_PORTAUP_FINE: chn.autoSlide.SetActive(AutoSlideCommand::FinePortamentoUp, param != 0); chn.nOldFinePortaUpDown = static_cast(param); break; case CMD_AUTO_PORTADOWN_FINE: chn.autoSlide.SetActive(AutoSlideCommand::FinePortamentoDown, param != 0); chn.nOldFinePortaUpDown = static_cast(param); break; case CMD_AUTO_PORTAMENTO_FC: chn.autoSlide.SetActive(AutoSlideCommand::PortamentoFC, param != 0); chn.nOldPortaUp = chn.nOldPortaDown = static_cast(param); break; // Volume Slide case CMD_VOLUMESLIDE: if (param || (GetType() != MOD_TYPE_MOD)) VolumeSlide(chn, static_cast(param)); break; // Tone-Portamento case CMD_TONEPORTAMENTO: TonePortamento(nChn, static_cast(param)); break; // Tone-Portamento + Volume Slide case CMD_TONEPORTAVOL: if(param || GetType() != MOD_TYPE_MOD) { // ST3 compatibility: Do not run combined slides (Kxy / Lxy) on first tick // Test cases: NoCombinedSlidesOnFirstTick-Normal.s3m, NoCombinedSlidesOnFirstTick-Fast.s3m if(!chn.isFirstTick || !m_playBehaviour[kS3MIgnoreCombinedFineSlides]) VolumeSlide(chn, static_cast(param)); } TonePortamento(nChn, 0); break; // Vibrato case CMD_VIBRATO: Vibrato(chn, param); break; // Vibrato + Volume Slide case CMD_VIBRATOVOL: if(param || GetType() != MOD_TYPE_MOD) { // ST3 compatibility: Do not run combined slides (Kxy / Lxy) on first tick // Test cases: NoCombinedSlidesOnFirstTick-Normal.s3m, NoCombinedSlidesOnFirstTick-Fast.s3m if(!chn.isFirstTick || !m_playBehaviour[kS3MIgnoreCombinedFineSlides]) VolumeSlide(chn, static_cast(param)); } Vibrato(chn, 0); break; // Set Speed case CMD_SPEED: if(m_PlayState.m_flags[SONG_FIRSTTICK]) SetSpeed(m_PlayState, param); break; // Set Tempo case CMD_TEMPO: if(m_playBehaviour[kMODVBlankTiming]) { // ProTracker MODs with VBlank timing: All Fxx parameters set the tick count. if(m_PlayState.m_flags[SONG_FIRSTTICK] && param != 0) SetSpeed(m_PlayState, param); } else { param = CalculateXParam(m_PlayState.m_nPattern, m_PlayState.m_nRow, nChn); if (GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)) { if (param) chn.nOldTempo = static_cast(param); else param = chn.nOldTempo; } SetTempo(m_PlayState, TEMPO(param, 0)); } break; // Set Offset case CMD_OFFSET: if(triggerNote) { // FT2 compatibility: Portamento + Offset = Ignore offset // Test case: porta-offset.xm if(bPorta && (GetType() & (MOD_TYPE_XM | MOD_TYPE_DBM))) break; ProcessSampleOffset(chn, nChn, m_PlayState); } break; // Disorder Tracker 2 percentage offset case CMD_OFFSETPERCENTAGE: if(triggerNote) { SampleOffset(chn, Util::muldiv_unsigned(chn.nLength, param, 256)); } break; // Arpeggio case CMD_ARPEGGIO: // IT compatibility 01. Don't ignore Arpeggio if no note is playing (also valid for ST3) if(m_PlayState.m_nTickCount) break; if((!chn.nPeriod || !chn.nNote) && (chn.pModInstrument == nullptr || !chn.pModInstrument->HasValidMIDIChannel()) // Plugin arpeggio && !m_playBehaviour[kITArpeggio] && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) break; if (!param && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD))) break; // Only important when editing MOD/XM files (000 effects are removed when loading files where this means "no effect") chn.nCommand = CMD_ARPEGGIO; if (param) chn.nArpeggio = static_cast(param); break; // Retrig case CMD_RETRIG: if (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2)) { if (!(param & 0xF0)) param |= chn.nRetrigParam & 0xF0; if (!(param & 0x0F)) param |= chn.nRetrigParam & 0x0F; param |= 0x100; // increment retrig count on first row } // IT compatibility 15. Retrigger if(m_playBehaviour[kITRetrigger]) { if (param) chn.nRetrigParam = static_cast(param & 0xFF); RetrigNote(nChn, chn.nRetrigParam, (volcmd == VOLCMD_OFFSET) ? vol + 1 : 0); } else { // XM Retrig if (param) chn.nRetrigParam = static_cast(param & 0xFF); else param = chn.nRetrigParam; RetrigNote(nChn, param, (volcmd == VOLCMD_OFFSET) ? vol + 1 : 0); } break; // Tremor case CMD_TREMOR: if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { break; } // IT compatibility 12. / 13. Tremor (using modified DUMB's Tremor logic here because of old effects - http://dumb.sf.net/) if(m_playBehaviour[kITTremor]) { if(param && !m_SongFlags[SONG_ITOLDEFFECTS]) { // Old effects have different length interpretation (+1 for both on and off) if(param & 0xF0) param -= 0x10; if(param & 0x0F) param -= 0x01; chn.nTremorParam = static_cast(param); } chn.nTremorCount |= 0x80; // set on/off flag } else if(m_playBehaviour[kFT2Tremor]) { // XM Tremor. Logic is being processed in sndmix.cpp chn.nTremorCount |= 0x80; // set on/off flag } chn.nCommand = CMD_TREMOR; if(param) chn.nTremorParam = static_cast(param); break; // Set Global Volume case CMD_GLOBALVOLUME: // IT compatibility: Only apply global volume on first tick (and multiples) // Test case: GlobalVolFirstTick.it if(!m_PlayState.m_flags[SONG_FIRSTTICK]) break; // ST3 applies global volume on tick 1 and does other weird things, but we won't emulate this for now. // if(((GetType() & MOD_TYPE_S3M) && m_nTickCount != 1) // || (!(GetType() & MOD_TYPE_S3M) && !m_PlayState.m_flags[SONG_FIRSTTICK])) // { // break; // } // FT2 compatibility: On channels that are "left" of the global volume command, the new global volume is not applied // until the second tick of the row. Since we apply global volume on the mix buffer rather than note volumes, this // cannot be fixed for now. // Test case: GlobalVolume.xm // if(IsCompatibleMode(TRK_FASTTRACKER2) && m_PlayState.m_flags[SONG_FIRSTTICK] && m_nMusicSpeed > 1) // { // break; // } if (!(GetType() & GLOBALVOL_7BIT_FORMATS)) param *= 2; // IT compatibility 16. ST3 and IT ignore out-of-range values. // Test case: globalvol-invalid.it if(param <= 128) { m_PlayState.m_nGlobalVolume = param * 2; } else if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_S3M))) { m_PlayState.m_nGlobalVolume = 256; } m_PlayState.Chn[m_playBehaviour[kPerChannelGlobalVolSlide] ? nChn : 0].autoSlide.SetActive(AutoSlideCommand::GlobalVolumeSlide, false); break; // Global Volume Slide case CMD_GLOBALVOLSLIDE: //IT compatibility 16. Saving last global volume slide param per channel (FT2/IT) GlobalVolSlide(m_PlayState, static_cast(param), m_playBehaviour[kPerChannelGlobalVolSlide] ? nChn : 0); break; // Set 8-bit Panning case CMD_PANNING8: if(m_PlayState.m_flags[SONG_FIRSTTICK]) { Panning(chn, param, Pan8bit); } break; // Panning Slide case CMD_PANNINGSLIDE: PanningSlide(chn, static_cast(param)); break; // Tremolo case CMD_TREMOLO: Tremolo(chn, param); break; // Fine Vibrato case CMD_FINEVIBRATO: FineVibrato(chn, param); break; // MOD/XM Exx Extended Commands case CMD_MODCMDEX: ExtendedMODCommands(nChn, static_cast(param)); break; // S3M/IT Sxx Extended Commands case CMD_S3MCMDEX: ExtendedS3MCommands(nChn, static_cast(param)); break; // Key Off case CMD_KEYOFF: // This is how Key Off is supposed to sound... (in FT2 at least) if(m_playBehaviour[kFT2KeyOff]) { if (m_PlayState.m_nTickCount == param) { // XM: Key-Off + Sample == Note Cut if(chn.pModInstrument == nullptr || !chn.pModInstrument->VolEnv.dwFlags[ENV_ENABLED]) { if(param == 0 && (chn.rowCommand.instr || chn.rowCommand.volcmd != VOLCMD_NONE)) // FT2 is weird.... { chn.dwFlags.set(CHN_NOTEFADE); } else { chn.dwFlags.set(CHN_FASTVOLRAMP); chn.nVolume = 0; } } KeyOff(chn); } } // This is how it's NOT supposed to sound... else { if(m_PlayState.m_flags[SONG_FIRSTTICK]) KeyOff(chn); } break; // Extra-fine porta up/down case CMD_XFINEPORTAUPDOWN: switch(param & 0xF0) { case 0x10: ExtraFinePortamentoUp(chn, param & 0x0F); if(!m_playBehaviour[kPluginIgnoreTonePortamento]) MidiPortamento(nChn, 0xE0 | (param & 0x0F), true); break; case 0x20: ExtraFinePortamentoDown(chn, param & 0x0F); if(!m_playBehaviour[kPluginIgnoreTonePortamento]) MidiPortamento(nChn, -static_cast(0xE0 | (param & 0x0F)), true); break; // ModPlug XM Extensions (ignore in compatible mode) case 0x50: case 0x60: case 0x70: case 0x90: case 0xA0: if(!m_playBehaviour[kFT2RestrictXCommand]) ExtendedS3MCommands(nChn, static_cast(param)); break; } break; case CMD_FINETUNE: case CMD_FINETUNE_SMOOTH: if(m_PlayState.m_flags[SONG_FIRSTTICK] || cmd == CMD_FINETUNE_SMOOTH) SetFinetune(m_PlayState.m_nPattern, m_PlayState.m_nRow, nChn, m_PlayState, cmd == CMD_FINETUNE_SMOOTH); break; // Set Channel Global Volume case CMD_CHANNELVOLUME: if(!m_PlayState.m_flags[SONG_FIRSTTICK]) break; if (param <= 64) { chn.nGlobalVol = static_cast(param); chn.dwFlags.set(CHN_FASTVOLRAMP); } break; // Channel volume slide case CMD_CHANNELVOLSLIDE: ChannelVolSlide(chn, static_cast(param)); break; // Panbrello (IT) case CMD_PANBRELLO: Panbrello(chn, param); break; // Set Envelope Position case CMD_SETENVPOSITION: if(m_PlayState.m_flags[SONG_FIRSTTICK]) { chn.VolEnv.nEnvPosition = param; // FT2 compatibility: FT2 only sets the position of the panning envelope if the volume envelope's sustain flag is set // Test case: SetEnvPos.xm if(!m_playBehaviour[kFT2SetPanEnvPos] || chn.VolEnv.flags[ENV_SUSTAIN]) { chn.PanEnv.nEnvPosition = param; chn.PitchEnv.nEnvPosition = param; } } break; // MED Synth Jump (handled in InstrumentSynth) / MIDI Panning case CMD_MED_SYNTH_JUMP: #ifndef NO_PLUGINS if(chn.isFirstTick) { if(IMixPlugin *plugin = GetChannelInstrumentPlugin(chn); plugin != nullptr) plugin->MidiCC(MIDIEvents::MIDICC_Panposition_Coarse, static_cast(param & 0x7F), nChn); } #endif // NO_PLUGINS break; // Position Jump case CMD_POSITIONJUMP: PositionJump(m_PlayState, nChn); break; // Pattern Break case CMD_PATTERNBREAK: if(ROWINDEX row = PatternBreak(m_PlayState, nChn, static_cast(param)); row != ROWINDEX_INVALID) { m_PlayState.m_breakRow = row; if(m_PlayState.m_flags[SONG_PATTERNLOOP]) { //If song is set to loop and a pattern break occurs we should stay on the same pattern. //Use nPosJump to force playback to "jump to this pattern" rather than move to next, as by default. m_PlayState.m_posJump = m_PlayState.m_nCurrentOrder; } } break; // IMF / PTM Note Slides case CMD_NOTESLIDEUP: case CMD_NOTESLIDEDOWN: case CMD_NOTESLIDEUPRETRIG: case CMD_NOTESLIDEDOWNRETRIG: // Note that this command seems to be a bit buggy in Polytracker... Luckily, no tune seems to seriously use this // (Vic uses it e.g. in Spaceman or Perfect Reason to slide effect samples, noone will notice the difference :) NoteSlide(chn, param, cmd == CMD_NOTESLIDEUP || cmd == CMD_NOTESLIDEUPRETRIG, cmd == CMD_NOTESLIDEUPRETRIG || cmd == CMD_NOTESLIDEDOWNRETRIG); break; // PTM Reverse sample + offset (executed on every tick) case CMD_REVERSEOFFSET: ReverseSampleOffset(chn, static_cast(param)); break; #ifndef NO_PLUGINS // DBM: Toggle DSP Echo case CMD_DBMECHO: if(m_PlayState.m_nTickCount == 0) { uint32 echoType = (param >> 4), enable = (param & 0x0F); if(echoType > 2 || enable > 1) { break; } CHANNELINDEX firstChn = nChn, lastChn = nChn; if(echoType == 1) { firstChn = 0; lastChn = GetNumChannels() - 1; } for(CHANNELINDEX c = firstChn; c <= lastChn; c++) { ChnSettings[c].dwFlags.set(CHN_NOFX, enable == 1); m_PlayState.Chn[c].dwFlags.set(CHN_NOFX, enable == 1); } } break; #endif // NO_PLUGINS // Digi Booster sample reverse case CMD_DIGIREVERSESAMPLE: DigiBoosterSampleReverse(chn, static_cast(param)); break; case CMD_AUTO_VOLUMESLIDE: AutoVolumeSlide(chn, static_cast(param)); break; case CMD_VOLUMEDOWN_ETX: if(chn.isFirstTick) VolumeDownETX(m_PlayState, chn, static_cast(param)); break; case CMD_TONEPORTA_DURATION: if(chn.rowCommand.IsNote() && triggerNote) TonePortamentoWithDuration(chn, static_cast(param)); break; case CMD_VOLUMEDOWN_DURATION: if(m_PlayState.m_nTickCount == 0) ChannelVolumeDownWithDuration(chn, static_cast(param)); break; default: break; } if(m_playBehaviour[kST3EffectMemory] && cmd != CMD_NONE && param != 0) { UpdateS3MEffectMemory(chn, static_cast(param)); } if(chn.rowCommand.instr) { // Not necessarily consistent with actually playing instrument for IT compatibility chn.nOldIns = chn.rowCommand.instr; } ProcessAutoSlides(m_PlayState, nChn); } // for(...) end // Navigation Effects if(m_PlayState.m_flags[SONG_FIRSTTICK]) { if(HandleNextRow(m_PlayState, Order(), true)) m_PlayState.m_flags.set(SONG_BREAKTOROW); } return true; } bool CSoundFile::HandleNextRow(PlayState &state, const ModSequence &order, bool honorPatternLoop) const { const bool doPatternLoop = (state.m_patLoopRow != ROWINDEX_INVALID); const bool doBreakRow = (state.m_breakRow != ROWINDEX_INVALID); const bool doPosJump = (state.m_posJump != ORDERINDEX_INVALID); bool breakToRow = false; // Pattern Break / Position Jump only if no loop running // Exception: FastTracker 2 in all cases, Impulse Tracker in case of position jump // Test case for FT2 exception: PatLoop-Jumps.xm, PatLoop-Various.xm // Test case for IT: exception: LoopBreak.it, sbx-priority.it if((doBreakRow || doPosJump) && (!doPatternLoop || m_playBehaviour[kFT2PatternLoopWithJumps] || (m_playBehaviour[kITPatternLoopWithJumps] && doPosJump) || (m_playBehaviour[kITPatternLoopWithJumpsOld] && doPosJump))) { if(!doPosJump) state.m_posJump = state.m_nCurrentOrder + 1; if(!doBreakRow) state.m_breakRow = 0; breakToRow = true; if(state.m_posJump >= order.size()) state.m_posJump = order.GetRestartPos(); // IT / FT2 compatibility: don't reset loop count on pattern break. // Test case: gm-trippy01.it, PatLoop-Break.xm, PatLoop-Weird.xm, PatLoop-Break.mod if(state.m_posJump != state.m_nCurrentOrder && !m_playBehaviour[kITPatternLoopBreak] && !m_playBehaviour[kFT2PatternLoopWithJumps] && GetType() != MOD_TYPE_MOD) { for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { state.Chn[i].nPatternLoopCount = 0; } } state.m_nNextRow = state.m_breakRow; if(!honorPatternLoop || !m_PlayState.m_flags[SONG_PATTERNLOOP]) state.m_nNextOrder = state.m_posJump; } else if(doPatternLoop) { // Pattern Loop state.m_nNextOrder = state.m_nCurrentOrder; state.m_nNextRow = state.m_patLoopRow; // FT2 skips the first row of the pattern loop if there's a pattern delay, ProTracker sometimes does it too (didn't quite figure it out yet). // But IT and ST3 don't do this. // Test cases: PatLoopWithDelay.it, PatLoopWithDelay.s3m if(state.m_nPatternDelay && (GetType() != MOD_TYPE_IT || !m_playBehaviour[kITPatternLoopWithJumps]) && GetType() != MOD_TYPE_S3M) { state.m_nNextRow++; } // IT Compatibility: If the restart row is past the end of the current pattern // (e.g. when continued from a previous pattern without explicit SB0 effect), continue the next pattern. // Test case: LoopStartAfterPatternEnd.it if(state.m_patLoopRow >= Patterns[state.m_nPattern].GetNumRows()) { state.m_nNextOrder++; state.m_nNextRow = 0; } } return breakToRow; } //////////////////////////////////////////////////////////// // Channels effects void CSoundFile::ResetAutoSlides(ModChannel &chn) const { const auto cmd = chn.rowCommand.command; const auto volcmd = chn.rowCommand.volcmd; if(cmd != CMD_NONE && GetType() == MOD_TYPE_669) { chn.autoSlide.Reset(); return; } if((cmd == CMD_NONE || !chn.rowCommand.param) && chn.autoSlide.IsActive(AutoSlideCommand::VolumeSlideSTK)) chn.autoSlide.SetActive(AutoSlideCommand::VolumeSlideSTK, false); if((cmd == CMD_CHANNELVOLUME || cmd == CMD_CHANNELVOLSLIDE) && chn.autoSlide.IsActive(AutoSlideCommand::VolumeDownWithDuration)) chn.autoSlide.SetActive(AutoSlideCommand::VolumeDownWithDuration, false); if(chn.autoSlide.IsActive(AutoSlideCommand::FinePortamentoDown) || chn.autoSlide.IsActive(AutoSlideCommand::PortamentoDown) || chn.autoSlide.IsActive(AutoSlideCommand::FinePortamentoUp) || chn.autoSlide.IsActive(AutoSlideCommand::PortamentoUp)) { if(!chn.rowCommand.IsTonePortamento() && chn.rowCommand.IsAnyPitchSlide()) { chn.autoSlide.SetActive(AutoSlideCommand::FinePortamentoDown, false); chn.autoSlide.SetActive(AutoSlideCommand::PortamentoDown, false); chn.autoSlide.SetActive(AutoSlideCommand::FinePortamentoUp, false); chn.autoSlide.SetActive(AutoSlideCommand::PortamentoUp, false); } } if(chn.autoSlide.IsActive(AutoSlideCommand::FineVolumeSlideUp) || chn.autoSlide.IsActive(AutoSlideCommand::FineVolumeSlideDown) || chn.autoSlide.IsActive(AutoSlideCommand::VolumeDownETX)) { if(cmd == CMD_VOLUME || cmd == CMD_AUTO_VOLUMESLIDE || cmd == CMD_VOLUMEDOWN_ETX || chn.rowCommand.IsNormalVolumeSlide() || volcmd == VOLCMD_VOLUME || volcmd == VOLCMD_VOLSLIDEUP || volcmd == VOLCMD_VOLSLIDEDOWN || volcmd == VOLCMD_FINEVOLUP || volcmd == VOLCMD_FINEVOLDOWN) { chn.autoSlide.SetActive(AutoSlideCommand::FineVolumeSlideUp, false); chn.autoSlide.SetActive(AutoSlideCommand::FineVolumeSlideDown, false); chn.autoSlide.SetActive(AutoSlideCommand::VolumeDownETX, false); } } } void CSoundFile::ProcessAutoSlides(PlayState &playState, CHANNELINDEX channel) { ModChannel &chn = playState.Chn[channel]; if(chn.autoSlide.IsActive(AutoSlideCommand::TonePortamento) && !chn.rowCommand.IsTonePortamento()) TonePortamento(channel, chn.portamentoSlide); else if(chn.autoSlide.IsActive(AutoSlideCommand::TonePortamentoWithDuration)) TonePortamentoWithDuration(chn); if(chn.autoSlide.IsActive(AutoSlideCommand::PortamentoUp)) PortamentoUp(channel, chn.nOldPortaUp, true); else if(chn.autoSlide.IsActive(AutoSlideCommand::PortamentoDown)) PortamentoDown(channel, chn.nOldPortaDown, true); else if(chn.autoSlide.IsActive(AutoSlideCommand::FinePortamentoUp)) FinePortamentoUp(chn, chn.nOldFinePortaUpDown); else if(chn.autoSlide.IsActive(AutoSlideCommand::FinePortamentoDown)) FinePortamentoDown(chn, chn.nOldFinePortaUpDown); if(chn.autoSlide.IsActive(AutoSlideCommand::PortamentoFC)) PortamentoFC(chn); if(chn.autoSlide.IsActive(AutoSlideCommand::FineVolumeSlideUp) && chn.rowCommand.command != CMD_AUTO_VOLUMESLIDE) FineVolumeUp(chn, 0, false); if(chn.autoSlide.IsActive(AutoSlideCommand::FineVolumeSlideDown) && chn.rowCommand.command != CMD_AUTO_VOLUMESLIDE) FineVolumeDown(chn, 0, false); if(chn.autoSlide.IsActive(AutoSlideCommand::VolumeDownETX)) chn.nVolume = std::max(int32(0), chn.nVolume - chn.nOldVolumeSlide); if(chn.autoSlide.IsActive(AutoSlideCommand::VolumeSlideSTK)) VolumeSlide(chn, 0); if(chn.autoSlide.IsActive(AutoSlideCommand::GlobalVolumeSlide) && chn.rowCommand.command != CMD_GLOBALVOLSLIDE) GlobalVolSlide(playState, chn.nOldGlobalVolSlide, channel); if(chn.autoSlide.IsActive(AutoSlideCommand::VolumeDownWithDuration)) ChannelVolumeDownWithDuration(chn); if(chn.autoSlide.IsActive(AutoSlideCommand::Vibrato)) chn.dwFlags.set(CHN_VIBRATO); if(chn.autoSlide.IsActive(AutoSlideCommand::Tremolo)) chn.dwFlags.set(CHN_TREMOLO); } // Update the effect memory of all S3M effects that use the last non-zero effect parameter as memory (Dxy, Exx, Fxx, Ixy, Jxy, Kxy, Lxy, Qxy, Rxy, Sxy) // Test case: ParamMemory.s3m void CSoundFile::UpdateS3MEffectMemory(ModChannel &chn, ModCommand::PARAM param) const { chn.nOldVolumeSlide = param; // Dxy / Kxy / Lxy chn.nOldPortaUp = param; // Exx / Fxx chn.nOldPortaDown = param; // Exx / Fxx chn.nTremorParam = param; // Ixy chn.nArpeggio = param; // Jxy chn.nRetrigParam = param; // Qxy chn.nTremoloDepth = (param & 0x0F) << 2; // Rxy chn.nTremoloSpeed = (param >> 4) & 0x0F; // Rxy chn.nOldCmdEx = param; // Sxy } // Calculate full parameter for effects that support parameter extension at the given pattern location. // maxCommands sets the maximum number of XParam commands to look at for this effect // extendedRows returns how many extended rows are used (i.e. a value of 0 means the command is not extended). uint32 CSoundFile::CalculateXParam(PATTERNINDEX pat, ROWINDEX row, CHANNELINDEX chn, uint32 *extendedRows) const { if(extendedRows != nullptr) *extendedRows = 0; if(!Patterns.IsValidPat(pat)) { #ifdef MPT_BUILD_FUZZER // Ending up in this situation implies a logic error std::abort(); #else return 0; #endif } ROWINDEX maxCommands = 4; const ModCommand *m = Patterns[pat].GetpModCommand(row, chn); const auto startCmd = m->command; uint32 val = m->param; switch(m->command) { case CMD_OFFSET: // 24 bit command maxCommands = 2; break; case CMD_TEMPO: case CMD_PATTERNBREAK: case CMD_POSITIONJUMP: case CMD_FINETUNE: case CMD_FINETUNE_SMOOTH: // 16 bit command maxCommands = 1; break; default: return val; } const bool xmTempoFix = m->command == CMD_TEMPO && GetType() == MOD_TYPE_XM; ROWINDEX numRows = std::min(Patterns[pat].GetNumRows() - row - 1, maxCommands); uint32 extRows = 0; while(numRows > 0) { m += Patterns[pat].GetNumChannels(); if(m->command != CMD_XPARAM) break; if(xmTempoFix && val >= 0x20 && val < 256) { // With XM, 0x20 is the lowest tempo. Anything below changes ticks per row. val -= 0x20; } val = (val << 8) | m->param; numRows--; extRows++; } // Always return a full-precision value for finetune if((startCmd == CMD_FINETUNE || startCmd == CMD_FINETUNE_SMOOTH) && !extRows) val <<= 8; if(extendedRows != nullptr) *extendedRows = extRows; return val; } void CSoundFile::PositionJump(PlayState &state, CHANNELINDEX chn) const { state.m_nextPatStartRow = 0; // FT2 E60 bug state.m_posJump = static_cast(CalculateXParam(state.m_nPattern, state.m_nRow, chn)); // see https://forum.openmpt.org/index.php?topic=2769.0 - FastTracker resets Dxx if Bxx is called _after_ Dxx // Test case: PatternJump.mod if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM)) && state.m_breakRow != ROWINDEX_INVALID) { state.m_breakRow = 0; } } ROWINDEX CSoundFile::PatternBreak(PlayState &state, CHANNELINDEX chn, uint8 param) const { if(param >= 64 && (GetType() & MOD_TYPE_S3M)) { // ST3 ignores invalid pattern breaks. return ROWINDEX_INVALID; } state.m_nextPatStartRow = 0; // FT2 E60 bug return static_cast(CalculateXParam(state.m_nPattern, state.m_nRow, chn)); } void CSoundFile::PortamentoFC(ModChannel &chn) const { chn.fcPortaTick = !chn.fcPortaTick; if(!chn.fcPortaTick) return; chn.nPeriod -= static_cast(chn.nOldPortaUp) * 4; } void CSoundFile::PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) { PortamentoUp(m_PlayState, nChn, param, doFinePortamentoAsRegular); MidiPortamento(nChn, m_PlayState.Chn[nChn].nOldPortaUp, !doFinePortamentoAsRegular && UseCombinedPortamentoCommands()); } void CSoundFile::PortamentoUp(PlayState &playState, CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) const { ModChannel &chn = playState.Chn[nChn]; // IT compatibility: Initialize effect memory in the right order in case there are portamentos in both effect columns. // Test cases: DoubleSlide.it, DoubleSlideCompatGxx.it if(param && !m_playBehaviour[kITDoublePortamentoSlides]) { // FT2 compatibility: Separate effect memory for all portamento commands // Test case: Porta-LinkMem.xm if(!m_playBehaviour[kFT2PortaUpDownMemory]) chn.nOldPortaDown = param; chn.nOldPortaUp = param; } else { param = chn.nOldPortaUp; } const bool doFineSlides = !doFinePortamentoAsRegular && UseCombinedPortamentoCommands(); if(GetType() == MOD_TYPE_MPT && chn.pModInstrument && chn.pModInstrument->pTuning) { // Portamento for instruments with custom tuning if(param >= 0xF0 && !doFinePortamentoAsRegular) PortamentoFineMPT(playState, nChn, param - 0xF0); else if(param >= 0xE0 && !doFinePortamentoAsRegular) PortamentoExtraFineMPT(chn, param - 0xE0); else PortamentoMPT(chn, param); return; } else if(GetType() == MOD_TYPE_PLM) { // A normal portamento up or down makes a follow-up tone portamento go the same direction. chn.nPortamentoDest = 1; } if (doFineSlides && param >= 0xE0) { if (param & 0x0F) { if ((param & 0xF0) == 0xF0) { FinePortamentoUp(chn, param & 0x0F); return; } else if ((param & 0xF0) == 0xE0 && GetType() != MOD_TYPE_DBM) { ExtraFinePortamentoUp(chn, param & 0x0F); return; } } if(GetType() != MOD_TYPE_DBM) { // DBM only has fine slides, no extra-fine slides. return; } } // Regular Slide if(!chn.isFirstTick || (m_PlayState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1]) || m_SongFlags[SONG_FASTPORTAS]) { DoFreqSlide(chn, chn.nPeriod, param * 4); } } void CSoundFile::PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) { PortamentoDown(m_PlayState, nChn, param, doFinePortamentoAsRegular); MidiPortamento(nChn, -static_cast(m_PlayState.Chn[nChn].nOldPortaDown), !doFinePortamentoAsRegular && UseCombinedPortamentoCommands()); } void CSoundFile::PortamentoDown(PlayState &playState, CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) const { ModChannel &chn = playState.Chn[nChn]; // IT compatibility: Initialize effect memory in the right order in case there are portamentos in both effect columns. // Test cases: DoubleSlide.it, DoubleSlideCompatGxx.it if(param && !m_playBehaviour[kITDoublePortamentoSlides]) { // FT2 compatibility: Separate effect memory for all portamento commands // Test case: Porta-LinkMem.xm if(!m_playBehaviour[kFT2PortaUpDownMemory]) chn.nOldPortaUp = param; chn.nOldPortaDown = param; } else { param = chn.nOldPortaDown; } const bool doFineSlides = !doFinePortamentoAsRegular && UseCombinedPortamentoCommands(); if(GetType() == MOD_TYPE_MPT && chn.pModInstrument && chn.pModInstrument->pTuning) { // Portamento for instruments with custom tuning if(param >= 0xF0 && !doFinePortamentoAsRegular) PortamentoFineMPT(playState, nChn, -static_cast(param - 0xF0)); else if(param >= 0xE0 && !doFinePortamentoAsRegular) PortamentoExtraFineMPT(chn, -static_cast(param - 0xE0)); else PortamentoMPT(chn, -static_cast(param)); return; } else if(GetType() == MOD_TYPE_PLM) { // A normal portamento up or down makes a follow-up tone portamento go the same direction. chn.nPortamentoDest = 65535; } if(doFineSlides && param >= 0xE0) { if (param & 0x0F) { if ((param & 0xF0) == 0xF0) { FinePortamentoDown(chn, param & 0x0F); return; } else if ((param & 0xF0) == 0xE0 && GetType() != MOD_TYPE_DBM) { ExtraFinePortamentoDown(chn, param & 0x0F); return; } } if(GetType() != MOD_TYPE_DBM) { // DBM only has fine slides, no extra-fine slides. return; } } if(!chn.isFirstTick || (m_PlayState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1]) || m_SongFlags[SONG_FASTPORTAS]) { DoFreqSlide(chn, chn.nPeriod, param * -4); } } // Send portamento commands to plugins void CSoundFile::MidiPortamento(CHANNELINDEX nChn, int param, const bool doFineSlides) { int actualParam = std::abs(param); int pitchBend = 0; // Old MIDI Pitch Bends: // - Applied on every tick // - No fine pitch slides (they are interpreted as normal slides) // New MIDI Pitch Bends: // - Behaviour identical to sample pitch bends if the instrument's PWD parameter corresponds to the actual VSTi setting. if(doFineSlides && actualParam >= 0xE0 && !m_playBehaviour[kOldMIDIPitchBends]) { if(m_PlayState.Chn[nChn].isFirstTick) { // Extra fine slide... pitchBend = (actualParam & 0x0F) * mpt::signum(param); if(actualParam >= 0xF0) { // ... or just a fine slide! pitchBend *= 4; } } } else if(!m_PlayState.Chn[nChn].isFirstTick || m_playBehaviour[kOldMIDIPitchBends]) { // Regular slide pitchBend = param * 4; } if(pitchBend) { #ifndef NO_PLUGINS IMixPlugin *plugin = GetChannelInstrumentPlugin(m_PlayState.Chn[nChn]); if(plugin != nullptr) { int8 pwd = 13; // Early OpenMPT legacy... Actually it's not *exactly* 13, but close enough... if(m_PlayState.Chn[nChn].pModInstrument != nullptr) { pwd = m_PlayState.Chn[nChn].pModInstrument->midiPWD; } plugin->MidiPitchBend(pitchBend, pwd, nChn); } #endif // NO_PLUGINS } } void CSoundFile::FinePortamentoUp(ModChannel &chn, ModCommand::PARAM param) const { MPT_ASSERT(!chn.HasCustomTuning()); if(GetType() == MOD_TYPE_XM) { // FT2 compatibility: E1x / E2x / X1x / X2x memory is not linked // Test case: Porta-LinkMem.xm if(param) chn.nOldFinePortaUpDown = (chn.nOldFinePortaUpDown & 0x0F) | (param << 4); else param = (chn.nOldFinePortaUpDown >> 4); } else if(GetType() == MOD_TYPE_MT2) { if(param) chn.nOldFinePortaUpDown = param; else param = chn.nOldFinePortaUpDown; } if(chn.isFirstTick && chn.nPeriod && param) DoFreqSlide(chn, chn.nPeriod, param * 4); } void CSoundFile::FinePortamentoDown(ModChannel &chn, ModCommand::PARAM param) const { MPT_ASSERT(!chn.HasCustomTuning()); if(GetType() == MOD_TYPE_XM) { // FT2 compatibility: E1x / E2x / X1x / X2x memory is not linked // Test case: Porta-LinkMem.xm if(param) chn.nOldFinePortaUpDown = (chn.nOldFinePortaUpDown & 0xF0) | (param & 0x0F); else param = (chn.nOldFinePortaUpDown & 0x0F); } else if(GetType() == MOD_TYPE_MT2) { if(param) chn.nOldFinePortaUpDown = param; else param = chn.nOldFinePortaUpDown; } if(chn.isFirstTick && chn.nPeriod && param) { DoFreqSlide(chn, chn.nPeriod, param * -4); if(chn.nPeriod > 0xFFFF && !m_playBehaviour[kPeriodsAreHertz] && (!m_SongFlags[SONG_LINEARSLIDES] || GetType() == MOD_TYPE_XM)) chn.nPeriod = 0xFFFF; } } void CSoundFile::ExtraFinePortamentoUp(ModChannel &chn, ModCommand::PARAM param) const { MPT_ASSERT(!chn.HasCustomTuning()); if(GetType() == MOD_TYPE_XM) { // FT2 compatibility: E1x / E2x / X1x / X2x memory is not linked // Test case: Porta-LinkMem.xm if(param) chn.nOldExtraFinePortaUpDown = (chn.nOldExtraFinePortaUpDown & 0x0F) | (param << 4); else param = (chn.nOldExtraFinePortaUpDown >> 4); } else if(GetType() == MOD_TYPE_MT2) { if(param) chn.nOldFinePortaUpDown = param; else param = chn.nOldFinePortaUpDown; } if(chn.isFirstTick && chn.nPeriod && param) DoFreqSlide(chn, chn.nPeriod, param); } void CSoundFile::ExtraFinePortamentoDown(ModChannel &chn, ModCommand::PARAM param) const { MPT_ASSERT(!chn.HasCustomTuning()); if(GetType() == MOD_TYPE_XM) { // FT2 compatibility: E1x / E2x / X1x / X2x memory is not linked // Test case: Porta-LinkMem.xm if(param) chn.nOldExtraFinePortaUpDown = (chn.nOldExtraFinePortaUpDown & 0xF0) | (param & 0x0F); else param = (chn.nOldExtraFinePortaUpDown & 0x0F); } else if(GetType() == MOD_TYPE_MT2) { if(param) chn.nOldFinePortaUpDown = param; else param = chn.nOldFinePortaUpDown; } if(chn.isFirstTick && chn.nPeriod && param) { DoFreqSlide(chn, chn.nPeriod, -static_cast(param)); if(chn.nPeriod > 0xFFFF && !m_playBehaviour[kPeriodsAreHertz] && (!m_SongFlags[SONG_LINEARSLIDES] || GetType() == MOD_TYPE_XM)) chn.nPeriod = 0xFFFF; } } // Process finetune command from pattern editor void CSoundFile::ProcessFinetune(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel, bool isSmooth) { SetFinetune(pattern, row, channel, m_PlayState, isSmooth); // Also apply to notes played via CModDoc::PlayNote for(ModChannel &chn : m_PlayState.BackgroundChannels(*this)) { if(chn.nMasterChn == channel + 1 && chn.isPreviewNote && !chn.dwFlags[CHN_KEYOFF]) chn.microTuning = m_PlayState.Chn[channel].microTuning; } } void CSoundFile::SetFinetune(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel, PlayState &playState, bool isSmooth) const { ModChannel &chn = playState.Chn[channel]; int16 newTuning = CalculateFinetuneTarget(pattern, row, channel); if(isSmooth) { const int32 ticksLeft = playState.TicksOnRow() - playState.m_nTickCount; if(ticksLeft > 1) { const int32 step = (newTuning - chn.microTuning) / ticksLeft; newTuning = mpt::saturate_cast(chn.microTuning + step); } } chn.microTuning = newTuning; #ifndef NO_PLUGINS if(IMixPlugin *plugin = GetChannelInstrumentPlugin(chn); plugin != nullptr) plugin->MidiPitchBendRaw(chn.GetMIDIPitchBend(), channel); #endif // NO_PLUGINS } int16 CSoundFile::CalculateFinetuneTarget(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel) const { return mpt::saturate_cast(static_cast(CalculateXParam(pattern, row, channel, nullptr)) - 0x8000); } // Implemented for IMF / PTM / OKT compatibility, can't actually save this in any formats // Slide up / down every x ticks by y semitones // Oktalyzer: Slide down on first tick only, or on every tick void CSoundFile::NoteSlide(ModChannel &chn, uint32 param, bool slideUp, bool retrig) const { if(chn.isFirstTick) { if(param & 0xF0) chn.noteSlideParam = static_cast(param & 0xF0) | (chn.noteSlideParam & 0x0F); if(param & 0x0F) chn.noteSlideParam = (chn.noteSlideParam & 0xF0) | static_cast(param & 0x0F); chn.noteSlideCounter = (chn.noteSlideParam >> 4); } bool doTrigger = false; if(GetType() == MOD_TYPE_OKT) doTrigger = ((chn.noteSlideParam & 0xF0) == 0x10) || m_PlayState.m_flags[SONG_FIRSTTICK]; else doTrigger = !chn.isFirstTick && (--chn.noteSlideCounter == 0); if(doTrigger) { const uint8 speed = (chn.noteSlideParam >> 4), steps = (chn.noteSlideParam & 0x0F); chn.noteSlideCounter = speed; // update it const int32 delta = (slideUp ? steps : -steps); if(chn.HasCustomTuning()) chn.m_PortamentoFineSteps += delta * chn.pModInstrument->pTuning->GetFineStepCount(); else chn.nPeriod = GetPeriodFromNote(delta + GetNoteFromPeriod(chn.nPeriod, chn.nFineTune, chn.nC5Speed), chn.nFineTune, chn.nC5Speed); if(retrig) chn.position.Set(0); } } std::pair CSoundFile::GetVolCmdTonePorta(const ModCommand &m, uint32 startTick) const { if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_AMS | MOD_TYPE_DMF | MOD_TYPE_DBM | MOD_TYPE_IMF | MOD_TYPE_PSM | MOD_TYPE_J2B | MOD_TYPE_ULT | MOD_TYPE_OKT | MOD_TYPE_MT2 | MOD_TYPE_MDL)) { return {ImpulseTrackerPortaVolCmd[m.vol & 0x0F], false}; } else { bool clearEffectColumn = false; uint16 vol = m.vol; if(m.command == CMD_TONEPORTAMENTO && GetType() == MOD_TYPE_XM) { // Yes, FT2 is *that* weird. If there is a Mx command in the volume column // and a normal 3xx command, the 3xx command is ignored but the Mx command's // effectiveness is doubled. // Test case: TonePortamentoMemory.xm clearEffectColumn = true; vol *= 2; } // FT2 compatibility: If there's a portamento and a note delay, execute the portamento, but don't update the parameter // Test case: PortaDelay.xm if(m_playBehaviour[kFT2PortaDelay] && startTick != 0) return {uint16(0), clearEffectColumn}; else return {static_cast(vol * 16), clearEffectColumn}; } } bool CSoundFile::TonePortamentoSharesEffectMemory() const { return (!m_SongFlags[SONG_ITCOMPATGXX] && m_playBehaviour[kITPortaMemoryShare]) || GetType() == MOD_TYPE_PLM; } void CSoundFile::InitTonePortamento(ModChannel &chn, uint16 param) const { // IT compatibility 03: Share effect memory with portamento up/down if(TonePortamentoSharesEffectMemory()) { if(param == 0) param = chn.nOldPortaUp; chn.nOldPortaUp = chn.nOldPortaDown = static_cast(param); } if(param) chn.portamentoSlide = param; } void CSoundFile::TonePortamento(CHANNELINDEX nChn, uint16 param) { auto delta = TonePortamento(m_PlayState, nChn, param); if(!delta) return; #ifndef NO_PLUGINS ModChannel &chn = m_PlayState.Chn[nChn]; if(!m_playBehaviour[kPluginIgnoreTonePortamento] && chn.pModInstrument != nullptr && chn.pModInstrument->midiPWD != 0) { IMixPlugin *plugin = GetChannelInstrumentPlugin(chn); if(plugin != nullptr) { plugin->MidiTonePortamento(delta, chn.GetPluginNote(true), chn.pModInstrument->midiPWD, nChn); } } #endif // NO_PLUGINS } // Portamento Slide int32 CSoundFile::TonePortamento(PlayState &playState, CHANNELINDEX nChn, uint16 param) const { ModChannel &chn = playState.Chn[nChn]; chn.dwFlags.set(CHN_PORTAMENTO); if(m_SongFlags[SONG_AUTO_TONEPORTA]) chn.autoSlide.SetActive(AutoSlideCommand::TonePortamento, param != 0 || m_SongFlags[SONG_AUTO_TONEPORTA_CONT]); // IT compatibility: Initialize effect memory in the right order in case there are portamentos in both effect columns. // Test cases: DoubleSlide.it, DoubleSlideCompatGxx.it if(!m_playBehaviour[kITDoublePortamentoSlides]) InitTonePortamento(chn, param); int32 delta = chn.portamentoSlide; if(chn.HasCustomTuning()) { //Behavior: Param tells number of finesteps(or 'fullsteps'(notes) with glissando) //to slide per row(not per tick). if(delta == 0) return 0; const int32 oldPortamentoTickSlide = (playState.m_nTickCount != 0) ? chn.m_PortamentoTickSlide : 0; if(chn.nPortamentoDest < 0) delta = -delta; chn.m_PortamentoTickSlide = static_cast((playState.m_nTickCount + 1.0) * delta / playState.m_nMusicSpeed); if(chn.dwFlags[CHN_GLISSANDO]) { chn.m_PortamentoTickSlide *= chn.pModInstrument->pTuning->GetFineStepCount() + 1; //With glissando interpreting param as notes instead of finesteps. } const int32 slide = chn.m_PortamentoTickSlide - oldPortamentoTickSlide; if(std::abs(chn.nPortamentoDest) <= std::abs(slide)) { if(chn.nPortamentoDest != 0) { chn.m_PortamentoFineSteps += chn.nPortamentoDest; chn.nPortamentoDest = 0; chn.m_CalculateFreq = true; } } else { chn.m_PortamentoFineSteps += slide; chn.nPortamentoDest -= slide; chn.m_CalculateFreq = true; } return 0; } // ST3: Adlib Note + Tone Portamento does not execute the slide, but changes to the target note instantly on the next row (unless there is another note with tone portamento) // Test case: TonePortamentoWithAdlibNote.s3m if(m_playBehaviour[kST3TonePortaWithAdlibNote] && chn.dwFlags[CHN_ADLIB] && chn.rowCommand.IsNote()) return 0; bool doPorta = !chn.isFirstTick || GetType() == MOD_TYPE_DBM || (playState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1]) || m_SongFlags[SONG_FASTPORTAS]; if(GetType() == MOD_TYPE_PLM && delta >= 0xF0) { delta -= 0xF0; doPorta = chn.isFirstTick; } delta *= (GetType() == MOD_TYPE_669) ? 2 : 4; if(chn.nPeriod && chn.nPortamentoDest && doPorta) { const int32 actualDelta = PeriodsAreFrequencies() ? delta : -delta; // IT compatibility: Command Lxx, with no tone portamento set up before, will always execute the "portamento down" branch. // Test cases: LxxWith0Portamento-Linear.it, LxxWith0Portamento-Amiga.it if(m_playBehaviour[kITDoublePortamentoSlides] && !delta && chn.rowCommand.command == CMD_TONEPORTAVOL) { if(chn.nPeriod > 1 && m_SongFlags[SONG_LINEARSLIDES]) chn.nPeriod--; if(chn.nPeriod < chn.nPortamentoDest) chn.nPeriod = chn.nPortamentoDest; } else if(chn.nPeriod < chn.nPortamentoDest || chn.portaTargetReached) { DoFreqSlide(chn, chn.nPeriod, actualDelta, true); if(chn.nPeriod > chn.nPortamentoDest) chn.nPeriod = chn.nPortamentoDest; } else if(chn.nPeriod > chn.nPortamentoDest) { DoFreqSlide(chn, chn.nPeriod, -actualDelta, true); if(chn.nPeriod < chn.nPortamentoDest) chn.nPeriod = chn.nPortamentoDest; // FT2 compatibility: Reaching portamento target from below forces subsequent portamentos on the same note to use the logic for reaching the note from above instead. // Test case: PortaResetDirection.xm if(chn.nPeriod == chn.nPortamentoDest && m_playBehaviour[kFT2PortaResetDirection]) chn.portaTargetReached = true; } } // IT compatibility 23. Portamento with no note // ProTracker also disables portamento once the target is reached. // Test case: PortaTarget.mod if(chn.nPeriod == chn.nPortamentoDest && (m_playBehaviour[kITPortaTargetReached] || GetType() == MOD_TYPE_MOD)) chn.nPortamentoDest = 0; return doPorta ? delta : 0; } void CSoundFile::TonePortamentoWithDuration(ModChannel &chn, uint16 param) const { if(param != uint16_max) { // Prepare portamento if(!chn.rowCommand.IsNote()) return; chn.autoSlide.SetActive(AutoSlideCommand::TonePortamentoWithDuration, param != 0); if(param == 0) { chn.nPeriod = chn.nPortamentoDest; return; } uint32 sourceNote = GetNoteFromPeriod(chn.nPeriod, chn.nFineTune, chn.nC5Speed); chn.portamentoSlide = static_cast(Util::muldivr_unsigned(std::abs(static_cast(chn.rowCommand.note - sourceNote)), 64, m_PlayState.m_nMusicSpeed * param)); } else if(chn.nPeriod && chn.nPortamentoDest) { // Run portamento chn.dwFlags.set(CHN_PORTAMENTO); const int32 actualDelta = PeriodsAreFrequencies() ? chn.portamentoSlide : -chn.portamentoSlide; if(chn.nPeriod < chn.nPortamentoDest) { DoFreqSlide(chn, chn.nPeriod, actualDelta, true); if(chn.nPeriod >= chn.nPortamentoDest) { chn.nPeriod = chn.nPortamentoDest; chn.nPortamentoDest = 0; } } else if(chn.nPeriod > chn.nPortamentoDest) { DoFreqSlide(chn, chn.nPeriod, -actualDelta, true); if(chn.nPeriod <= chn.nPortamentoDest) { chn.nPeriod = chn.nPortamentoDest; chn.nPortamentoDest = 0; } } } } void CSoundFile::Vibrato(ModChannel &chn, uint32 param) const { if (param & 0x0F) chn.nVibratoDepth = (param & 0x0F) * 4; if (param & 0xF0) chn.nVibratoSpeed = (param >> 4) & 0x0F; if(m_SongFlags[SONG_AUTO_VIBRATO]) chn.autoSlide.SetActive(AutoSlideCommand::Vibrato, param != 0); else chn.dwFlags.set(CHN_VIBRATO); } void CSoundFile::FineVibrato(ModChannel &chn, uint32 param) const { if (param & 0x0F) chn.nVibratoDepth = param & 0x0F; if (param & 0xF0) chn.nVibratoSpeed = (param >> 4) & 0x0F; if(m_SongFlags[SONG_AUTO_VIBRATO]) chn.autoSlide.SetActive(AutoSlideCommand::Vibrato, param != 0); else chn.dwFlags.set(CHN_VIBRATO); // ST3 compatibility: Do not distinguish between vibrato types in effect memory // Test case: VibratoTypeChange.s3m if(m_playBehaviour[kST3VibratoMemory] && (param & 0x0F)) { chn.nVibratoDepth *= 4u; } } void CSoundFile::Panbrello(ModChannel &chn, uint32 param) const { if (param & 0x0F) chn.nPanbrelloDepth = param & 0x0F; if (param & 0xF0) chn.nPanbrelloSpeed = (param >> 4) & 0x0F; } void CSoundFile::Panning(ModChannel &chn, uint32 param, PanningType panBits) const { // No panning in ProTracker mode if(m_playBehaviour[kMODIgnorePanning]) { return; } // IT Compatibility (and other trackers as well): panning disables surround (unless panning in rear channels is enabled, which is not supported by the original trackers anyway) if (!m_PlayState.m_flags[SONG_SURROUNDPAN] && (panBits == Pan8bit || m_playBehaviour[kPanOverride])) { chn.dwFlags.reset(CHN_SURROUND); } if(panBits == Pan4bit) { // 0...15 panning chn.nPan = (param * 256 + 8) / 15; } else if(panBits == Pan6bit) { // 0...64 panning if(param > 64) param = 64; chn.nPan = param * 4; } else { if(!(GetType() & (MOD_TYPE_S3M | MOD_TYPE_DSM | MOD_TYPE_AMF0 | MOD_TYPE_AMF | MOD_TYPE_MTM))) { // Real 8-bit panning chn.nPan = param; } else { // 7-bit panning + surround if(param <= 0x80) { chn.nPan = param << 1; } else if(param == 0xA4) { chn.dwFlags.set(CHN_SURROUND); chn.nPan = 0x80; } } } chn.dwFlags.set(CHN_FASTVOLRAMP); chn.nRestorePanOnNewNote = 0; //IT compatibility 20. Set pan overrides random pan if(m_playBehaviour[kPanOverride]) { chn.nPanSwing = 0; chn.nPanbrelloOffset = 0; } } void CSoundFile::AutoVolumeSlide(ModChannel &chn, ModCommand::PARAM param) const { if(m_SongFlags[SONG_AUTO_VOLSLIDE_STK]) { chn.nOldVolumeSlide = param; chn.autoSlide.SetActive(AutoSlideCommand::VolumeSlideSTK); } else { if(param & 0x0F) { FineVolumeDown(chn, param, false); chn.autoSlide.SetActive(AutoSlideCommand::FineVolumeSlideDown); } else { FineVolumeUp(chn, param, false); chn.autoSlide.SetActive(AutoSlideCommand::FineVolumeSlideUp); } } } void CSoundFile::VolumeDownETX(const PlayState &playState, ModChannel &chn, ModCommand::PARAM param) const { chn.autoSlide.SetActive(AutoSlideCommand::VolumeDownETX, param != 0); if(!param || !playState.m_nSamplesPerTick) return; const uint32 slideDuration = Util::muldivr_unsigned(m_MixerSettings.gdwMixingFreq, 600, 1000) / param; // 600ms at maximum volume const uint32 neededTicks = std::max(uint32(1), (slideDuration + playState.m_nSamplesPerTick / 2u) / playState.m_nSamplesPerTick); chn.nOldVolumeSlide = mpt::saturate_cast(256 / neededTicks); } void CSoundFile::VolumeSlide(ModChannel &chn, ModCommand::PARAM param) const { if (param) chn.nOldVolumeSlide = param; else param = chn.nOldVolumeSlide; if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM))) { // MOD / XM nibble priority if((param & 0xF0) != 0) { param &= 0xF0; } else { param &= 0x0F; } } int newVolume = chn.nVolume; if(!(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_AMF0 | MOD_TYPE_MED | MOD_TYPE_DIGI))) { if ((param & 0x0F) == 0x0F) //Fine upslide or slide -15 { if (param & 0xF0) //Fine upslide { FineVolumeUp(chn, (param >> 4), false); return; } else //Slide -15 { if(chn.isFirstTick && !m_SongFlags[SONG_FASTVOLSLIDES]) { newVolume -= 0x0F * 4; } } } else if ((param & 0xF0) == 0xF0) //Fine downslide or slide +15 { if (param & 0x0F) //Fine downslide { FineVolumeDown(chn, (param & 0x0F), false); return; } else //Slide +15 { if(chn.isFirstTick && !m_SongFlags[SONG_FASTVOLSLIDES]) { newVolume += 0x0F * 4; } } } } if(!chn.isFirstTick || m_SongFlags[SONG_FASTVOLSLIDES] || (m_PlayState.m_nMusicSpeed == 1 && GetType() == MOD_TYPE_DBM)) { // IT compatibility: Ignore slide commands with both nibbles set. if (param & 0x0F) { if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) || (param & 0xF0) == 0) newVolume -= (int)((param & 0x0F) * 4); } else { newVolume += (int)((param & 0xF0) >> 2); } if (GetType() == MOD_TYPE_MOD) chn.dwFlags.set(CHN_FASTVOLRAMP); } newVolume = Clamp(newVolume, 0, 256); chn.nVolume = newVolume; } void CSoundFile::PanningSlide(ModChannel &chn, ModCommand::PARAM param, bool memory) const { if(memory) { // FT2 compatibility: Use effect memory (lxx and rxx in XM shouldn't use effect memory). // Test case: PanSlideMem.xm if(param) chn.nOldPanSlide = param; else param = chn.nOldPanSlide; } if((GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) { // XM nibble priority if((param & 0xF0) != 0) { param &= 0xF0; } else { param &= 0x0F; } } int32 nPanSlide = 0; if(!(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) { if (((param & 0x0F) == 0x0F) && (param & 0xF0)) { if(m_PlayState.m_flags[SONG_FIRSTTICK]) { param = (param & 0xF0) / 4u; nPanSlide = - (int)param; } } else if (((param & 0xF0) == 0xF0) && (param & 0x0F)) { if(m_PlayState.m_flags[SONG_FIRSTTICK]) { nPanSlide = (param & 0x0F) * 4u; } } else if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { if (param & 0x0F) { // IT compatibility: Ignore slide commands with both nibbles set. if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) || (param & 0xF0) == 0) nPanSlide = (int)((param & 0x0F) * 4u); } else { nPanSlide = -(int)((param & 0xF0) / 4u); } } } else { if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { if (param & 0xF0) { nPanSlide = (int)((param & 0xF0) / 4u); } else { nPanSlide = -(int)((param & 0x0F) * 4u); } // FT2 compatibility: FT2's panning slide is like IT's fine panning slide (not as deep) if(m_playBehaviour[kFT2PanSlide]) nPanSlide /= 4; } } if (nPanSlide) { nPanSlide += chn.nPan; nPanSlide = Clamp(nPanSlide, 0, 256); chn.nPan = nPanSlide; chn.nRestorePanOnNewNote = 0; } } void CSoundFile::FineVolumeUp(ModChannel &chn, ModCommand::PARAM param, bool volCol) const { if(GetType() == MOD_TYPE_XM) { // FT2 compatibility: EAx / EBx memory is not linked // Test case: FineVol-LinkMem.xm if(param) chn.nOldFineVolUpDown = (param << 4) | (chn.nOldFineVolUpDown & 0x0F); else param = (chn.nOldFineVolUpDown >> 4); } else if(volCol) { if(param) chn.nOldVolParam = param; else param = chn.nOldVolParam; } else { if(param) chn.nOldFineVolUpDown = param; else param = chn.nOldFineVolUpDown; } if(chn.isFirstTick) { chn.nVolume += param * 4; if(chn.nVolume > 256) chn.nVolume = 256; if(GetType() & MOD_TYPE_MOD) chn.dwFlags.set(CHN_FASTVOLRAMP); } } void CSoundFile::FineVolumeDown(ModChannel &chn, ModCommand::PARAM param, bool volCol) const { if(GetType() == MOD_TYPE_XM) { // FT2 compatibility: EAx / EBx memory is not linked // Test case: FineVol-LinkMem.xm if(param) chn.nOldFineVolUpDown = param | (chn.nOldFineVolUpDown & 0xF0); else param = (chn.nOldFineVolUpDown & 0x0F); } else if(volCol) { if(param) chn.nOldVolParam = param; else param = chn.nOldVolParam; } else { if(param) chn.nOldFineVolUpDown = param; else param = chn.nOldFineVolUpDown; } if(chn.isFirstTick) { chn.nVolume -= param * 4; if(chn.nVolume < 0) chn.nVolume = 0; if(GetType() & MOD_TYPE_MOD) chn.dwFlags.set(CHN_FASTVOLRAMP); } } void CSoundFile::Tremolo(ModChannel &chn, uint32 param) const { if (param & 0x0F) chn.nTremoloDepth = (param & 0x0F) << 2; if (param & 0xF0) chn.nTremoloSpeed = (param >> 4) & 0x0F; if(m_SongFlags[SONG_AUTO_TREMOLO]) chn.autoSlide.SetActive(AutoSlideCommand::Tremolo, (param & 0x0F) != 0); else chn.dwFlags.set(CHN_TREMOLO); } void CSoundFile::ChannelVolSlide(ModChannel &chn, ModCommand::PARAM param) const { int32 nChnSlide = 0; if (param) chn.nOldChnVolSlide = param; else param = chn.nOldChnVolSlide; if (((param & 0x0F) == 0x0F) && (param & 0xF0)) { if(m_PlayState.m_flags[SONG_FIRSTTICK]) nChnSlide = param >> 4; } else if (((param & 0xF0) == 0xF0) && (param & 0x0F)) { if(m_PlayState.m_flags[SONG_FIRSTTICK]) nChnSlide = - (int)(param & 0x0F); } else { if(!m_PlayState.m_flags[SONG_FIRSTTICK]) { if (param & 0x0F) { if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_J2B | MOD_TYPE_DBM)) || (param & 0xF0) == 0) nChnSlide = -(int)(param & 0x0F); } else { nChnSlide = (int)((param & 0xF0) >> 4); } } } if (nChnSlide) { nChnSlide += chn.nGlobalVol; Limit(nChnSlide, 0, 64); chn.nGlobalVol = static_cast(nChnSlide); } } void CSoundFile::ChannelVolumeDownWithDuration(ModChannel &chn, uint16 param) const { if(param != uint16_max) { // Prepare slide chn.autoSlide.SetActive(AutoSlideCommand::VolumeDownWithDuration, param != 0); if(param == 0) { chn.nGlobalVol = 0; return; } chn.volSlideDownStart = chn.nGlobalVol; chn.volSlideDownTotal = chn.volSlideDownRemain = mpt::saturate_cast(param * m_PlayState.m_nMusicSpeed); } else if(chn.volSlideDownTotal) { // Run slide if(chn.volSlideDownRemain) chn.nGlobalVol = static_cast(Util::muldivr(chn.volSlideDownStart, --chn.volSlideDownRemain, chn.volSlideDownTotal)); else chn.nGlobalVol = 0; } } void CSoundFile::ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param) { ModChannel &chn = m_PlayState.Chn[nChn]; uint8 command = param & 0xF0; param &= 0x0F; switch(command) { // E0x: Set Filter case 0x00: for(CHANNELINDEX channel = 0; channel < GetNumChannels(); channel++) { m_PlayState.Chn[channel].dwFlags.set(CHN_AMIGAFILTER, !(param & 1)); } break; // E1x: Fine Portamento Up case 0x10: if(param || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) { FinePortamentoUp(chn, param); if(!m_playBehaviour[kPluginIgnoreTonePortamento]) MidiPortamento(nChn, 0xF0 | param, true); } break; // E2x: Fine Portamento Down case 0x20: if(param || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) { FinePortamentoDown(chn, param); if(!m_playBehaviour[kPluginIgnoreTonePortamento]) MidiPortamento(nChn, -static_cast(0xF0 | param), true); } break; // E3x: Set Glissando Control case 0x30: chn.dwFlags.set(CHN_GLISSANDO, param != 0); break; // E4x: Set Vibrato WaveForm case 0x40: chn.nVibratoType = param & 0x07; break; // E5x: Set FineTune case 0x50: if(!m_PlayState.m_flags[SONG_FIRSTTICK]) break; if(GetType() & (MOD_TYPE_MOD | MOD_TYPE_DIGI | MOD_TYPE_AMF0 | MOD_TYPE_MED)) { chn.nFineTune = MOD2XMFineTune(param); if(chn.nPeriod && chn.rowCommand.IsNote()) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed); } else if(GetType() == MOD_TYPE_MTM) { if(chn.rowCommand.IsNote() && chn.pModSample != nullptr) { // Effect is permanent in MultiTracker const_cast(chn.pModSample)->nFineTune = param; chn.nFineTune = param; if(chn.nPeriod) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed); } } else if(chn.rowCommand.IsNote()) { chn.nFineTune = MOD2XMFineTune(param - 8); if(chn.nPeriod) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed); } break; // E6x: Pattern Loop case 0x60: if(m_PlayState.m_flags[SONG_FIRSTTICK]) PatternLoop(m_PlayState, nChn, param & 0x0F); break; // E7x: Set Tremolo WaveForm case 0x70: chn.nTremoloType = param & 0x07; break; // E8x: Set 4-bit Panning case 0x80: if(m_PlayState.m_flags[SONG_FIRSTTICK]) { Panning(chn, param, Pan4bit); } break; // E9x: Retrig case 0x90: RetrigNote(nChn, param); break; // EAx: Fine Volume Up case 0xA0: if ((param) || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeUp(chn, param, false); break; // EBx: Fine Volume Down case 0xB0: if ((param) || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeDown(chn, param, false); break; // ECx: Note Cut case 0xC0: NoteCut(nChn, param, false); break; // EDx: Note Delay // EEx: Pattern Delay case 0xF0: if(GetType() == MOD_TYPE_MOD) // MOD: Invert Loop { chn.nEFxSpeed = param; if(m_PlayState.m_flags[SONG_FIRSTTICK]) InvertLoop(chn); } else // XM: Set Active Midi Macro { chn.nActiveMacro = param; } break; } } void CSoundFile::ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param) { ModChannel &chn = m_PlayState.Chn[nChn]; uint8 command = param & 0xF0; param &= 0x0F; switch(command) { // S0x: Set Filter // S1x: Set Glissando Control case 0x10: chn.dwFlags.set(CHN_GLISSANDO, param != 0); break; // S2x: Set FineTune case 0x20: if(!m_PlayState.m_flags[SONG_FIRSTTICK]) break; if(chn.HasCustomTuning()) { chn.nFineTune = param - 8; chn.m_CalculateFreq = true; } else if(GetType() != MOD_TYPE_669) { chn.nC5Speed = S3MFineTuneTable[param]; chn.nFineTune = MOD2XMFineTune(param); if(chn.nPeriod) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed); } else if(chn.pModSample != nullptr) { chn.nC5Speed = chn.pModSample->nC5Speed + param * 80; } break; // S3x: Set Vibrato Waveform case 0x30: if(GetType() == MOD_TYPE_S3M) { chn.nVibratoType = param & 0x03; } else { // IT compatibility: Ignore waveform types > 3 if(m_playBehaviour[kITVibratoTremoloPanbrello]) chn.nVibratoType = (param < 0x04) ? param : 0; else chn.nVibratoType = param & 0x07; } break; // S4x: Set Tremolo Waveform case 0x40: if(GetType() == MOD_TYPE_S3M) { chn.nTremoloType = param & 0x03; } else { // IT compatibility: Ignore waveform types > 3 if(m_playBehaviour[kITVibratoTremoloPanbrello]) chn.nTremoloType = (param < 0x04) ? param : 0; else chn.nTremoloType = param & 0x07; } break; // S5x: Set Panbrello Waveform case 0x50: // IT compatibility: Ignore waveform types > 3 if(m_playBehaviour[kITVibratoTremoloPanbrello]) { chn.nPanbrelloType = (param < 0x04) ? param : 0; chn.nPanbrelloPos = 0; } else { chn.nPanbrelloType = param & 0x07; } break; // S6x: Pattern Delay for x frames case 0x60: if(m_PlayState.m_flags[SONG_FIRSTTICK] && m_PlayState.m_nTickCount == 0) { // Tick delays are added up. // Scream Tracker 3 does actually not support this command. // We'll use the same behaviour as for Impulse Tracker, as we can assume that // most S3Ms that make use of this command were made with Impulse Tracker. // MPT added this command to the XM format through the X6x effect, so we will use // the same behaviour here as well. // Test cases: PatternDelays.it, PatternDelays.s3m, PatternDelays.xm m_PlayState.m_nFrameDelay += param; } break; // S7x: Envelope Control / Instrument Control case 0x70: if(!m_PlayState.m_flags[SONG_FIRSTTICK]) break; switch(param) { case 0: case 1: case 2: { for(CHANNELINDEX i = GetNumChannels(); i < m_PlayState.Chn.size(); i++) { ModChannel &bkChn = m_PlayState.Chn[i]; if (bkChn.nMasterChn == nChn + 1) { if (param == 1) { KeyOff(bkChn); if(bkChn.dwFlags[CHN_ADLIB] && m_opl) m_opl->NoteOff(i); } else if (param == 2) { bkChn.dwFlags.set(CHN_NOTEFADE); if(bkChn.dwFlags[CHN_ADLIB] && m_opl) m_opl->NoteOff(i); } else { bkChn.dwFlags.set(CHN_NOTEFADE); bkChn.nFadeOutVol = 0; if(bkChn.dwFlags[CHN_ADLIB] && m_opl) m_opl->NoteCut(i); } #ifndef NO_PLUGINS const ModInstrument *pIns = bkChn.pModInstrument; IMixPlugin *pPlugin; if(pIns != nullptr && pIns->nMixPlug && (pPlugin = m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin) != nullptr) { pPlugin->MidiCommand(*pIns, bkChn.nNote | IMixPlugin::MIDI_NOTE_OFF, 0, m_playBehaviour[kLegacyPluginNNABehaviour] ? nChn : i); } #endif // NO_PLUGINS } } } break; default: // S73-S7E chn.InstrumentControl(param, *this); break; } break; // S8x: Set 4-bit Panning case 0x80: if(m_PlayState.m_flags[SONG_FIRSTTICK]) { Panning(chn, param, Pan4bit); } break; // S9x: Sound Control case 0x90: if(m_PlayState.m_flags[SONG_FIRSTTICK]) { ExtendedChannelEffect(chn, param, m_PlayState); break; } break; // SAx: Set 64k Offset case 0xA0: if(m_PlayState.m_flags[SONG_FIRSTTICK]) { chn.nOldHiOffset = static_cast(param); if (!m_playBehaviour[kITHighOffsetNoRetrig] && chn.rowCommand.IsNote()) { SmpLength pos = param << 16; if (pos < chn.nLength) chn.position.SetInt(pos); } } break; // SBx: Pattern Loop case 0xB0: if(m_PlayState.m_flags[SONG_FIRSTTICK]) PatternLoop(m_PlayState, nChn, param & 0x0F); break; // SCx: Note Cut case 0xC0: if(param == 0) { //IT compatibility 22. SC0 == SC1 if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) param = 1; // ST3 doesn't cut notes with SC0 else if(GetType() == MOD_TYPE_S3M) return; } // S3M/IT compatibility: Note Cut really cuts notes and does not just mute them (so that following volume commands could restore the sample) // Test case: scx.it NoteCut(nChn, param, m_playBehaviour[kITSCxStopsSample] || GetType() == MOD_TYPE_S3M); break; // SDx: Note Delay // SEx: Pattern Delay for x rows // SFx: S3M: Not used, IT: Set Active Midi Macro case 0xF0: if(GetType() != MOD_TYPE_S3M) { chn.nActiveMacro = static_cast(param); } break; } } void CSoundFile::ExtendedChannelEffect(ModChannel &chn, uint32 param, PlayState &playState) const { // S9x and X9x commands (S3M/XM/IT only) switch(param & 0x0F) { // S90: Surround Off case 0x00: chn.dwFlags.reset(CHN_SURROUND); break; // S91: Surround On case 0x01: chn.dwFlags.set(CHN_SURROUND); chn.nPan = 128; break; //////////////////////////////////////////////////////////// // ModPlug Extensions // S98: Reverb Off case 0x08: chn.dwFlags.reset(CHN_REVERB); chn.dwFlags.set(CHN_NOREVERB); break; // S99: Reverb On case 0x09: chn.dwFlags.reset(CHN_NOREVERB); chn.dwFlags.set(CHN_REVERB); break; // S9A: 2-Channels surround mode case 0x0A: playState.m_flags.reset(SONG_SURROUNDPAN); break; // S9B: 4-Channels surround mode case 0x0B: playState.m_flags.set(SONG_SURROUNDPAN); break; // S9C: IT Filter Mode case 0x0C: playState.m_flags.reset(SONG_MPTFILTERMODE); break; // S9D: MPT Filter Mode case 0x0D: playState.m_flags.set(SONG_MPTFILTERMODE); break; // S9E: Go forward case 0x0E: chn.dwFlags.reset(CHN_PINGPONGFLAG); break; // S9F: Go backward (and set playback position to the end if sample just started) case 0x0F: if(chn.position.IsZero() && chn.nLength && (chn.rowCommand.IsNote() || !chn.dwFlags[CHN_LOOP])) { chn.position.Set(chn.nLength - 1, SamplePosition::fractMax); } chn.dwFlags.set(CHN_PINGPONGFLAG); break; } } void CSoundFile::InvertLoop(ModChannel &chn) { // EFx implementation for MOD files (PT 1.1A and up: Invert Loop) // This effect trashes samples. Thanks to 8bitbubsy for making this work. :) if(GetType() != MOD_TYPE_MOD || chn.nEFxSpeed == 0) return; ModSample *pModSample = const_cast(chn.pModSample); if(pModSample == nullptr || !pModSample->HasSampleData() || !pModSample->uFlags[CHN_LOOP | CHN_SUSTAINLOOP]) return; chn.nEFxDelay += ModEFxTable[chn.nEFxSpeed & 0x0F]; if(chn.nEFxDelay < 128) return; chn.nEFxDelay = 0; const SmpLength loopStart = pModSample->uFlags[CHN_LOOP] ? pModSample->nLoopStart : pModSample->nSustainStart; const SmpLength loopEnd = pModSample->uFlags[CHN_LOOP] ? pModSample->nLoopEnd : pModSample->nSustainEnd; if(++chn.nEFxOffset >= loopEnd - loopStart) chn.nEFxOffset = 0; // TRASH IT!!! (Yes, the sample!) const uint8 bps = pModSample->GetBytesPerSample(); uint8 *begin = mpt::byte_cast(pModSample->sampleb()) + (loopStart + chn.nEFxOffset) * bps; for(auto &sample : mpt::as_span(begin, bps)) { sample = ~sample; } pModSample->PrecomputeLoops(*this, false); } // Process a MIDI Macro. // Parameters: // playState: The playback state to operate on. // nChn: Mod channel to apply macro on // isSmooth: If true, internal macros are interpolated between two rows // macro: MIDI Macro string to process // param: Parameter for parametric macros (Zxx / \xx parameter) // plugin: Plugin to send MIDI message to (if not specified but needed, it is autodetected) void CSoundFile::ProcessMIDIMacro(PlayState &playState, CHANNELINDEX nChn, bool isSmooth, const MIDIMacroConfigData::Macro ¯o, uint8 param, PLUGINDEX plugin) { playState.m_midiMacroScratchSpace.resize(macro.Length() + 1); MIDIMacroParser parser{*this, &playState, nChn, isSmooth, macro, mpt::as_span(playState.m_midiMacroScratchSpace), param, plugin}; mpt::span midiMsg; while(parser.NextMessage(midiMsg)) { SendMIDIData(playState, nChn, isSmooth, midiMsg, plugin); } } // Calculate smooth MIDI macro slide parameter for current tick. float CSoundFile::CalculateSmoothParamChange(const PlayState &playState, float currentValue, float param) { MPT_ASSERT(playState.TicksOnRow() > playState.m_nTickCount); const uint32 ticksLeft = playState.TicksOnRow() - playState.m_nTickCount; if(ticksLeft > 1) { // Slide param const float step = (param - currentValue) / static_cast(ticksLeft); return (currentValue + step); } else { // On last tick, set exact value. return param; } } // Process exactly one MIDI message parsed by ProcessMIDIMacro. Returns bytes sent on success, 0 on (parse) failure. void CSoundFile::SendMIDIData(PlayState &playState, CHANNELINDEX nChn, bool isSmooth, const mpt::span macro, PLUGINDEX plugin) { if(macro.size() < 1) return; // Don't do anything that modifies state outside of the playState itself. const bool localOnly = playState.m_midiMacroEvaluationResults.has_value(); if(macro[0] == 0xFA || macro[0] == 0xFC || macro[0] == 0xFF) { // Start Song, Stop Song, MIDI Reset - both interpreted internally and sent to plugins for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { playState.Chn[chn].nCutOff = 0x7F; playState.Chn[chn].nResonance = 0x00; } } ModChannel &chn = playState.Chn[nChn]; if(macro.size() == 4 && macro[0] == 0xF0 && (macro[1] == 0xF0 || macro[1] == 0xF1)) { // Internal device. const bool isExtended = (macro[1] == 0xF1); const uint8 macroCode = macro[2]; const uint8 param = macro[3]; if(macroCode == 0x00 && !isExtended && param < 0x80) { // F0.F0.00.xx: Set CutOff if(!isSmooth) chn.nCutOff = param; else chn.nCutOff = mpt::saturate_round(CalculateSmoothParamChange(playState, chn.nCutOff, param)); chn.nRestoreCutoffOnNewNote = 0; int cutoff = SetupChannelFilter(chn, !chn.dwFlags[CHN_FILTER]); if(cutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl && !localOnly) { // Cutoff doubles as modulator intensity for FM instruments m_opl->Volume(nChn, static_cast(cutoff / 4), true); } } else if(macroCode == 0x01 && !isExtended && param < 0x80) { // F0.F0.01.xx: Set Resonance if(!isSmooth) chn.nResonance = param; else chn.nResonance = mpt::saturate_round(CalculateSmoothParamChange(playState, chn.nResonance, param)); chn.nRestoreResonanceOnNewNote = 0; SetupChannelFilter(chn, !chn.dwFlags[CHN_FILTER]); } else if(macroCode == 0x02 && !isExtended) { // F0.F0.02.xx: Set filter mode (high nibble determines filter mode) if(param < 0x20) { chn.nFilterMode = static_cast(param >> 4); SetupChannelFilter(chn, !chn.dwFlags[CHN_FILTER]); } #ifndef NO_PLUGINS } else if(macroCode == 0x03 && !isExtended) { // F0.F0.03.xx: Set plug dry/wet PLUGINDEX plug = (plugin != 0) ? plugin : GetBestPlugin(chn, nChn, PrioritiseChannel, EvenIfMuted); if(plug > 0 && plug <= MAX_MIXPLUGINS && param < 0x80) { plug--; if(IMixPlugin* pPlugin = m_MixPlugins[plug].pMixPlugin; pPlugin) { const float newRatio = (127 - param) / 127.0f; if(localOnly) playState.m_midiMacroEvaluationResults->pluginDryWetRatio[plug] = newRatio; else if(!isSmooth) pPlugin->SetDryRatio(newRatio); else pPlugin->SetDryRatio(CalculateSmoothParamChange(playState, m_MixPlugins[plug].fDryRatio, newRatio)); } } } else if((macroCode & 0x80) || isExtended) { // F0.F0.{80|n}.xx / F0.F1.n.xx: Set VST effect parameter n to xx PLUGINDEX plug = (plugin != 0) ? plugin : GetBestPlugin(chn, nChn, PrioritiseChannel, EvenIfMuted); if(plug > 0 && plug <= MAX_MIXPLUGINS && param < 0x80) { plug--; if(IMixPlugin *pPlugin = m_MixPlugins[plug].pMixPlugin; pPlugin) { const PlugParamIndex plugParam = isExtended ? (0x80 + macroCode) : (macroCode & 0x7F); const PlugParamValue value = param / 127.0f; if(localOnly) playState.m_midiMacroEvaluationResults->pluginParameter[{plug, plugParam}] = value; else if(!isSmooth) pPlugin->SetParameter(plugParam, value, &playState, nChn); else pPlugin->SetParameter(plugParam, CalculateSmoothParamChange(playState, pPlugin->GetParameter(plugParam), value), &playState, nChn); } } #endif // NO_PLUGINS } } else if(!localOnly) { #ifndef NO_PLUGINS // Not an internal device. Pass on to appropriate plugin. const CHANNELINDEX plugChannel = (nChn < GetNumChannels()) ? nChn + 1 : chn.nMasterChn; if(plugChannel > 0 && plugChannel <= GetNumChannels()) // XXX do we need this? I guess it might be relevant for previewing notes in the pattern... Or when using this mechanism for volume/panning! { PLUGINDEX plug = 0; if(!chn.dwFlags[CHN_NOFX]) { plug = (plugin != 0) ? plugin : GetBestPlugin(chn, nChn, PrioritiseChannel, EvenIfMuted); } if(plug > 0 && plug <= MAX_MIXPLUGINS) { if(IMixPlugin *pPlugin = m_MixPlugins[plug - 1].pMixPlugin; pPlugin != nullptr) { pPlugin->MidiSend(mpt::byte_cast(macro)); } } } #else MPT_UNREFERENCED_PARAMETER(plugin); #endif // NO_PLUGINS } } void CSoundFile::SendMIDINote(CHANNELINDEX chn, uint16 note, uint16 volume, IMixPlugin *plugin) { #ifndef NO_PLUGINS auto &channel = m_PlayState.Chn[chn]; const ModInstrument *pIns = channel.pModInstrument; // instro sends to a midi chan if(pIns && pIns->HasValidMIDIChannel()) { if(plugin == nullptr && pIns->nMixPlug > 0 && pIns->nMixPlug <= MAX_MIXPLUGINS) plugin = m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin; if(plugin != nullptr) { plugin->MidiCommand(*pIns, note, volume, chn); if(note < NOTE_MIN_SPECIAL) channel.nLeftVU = channel.nRightVU = 0xFF; } } #endif // NO_PLUGINS } void CSoundFile::ProcessSampleOffset(ModChannel &chn, CHANNELINDEX nChn, const PlayState &playState) const { const ModCommand &m = chn.rowCommand; uint32 extendedRows = 0; SmpLength offset = CalculateXParam(playState.m_nPattern, playState.m_nRow, nChn, &extendedRows), highOffset = 0; if(!extendedRows) { // No X-param (normal behaviour) const bool isPercentageOffset = (m.volcmd == VOLCMD_OFFSET && m.vol == 0); offset <<= 8; // FT2 compatibility: 9xx command without a note next to it does not update effect memory. // Test case: OffsetWithoutNote.xm if(offset && (!m_playBehaviour[kFT2OffsetMemoryRequiresNote] || m.IsNote())) chn.oldOffset = offset; else if(m.volcmd != VOLCMD_OFFSET) offset = chn.oldOffset; if(!isPercentageOffset) highOffset = static_cast(chn.nOldHiOffset) << 16; } if(m.volcmd == VOLCMD_OFFSET) { if(m.vol == 0) offset = Util::muldivr_unsigned(chn.nLength, offset, 256u << (8u * std::max(uint32(1), extendedRows))); // o00 + Oxx = Percentage Offset else if(m.vol <= std::size(ModSample().cues) && chn.pModSample != nullptr && !chn.pModSample->uFlags[CHN_ADLIB]) offset += chn.pModSample->cues[m.vol - 1]; // Offset relative to cue point chn.oldOffset = offset; } SampleOffset(chn, offset + highOffset); } void CSoundFile::SampleOffset(ModChannel &chn, SmpLength param) const { // ST3 compatibility: Instrument-less note recalls previous note's offset // Test case: OxxMemory.s3m if(m_playBehaviour[kST3OffsetWithoutInstrument] || GetType() == MOD_TYPE_MED) chn.prevNoteOffset = 0; chn.prevNoteOffset += param; if(param >= chn.nLoopEnd && (GetType() & (MOD_TYPE_S3M | MOD_TYPE_MTM)) && chn.dwFlags[CHN_LOOP] && chn.nLoopEnd > 0) { // Offset wrap-around // Note that ST3 only does this in GUS mode. SoundBlaster stops the sample entirely instead. // Test case: OffsetLoopWraparound.s3m param = (param - chn.nLoopStart) % (chn.nLoopEnd - chn.nLoopStart) + chn.nLoopStart; } if((GetType() & (MOD_TYPE_MDL | MOD_TYPE_PTM)) && chn.dwFlags[CHN_16BIT]) { // Digitrakker and Polytracker use byte offsets, not sample offsets. param /= 2u; } // IT compatibility: Offset with instrument number but note note recalls previous note and executes offset. // Test case: OffsetWithInstr.it const auto note = (m_playBehaviour[kITOffsetWithInstrNumber] && chn.rowCommand.instr) ? chn.nNewNote : chn.rowCommand.note; if(ModCommand::IsNote(note) || m_playBehaviour[kApplyOffsetWithoutNote]) { // IT compatibility: If this note is not mapped to a sample, ignore it. // Test case: empty_sample_offset.it if(chn.pModInstrument != nullptr && ModCommand::IsNote(note)) { SAMPLEINDEX smp = chn.pModInstrument->Keyboard[note - NOTE_MIN]; if(smp == 0 || smp > GetNumSamples()) return; } if(m_SongFlags[SONG_PT_MODE]) { // ProTracker compatibility: PT1/2-style funky 9xx offset command // Test case: ptoffset.mod chn.position.Set(chn.prevNoteOffset); chn.prevNoteOffset += param; } else { chn.position.Set(param); } if (chn.position.GetUInt() >= chn.nLength || (chn.dwFlags[CHN_LOOP] && chn.position.GetUInt() >= chn.nLoopEnd)) { // Offset beyond sample size if(m_playBehaviour[kFT2ST3OffsetOutOfRange] || GetType() == MOD_TYPE_MTM) { // FT2 Compatibility: Don't play note if offset is beyond sample length // ST3 Compatibility: Don't play note if offset is beyond sample length (non-looped samples only) // Test cases: 3xx-no-old-samp.xm, OffsetPastSampleEnd.s3m chn.dwFlags.set(CHN_FASTVOLRAMP); chn.nPeriod = 0; } else if(!(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MOD))) { // IT Compatibility: Offset if(m_playBehaviour[kITOffset]) { if(m_SongFlags[SONG_ITOLDEFFECTS]) chn.position.Set(chn.nLength); // Old FX: Clip to end of sample else chn.position.Set(0); // Reset to beginning of sample } else { chn.position.Set(chn.nLoopStart); if(m_SongFlags[SONG_ITOLDEFFECTS] && chn.nLength > 4) { chn.position.Set(chn.nLength - 2); } } } else if(GetType() == MOD_TYPE_MOD && chn.dwFlags[CHN_LOOP]) { chn.position.Set(chn.nLoopStart); } } } else if ((param < chn.nLength) && (GetType() & (MOD_TYPE_MTM | MOD_TYPE_DMF | MOD_TYPE_MDL | MOD_TYPE_PLM))) { // Some trackers can also call offset effects without notes next to them... chn.position.Set(param); } } void CSoundFile::ReverseSampleOffset(ModChannel &chn, ModCommand::PARAM param) const { if(chn.pModSample != nullptr && chn.pModSample->nLength > 0) { chn.dwFlags.set(CHN_PINGPONGFLAG); chn.dwFlags.reset(CHN_LOOP); chn.nLength = chn.pModSample->nLength; // If there was a loop, extend sample to whole length. SmpLength offset = param << 8; if(GetType() == MOD_TYPE_PTM && chn.dwFlags[CHN_16BIT]) offset /= 2; chn.position.Set((chn.nLength - 1) - std::min(offset, chn.nLength - SmpLength(1)), 0); } } void CSoundFile::DigiBoosterSampleReverse(ModChannel &chn, ModCommand::PARAM param) const { if(chn.isFirstTick && chn.pModSample != nullptr && chn.pModSample->nLength > 0) { chn.dwFlags.set(CHN_PINGPONGFLAG); chn.nLength = chn.pModSample->nLength; // If there was a loop, extend sample to whole length. chn.position.Set(chn.nLength - 1, 0); chn.dwFlags.set(CHN_LOOP | CHN_PINGPONGLOOP, param > 0); if(param > 0) { chn.nLoopStart = 0; chn.nLoopEnd = chn.nLength; // TODO: When the sample starts playing in forward direction again, the loop should be updated to the normal sample loop. } } } void CSoundFile::HandleDigiSamplePlayDirection(PlayState &state, CHANNELINDEX chn) const { // Digi Booster mixes two channels into one Paula channel, and when a note is triggered on one of them it resets the reverse play flag on the other. if(GetType() == MOD_TYPE_DIGI) { state.Chn[chn].dwFlags.reset(CHN_PINGPONGFLAG); const CHANNELINDEX otherChn = chn ^ 1; if(otherChn < GetNumChannels()) state.Chn[otherChn].dwFlags.reset(CHN_PINGPONGFLAG); } } void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset) { // Retrig: bit 8 is set if it's the new XM retrig ModChannel &chn = m_PlayState.Chn[nChn]; int retrigSpeed = param & 0x0F; uint8 retrigCount = chn.nRetrigCount; bool doRetrig = false; // IT compatibility 15. Retrigger if(m_playBehaviour[kITRetrigger]) { if(m_PlayState.m_nTickCount == 0 && chn.rowCommand.note) { chn.nRetrigCount = param & 0x0F; } else if(!chn.nRetrigCount || !--chn.nRetrigCount) { chn.nRetrigCount = param & 0x0F; doRetrig = true; } } else if(m_playBehaviour[kFT2Retrigger] && (param & 0x100)) { // Buggy-like-hell FT2 Rxy retrig! // Test case: retrig.xm if(m_PlayState.m_flags[SONG_FIRSTTICK]) { // Here are some really stupid things FT2 does on the first tick. // Test case: RetrigTick0.xm if(chn.rowCommand.instr > 0 && chn.rowCommand.IsNoteOrEmpty()) retrigCount = 1; if(chn.rowCommand.volcmd == VOLCMD_VOLUME && chn.rowCommand.vol != 0) { // I guess this condition simply checked if the volume byte was != 0 in FT2. chn.nRetrigCount = retrigCount; return; } } if(retrigCount >= retrigSpeed) { if(!m_PlayState.m_flags[SONG_FIRSTTICK] || !chn.rowCommand.IsNote()) { doRetrig = true; retrigCount = 0; } } } else { // old routines if (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT)) { if(!retrigSpeed) retrigSpeed = 1; if(retrigCount && !(retrigCount % retrigSpeed)) doRetrig = true; retrigCount++; } else if(GetType() == MOD_TYPE_MOD) { // ProTracker-style retrigger // Test case: PTRetrigger.mod const auto tick = m_PlayState.m_nTickCount % m_PlayState.m_nMusicSpeed; if(!tick && chn.rowCommand.IsNote()) return; if(retrigSpeed && !(tick % retrigSpeed)) doRetrig = true; } else if(GetType() == MOD_TYPE_MTM) { // In MultiTracker, E9x retriggers the last note at exactly the x-th tick of the row doRetrig = m_PlayState.m_nTickCount == static_cast(param & 0x0F) && retrigSpeed != 0; } else { int realspeed = retrigSpeed; // FT2 bug: if a retrig (Rxy) occurs together with a volume command, the first retrig interval is increased by one tick if((param & 0x100) && (chn.rowCommand.volcmd == VOLCMD_VOLUME) && (chn.rowCommand.param & 0xF0)) realspeed++; if(!m_PlayState.m_flags[SONG_FIRSTTICK] || (param & 0x100)) { if(!realspeed) realspeed = 1; if(!(param & 0x100) && m_PlayState.m_nMusicSpeed && !(m_PlayState.m_nTickCount % realspeed)) doRetrig = true; retrigCount++; } else if(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)) retrigCount = 0; if (retrigCount >= realspeed) { if(m_PlayState.m_nTickCount || ((param & 0x100) && !chn.rowCommand.note)) doRetrig = true; } if(m_playBehaviour[kFT2Retrigger] && param == 0) { // E90 = Retrig instantly, and only once doRetrig = (m_PlayState.m_nTickCount == 0); } } } // IT compatibility: If a sample is shorter than the retrig time (i.e. it stops before the retrig counter hits zero), it is not retriggered. // Test case: retrig-short.it if(chn.nLength == 0 && m_playBehaviour[kITShortSampleRetrig] && !chn.HasMIDIOutput()) return; // ST3 compatibility: No retrig after Note Cut // Test case: RetrigAfterNoteCut.s3m if(m_playBehaviour[kST3RetrigAfterNoteCut] && !chn.nFadeOutVol) return; if(doRetrig) { uint32 dv = (param >> 4) & 0x0F; int vol = chn.nVolume; if(dv) { // FT2 compatibility: Retrig + volume will not change volume of retrigged notes if(!m_playBehaviour[kFT2Retrigger] || !(chn.rowCommand.volcmd == VOLCMD_VOLUME)) { if(retrigTable1[dv]) vol = (vol * retrigTable1[dv]) / 16; else vol += ((int)retrigTable2[dv]) * 4; } Limit(vol, 0, 256); chn.dwFlags.set(CHN_FASTVOLRAMP); } uint32 note = chn.nNewNote; int32 oldPeriod = chn.nPeriod; // ST3 doesn't retrigger OPL notes // Test case: RetrigSlide.s3m const bool oplRealRetrig = chn.dwFlags[CHN_ADLIB] && m_playBehaviour[kOPLRealRetrig]; if(note >= NOTE_MIN && note <= NOTE_MAX && chn.nLength && (GetType() != MOD_TYPE_S3M || oplRealRetrig)) CheckNNA(nChn, 0, note, true); bool resetEnv = false; if(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)) { if(chn.rowCommand.instr && param < 0x100) { InstrumentChange(chn, chn.rowCommand.instr, false, false); resetEnv = true; } if(param < 0x100) resetEnv = true; } // ProTracker Compatibility: Retrigger with lone instrument number causes instant sample change // Test case: InstrSwapRetrigger.mod if(m_playBehaviour[kMODSampleSwap] && chn.rowCommand.instr) { auto oldFineTune = chn.nFineTune; InstrumentChange(chn, chn.rowCommand.instr, false, false); chn.nFineTune = oldFineTune; } const bool fading = chn.dwFlags[CHN_NOTEFADE]; const auto oldPrevNoteOffset = chn.prevNoteOffset; // Retriggered notes should not use previous offset in S3M // Test cases: OxxMemoryWithRetrig.s3m, PTOffsetRetrigger.mod if(GetType() == MOD_TYPE_S3M) chn.prevNoteOffset = 0; // IT compatibility: Really weird combination of envelopes and retrigger (see Storlek's q.it testcase) // Test cases: retrig.it, RetrigSlide.s3m const bool itS3Mstyle = m_playBehaviour[kITRetrigger] || (GetType() == MOD_TYPE_S3M && chn.nLength && !oplRealRetrig); NoteChange(chn, note, itS3Mstyle, resetEnv, false, nChn); if(!chn.rowCommand.instr) chn.prevNoteOffset = oldPrevNoteOffset; // XM compatibility: Prevent NoteChange from resetting the fade flag in case an instrument number + note-off is present. // Test case: RetrigFade.xm if(fading && GetType() == MOD_TYPE_XM) chn.dwFlags.set(CHN_NOTEFADE); chn.nVolume = vol; if(m_nInstruments) { chn.rowCommand.note = static_cast(note); // No retrig without note... #ifndef NO_PLUGINS ProcessMidiOut(nChn); //Send retrig to Midi #endif // NO_PLUGINS } if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && chn.rowCommand.note == NOTE_NONE && oldPeriod != 0) chn.nPeriod = oldPeriod; if(!(GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT))) retrigCount = 0; // IT compatibility: see previous IT compatibility comment =) if(itS3Mstyle) chn.position.Set(0); offset--; if(chn.pModSample != nullptr && !chn.pModSample->uFlags[CHN_ADLIB] && offset >= 0 && offset <= static_cast(std::size(chn.pModSample->cues))) { if(offset == 0) offset = chn.oldOffset; else offset = chn.oldOffset = chn.pModSample->cues[offset - 1]; SampleOffset(chn, offset); } } // buggy-like-hell FT2 Rxy retrig! if(m_playBehaviour[kFT2Retrigger] && (param & 0x100)) retrigCount++; // Now we can also store the retrig value for IT... if(!m_playBehaviour[kITRetrigger]) chn.nRetrigCount = retrigCount; } // Execute a frequency slide on given channel. // Positive amounts increase the frequency, negative amounts decrease it. // The period or frequency that is read and written is in the period variable, chn.nPeriod is not touched. void CSoundFile::DoFreqSlide(ModChannel &chn, int32 &period, int32 amount, bool isTonePorta) const { if(!period || !amount) return; MPT_ASSERT(!chn.HasCustomTuning()); if(GetType() == MOD_TYPE_669) { // Like other oldskool trackers, Composer 669 doesn't have linear slides... // But the slides are done in Hertz rather than periods, meaning that they // are more effective in the lower notes (rather than the higher notes). period += amount * 20; } else if(GetType() == MOD_TYPE_FAR) { period += (amount * 36318 / 1024); } else if(m_SongFlags[SONG_LINEARSLIDES] && !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD))) { // IT Linear slides const auto oldPeriod = period; uint32 absAmount = std::abs(amount); // Note: IT ignores the lower 2 bits when abs(mount) > 16 (it either uses the fine *or* the regular table, not both) // This means that vibratos are slightly less accurate in this range than they could be. // Other code paths will *either* have an amount that's a multiple of 4 *or* it's less than 16. if(absAmount < 16) { if(amount > 0) period = Util::muldivr(period, GetFineLinearSlideUpTable(this, absAmount), 65536); else period = Util::muldivr(period, GetFineLinearSlideDownTable(this, absAmount), 65536); } else { absAmount /= 4u; while(absAmount > 0) { const uint32 n = std::min(absAmount, static_cast(std::size(LinearSlideUpTable) - 1)); if(amount > 0) period = Util::muldivr(period, GetLinearSlideUpTable(this, n), 65536); else period = Util::muldivr(period, GetLinearSlideDownTable(this, n), 65536); absAmount -= n; } } if(period == oldPeriod) { const bool incPeriod = m_playBehaviour[kPeriodsAreHertz] == (amount > 0); if(incPeriod && period < Util::MaxValueOfType(period)) period++; else if(!incPeriod && period > 1) period--; } } else if(!m_SongFlags[SONG_LINEARSLIDES] && m_playBehaviour[kPeriodsAreHertz]) { // IT Amiga slides if(amount < 0) { // Go down period = mpt::saturate_cast(Util::mul32to64_unsigned(1712 * 8363, period) / (Util::mul32to64_unsigned(period, -amount) + 1712 * 8363)); } else if(amount > 0) { // Go up const auto periodDiv = 1712 * 8363 - Util::mul32to64(period, amount); if(periodDiv <= 0) { if(isTonePorta) { period = int32_max; return; } else { period = 0; chn.nFadeOutVol = 0; chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP); } return; } period = mpt::saturate_cast(Util::mul32to64_unsigned(1712 * 8363, period) / periodDiv); } } else { period -= amount; } if(period < 1) { period = 1; if(GetType() == MOD_TYPE_S3M && !isTonePorta) { chn.nFadeOutVol = 0; chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP); } } } void CSoundFile::NoteCut(CHANNELINDEX nChn, uint32 nTick, bool cutSample) { ModChannel &chn = m_PlayState.Chn[nChn]; auto tickCount = m_PlayState.m_nTickCount; // IT compatibility: If there is a note and a tone portamento next to a Note Cut effect, // the Note Cut is not executed - unless there is also a row delay effect and we are on the second repetition of the row. // Test case: SCx-Reset.it if(m_playBehaviour[kITNoteCutWithPorta] && chn.rowCommand.IsNote() && chn.rowCommand.IsTonePortamento()) { const uint32 rowLength = m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay; if(m_PlayState.m_nTickCount < rowLength) return; if(m_PlayState.m_nPatternDelay != 0 && m_PlayState.m_nTickCount >= rowLength) tickCount %= rowLength; } if(tickCount == nTick) { if(cutSample) { // IT compatibility: Picking up a note after a Note Cut effect through a lone instrument number also restores the // original note pitch without any portamento slides, as if there was a note. // Test case: SCx-Reset.it if(m_playBehaviour[kITNoteCutWithPorta]) chn.nPeriod = 0; chn.increment.Set(0); chn.nFadeOutVol = 0; chn.dwFlags.set(CHN_NOTEFADE); } else { chn.nVolume = 0; } chn.dwFlags.set(CHN_FASTVOLRAMP); // instro sends to a midi chan SendMIDINote(nChn, NOTE_KEYOFF, 0); if(chn.dwFlags[CHN_ADLIB] && m_opl) { m_opl->NoteCut(nChn, false); } } } void CSoundFile::KeyOff(ModChannel &chn) const { const bool keyIsOn = !chn.dwFlags[CHN_KEYOFF]; chn.dwFlags.set(CHN_KEYOFF); if(chn.pModInstrument != nullptr && !chn.VolEnv.flags[ENV_ENABLED]) { chn.dwFlags.set(CHN_NOTEFADE); } if (!chn.nLength) return; if (chn.dwFlags[CHN_SUSTAINLOOP] && chn.pModSample && keyIsOn) { const ModSample *pSmp = chn.pModSample; if(pSmp->uFlags[CHN_LOOP]) { if (pSmp->uFlags[CHN_PINGPONGLOOP]) chn.dwFlags.set(CHN_PINGPONGLOOP); else chn.dwFlags.reset(CHN_PINGPONGLOOP | CHN_PINGPONGFLAG); chn.dwFlags.set(CHN_LOOP); chn.nLength = pSmp->nLength; chn.nLoopStart = pSmp->nLoopStart; chn.nLoopEnd = pSmp->nLoopEnd; if (chn.nLength > chn.nLoopEnd) chn.nLength = chn.nLoopEnd; if(chn.position.GetUInt() > chn.nLength) { // Test case: SusAfterLoop.it chn.position.Set(chn.nLoopStart + ((chn.position.GetInt() - chn.nLoopStart) % (chn.nLoopEnd - chn.nLoopStart))); } } else { chn.dwFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP | CHN_PINGPONGFLAG); chn.nLength = pSmp->nLength; } } if (chn.pModInstrument) { const ModInstrument *pIns = chn.pModInstrument; if((pIns->VolEnv.dwFlags[ENV_LOOP] || (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MDL))) && pIns->nFadeOut != 0) { chn.dwFlags.set(CHN_NOTEFADE); } if (pIns->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET && chn.VolEnv.nEnvValueAtReleaseJump == NOT_YET_RELEASED) { chn.VolEnv.nEnvValueAtReleaseJump = mpt::saturate_cast(pIns->VolEnv.GetValueFromPosition(chn.VolEnv.nEnvPosition, 256)); chn.VolEnv.nEnvPosition = pIns->VolEnv[pIns->VolEnv.nReleaseNode].tick; } } } ////////////////////////////////////////////////////////// // CSoundFile: Global Effects void CSoundFile::SetSpeed(PlayState &playState, uint32 param) const { #ifdef MODPLUG_TRACKER // FT2 appears to be decrementing the tick count before checking for zero, // so it effectively counts down 65536 ticks with speed = 0 (song speed is a 16-bit variable in FT2) if(GetType() == MOD_TYPE_XM && !param) { playState.m_nMusicSpeed = uint16_max; } #endif // MODPLUG_TRACKER if(param > 0) playState.m_nMusicSpeed = param; if(GetType() == MOD_TYPE_STM && param > 0) { playState.m_nMusicSpeed = std::max(param >> 4, uint32(1)); playState.m_nMusicTempo = ConvertST2Tempo(static_cast(param)); } } // Convert a ST2 tempo byte to classic tempo and speed combination TEMPO CSoundFile::ConvertST2Tempo(uint8 tempo) { static constexpr uint8 ST2TempoFactor[] = { 140, 50, 25, 15, 10, 7, 6, 4, 3, 3, 2, 2, 2, 2, 1, 1 }; static constexpr uint32 st2MixingRate = 23863; // Highest possible setting in ST2 // This underflows at tempo 06...0F, and the resulting tick lengths depend on the mixing rate. // Note: ST2.3 uses the constant 50 below, earlier versions use 49 but they also play samples at a different speed. int32 samplesPerTick = st2MixingRate / (50 - ((ST2TempoFactor[tempo >> 4u] * (tempo & 0x0F)) >> 4u)); if(samplesPerTick <= 0) samplesPerTick += 65536; return TEMPO().SetRaw(Util::muldivrfloor(st2MixingRate, 5 * TEMPO::fractFact, samplesPerTick * 2)); } void CSoundFile::SetTempo(PlayState &playState, TEMPO param, bool setFromUI) const { const CModSpecifications &specs = GetModSpecifications(); // Anything lower than the minimum tempo is considered to be a tempo slide const TEMPO minTempo = GetMinimumTempoParam(GetType()); TEMPO maxTempo = specs.GetTempoMax(); // MED files may be imported with #xx parameter extension for tempos above 255, but they may be imported as either MOD or XM. // As regular MOD files cannot contain effect #xx, the tempo parameter cannot exceed 255 anyway, so we simply ignore their max tempo in CModSpecifications here. if(!(GetType() & (MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT))) maxTempo = GetModSpecifications(MOD_TYPE_MPT).GetTempoMax(); if(m_playBehaviour[kTempoClamp]) maxTempo.Set(255); if(setFromUI) { // Set tempo from UI - ignore slide commands and such. playState.m_nMusicTempo = Clamp(param, specs.GetTempoMin(), maxTempo); } else if(param >= minTempo && playState.m_flags[SONG_FIRSTTICK] == !m_playBehaviour[kMODTempoOnSecondTick]) { // ProTracker sets the tempo after the first tick. // Note: The case of one tick per row is handled in ProcessRow() instead. // Test case: TempoChange.mod playState.m_nMusicTempo = std::min(param, maxTempo); } else if(param < minTempo && !playState.m_flags[SONG_FIRSTTICK]) { // Tempo Slide TEMPO tempDiff(param.GetInt() & 0x0F, 0); if((param.GetInt() & 0xF0) == 0x10) playState.m_nMusicTempo += tempDiff; else playState.m_nMusicTempo -= tempDiff; TEMPO tempoMin = specs.GetTempoMin(); Limit(playState.m_nMusicTempo, tempoMin, maxTempo); } } void CSoundFile::PatternLoop(PlayState &state, CHANNELINDEX nChn, ModCommand::PARAM param) const { if(m_playBehaviour[kST3NoMutedChannels] && state.Chn[nChn].dwFlags[CHN_MUTE | CHN_SYNCMUTE]) return; // not even effects are processed on muted S3M channels // ST3 doesn't have per-channel pattern loop memory. ModChannel &chn = state.Chn[(GetType() == MOD_TYPE_S3M) ? 0 : nChn]; if(!param) { // Loop Start chn.nPatternLoop = state.m_nRow; return; } // Loop Repeat if(chn.nPatternLoopCount) { // There's a loop left chn.nPatternLoopCount--; if(!chn.nPatternLoopCount) { // IT compatibility 10. Pattern loops (+ same fix for S3M files) // When finishing a pattern loop, the next loop without a dedicated SB0 starts on the first row after the previous loop. if(m_playBehaviour[kITPatternLoopTargetReset] || (GetType() == MOD_TYPE_S3M)) chn.nPatternLoop = state.m_nRow + 1; return; } } else { // First time we get into the loop => Set loop count. // IT compatibility 10. Pattern loops (+ same fix for XM / MOD / S3M files) if(!m_playBehaviour[kITFT2PatternLoop] && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_S3M))) { for(const ModChannel &otherChn : state.PatternChannels(*this)) { // Loop on other channel if(&otherChn != &chn && otherChn.nPatternLoopCount) return; } } chn.nPatternLoopCount = param; } state.m_nextPatStartRow = chn.nPatternLoop; // Nasty FT2 E60 bug emulation! const auto loopTarget = chn.nPatternLoop; if(loopTarget != ROWINDEX_INVALID) { // FT2 compatibility: E6x overwrites jump targets of Dxx effects that are located left of the E6x effect. // Test cases: PatLoop-Jumps.xm, PatLoop-Various.xm if(state.m_breakRow != ROWINDEX_INVALID && m_playBehaviour[kFT2PatternLoopWithJumps]) state.m_breakRow = loopTarget; state.m_patLoopRow = loopTarget; // IT compatibility: SBx is prioritized over Position Jump (Bxx) effects that are located left of the SBx effect. // Test case: sbx-priority.it, LoopBreak.it if(m_playBehaviour[kITPatternLoopWithJumps]) state.m_posJump = ORDERINDEX_INVALID; } } void CSoundFile::GlobalVolSlide(PlayState &playState, ModCommand::PARAM param, CHANNELINDEX chn) const { if(m_SongFlags[SONG_AUTO_GLOBALVOL]) playState.Chn[chn].autoSlide.SetActive(AutoSlideCommand::GlobalVolumeSlide, param != 0); if(param) playState.Chn[chn].nOldGlobalVolSlide = param; else param = playState.Chn[chn].nOldGlobalVolSlide; if((GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) { // XM nibble priority if((param & 0xF0) != 0) { param &= 0xF0; } else { param &= 0x0F; } } int32 nGlbSlide = 0; if (((param & 0x0F) == 0x0F) && (param & 0xF0)) { if(playState.m_flags[SONG_FIRSTTICK]) nGlbSlide = (param >> 4) * 2; } else if (((param & 0xF0) == 0xF0) && (param & 0x0F)) { if(playState.m_flags[SONG_FIRSTTICK]) nGlbSlide = - (int)((param & 0x0F) * 2); } else { if(!playState.m_flags[SONG_FIRSTTICK]) { if (param & 0xF0) { // IT compatibility: Ignore slide commands with both nibbles set. if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_IMF | MOD_TYPE_J2B | MOD_TYPE_MID | MOD_TYPE_AMS | MOD_TYPE_DBM)) || (param & 0x0F) == 0) nGlbSlide = (int)((param & 0xF0) >> 4) * 2; } else { nGlbSlide = -(int)((param & 0x0F) * 2); } } } if (nGlbSlide) { if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_IMF | MOD_TYPE_J2B | MOD_TYPE_MID | MOD_TYPE_AMS | MOD_TYPE_DBM))) nGlbSlide *= 2; nGlbSlide += playState.m_nGlobalVolume; Limit(nGlbSlide, 0, 256); playState.m_nGlobalVolume = nGlbSlide; } } ////////////////////////////////////////////////////// // Note/Period/Frequency functions // Find lowest note which has same or lower period as a given period (i.e. the note has the same or higher frequency) uint32 CSoundFile::GetNoteFromPeriod(uint32 period, int32 nFineTune, uint32 nC5Speed) const { if(!period) return 0; if(m_playBehaviour[kFT2Periods]) { // FT2's "RelocateTon" function actually rounds up and down, while GetNoteFromPeriod normally just truncates. nFineTune += 64; } // This essentially implements std::lower_bound, with the difference that we don't need an iterable container. uint32 minNote = NOTE_MIN, maxNote = NOTE_MAX, count = maxNote - minNote + 1; const bool periodIsFreq = PeriodsAreFrequencies(); while(count > 0) { const uint32 step = count / 2, midNote = minNote + step; uint32 n = GetPeriodFromNote(midNote, nFineTune, nC5Speed); if((n > period && !periodIsFreq) || (n < period && periodIsFreq) || !n) { minNote = midNote + 1; count -= step + 1; } else { count = step; } } return minNote; } uint32 CSoundFile::GetPeriodFromNote(uint32 note, int32 nFineTune, uint32 nC5Speed) const { if (note == NOTE_NONE || (note >= NOTE_MIN_SPECIAL)) return 0; note -= NOTE_MIN; if(!UseFinetuneAndTranspose()) { if(GetType() == MOD_TYPE_MDL) { // MDL uses non-linear slides, but their effectiveness does not depend on the middle-C frequency. MPT_ASSERT(!PeriodsAreFrequencies()); return (FreqS3MTable[note % 12u] << 4) >> (note / 12); } else if(GetType() == MOD_TYPE_DTM) { // Similar to MDL, but finetune is factored in and we don't transpose everything by an octave MPT_ASSERT(!PeriodsAreFrequencies()); return (ProTrackerTunedPeriods[XM2MODFineTune(nFineTune) * 12u + note % 12u] << 5) >> (note / 12u); } if(!nC5Speed) nC5Speed = 8363; if(PeriodsAreFrequencies()) { // Compute everything in Hertz rather than periods. uint32 freq = Util::muldiv_unsigned(nC5Speed, LinearSlideUpTable[(note % 12u) * 16u] << (note / 12u), 65536 << 5); LimitMax(freq, static_cast(int32_max)); return freq; } else if(m_SongFlags[SONG_LINEARSLIDES]) { return (FreqS3MTable[note % 12u] << 5) >> (note / 12); } else { LimitMax(nC5Speed, uint32_max >> (note / 12u)); //(a*b)/c return Util::muldiv_unsigned(8363, (FreqS3MTable[note % 12u] << 5), nC5Speed << (note / 12u)); //8363 * freq[note%12] / nC5Speed * 2^(5-note/12) } } else if((GetType() & (MOD_TYPE_XM | MOD_TYPE_MTM)) || m_SongFlags[SONG_LINEARSLIDES]) { if (note < 12) note = 12; note -= 12; if(GetType() == MOD_TYPE_MTM) { nFineTune *= 16; } else if(m_playBehaviour[kFT2FinetunePrecision]) { // FT2 Compatibility: The lower three bits of the finetune are truncated. // Test case: Finetune-Precision.xm nFineTune &= ~7; } if(m_SongFlags[SONG_LINEARSLIDES]) { int l = ((120 - note) << 6) - (nFineTune / 2); if (l < 1) l = 1; return static_cast(l); } else { int finetune = nFineTune; uint32 rnote = (note % 12) << 3; uint32 roct = note / 12; int rfine = finetune / 16; int i = rnote + rfine + 8; Limit(i , 0, 103); uint32 per1 = XMPeriodTable[i]; if(finetune < 0) { rfine--; finetune = -finetune; } else rfine++; i = rnote+rfine+8; if (i < 0) i = 0; if (i >= 104) i = 103; uint32 per2 = XMPeriodTable[i]; rfine = finetune & 0x0F; per1 *= 16-rfine; per2 *= rfine; return ((per1 + per2) << 1) >> roct; } } else { nFineTune = XM2MODFineTune(nFineTune); if ((nFineTune) || (note < 24) || (note >= 24 + std::size(ProTrackerPeriodTable))) return (ProTrackerTunedPeriods[nFineTune * 12u + note % 12u] << 5) >> (note / 12u); else return (ProTrackerPeriodTable[note - 24] << 2); } } // Converts period value to sample frequency. Return value is fixed point, with FREQ_FRACBITS fractional bits. uint32 CSoundFile::GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPeriodFrac) const { if (!period) return 0; if ((GetType() & (MOD_TYPE_XM | MOD_TYPE_MTM)) || (m_SongFlags[SONG_LINEARSLIDES] && UseFinetuneAndTranspose())) { if(m_playBehaviour[kFT2Periods]) { // FT2 compatibility: Period is a 16-bit value in FT2, and it overflows happily. // Test case: FreqWraparound.xm period &= 0xFFFF; } if(m_SongFlags[SONG_LINEARSLIDES]) { uint32 octave; if(m_playBehaviour[kFT2Periods]) { // Under normal circumstances, this calculation returns the same values as the non-compatible one. // However, once the 12 octaves are exceeded (through portamento slides), the octave shift goes // crazy in FT2, meaning that the frequency wraps around randomly... // The entries in FT2's conversion table are four times as big, hence we have to do an additional shift by two bits. // Test case: FreqWraparound.xm // 12 octaves * (12 * 64) LUT entries = 9216, add 767 for rounding uint32 div = ((9216u + 767u - period) / 768); octave = ((14 - div) & 0x1F); } else { if(period > 29 * 768) return 0; octave = (period / 768) + 2; } return (XMLinearTable[period % 768] << (FREQ_FRACBITS + 2)) >> octave; } else { if(!period) period = 1; return ((8363 * 1712L) << FREQ_FRACBITS) / period; } } else if(UseFinetuneAndTranspose()) { return ((3546895L * 4) << FREQ_FRACBITS) / period; } else if(GetType() == MOD_TYPE_669) { // We only really use c5speed for the finetune pattern command. All samples in 669 files have the same middle-C speed (imported as 8363 Hz). return (period + c5speed - 8363) << FREQ_FRACBITS; } else if(GetType() == MOD_TYPE_MDL) { MPT_ASSERT(!PeriodsAreFrequencies()); LimitMax(period, Util::MaxValueOfType(period) >> 8); if (!c5speed) c5speed = 8363; return Util::muldiv_unsigned(c5speed, (1712L << 7) << FREQ_FRACBITS, (period << 8) + nPeriodFrac); } else { LimitMax(period, Util::MaxValueOfType(period) >> 8); if(PeriodsAreFrequencies()) { // Input is already a frequency in Hertz, not a period. static_assert(FREQ_FRACBITS <= 8, "Check this shift operator"); return uint32(((uint64(period) << 8) + nPeriodFrac) >> (8 - FREQ_FRACBITS)); } else if(m_SongFlags[SONG_LINEARSLIDES] || GetType() == MOD_TYPE_DTM) { if(!c5speed) c5speed = 8363; return Util::muldiv_unsigned(c5speed, (1712L << 8) << FREQ_FRACBITS, (period << 8) + nPeriodFrac); } else { return Util::muldiv_unsigned(8363, (1712L << 8) << FREQ_FRACBITS, (period << 8) + nPeriodFrac); } } } PLUGINDEX CSoundFile::GetBestPlugin(const ModChannel &channel, CHANNELINDEX nChn, PluginPriority priority, PluginMutePriority respectMutes) const { //Define search source order PLUGINDEX plugin = 0; switch(priority) { case ChannelOnly: plugin = GetChannelPlugin(channel, nChn, respectMutes); break; case InstrumentOnly: plugin = GetActiveInstrumentPlugin(channel, respectMutes); break; case PrioritiseInstrument: plugin = GetActiveInstrumentPlugin(channel, respectMutes); if(!plugin || plugin > MAX_MIXPLUGINS) { plugin = GetChannelPlugin(channel, nChn, respectMutes); } break; case PrioritiseChannel: plugin = GetChannelPlugin(channel, nChn, respectMutes); if(!plugin || plugin > MAX_MIXPLUGINS) { plugin = GetActiveInstrumentPlugin(channel, respectMutes); } break; } return plugin; // 0 Means no plugin found. } PLUGINDEX CSoundFile::GetChannelPlugin(const ModChannel &channel, CHANNELINDEX nChn, PluginMutePriority respectMutes) const { PLUGINDEX plugin; if((respectMutes == RespectMutes && channel.dwFlags[CHN_MUTE | CHN_SYNCMUTE]) || channel.dwFlags[CHN_NOFX]) { plugin = 0; } else { // If it looks like this is an NNA channel, we need to find the master channel. // This ensures we pick up the right ChnSettings. if(channel.nMasterChn > 0) nChn = channel.nMasterChn - 1; if(nChn < ChnSettings.size()) plugin = ChnSettings[nChn].nMixPlugin; else plugin = 0; } return plugin; } PLUGINDEX CSoundFile::GetActiveInstrumentPlugin(const ModChannel &chn, PluginMutePriority respectMutes) { // Unlike channel settings, pModInstrument is copied from the original chan to the NNA chan, // so we don't need to worry about finding the master chan. PLUGINDEX plug = 0; if(chn.pModInstrument != nullptr) { if(respectMutes == RespectMutes && chn.pModInstrument->dwFlags[INS_MUTE]) plug = 0; else plug = chn.pModInstrument->nMixPlug; } return plug; } // Retrieve the plugin that is associated with the channel's current instrument. // No plugin is returned if the channel is muted or if the instrument doesn't have a MIDI channel set up, // As this is meant to be used with instrument plugins. IMixPlugin *CSoundFile::GetChannelInstrumentPlugin(const ModChannel &chn) const { #ifndef NO_PLUGINS if(chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE]) { // Don't process portamento on muted channels. Note that this might have a side-effect // on other channels which trigger notes on the same MIDI channel of the same plugin, // as those won't be pitch-bent anymore. return nullptr; } if(chn.HasMIDIOutput()) { const ModInstrument *pIns = chn.pModInstrument; // Instrument sends to a MIDI channel if(pIns->nMixPlug != 0 && pIns->nMixPlug <= MAX_MIXPLUGINS) { return m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin; } } #else MPT_UNREFERENCED_PARAMETER(chn); #endif // NO_PLUGINS return nullptr; } #ifdef MODPLUG_TRACKER void CSoundFile::HandleRowTransitionEvents(bool nextPattern) { bool doTransition = nextPattern; // Jump to another pattern? if(m_PlayState.m_nSeqOverride != ORDERINDEX_INVALID && m_PlayState.m_nSeqOverride < Order().size()) { switch(m_PlayState.m_seqOverrideMode) { case OrderTransitionMode::AtPatternEnd: doTransition = nextPattern; break; case OrderTransitionMode::AtMeasureEnd: if(m_PlayState.m_nCurrentRowsPerMeasure > 0) doTransition = (m_PlayState.m_nRow % m_PlayState.m_nCurrentRowsPerMeasure) == 0; break; case OrderTransitionMode::AtBeatEnd: if(m_PlayState.m_nCurrentRowsPerBeat > 0) doTransition = (m_PlayState.m_nRow % m_PlayState.m_nCurrentRowsPerBeat) == 0; break; case OrderTransitionMode::AtRowEnd: doTransition = true; break; } if(doTransition) { if(m_PlayState.m_flags[SONG_PATTERNLOOP]) m_PlayState.m_nPattern = Order()[m_PlayState.m_nSeqOverride]; m_PlayState.m_nCurrentOrder = m_PlayState.m_nSeqOverride; m_PlayState.m_nSeqOverride = ORDERINDEX_INVALID; } } if(doTransition && GetpModDoc()) { // Update channel mutes for(CHANNELINDEX chan = 0; chan < GetNumChannels(); chan++) { if(m_bChannelMuteTogglePending[chan]) { GetpModDoc()->MuteChannel(chan, !GetpModDoc()->IsChannelMuted(chan)); m_bChannelMuteTogglePending[chan] = false; } } } // Metronome if(IsMetronomeEnabled() && !IsRenderingToDisc() && !m_PlayState.m_flags[SONG_PAUSED | SONG_STEP]) { const ROWINDEX rpm = m_PlayState.m_nCurrentRowsPerMeasure ? m_PlayState.m_nCurrentRowsPerMeasure : DEFAULT_ROWS_PER_MEASURE; const ROWINDEX rpb = m_PlayState.m_nCurrentRowsPerBeat ? m_PlayState.m_nCurrentRowsPerBeat : DEFAULT_ROWS_PER_BEAT; const ModSample *sample = nullptr; if(!m_PlayState.m_lTotalSampleCount || !(m_PlayState.m_nRow % rpm)) sample = m_metronomeMeasure; else if(!(m_PlayState.m_nRow % rpm % rpb)) sample = m_metronomeBeat; if(sample) { m_metronomeChn.pModSample = sample; m_metronomeChn.pCurrentSample = sample->samplev(); m_metronomeChn.dwFlags = (sample->uFlags & CHN_SAMPLEFLAGS) | CHN_NOREVERB; m_metronomeChn.position.Set(0); m_metronomeChn.increment = SamplePosition::Ratio(sample->nC5Speed, m_MixerSettings.gdwMixingFreq); m_metronomeChn.rampLeftVol = m_metronomeChn.rampRightVol = m_metronomeChn.leftVol = m_metronomeChn.rightVol = sample->nVolume * 16; m_metronomeChn.leftRamp = m_metronomeChn.rightRamp = 0; m_metronomeChn.nLength = m_metronomeChn.pModSample->nLength; m_metronomeChn.resamplingMode = m_Resampler.m_Settings.SrcMode; } } else { m_metronomeChn.pCurrentSample = nullptr; } } #endif // MODPLUG_TRACKER void CSoundFile::PortamentoMPT(ModChannel &chn, int param) const { //Behavior: Modifies portamento by param-steps on every tick. //Note that step meaning depends on tuning. chn.m_PortamentoFineSteps += param; chn.m_CalculateFreq = true; } void CSoundFile::PortamentoFineMPT(PlayState &playState, CHANNELINDEX nChn, int param) const { ModChannel &chn = playState.Chn[nChn]; //Behavior: Divides portamento change between ticks/row. For example //if Ticks/row == 6, and param == +-6, portamento goes up/down by one tuning-dependent //fine step every tick. if(playState.m_nTickCount == 0) chn.nOldFinePortaUpDown = 0; const int tickParam = static_cast((playState.m_nTickCount + 1.0) * param / playState.m_nMusicSpeed); chn.m_PortamentoFineSteps += (param >= 0) ? tickParam - chn.nOldFinePortaUpDown : tickParam + chn.nOldFinePortaUpDown; if(playState.m_nTickCount + 1 == playState.m_nMusicSpeed) chn.nOldFinePortaUpDown = static_cast(std::abs(param)); else chn.nOldFinePortaUpDown = static_cast(std::abs(tickParam)); chn.m_CalculateFreq = true; } void CSoundFile::PortamentoExtraFineMPT(ModChannel &chn, int param) const { // This kinda behaves like regular fine portamento. // It changes the pitch by n finetune steps on the first tick. if(chn.isFirstTick) { chn.m_PortamentoFineSteps += param; chn.m_CalculateFreq = true; } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_itp.cpp0000644000175000017500000003142014741767466020362 00000000000000/* * Load_itp.cpp * ------------ * Purpose: Impulse Tracker Project (ITP) module loader * Notes : Despite its name, ITP is not a format supported by Impulse Tracker. * In fact, it's a format invented by the OpenMPT team to allow people to work * with the IT format, but keeping the instrument files with big samples separate * from the pattern data, to keep the work files small and handy. * The design of the format is quite flawed, though, so it was superseded by * extra functionality in the MPTM format in OpenMPT 1.24. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "../common/version.h" #include "Loaders.h" #include "ITTools.h" #ifdef MODPLUG_TRACKER // For loading external instruments #include "../mptrack/Moddoc.h" #endif // MODPLUG_TRACKER #ifdef MPT_EXTERNAL_SAMPLES #include "mpt/io_file/inputfile.hpp" #include "mpt/io_file_read/inputfile_filecursor.hpp" #include "../common/mptFileIO.h" #endif // MPT_EXTERNAL_SAMPLES OPENMPT_NAMESPACE_BEGIN // Version changelog: // v1.03: - Relative unicode instrument paths instead of absolute ANSI paths // - Per-path variable string length // - Embedded samples are IT-compressed // (rev. 3249) // v1.02: Explicitly updated format to use new instrument flags representation (rev. 483) // v1.01: Added option to embed instrument headers struct ITPModCommand { uint8 note; uint8 instr; uint8 volcmd; uint8 command; uint8 vol; uint8 param; operator ModCommand() const { static constexpr VolumeCommand ITPVolCmds[] = { VOLCMD_NONE, VOLCMD_VOLUME, VOLCMD_PANNING, VOLCMD_VOLSLIDEUP, VOLCMD_VOLSLIDEDOWN, VOLCMD_FINEVOLUP, VOLCMD_FINEVOLDOWN, VOLCMD_VIBRATOSPEED, VOLCMD_VIBRATODEPTH, VOLCMD_PANSLIDELEFT, VOLCMD_PANSLIDERIGHT, VOLCMD_TONEPORTAMENTO, VOLCMD_PORTAUP, VOLCMD_PORTADOWN, VOLCMD_PLAYCONTROL, VOLCMD_OFFSET, }; static constexpr EffectCommand ITPCommands[] = { CMD_NONE, CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, CMD_PANNING8, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_POSITIONJUMP, CMD_VOLUME, CMD_PATTERNBREAK, CMD_RETRIG, CMD_SPEED, CMD_TEMPO, CMD_TREMOR, CMD_MODCMDEX, CMD_S3MCMDEX, CMD_CHANNELVOLUME, CMD_CHANNELVOLSLIDE, CMD_GLOBALVOLUME, CMD_GLOBALVOLSLIDE, CMD_KEYOFF, CMD_FINEVIBRATO, CMD_PANBRELLO, CMD_XFINEPORTAUPDOWN, CMD_PANNINGSLIDE, CMD_SETENVPOSITION, CMD_MIDI, CMD_SMOOTHMIDI, CMD_DELAYCUT, CMD_XPARAM, }; ModCommand result; result.note = (ModCommand::IsNote(note) || ModCommand::IsSpecialNote(note)) ? static_cast(note) : static_cast(NOTE_NONE); result.instr = instr; result.volcmd = (volcmd < std::size(ITPVolCmds)) ? ITPVolCmds[volcmd] : VOLCMD_NONE; result.command = (command < std::size(ITPCommands)) ? ITPCommands[command] : CMD_NONE; result.vol = vol; result.param = param; return result; } }; MPT_BINARY_STRUCT(ITPModCommand, 6) struct ITPHeader { uint32le magic; uint32le version; bool IsValid() const { return magic == MagicBE(".itp") && version >= 0x00000100 && version <= 0x00000103; } uint32 GetHeaderMinimumAdditionalSize() const { return 76 + (version <= 0x102 ? 4 : 0); } }; MPT_BINARY_STRUCT(ITPHeader, 8) struct ITPSongHeader { enum SongFlags { ITP_EMBEDMIDICFG = 0x00001, // Embed macros in file ITP_ITOLDEFFECTS = 0x00004, // Old Impulse Tracker effect implementations ITP_ITCOMPATGXX = 0x00008, // IT "Compatible Gxx" (IT's flag to behave more like other trackers w/r/t portamento effects) ITP_LINEARSLIDES = 0x00010, // Linear slides vs. Amiga slides ITP_EXFILTERRANGE = 0x08000, // Cutoff Filter has double frequency range (up to ~10Khz) ITP_ITPROJECT = 0x20000, // Is a project file ITP_ITPEMBEDIH = 0x40000, // Embed instrument headers in project file }; uint32le flags; // See SongFlangs uint32le globalVolume; uint32le samplePreAmp; uint32le speed; uint32le tempo; uint32le numChannels; uint32le channelNameLength; bool IsValid() const { return (flags & ITP_ITPROJECT) != 0 && speed >= 1 && tempo >= 32 && numChannels >= 1 && numChannels <= MAX_BASECHANNELS; } }; MPT_BINARY_STRUCT(ITPSongHeader, 28) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize) { ITPHeader hdr; if(!file.ReadStruct(hdr)) return ProbeWantMoreData; if(!hdr.IsValid()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, hdr.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadITP(FileReader &file, ModLoadingFlags loadFlags) { #if !defined(MPT_EXTERNAL_SAMPLES) && !defined(MPT_FUZZ_TRACKER) // Doesn't really make sense to support this format when there's no support for external files... MPT_UNREFERENCED_PARAMETER(file); MPT_UNREFERENCED_PARAMETER(loadFlags); return false; #else // !MPT_EXTERNAL_SAMPLES && !MPT_FUZZ_TRACKER file.Rewind(); ITPHeader hdr; if(!file.ReadStruct(hdr)) return false; if(!hdr.IsValid()) return false; if(!file.CanRead(hdr.GetHeaderMinimumAdditionalSize())) return false; if(loadFlags == onlyVerifyHeader) return true; const uint32 version = hdr.version; std::string songName, songMessage; file.ReadSizedString(songName); file.ReadSizedString(songMessage); ITPSongHeader songHeader; if(!file.ReadStruct(songHeader) || !songHeader.IsValid()) return false; InitializeGlobals(MOD_TYPE_IT, static_cast(songHeader.numChannels)); m_playBehaviour.reset(); m_SongFlags.set(SONG_IMPORTED); if(songHeader.flags & ITPSongHeader::ITP_ITOLDEFFECTS) m_SongFlags.set(SONG_ITOLDEFFECTS); if(songHeader.flags & ITPSongHeader::ITP_ITCOMPATGXX) m_SongFlags.set(SONG_ITCOMPATGXX); if(songHeader.flags & ITPSongHeader::ITP_LINEARSLIDES) m_SongFlags.set(SONG_LINEARSLIDES); if(songHeader.flags & ITPSongHeader::ITP_EXFILTERRANGE) m_SongFlags.set(SONG_EXFILTERRANGE); m_nDefaultGlobalVolume = songHeader.globalVolume; m_nSamplePreAmp = songHeader.samplePreAmp; Order().SetDefaultSpeed(songHeader.speed); Order().SetDefaultTempoInt(songHeader.tempo); m_songName = std::move(songName); m_songMessage.SetRaw(std::move(songMessage)); // Channels' data uint32 size = songHeader.channelNameLength; for(auto &chn : ChnSettings) { chn.nPan = std::min(static_cast(file.ReadUint32LE()), uint16(256)); chn.dwFlags.reset(); uint32 flags = file.ReadUint32LE(); if(flags & 0x100) chn.dwFlags.set(CHN_MUTE); if(flags & 0x800) chn.dwFlags.set(CHN_SURROUND); chn.nVolume = std::min(static_cast(file.ReadUint32LE()), uint8(64)); file.ReadString(chn.szName, size); } // Song mix plugins { FileReader plugChunk = file.ReadChunk(file.ReadUint32LE()); LoadMixPlugins(plugChunk); } // MIDI Macro config file.ReadStructPartial(m_MidiCfg, file.ReadUint32LE()); m_MidiCfg.Sanitize(); // Song Instruments if(uint32 numIns = file.ReadUint32LE(); numIns < MAX_INSTRUMENTS) m_nInstruments = static_cast(numIns); else return false; // Instruments' paths if(version <= 0x102) { size = file.ReadUint32LE(); // path string length } std::vector instrPaths(GetNumInstruments()); for(INSTRUMENTINDEX ins = 0; ins < GetNumInstruments(); ins++) { if(version > 0x102) { size = file.ReadUint32LE(); // path string length } std::string path; file.ReadString(path, size); #ifdef MODPLUG_TRACKER if(version <= 0x102) { instrPaths[ins] = mpt::PathString::FromLocale(path); } else #endif // MODPLUG_TRACKER { instrPaths[ins] = mpt::PathString::FromUTF8(path); } #ifdef MODPLUG_TRACKER if(const auto fileName = file.GetOptionalFileName(); fileName.has_value()) { instrPaths[ins] = mpt::RelativePathToAbsolute(instrPaths[ins], fileName->GetDirectoryWithDrive()); } else if(GetpModDoc() != nullptr) { instrPaths[ins] = mpt::RelativePathToAbsolute(instrPaths[ins], GetpModDoc()->GetPathNameMpt().GetDirectoryWithDrive()); } #endif // MODPLUG_TRACKER } // Song Orders size = file.ReadUint32LE(); ReadOrderFromFile(Order(), file, size, 0xFF, 0xFE); // Song Patterns const PATTERNINDEX numPats = static_cast(file.ReadUint32LE()); const PATTERNINDEX numNamedPats = static_cast(file.ReadUint32LE()); size_t patNameLen = file.ReadUint32LE(); // Size of each pattern name FileReader pattNames = file.ReadChunk(numNamedPats * patNameLen); // modcommand data length size = file.ReadUint32LE(); if(size != sizeof(ITPModCommand)) { return false; } if(loadFlags & loadPatternData) Patterns.ResizeArray(numPats); for(PATTERNINDEX pat = 0; pat < numPats; pat++) { const ROWINDEX numRows = file.ReadUint32LE(); FileReader patternChunk = file.ReadChunk(numRows * size * GetNumChannels()); // Allocate pattern if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, numRows)) { pattNames.Skip(patNameLen); continue; } if(pat < numNamedPats) { char patName[32]; if(pattNames.ReadString(patName, patNameLen)) Patterns[pat].SetName(patName); } // Pattern data size_t numCommands = GetNumChannels() * numRows; if(patternChunk.CanRead(sizeof(ITPModCommand) * numCommands)) { for(ModCommand &m : Patterns[pat]) { ITPModCommand data; patternChunk.ReadStruct(data); m = data; } } } // Load embedded samples // Read original number of samples m_nSamples = static_cast(file.ReadUint32LE()); LimitMax(m_nSamples, SAMPLEINDEX(MAX_SAMPLES - 1)); // Read number of embedded samples - at most as many as there are real samples in a valid file uint32 embeddedSamples = file.ReadUint32LE(); if(embeddedSamples > GetNumSamples()) { return false; } // Read samples for(uint32 smp = 0; smp < embeddedSamples && file.CanRead(8 + sizeof(ITSample)); smp++) { uint32 realSample = file.ReadUint32LE(); ITSample sampleHeader; file.ReadStruct(sampleHeader); FileReader sampleData = file.ReadChunk(file.ReadUint32LE()); if((loadFlags & loadSampleData) && realSample >= 1 && realSample <= GetNumSamples() && Samples[realSample].pData.pSample == nullptr && !memcmp(sampleHeader.id, "IMPS", 4)) { sampleHeader.ConvertToMPT(Samples[realSample]); m_szNames[realSample] = mpt::String::ReadBuf(mpt::String::nullTerminated, sampleHeader.name); // Read sample data sampleHeader.GetSampleFormat().ReadSample(Samples[realSample], sampleData); } } // Load instruments for(INSTRUMENTINDEX ins = 0; ins < GetNumInstruments(); ins++) { if(instrPaths[ins].empty()) continue; #ifdef MPT_EXTERNAL_SAMPLES mpt::IO::InputFile f(instrPaths[ins], SettingCacheCompleteFileBeforeLoading()); FileReader instrFile = GetFileReader(f); if(!ReadInstrumentFromFile(ins + 1, instrFile, true)) { AddToLog(LogWarning, U_("Unable to open instrument: ") + instrPaths[ins].ToUnicode()); } #else AddToLog(LogWarning, MPT_UFORMAT("Loading external instrument {} ('{}') failed: External instruments are not supported.")(ins + 1, instrPaths[ins].ToUnicode())); #endif // MPT_EXTERNAL_SAMPLES } // Extra info data uint32 code = file.ReadUint32LE(); // Embed instruments' header [v1.01] if(version >= 0x101 && (songHeader.flags & ITPSongHeader::ITP_ITPEMBEDIH) && code == MagicBE("EBIH")) { code = file.ReadUint32LE(); INSTRUMENTINDEX ins = 1; while(ins <= GetNumInstruments() && file.CanRead(4)) { if(code == MagicBE("MPTS")) { break; } else if(code == MagicBE("SEP@") || code == MagicBE("MPTX")) { // jump code - switch to next instrument ins++; } else { ReadExtendedInstrumentProperty(mpt::as_span(&Instruments[ins], 1), code, file); } code = file.ReadUint32LE(); } } for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { Samples[smp].SetDefaultCuePoints(); } // Song extensions if(code == MagicBE("MPTS")) { file.SkipBack(4); LoadExtendedSongProperties(file, true); } m_nMaxPeriod = 0xF000; m_nMinPeriod = 8; // Before OpenMPT 1.20.01.09, the MIDI macros were always read from the file, even if the "embed" flag was not set. if(m_dwLastSavedWithVersion >= MPT_V("1.20.01.09") && !(songHeader.flags & ITPSongHeader::ITP_EMBEDMIDICFG)) { m_MidiCfg.Reset(); } m_modFormat.formatName = UL_("Impulse Tracker Project"); m_modFormat.type = UL_("itp"); m_modFormat.madeWithTracker = UL_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion); m_modFormat.charset = mpt::Charset::Windows1252; return true; #endif // MPT_EXTERNAL_SAMPLES } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_xmf.cpp0000644000175000017500000001541714630721373020350 00000000000000/* * Load_xmf.cpp * ------------ * Purpose: Module loader for music files from the DOS game "Imperium Galactica" and various Astroidea demos * Notes : This format has nothing to do with the XMF format by the MIDI foundation. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "mpt/endian/int24.hpp" OPENMPT_NAMESPACE_BEGIN struct XMFSampleHeader { using uint24le = mpt::uint24le; enum SampleFlags : uint8 { smp16Bit = 0x04, smpEnableLoop = 0x08, smpBidiLoop = 0x10, }; uint24le loopStart; uint24le loopEnd; uint24le dataStart; uint24le dataEnd; uint8 defaultVolume; uint8 flags; uint16le sampleRate; bool IsValid(uint8 type) const noexcept { if(flags & ~(smp16Bit | smpEnableLoop | smpBidiLoop)) return false; if((flags & (smpEnableLoop | smpBidiLoop)) == smpBidiLoop) return false; if(dataStart.get() > dataEnd.get()) return false; const uint32 length = dataEnd.get() - dataStart.get(); if(type != 2 && length > 0 && sampleRate < 100) return false; if(type == 2 && length > 0 && sampleRate >= 0x8000) // Any values != 0 are not really usable but when they turn negative, playback really goes haywire return false; if((flags & smp16Bit) && (length % 2u)) return false; if((flags & smpEnableLoop) && !loopEnd.get()) return false; if(loopStart.get() > loopEnd.get() || loopStart.get() > length) return false; if(loopEnd.get() != 0 && (loopEnd.get() >= length || loopStart.get() >= loopEnd.get())) return false; return true; } bool HasSampleData() const noexcept { return dataEnd.get() > dataStart.get(); } void ConvertToMPT(ModSample &mptSmp, uint8 type) const { mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.nLength = dataEnd.get() - dataStart.get(); mptSmp.nLoopStart = loopStart.get() + 1u; mptSmp.nLoopEnd = loopEnd.get() + 1u; mptSmp.uFlags.set(CHN_LOOP, flags & smpEnableLoop); mptSmp.uFlags.set(CHN_PINGPONGLOOP, flags & smpBidiLoop); if(flags & smp16Bit) { mptSmp.uFlags.set(CHN_16BIT); mptSmp.nLength /= 2; } mptSmp.nVolume = defaultVolume; if(type != 2) mptSmp.nC5Speed = sampleRate; mptSmp.FrequencyToTranspose(); } }; MPT_BINARY_STRUCT(XMFSampleHeader, 16) static bool TranslateXMFEffect(ModCommand &m, uint8 command, uint8 param, uint8 type) { if(command == 0x0B && param < 0xFF) { param++; } else if(command == 0x10 || command == 0x11) { param = 0x80 | (command << 4) | (param & 0x0F); command = 0x0E; } else if(command == 0x12) { // The ULT to XMF converter uses this to translate ULT command 5 but the player does not handle this command. Thus we will simply ignore it. command = param = 0; } else if(command > 0x12) { return false; } CSoundFile::ConvertModCommand(m, command, param); if(type == 4 && m.command == CMD_VOLUME && (!(m.param & 0x03) || m.param == 0xFF)) m.param = static_cast((m.param + 3u) / 4u); else if(m.command == CMD_VOLUME) m.command = CMD_VOLUME8; if(type != 4 && m.command == CMD_TEMPO && m.param == 0x20) m.command = CMD_SPEED; return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXMF(MemoryFileReader file, const uint64 *pfilesize) { if(!file.CanRead(1)) return ProbeWantMoreData; uint8 type = file.ReadUint8(); if(type < 2 || type > 4) return ProbeFailure; constexpr size_t probeHeaders = std::min(size_t(256), (ProbeRecommendedSize - 1) / sizeof(XMFSampleHeader)); for(size_t sample = 0; sample < probeHeaders; sample++) { XMFSampleHeader sampleHeader; if(!file.ReadStruct(sampleHeader)) return ProbeWantMoreData; if(!sampleHeader.IsValid(type)) return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadXMF(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); uint8 type = file.ReadUint8(); // Type 2: Old UltraTracker finetune behaviour, automatic tone portamento // Type 3: Normal finetune behaviour, automatic tone portamento (like in ULT) // Type 4: Normal finetune behaviour, manual tone portamento (like in MOD) if(type < 2 || type > 4) return false; if(!file.CanRead(256 * sizeof(XMFSampleHeader) + 256 + 3)) return false; static_assert(MAX_SAMPLES > 256); SAMPLEINDEX numSamples = 0; for(SAMPLEINDEX smp = 1; smp <= 256; smp++) { XMFSampleHeader sampleHeader; file.ReadStruct(sampleHeader); if(!sampleHeader.IsValid(type)) return false; if(sampleHeader.HasSampleData()) numSamples = smp; } if(!numSamples) return false; file.Skip(256); const uint8 lastChannel = file.ReadUint8(); if(lastChannel > 31) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_MOD, lastChannel + 1); m_SongFlags.set(SONG_IMPORTED); m_SongFlags.reset(SONG_ISAMIGA); m_SongFlags.set(SONG_AUTO_TONEPORTA | SONG_AUTO_TONEPORTA_CONT, type < 4); m_nSamples = numSamples; m_nSamplePreAmp = (type == 3) ? 192 : 48; // Imperium Galactica files are really quiet, no other XMFs appear to use type 3 file.Seek(1); for(SAMPLEINDEX smp = 1; smp <= numSamples; smp++) { XMFSampleHeader sampleHeader; file.ReadStruct(sampleHeader); sampleHeader.ConvertToMPT(Samples[smp], type); m_szNames[smp] = ""; } file.Seek(1 + 256 * sizeof(XMFSampleHeader)); ReadOrderFromFile(Order(), file, 256, 0xFF); file.Skip(1); // Channel count already read const PATTERNINDEX numPatterns = file.ReadUint8() + 1u; if(!file.CanRead(GetNumChannels() + numPatterns * GetNumChannels() * 64 * 6)) return false; for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = file.ReadUint8() * 0x11; } Patterns.ResizeArray(numPatterns); for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { file.Skip(GetNumChannels() * 64 * 6); continue; } ModCommand dummy; for(ModCommand &m : Patterns[pat]) { const auto data = file.ReadArray(); if(data[0] > 0 && data[0] <= 77) m.note = NOTE_MIN + 35 + data[0]; m.instr = data[1]; if(!TranslateXMFEffect(m, data[2], data[5], type) || !TranslateXMFEffect(dummy, data[3], data[4], type)) return false; if(dummy.command != CMD_NONE) m.FillInTwoCommands(m.command, m.param, dummy.command, dummy.param); } } if(loadFlags & loadSampleData) { for(SAMPLEINDEX smp = 1; smp <= numSamples; smp++) { SampleIO(Samples[smp].uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM).ReadSample(Samples[smp], file); } } m_modFormat.formatName = UL_("Astroidea XMF"); m_modFormat.type = UL_("xmf"); m_modFormat.madeWithTracker.clear(); m_modFormat.charset = mpt::Charset::CP437; // No strings in this format... return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleFormatSFZ.cpp0000644000175000017500000012416314730244445021574 00000000000000/* * SampleFormatSFZ.cpp * ------------------- * Purpose: Loading and saving SFZ instruments. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Sndfile.h" #ifdef MODPLUG_TRACKER #include "../mptrack/TrackerSettings.h" #include "mpt/io_file/inputfile.hpp" #include "mpt/io_file_read/inputfile_filecursor.hpp" #include "../common/mptFileIO.h" #endif // MODPLUG_TRACKER #ifndef MODPLUG_NO_FILESAVE #include "mpt/io_file/outputfile.hpp" #include "../common/mptFileIO.h" #ifdef MODPLUG_TRACKER #include "mpt/fs/fs.hpp" #endif // MODPLUG_TRACKER #endif // !MODPLUG_NO_FILESAVE #include "modsmp_ctrl.h" #include "mpt/base/numbers.hpp" #include "mpt/parse/parse.hpp" #include OPENMPT_NAMESPACE_BEGIN #ifdef MPT_EXTERNAL_SAMPLES template static bool SFZStartsWith(const std::string_view &l, const char(&r)[N]) { return l.substr(0, N - 1) == r; } template static bool SFZEndsWith(const std::string_view &l, const char (&r)[N]) { return l.size() >= (N - 1) && l.substr(l.size() - (N - 1), N - 1) == r; } static bool SFZIsNumeric(const std::string_view &str) { return std::find_if(str.begin(), str.end(), [](char c) { return c < '0' || c > '9'; }) == str.end(); } struct SFZControl { std::string defaultPath; int8 octaveOffset = 0, noteOffset = 0; void Parse(const std::string_view key, const std::string &value) { if(key == "default_path") defaultPath = value; else if(key == "octave_offset") octaveOffset = mpt::parse(value); else if(key == "note_offset") noteOffset = mpt::parse(value); } }; struct SFZFlexEG { using PointIndex = decltype(InstrumentEnvelope().nLoopStart); std::vector> points; double amplitude = 0; // percentage (100 = full volume range) double pan = 0; // percentage (100 = full pan range) double pitch = 0; // in cents double cutoff = 0; // in cents PointIndex sustain = 0; void Parse(std::string_view key, const std::string &value) { key = key.substr(key.find('_') + 1); const double v = mpt::parse(value); const bool isTime = SFZStartsWith(key, "time"), isLevel = SFZStartsWith(key, "level"); std::string_view pointStr; if(isTime) pointStr = key.substr(4); else if(isLevel) pointStr = key.substr(5); if(!pointStr.empty() && SFZIsNumeric(pointStr)) { PointIndex point = mpt::parse(std::string(pointStr)); if(point >= points.size() && point < MAX_ENVPOINTS) points.resize(point + 1); if(point < points.size()) { if(isTime) points[point].first = v; else points[point].second = v; } return; } if(key == "points") points.resize(std::min(static_cast(v), static_cast(MAX_ENVPOINTS))); else if(key == "sustain") sustain = mpt::saturate_round(v); else if(key == "amplitude" || key == "ampeg") amplitude = v; else if(key == "pan") pan = v; else if(key == "pitch") pitch = v; else if(key == "cutoff") cutoff = v; } void ConvertToMPT(ModInstrument *ins, const CSoundFile &sndFile) const { if(amplitude) ConvertToMPT(ins, sndFile, ENV_VOLUME, amplitude / 100.0, 0.0, 1.0); if(pan) ConvertToMPT(ins, sndFile, ENV_PANNING, pan / 100.0, -1.0, 1.0); if(pitch) ConvertToMPT(ins, sndFile, ENV_PITCH, pitch / 1600.0, -1.0, 1.0); if(cutoff) ConvertToMPT(ins, sndFile, ENV_PITCH, cutoff, 0.0, 1.0, true); } void ConvertToMPT(ModInstrument *ins, const CSoundFile &sndFile, EnvelopeType envType, double scale, double minVal, double maxVal, bool forceFilter = false) const { const double tickDuration = sndFile.m_PlayState.m_nSamplesPerTick / static_cast(sndFile.GetSampleRate()); if(tickDuration <= 0 || points.empty() || scale == 0.0) return; auto &env = ins->GetEnvelope(envType); std::function conversionFunc = Identity; if(forceFilter && envType == ENV_PITCH) { env.dwFlags.set(ENV_FILTER); conversionFunc = FilterConversionFunc(*ins, sndFile); } env.clear(); env.reserve(points.size()); const auto ToValue = std::bind(SFZFlexEG::ToValue, std::placeholders::_1, scale, minVal, maxVal, conversionFunc); int32 prevTick = -1; // If the first envelope point's time is greater than 0, we fade in from a neutral value if(points.front().first > 0) { env.push_back({0, ToValue(0.0)}); prevTick = 0; } for(const auto &point : points) { const auto tick = mpt::saturate_cast(prevTick + ToTicks(point.first, tickDuration)); const auto value = ToValue(point.second); env.push_back({tick, value}); prevTick = tick; if(tick == Util::MaxValueOfType(tick)) break; } if(sustain < env.size() && !(envType == ENV_VOLUME && sustain == env.size() - 1u && env.back().value == 0)) { env.nSustainStart = env.nSustainEnd = sustain; env.dwFlags.set(ENV_SUSTAIN); } else { env.dwFlags.reset(ENV_SUSTAIN); } env.dwFlags.set(ENV_ENABLED); if(envType == ENV_VOLUME && env.nSustainEnd > 0) env.nReleaseNode = env.nSustainEnd; } protected: static EnvelopeNode::tick_t ToTicks(double duration, double tickDuration) { return std::max(EnvelopeNode::tick_t(1), mpt::saturate_round(duration / tickDuration)); } static EnvelopeNode::value_t ToValue(double value, double scale, double minVal, double maxVal, const std::function &conversionFunc) { value = conversionFunc((value * scale - minVal) / (maxVal - minVal)) * double(ENVELOPE_MAX) + double(ENVELOPE_MIN); Limit(value, double(ENVELOPE_MIN), double(ENVELOPE_MAX)); return mpt::saturate_round(value); } static double Identity(double v) noexcept { return v; } static double CentsToFilterCutoff(double v, const CSoundFile &sndFile, int envBaseCutoff, float envBaseFreq) { const auto freq = static_cast(envBaseFreq) * std::pow(2.0, v / 1200.0); return Util::muldivr(sndFile.FrequencyToCutOff(freq), 127, envBaseCutoff) / 127.0; } static std::function FilterConversionFunc(const ModInstrument &ins, const CSoundFile &sndFile) { const auto envBaseCutoff = ins.IsCutoffEnabled() ? ins.GetCutoff() : 127; const auto envBaseFreq = sndFile.CutOffToFrequency(envBaseCutoff); return std::bind(CentsToFilterCutoff, std::placeholders::_1, std::cref(sndFile), envBaseCutoff, envBaseFreq); } }; struct SFZEnvelope { double startLevel = 0, delay = 0, attack = 0, hold = 0; double decay = 0, sustainLevel = 100, release = 0, depth = 0; void Parse(std::string_view key, const std::string &value) { key = key.substr(key.find('_') + 1); double v = mpt::parse(value); if(key == "depth") Limit(v, -12000.0, 12000.0); else if(key == "start" || key == "sustain") Limit(v, -100.0, 100.0); else Limit(v, 0.0, 100.0); if(key == "start") startLevel = v; else if(key == "delay") delay = v; else if(key == "attack") attack = v; else if(key == "hold") hold = v; else if(key == "decay") decay = v; else if(key == "sustain") sustainLevel = v; else if(key == "release") release = v; else if(key == "depth") depth = v; } void ConvertToMPT(ModInstrument *ins, const CSoundFile &sndFile, EnvelopeType envType, bool forceFilter = false) const { SFZFlexEG eg; if(envType == ENV_VOLUME) eg.amplitude = 1.0; else if(envType == ENV_PITCH && !forceFilter) eg.pitch = depth / 100.0; else if(envType == ENV_PITCH && forceFilter) eg.cutoff = depth / 100.0; auto &env = eg.points; if(attack > 0 || delay > 0) { env.push_back({0.0, startLevel}); if(delay > 0) env.push_back({delay, env.back().second}); env.push_back({attack, 100.0}); } if(hold > 0) { if(env.empty()) env.push_back({0.0, 100.0}); env.push_back({hold, env.back().second}); } if(env.empty()) env.push_back({0.0, 100.0}); if(env.back().second != sustainLevel) env.push_back({decay, sustainLevel}); if(sustainLevel != 0) { eg.sustain = static_cast(env.size() - 1); env.push_back({release, 0.0}); } else { eg.sustain = std::numeric_limits::max(); } eg.ConvertToMPT(ins, sndFile); } }; struct SFZRegion { enum class LoopMode { kUnspecified, kContinuous, kOneShot, kSustain, kNoLoop }; enum class LoopType { kUnspecified, kForward, kBackward, kAlternate, }; size_t filenameOffset = 0; std::string filename, globalName, regionName; SFZEnvelope ampEnv, pitchEnv, filterEnv; std::vector flexEGs; SmpLength loopStart = 0, loopEnd = 0; SmpLength end = MAX_SAMPLE_LENGTH, offset = 0; LoopMode loopMode = LoopMode::kUnspecified; LoopType loopType = LoopType::kUnspecified; double loopCrossfade = 0.0; double cutoff = 0; // in Hz double resonance = 0; // 0...40dB double filterRandom = 0; // 0...9600 cents double volume = 0; // -144dB...+6dB double amplitude = 100.0; // 0...100 double pitchBend = 200; // -9600...9600 cents double pitchLfoFade = 0; // 0...100 seconds double pitchLfoDepth = 0; // -1200...12000 double pitchLfoFreq = 0; // 0...20 Hz double panning = -128; // -100...+100 double finetune = 0; // in cents int8 transpose = 0; uint8 keyLo = 0, keyHi = 127, keyRoot = 60; FilterMode filterType = FilterMode::Unchanged; uint8 polyphony = 255; bool useSampleKeyRoot = false; bool invertPhase = false; template static void Read(const std::string &valueStr, T &value, Tc valueMin = std::numeric_limits::min(), Tc valueMax = std::numeric_limits::max()) { double valueF = mpt::parse(valueStr); if constexpr(std::numeric_limits::is_integer) { valueF = mpt::round(valueF); } Limit(valueF, static_cast(valueMin), static_cast(valueMax)); value = static_cast(valueF); } static uint8 ReadKey(const std::string &value, const SFZControl &control) { if(value.empty()) return 0; int key = 0; if(value[0] >= '0' && value[0] <= '9') { // MIDI key key = mpt::parse(value); } else if(value.length() < 2) { return 0; } else { // Scientific pitch static constexpr int8 keys[] = { 9, 11, 0, 2, 4, 5, 7 }; static_assert(std::size(keys) == 'g' - 'a' + 1); auto keyC = value[0]; if(keyC >= 'A' && keyC <= 'G') key = keys[keyC - 'A']; if(keyC >= 'a' && keyC <= 'g') key = keys[keyC - 'a']; else return 0; uint8 octaveOffset = 1; if(value[1] == '#') { key++; octaveOffset = 2; } else if(value[1] == 'b' || value[1] == 'B') { key--; octaveOffset = 2; } if(octaveOffset >= value.length()) return 0; int8 octave = mpt::parse(value.c_str() + octaveOffset); key += (octave + 1) * 12; } key += control.octaveOffset * 12 + control.noteOffset; return static_cast(Clamp(key, 0, 127)); } void Parse(const std::string_view key, const std::string &value, const SFZControl &control) { if(key == "sample") { filename = control.defaultPath + value; filenameOffset = control.defaultPath.size(); } else if(key == "global_label") globalName = value; else if(key == "region_label") regionName = value; else if(key == "lokey") keyLo = ReadKey(value, control); else if(key == "hikey") keyHi = ReadKey(value, control); else if(key == "pitch_keycenter") { keyRoot = ReadKey(value, control); useSampleKeyRoot = (value == "sample"); } else if(key == "key") { keyLo = keyHi = keyRoot = ReadKey(value, control); useSampleKeyRoot = false; } else if(key == "bend_up" || key == "bendup") Read(value, pitchBend, -9600.0, 9600.0); else if(key == "pitchlfo_fade") Read(value, pitchLfoFade, 0.0, 100.0); else if(key == "pitchlfo_depth") Read(value, pitchLfoDepth, -12000.0, 12000.0); else if(key == "pitchlfo_freq") Read(value, pitchLfoFreq, 0.0, 20.0); else if(key == "volume") Read(value, volume, -144.0, 6.0); else if(key == "amplitude") Read(value, amplitude, 0.0, 100.0); else if(key == "pan") Read(value, panning, -100.0, 100.0); else if(key == "transpose") Read(value, transpose, -127, 127); else if(key == "tune") Read(value, finetune, -100.0, 100.0); else if(key == "end") Read(value, end, SmpLength(0), MAX_SAMPLE_LENGTH); else if(key == "offset") Read(value, offset, SmpLength(0), MAX_SAMPLE_LENGTH); else if(key == "loop_start" || key == "loopstart") Read(value, loopStart, SmpLength(0), MAX_SAMPLE_LENGTH); else if(key == "loop_end" || key == "loopend") Read(value, loopEnd, SmpLength(0), MAX_SAMPLE_LENGTH); else if(key == "loop_crossfade" || key == "loopcrossfade") Read(value, loopCrossfade, 0.0, DBL_MAX); else if(key == "loop_mode" || key == "loopmode") { if(value == "loop_continuous") loopMode = LoopMode::kContinuous; else if(value == "one_shot") loopMode = LoopMode::kOneShot; else if(value == "loop_sustain") loopMode = LoopMode::kSustain; else if(value == "no_loop") loopMode = LoopMode::kNoLoop; } else if(key == "loop_type" || key == "looptype") { if(value == "forward") loopType = LoopType::kForward; else if(value == "backward") loopType = LoopType::kBackward; else if(value == "alternate") loopType = LoopType::kAlternate; } else if(key == "cutoff") Read(value, cutoff, 0.0, 96000.0); else if(key == "fil_random") Read(value, filterRandom, 0.0, 9600.0); else if(key == "resonance") Read(value, resonance, 0.0, 40.0); else if(key == "polyphony") Read(value, polyphony, 0, 255); else if(key == "phase") invertPhase = (value == "invert"); else if(key == "fil_type" || key == "filtype") { if(value == "lpf_1p" || value == "lpf_2p" || value == "lpf_4p" || value == "lpf_6p") filterType = FilterMode::LowPass; else if(value == "hpf_1p" || value == "hpf_2p" || value == "hpf_4p" || value == "hpf_6p") filterType = FilterMode::HighPass; // Alternatives: bpf_2p, brf_2p } else if(SFZStartsWith(key, "ampeg_")) ampEnv.Parse(key, value); else if(SFZStartsWith(key, "fileg_")) filterEnv.Parse(key, value); else if(SFZStartsWith(key, "pitcheg_")) pitchEnv.Parse(key, value); else if(SFZStartsWith(key, "eg") && SFZIsNumeric(key.substr(2, 2)) && key.substr(4, 1) == "_") { uint8 eg = mpt::parse(std::string(key.substr(2, 2))); if(eg >= flexEGs.size()) flexEGs.resize(eg + 1); flexEGs[eg].Parse(key, value); } } }; struct SFZInputFile { FileReader file; std::unique_ptr inputFile; // FileReader has pointers into this so its address must not change std::string remain; SFZInputFile(FileReader f = {}, std::unique_ptr i = {}, std::string r = {}) : file{std::move(f)}, inputFile{std::move(i)}, remain{std::move(r)} {} SFZInputFile(SFZInputFile &&) = default; }; bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file) { file.Rewind(); enum { kNone, kGlobal, kMaster, kGroup, kRegion, kControl, kCurve, kEffect, kUnknown } section = kNone; bool inMultiLineComment = false; SFZControl control; SFZRegion group, master, globals; std::vector regions; std::map macros; std::vector files; files.emplace_back(file); std::string s; while(!files.empty()) { if(!files.back().file.ReadLine(s, 1024)) { // Finished reading file, so back to remaining characters of the #include line from the previous file s = std::move(files.back().remain); files.pop_back(); } if(inMultiLineComment) { if(auto commentEnd = s.find("*/"); commentEnd != std::string::npos) { s.erase(0, commentEnd + 2); inMultiLineComment = false; } else { continue; } } // First, terminate line at the start of a comment block if(auto commentPos = s.find("//"); commentPos != std::string::npos) { s.resize(commentPos); } // Now, read the tokens. // This format is so funky that no general tokenizer approach seems to work here... // Consider this jolly good example found at https://stackoverflow.com/questions/5923895/tokenizing-a-custom-text-file-format-file-using-c-sharp // sample=piano C3.wav key=48 ampeg_release=0.7 // a comment here // key = 49 sample = piano Db3.wav // // group=1 // key = 48 // sample = piano D3.ogg // The original sfz specification claims that spaces around = are not allowed, but a quick look into the real world tells us otherwise. while(!s.empty()) { s.erase(0, s.find_first_not_of(" \t")); const bool isDefine = SFZStartsWith(s, "#define ") || SFZStartsWith(s, "#define\t"); // Replace macros (unless this is a #define statement, to allow for macro re-definition) if(!isDefine) { for(const auto &[oldStr, newStr] : macros) { std::string::size_type pos = 0; while((pos = s.find(oldStr, pos)) != std::string::npos) { s.replace(pos, oldStr.length(), newStr); pos += newStr.length(); } } } if(s.empty()) break; std::string::size_type charsRead = 0; if(s[0] == '<' && (charsRead = s.find('>')) != std::string::npos) { // Section header const auto sec = std::string_view(s).substr(1, charsRead - 1); section = kUnknown; if(sec == "global") { section = kGlobal; // Reset global parameters globals = SFZRegion(); } else if(sec == "master") { section = kMaster; // Reset master parameters master = globals; } else if(sec == "group") { section = kGroup; // Reset group parameters group = master; } else if(sec == "region") { section = kRegion; regions.push_back(group); } else if(sec == "control") { section = kControl; } else if(sec == "curve") { section = kCurve; } else if(sec == "effect") { section = kEffect; } charsRead++; } else if(isDefine) { // Macro definition charsRead += 8; auto keyStart = s.find_first_not_of(" \t", 8); auto keyEnd = s.find_first_of(" \t", keyStart); auto valueStart = s.find_first_not_of(" \t", keyEnd); if(keyStart != std::string::npos && valueStart != std::string::npos) { charsRead = s.find_first_of(" \t", valueStart); const auto key = s.substr(keyStart, keyEnd - keyStart); if(key.length() > 1 && key[0] == '$') macros[std::move(key)] = s.substr(valueStart, charsRead - valueStart); } else { break; } } else if(SFZStartsWith(s, "#include ") || SFZStartsWith(s, "#include\t")) { // Include other sfz file auto fileStart = s.find("\"", 9); // Yes, there can be arbitrary characters before the opening quote, at least that's how sforzando does it. auto fileEnd = s.find("\"", fileStart + 1); if(fileStart != std::string::npos && fileEnd != std::string::npos) { charsRead = fileEnd + 1; fileStart++; } else { break; } std::string filenameU8 = s.substr(fileStart, fileEnd - fileStart); mpt::PathString filename = mpt::PathString::FromUTF8(filenameU8); if(!filename.empty()) { if(filenameU8.find(':') == std::string::npos) filename = file.GetOptionalFileName().value_or(P_("")).GetDirectoryWithDrive() + filename; filename = filename.Simplify(); // Avoid recursive #include if(std::find_if(files.begin(), files.end(), [&filename](const SFZInputFile &f) { return f.file.GetOptionalFileName().value_or(P_("")) == filename; }) == files.end()) { auto f = std::make_unique(filename); if(f->IsValid()) { s.erase(0, charsRead); files.emplace_back(GetFileReader(*f), std::move(f), std::move(s)); break; } else { AddToLog(LogWarning, U_("Unable to load include file: ") + filename.ToUnicode()); } } else { AddToLog(LogWarning, U_("Recursive include file ignored: ") + filename.ToUnicode()); } } } else if(SFZStartsWith(s, "/*")) { // Multi-line comment if(auto commentEnd = s.find("*/", charsRead + 2); commentEnd != std::string::npos) { charsRead = commentEnd; } else { inMultiLineComment = true; charsRead = s.length(); } } else if(section == kNone) { // Garbage before any section, probably not an sfz file return false; } else if(s.find('=') != std::string::npos) { // Read key=value pair auto keyEnd = s.find_first_of(" \t="); auto valueStart = s.find_first_not_of(" \t=", keyEnd); if(valueStart == std::string::npos) { break; } const std::string key = mpt::ToLowerCaseAscii(s.substr(0, keyEnd)); // Currently defined *_label opcodes are global_label, group_label, master_label, region_label, sw_label if(key == "sample" || key == "default_path" || SFZStartsWith(key, "label_cc") || SFZStartsWith(key, "label_key") || SFZEndsWith(key, "_label")) { // Sample / CC name may contain spaces... charsRead = s.find_first_of("=\t<", valueStart); if(charsRead != std::string::npos && s[charsRead] == '=') { // Backtrack to end of key while(charsRead > valueStart && s[charsRead] == ' ') charsRead--; // Backtrack to start of key while(charsRead > valueStart && s[charsRead] != ' ') charsRead--; } } else { charsRead = s.find_first_of(" \t<", valueStart); } const std::string value = s.substr(valueStart, charsRead - valueStart); switch(section) { case kGlobal: globals.Parse(key, value, control); [[fallthrough]]; case kMaster: master.Parse(key, value, control); [[fallthrough]]; case kGroup: group.Parse(key, value, control); break; case kRegion: regions.back().Parse(key, value, control); break; case kControl: control.Parse(key, value); break; case kNone: case kCurve: case kEffect: case kUnknown: break; } } else { // Garbage, probably not an sfz file return false; } // Remove the token(s) we just read s.erase(0, charsRead); } } if(regions.empty()) return false; ModInstrument *pIns = new (std::nothrow) ModInstrument(); if(pIns == nullptr) return false; RecalculateSamplesPerTick(); DestroyInstrument(nInstr, deleteAssociatedSamples); if(nInstr > m_nInstruments) m_nInstruments = nInstr; Instruments[nInstr] = pIns; pIns->name = mpt::ToCharset(GetCharsetInternal(), mpt::Charset::UTF8, globals.globalName); SAMPLEINDEX prevSmp = 0; for(auto ®ion : regions) { uint8 keyLo = region.keyLo, keyHi = region.keyHi; if(keyLo > keyHi) continue; Clamp(keyLo, 0, NOTE_MAX - NOTE_MIN); Clamp(keyHi, 0, NOTE_MAX - NOTE_MIN); SAMPLEINDEX smp = GetNextFreeSample(nInstr, prevSmp + 1); if(smp == SAMPLEINDEX_INVALID) break; prevSmp = smp; ModSample &sample = Samples[smp]; sample.Initialize(MOD_TYPE_MPT); if(const auto synthSample = std::string_view(region.filename).substr(region.filenameOffset); SFZStartsWith(synthSample, "*")) { sample.nLength = 256; sample.nC5Speed = mpt::saturate_round(sample.nLength * 261.6255653); sample.uFlags.set(CHN_16BIT); std::function generator; if(synthSample == "*sine") generator = [](int32 i) { return mpt::saturate_round(std::sin(i * ((2.0 * mpt::numbers::pi) / 256.0)) * int16_max); }; else if(synthSample == "*square") generator = [](int32 i) { return i < 128 ? int16_max : int16_min; }; else if(synthSample == "*triangle" || synthSample == "*tri") generator = [](int32 i) { return static_cast(i < 128 ? ((63 - i) * 512) : ((i - 192) * 512)); }; else if(synthSample == "*saw") generator = [](int32 i) { return static_cast((i - 128) * 256); }; else if(synthSample == "*silence") generator = [](int32) { return int16(0); }; else if(synthSample == "*noise") { sample.nLength = sample.nC5Speed; generator = [this](int32) { return mpt::random(AccessPRNG()); }; } else { AddToLog(LogWarning, U_("Unknown sample type: ") + mpt::ToUnicode(mpt::Charset::UTF8, std::string(synthSample))); prevSmp--; continue; } if(sample.AllocateSample()) { for(SmpLength i = 0; i < sample.nLength; i++) { sample.sample16()[i] = generator(static_cast(i)); } if(smp > m_nSamples) m_nSamples = smp; region.offset = 0; region.loopMode = SFZRegion::LoopMode::kContinuous; region.loopStart = 0; region.loopEnd = sample.nLength - 1; region.loopCrossfade = 0; region.keyRoot = 60; } } else if(auto filename = mpt::PathString::FromUTF8(region.filename); !filename.empty()) { if(region.filename.find(':') == std::string::npos) { filename = file.GetOptionalFileName().value_or(P_("")).GetDirectoryWithDrive() + filename; } filename = filename.Simplify(); SetSamplePath(smp, filename); mpt::IO::InputFile f(filename, SettingCacheCompleteFileBeforeLoading()); FileReader smpFile = GetFileReader(f); if(!ReadSampleFromFile(smp, smpFile, false)) { AddToLog(LogWarning, U_("Unable to load sample: ") + filename.ToUnicode()); prevSmp--; continue; } if(UseFinetuneAndTranspose()) sample.TransposeToFrequency(); sample.uFlags.set(SMP_KEEPONDISK, sample.HasSampleData()); } if(!region.regionName.empty()) m_szNames[smp] = mpt::ToCharset(GetCharsetInternal(), mpt::Charset::UTF8, region.regionName); if(!m_szNames[smp][0]) m_szNames[smp] = mpt::ToCharset(GetCharsetInternal(), mpt::PathString::FromUTF8(region.filename).GetFilenameBase().ToUnicode()); if(region.useSampleKeyRoot) { if(sample.rootNote != NOTE_NONE) region.keyRoot = sample.rootNote - NOTE_MIN; else region.keyRoot = 60; } const auto origSampleRate = sample.GetSampleRate(GetType()); int8 transp = region.transpose + (60 - region.keyRoot); for(uint8 i = keyLo; i <= keyHi; i++) { pIns->Keyboard[i] = smp; if(GetType() != MOD_TYPE_XM) pIns->NoteMap[i] = NOTE_MIN + i + transp; } if(GetType() == MOD_TYPE_XM) sample.Transpose(transp / 12.0); pIns->filterMode = region.filterType; if(region.cutoff != 0) pIns->SetCutoff(FrequencyToCutOff(region.cutoff), true); if(region.resonance != 0) pIns->SetResonance(mpt::saturate_round(region.resonance * 128.0 / 24.0), true); pIns->nCutSwing = mpt::saturate_round(region.filterRandom * (m_SongFlags[SONG_EXFILTERRANGE] ? 20 : 24) / 1200.0); pIns->midiPWD = mpt::saturate_round(region.pitchBend / 100.0); pIns->nNNA = NewNoteAction::NoteOff; if(region.polyphony == 1) { pIns->nDNA = DuplicateNoteAction::NoteCut; pIns->nDCT = DuplicateCheckType::Sample; } region.ampEnv.ConvertToMPT(pIns, *this, ENV_VOLUME); if(region.pitchEnv.depth) region.pitchEnv.ConvertToMPT(pIns, *this, ENV_PITCH); else if(region.filterEnv.depth) region.filterEnv.ConvertToMPT(pIns, *this, ENV_PITCH, true); for(const auto &flexEG : region.flexEGs) { flexEG.ConvertToMPT(pIns, *this); } if(region.ampEnv.release > 0) { const double tickDuration = m_PlayState.m_nSamplesPerTick / static_cast(GetSampleRate()); pIns->nFadeOut = std::min(mpt::saturate_trunc(32768.0 * tickDuration / region.ampEnv.release), uint32(32767)); if(GetType() == MOD_TYPE_IT) pIns->nFadeOut = std::min((pIns->nFadeOut + 16u) & ~31u, uint32(8192)); } sample.rootNote = region.keyRoot + NOTE_MIN; sample.nGlobalVol = mpt::saturate_round(64.0 * Clamp(std::pow(10.0, region.volume / 20.0) * region.amplitude / 100.0, 0.0, 1.0)); if(region.panning != -128) { sample.nPan = mpt::saturate_round((region.panning + 100) * 256.0 / 200.0); sample.uFlags.set(CHN_PANNING); } sample.Transpose(region.finetune / 1200.0); if(region.pitchLfoDepth && region.pitchLfoFreq) { sample.nVibSweep = 255; if(region.pitchLfoFade > 0) sample.nVibSweep = mpt::saturate_round(255.0 / region.pitchLfoFade); sample.nVibDepth = mpt::saturate_round(region.pitchLfoDepth * 32.0 / 100.0); sample.nVibRate = mpt::saturate_round(region.pitchLfoFreq * 4.0); } if(region.loopMode != SFZRegion::LoopMode::kUnspecified) { switch(region.loopMode) { case SFZRegion::LoopMode::kContinuous: sample.uFlags.set(CHN_LOOP); break; case SFZRegion::LoopMode::kSustain: sample.uFlags.set(CHN_SUSTAINLOOP); break; case SFZRegion::LoopMode::kNoLoop: case SFZRegion::LoopMode::kOneShot: sample.uFlags.reset(CHN_LOOP | CHN_SUSTAINLOOP); break; case SFZRegion::LoopMode::kUnspecified: MPT_ASSERT_NOTREACHED(); break; } } if(region.loopEnd > region.loopStart) { // Loop may also be defined in file, in which case loopStart and loopEnd are unset. if(region.loopMode == SFZRegion::LoopMode::kSustain) { sample.nSustainStart = region.loopStart; sample.nSustainEnd = region.loopEnd + 1; } else if(region.loopMode == SFZRegion::LoopMode::kContinuous || region.loopMode == SFZRegion::LoopMode::kOneShot) { sample.nLoopStart = region.loopStart; sample.nLoopEnd = region.loopEnd + 1; } } else if(sample.nLoopEnd <= sample.nLoopStart && region.loopMode != SFZRegion::LoopMode::kUnspecified && region.loopMode != SFZRegion::LoopMode::kNoLoop) { sample.nLoopEnd = sample.nLength; } switch(region.loopType) { case SFZRegion::LoopType::kUnspecified: break; case SFZRegion::LoopType::kForward: sample.uFlags.reset(CHN_PINGPONGLOOP | CHN_PINGPONGSUSTAIN | CHN_REVERSE); break; case SFZRegion::LoopType::kBackward: sample.uFlags.set(CHN_REVERSE); break; case SFZRegion::LoopType::kAlternate: sample.uFlags.set(CHN_PINGPONGLOOP | CHN_PINGPONGSUSTAIN); break; default: break; } if(sample.nSustainEnd <= sample.nSustainStart && sample.nLoopEnd > sample.nLoopStart && region.loopMode == SFZRegion::LoopMode::kSustain) { // Turn normal loop (imported from sample) into sustain loop std::swap(sample.nSustainStart, sample.nLoopStart); std::swap(sample.nSustainEnd, sample.nLoopEnd); sample.uFlags.set(CHN_SUSTAINLOOP); sample.uFlags.set(CHN_PINGPONGSUSTAIN, sample.uFlags[CHN_PINGPONGLOOP]); sample.uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP); } mpt::PathString filenameModifier; // Loop cross-fade SmpLength fadeSamples = mpt::saturate_round(region.loopCrossfade * origSampleRate); LimitMax(fadeSamples, sample.uFlags[CHN_SUSTAINLOOP] ? sample.nSustainStart : sample.nLoopStart); if(fadeSamples > 0) { ctrlSmp::XFadeSample(sample, fadeSamples, 50000, true, sample.uFlags[CHN_SUSTAINLOOP], *this); sample.uFlags.set(SMP_MODIFIED); filenameModifier += P_(" (cross-fade)"); } const SmpLength origSampleLength = sample.nLength; // Sample offset if(region.offset && region.offset < sample.nLength) { auto offset = region.offset * sample.GetBytesPerSample(); memmove(sample.sampleb(), sample.sampleb() + offset, sample.nLength * sample.GetBytesPerSample() - offset); if(region.end > region.offset) region.end -= region.offset; sample.nLength -= region.offset; sample.nLoopStart -= region.offset; sample.nLoopEnd -= region.offset; sample.uFlags.set(SMP_MODIFIED); filenameModifier += P_(" (offset)"); } LimitMax(sample.nLength, region.end); if(sample.nLength < origSampleLength && (origSampleLength - sample.nLength) >= 128 * 1024) { // If the sample was trimmed excessively, re-allocate to save memory. // This is crucial for SFZs like those generated by Sforzando's SF2 conversion process, // as the whole SF2 sample data chunk ends up in a single WAV file that is then referenced by each region and sliced accordingly. if(auto newData = ModSample::AllocateSample(sample.nLength, sample.GetBytesPerSample())) { memcpy(newData, sample.samplev(), sample.nLength * sample.GetBytesPerSample()); sample.FreeSample(); sample.pData.pSample = newData; } } if(region.invertPhase) { ctrlSmp::InvertSample(sample, 0, sample.nLength, *this); sample.uFlags.set(SMP_MODIFIED); filenameModifier += P_(" (inverted)"); } if(sample.uFlags.test_all(SMP_KEEPONDISK | SMP_MODIFIED)) { // Avoid ruining the original samples if(auto filename = GetSamplePath(smp); !filename.empty()) { filename = filename.GetDirectoryWithDrive() + filename.GetFilenameBase() + filenameModifier + filename.GetFilenameExtension(); SetSamplePath(smp, filename); } } sample.PrecomputeLoops(*this, false); sample.Convert(MOD_TYPE_MPT, GetType()); } pIns->Sanitize(MOD_TYPE_MPT); pIns->Convert(MOD_TYPE_MPT, GetType()); return true; } #ifndef MODPLUG_NO_FILESAVE static double SFZLinear2dB(double volume) { return (volume > 0.0 ? 20.0 * std::log10(volume) : -144.0); } static void WriteSFZEnvelope(std::ostream &f, double tickDuration, int index, const InstrumentEnvelope &env, const char *type, double scale, std::function convFunc) { if(!env.dwFlags[ENV_ENABLED] || env.empty()) return; const bool sustainAtEnd = (!env.dwFlags[ENV_SUSTAIN] || env.nSustainStart == (env.size() - 1)) && convFunc(env.back().value) != 0.0; const auto prefix = MPT_AFORMAT("\neg{}_")(mpt::afmt::dec0<2>(index)); f << "\n" << prefix << type << "=" << scale; f << prefix << "points=" << (env.size() + (sustainAtEnd ? 1 : 0)); EnvelopeNode::tick_t lastTick = 0; int nodeIndex = 0; for(const auto &node : env) { const double time = (node.tick - lastTick) * tickDuration; lastTick = node.tick; f << prefix << "time" << nodeIndex << "=" << time; f << prefix << "level" << nodeIndex << "=" << convFunc(node.value); nodeIndex++; } if(sustainAtEnd) { // Prevent envelope from going back to neutral f << prefix << "time" << nodeIndex << "=0"; f << prefix << "level" << nodeIndex << "=" << convFunc(env.back().value); } // We always must write a sustain point, or the envelope will be sustained on the first point of the envelope f << prefix << "sustain=" << (env.dwFlags[ENV_SUSTAIN] ? env.nSustainStart : (env.size() - 1)); if(env.dwFlags[ENV_LOOP]) f << "\n// Loop: " << static_cast(env.nLoopStart) << "-" << static_cast(env.nLoopEnd); if(env.dwFlags[ENV_SUSTAIN] && env.nSustainEnd > env.nSustainStart) f << "\n// Sustain Loop: " << static_cast(env.nSustainStart) << "-" << static_cast(env.nSustainEnd); if(env.nReleaseNode != ENV_RELEASE_NODE_UNSET) f << "\n// Release Node: " << static_cast(env.nReleaseNode); } static std::string SanitizeSFZString(std::string s, mpt::Charset sourceCharset) { using namespace std::literals; // Remove characters could trip up the parser std::string::size_type pos = 0; while((pos = s.find_first_of("<=\r\n\t\0"sv, pos)) != std::string::npos) { s[pos++] = ' '; } return mpt::ToCharset(mpt::Charset::UTF8, sourceCharset, s); } bool CSoundFile::SaveSFZInstrument(INSTRUMENTINDEX nInstr, std::ostream &f, const mpt::PathString &filename, bool useFLACsamples) const { #ifdef MODPLUG_TRACKER const mpt::IO::FlushMode flushMode = mpt::IO::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave); #else const mpt::IO::FlushMode flushMode = mpt::IO::FlushMode::Full; #endif const ModInstrument *ins = Instruments[nInstr]; if(ins == nullptr) return false; // Creating directory names with trailing spaces or dots is a bad idea, as they are difficult to remove in Windows. const mpt::RawPathString whitespaceDirName = PL_(" \n\r\t."); const mpt::PathString sampleBaseName = mpt::PathString::FromNative(mpt::trim(filename.GetFilenameBase().AsNative(), whitespaceDirName)); const mpt::PathString sampleDirName = (sampleBaseName.empty() ? P_("Samples") : sampleBaseName) + P_("/"); const mpt::PathString sampleBasePath = filename.GetDirectoryWithDrive() + sampleDirName; if(!mpt::native_fs{}.is_directory(sampleBasePath) && !::CreateDirectory(sampleBasePath.AsNative().c_str(), nullptr)) return false; const double tickDuration = m_PlayState.m_nSamplesPerTick / static_cast(m_MixerSettings.gdwMixingFreq); f << std::setprecision(10); f << "// Created with " << mpt::ToCharset(mpt::Charset::UTF8, Version::Current().GetOpenMPTVersionString()) << "\n"; f << "// Envelope tempo base: tempo " << m_PlayState.m_nMusicTempo.ToDouble(); switch(m_nTempoMode) { case TempoMode::Classic: f << " (classic tempo mode)"; break; case TempoMode::Alternative: f << " (alternative tempo mode)"; break; case TempoMode::Modern: f << ", " << m_PlayState.m_nMusicSpeed << " ticks per row, " << m_PlayState.m_nCurrentRowsPerBeat << " rows per beat (modern tempo mode)"; break; case TempoMode::NumModes: MPT_ASSERT_NOTREACHED(); break; } f << "\n\n\ndefault_path=" << sampleDirName.ToUTF8(); if(const auto globalName = SanitizeSFZString(ins->name, GetCharsetInternal()); !globalName.empty()) { f << "\n\n\nglobal_label=" << globalName; } f << "\n\n"; f << "\nbend_up=" << ins->midiPWD * 100; f << "\nbend_down=" << -ins->midiPWD * 100; const uint32 cutoff = ins->IsCutoffEnabled() ? ins->GetCutoff() : 127; // If filter envelope is active but cutoff is not set, we still need to set the base cutoff frequency to be modulated by the envelope. if(ins->IsCutoffEnabled() || ins->PitchEnv.dwFlags[ENV_FILTER]) f << "\ncutoff=" << CSoundFile::CutOffToFrequency(cutoff) << " // " << cutoff; if(ins->IsResonanceEnabled()) f << "\nresonance=" << Util::muldivr_unsigned(ins->GetResonance(), 24, 128) << " // " << static_cast(ins->GetResonance()); if(ins->IsCutoffEnabled() || ins->IsResonanceEnabled()) f << "\nfil_type=" << (ins->filterMode == FilterMode::HighPass ? "hpf_2p" : "lpf_2p"); if(ins->dwFlags[INS_SETPANNING]) f << "\npan=" << (Util::muldivr_unsigned(ins->nPan, 200, 256) - 100) << " // " << ins->nPan; if(ins->nGlobalVol != 64) f << "\nvolume=" << SFZLinear2dB(ins->nGlobalVol / 64.0) << " // " << ins->nGlobalVol; if(ins->nFadeOut) { f << "\nampeg_release=" << (32768.0 * tickDuration / ins->nFadeOut) << " // " << ins->nFadeOut; f << "\nampeg_release_shape=0"; } if(ins->nDNA == DuplicateNoteAction::NoteCut && ins->nDCT != DuplicateCheckType::None) f << "\npolyphony=1"; WriteSFZEnvelope(f, tickDuration, 1, ins->VolEnv, "amplitude", 100.0, [](int32 val) { return val / static_cast(ENVELOPE_MAX); }); WriteSFZEnvelope(f, tickDuration, 2, ins->PanEnv, "pan", 100.0, [](int32 val) { return 2.0 * (val - ENVELOPE_MID) / (ENVELOPE_MAX - ENVELOPE_MIN); }); if(ins->PitchEnv.dwFlags[ENV_FILTER]) { const auto envScale = 1200.0 * std::log(CutOffToFrequency(127, 256) / static_cast(CutOffToFrequency(0, -256))) / mpt::numbers::ln2; const auto cutoffNormal = CutOffToFrequency(cutoff); WriteSFZEnvelope(f, tickDuration, 3, ins->PitchEnv, "cutoff", envScale, [this, cutoff, cutoffNormal, envScale](int32 val) { // Convert interval between center frequency and envelope into cents const auto freq = CutOffToFrequency(cutoff, (val - ENVELOPE_MID) * 256 / (ENVELOPE_MAX - ENVELOPE_MID)); return 1200.0 * std::log(freq / static_cast(cutoffNormal)) / mpt::numbers::ln2 / envScale; }); } else { WriteSFZEnvelope(f, tickDuration, 3, ins->PitchEnv, "pitch", 1600.0, [](int32 val) { return 2.0 * (val - ENVELOPE_MID) / (ENVELOPE_MAX - ENVELOPE_MIN); }); } size_t numSamples = 0; for(size_t i = 0; i < std::size(ins->Keyboard); i++) { if(ins->Keyboard[i] < 1 || ins->Keyboard[i] > GetNumSamples()) continue; size_t endOfRegion = i + 1; while(endOfRegion < std::size(ins->Keyboard)) { if(ins->Keyboard[endOfRegion] != ins->Keyboard[i] || ins->NoteMap[endOfRegion] != (ins->NoteMap[i] + endOfRegion - i)) break; endOfRegion++; } endOfRegion--; const ModSample &sample = Samples[ins->Keyboard[i]]; const bool isAdlib = sample.uFlags[CHN_ADLIB]; if(!sample.HasSampleData()) { i = endOfRegion; continue; } numSamples++; mpt::PathString sampleName = sampleBasePath + (sampleBaseName.empty() ? P_("Sample") : sampleBaseName) + P_(" ") + mpt::PathString::FromUnicode(mpt::ufmt::val(numSamples)); if(isAdlib) sampleName += P_(".s3i"); else if(useFLACsamples) sampleName += P_(".flac"); else sampleName += P_(".wav"); bool success = false; try { mpt::IO::SafeOutputFile sfSmp(sampleName, std::ios::binary, flushMode); if(sfSmp) { mpt::IO::ofstream &fSmp = sfSmp; fSmp.exceptions(fSmp.exceptions() | std::ios::badbit | std::ios::failbit); if(isAdlib) success = SaveS3ISample(ins->Keyboard[i], fSmp); else if(useFLACsamples) success = SaveFLACSample(ins->Keyboard[i], fSmp); else success = SaveWAVSample(ins->Keyboard[i], fSmp); } } catch(const std::exception &) { success = false; } if(!success) { AddToLog(LogError, MPT_USTRING("Unable to save sample: ") + sampleName.ToUnicode()); } f << "\n\n"; if(const auto regionName = SanitizeSFZString(m_szNames[ins->Keyboard[i]], GetCharsetInternal()); !regionName.empty()) { f << "\nregion_label=" << regionName; } f << "\nsample=" << sampleName.GetFilename().ToUTF8(); f << "\nlokey=" << i; f << "\nhikey=" << endOfRegion; if(sample.rootNote != NOTE_NONE) f << "\npitch_keycenter=" << sample.rootNote - NOTE_MIN; else f << "\npitch_keycenter=" << NOTE_MIDDLEC + i - ins->NoteMap[i]; if(sample.uFlags[CHN_PANNING]) f << "\npan=" << (Util::muldivr_unsigned(sample.nPan, 200, 256) - 100) << " // " << sample.nPan; if(sample.nGlobalVol != 64) f << "\nvolume=" << SFZLinear2dB((ins->nGlobalVol * sample.nGlobalVol) / 4096.0) << " // " << sample.nGlobalVol; const char *loopMode = "no_loop", *loopType = "forward"; SmpLength loopStart = 0, loopEnd = 0; if(sample.uFlags[CHN_SUSTAINLOOP]) { loopMode = "loop_sustain"; loopStart = sample.nSustainStart; loopEnd = sample.nSustainEnd; if(sample.uFlags[CHN_PINGPONGSUSTAIN]) loopType = "alternate"; } else if(sample.uFlags[CHN_LOOP]) { loopMode = "loop_continuous"; loopStart = sample.nLoopStart; loopEnd = sample.nLoopEnd; if(sample.uFlags[CHN_PINGPONGLOOP]) loopType = "alternate"; else if(sample.uFlags[CHN_REVERSE]) loopType = "backward"; } f << "\nloop_mode=" << loopMode; if(loopStart < loopEnd) { f << "\nloop_start=" << loopStart; f << "\nloop_end=" << (loopEnd - 1); f << "\nloop_type=" << loopType; } if(sample.uFlags.test_all(CHN_SUSTAINLOOP | CHN_LOOP)) { f << "\n// Warning: Only sustain loop was exported!"; } i = endOfRegion; } return true; } #endif // MODPLUG_NO_FILESAVE #else bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX, FileReader &) { return false; } #endif // MPT_EXTERNAL_SAMPLES OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_dsm.cpp0000644000175000017500000003267614644610543020350 00000000000000/* * Load_dsm.cpp * ------------ * Purpose: - Digisound Interface Kit (DSIK) Internal Format (DSM v2 / RIFF) module loader * - Dynamic Studio (DSM) module loader * Notes : 1. There is also another fundamentally different DSIK DSM v1 module format, not handled here. * MilkyTracker can load it, but the only files of this format seen in the wild are also * available in their original format, so I did not bother implementing it so far. * * 2. S3M-style retrigger does not seem to exist - it is translated to volume slides by CONV.EXE, * and J00 in S3M files is not converted either. S3M pattern loops (SBx) are not converted * properly by CONV.EXE and completely ignored by PLAY.EXE. * Command 8 (set panning) uses 00-80 for regular panning and A4 for surround, probably * making DSIK one of the first applications to use this convention established by DSMI's AMF format. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN ///////////////////////////////////////////////////////////////////// // DMS (DSIK) loader struct DSMChunk { char magic[4]; uint32le size; }; MPT_BINARY_STRUCT(DSMChunk, 8) struct DSMSongHeader { char songName[28]; uint16le fileVersion; uint16le flags; uint16le orderPos; uint16le restartPos; uint16le numOrders; uint16le numSamples; uint16le numPatterns; uint16le numChannels; uint8le globalVol; uint8le mastervol; uint8le speed; uint8le bpm; uint8le panPos[16]; uint8le orders[128]; }; MPT_BINARY_STRUCT(DSMSongHeader, 192) struct DSMSampleHeader { char filename[13]; uint16le flags; uint8le volume; uint32le length; uint32le loopStart; uint32le loopEnd; uint32le dataPtr; // Interal sample pointer during playback in DSIK uint32le sampleRate; char sampleName[28]; // Convert a DSM sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename); mptSmp.nC5Speed = sampleRate; mptSmp.uFlags.set(CHN_LOOP, (flags & 1) != 0); mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4; } // Retrieve the internal sample format flags for this sample. SampleIO GetSampleFormat() const { SampleIO sampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::unsignedPCM); if(flags & 0x40) sampleIO |= SampleIO::deltaPCM; // fairlight.dsm by Comrade J else if(flags & 0x02) sampleIO |= SampleIO::signedPCM; if(flags & 0x04) sampleIO |= SampleIO::_16bit; return sampleIO; } }; MPT_BINARY_STRUCT(DSMSampleHeader, 64) struct DSMHeader { char fileMagic0[4]; char fileMagic1[4]; char fileMagic2[4]; }; MPT_BINARY_STRUCT(DSMHeader, 12) static bool ValidateHeader(const DSMHeader &fileHeader) { if(!std::memcmp(fileHeader.fileMagic0, "RIFF", 4) && !std::memcmp(fileHeader.fileMagic2, "DSMF", 4)) { // "Normal" DSM files with RIFF header // return true; } else if(!std::memcmp(fileHeader.fileMagic0, "DSMF", 4)) { // DSM files with alternative header // <4 bytes, usually 4x NUL or RIFF> <4 bytes, usually DSMF but not always> return true; } else { return false; } } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize) { DSMHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } if(std::memcmp(fileHeader.fileMagic0, "DSMF", 4) == 0) { if(!file.Skip(4)) { return ProbeWantMoreData; } } DSMChunk chunkHeader; if(!file.ReadStruct(chunkHeader)) { return ProbeWantMoreData; } if(std::memcmp(chunkHeader.magic, "SONG", 4)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); DSMHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(std::memcmp(fileHeader.fileMagic0, "DSMF", 4) == 0) { file.Skip(4); } DSMChunk chunkHeader; if(!file.ReadStruct(chunkHeader)) { return false; } // Technically, the song chunk could be anywhere in the file, but we're going to simplify // things by not using a chunk header here and just expect it to be right at the beginning. if(std::memcmp(chunkHeader.magic, "SONG", 4)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } DSMSongHeader songHeader; file.ReadStructPartial(songHeader, chunkHeader.size); if(songHeader.numOrders > 128 || songHeader.numChannels > 16 || songHeader.numPatterns > 256 || songHeader.restartPos > 128) { return false; } InitializeGlobals(MOD_TYPE_DSM, std::max(songHeader.numChannels.get(), uint16(1))); m_modFormat.formatName = UL_("DSIK Format"); m_modFormat.type = UL_("dsm"); m_modFormat.charset = mpt::Charset::CP437; m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, songHeader.songName); Order().SetDefaultSpeed(songHeader.speed); Order().SetDefaultTempoInt(songHeader.bpm); m_nDefaultGlobalVolume = std::min(songHeader.globalVol.get(), uint8(64)) * 4u; if(!m_nDefaultGlobalVolume) m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; if(songHeader.mastervol == 0x80) m_nSamplePreAmp = std::min(256u / GetNumChannels(), 128u); else m_nSamplePreAmp = songHeader.mastervol & 0x7F; // Read channel panning for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { if(songHeader.panPos[chn] <= 0x80) { ChnSettings[chn].nPan = songHeader.panPos[chn] * 2; } } ReadOrderFromArray(Order(), songHeader.orders, songHeader.numOrders, 0xFF, 0xFE); if(songHeader.restartPos < songHeader.numOrders) Order().SetRestartPos(songHeader.restartPos); // Read pattern and sample chunks PATTERNINDEX patNum = 0; while(file.ReadStruct(chunkHeader)) { FileReader chunk = file.ReadChunk(chunkHeader.size); if(!memcmp(chunkHeader.magic, "PATT", 4) && (loadFlags & loadPatternData)) { // Read pattern if(!Patterns.Insert(patNum, 64)) { continue; } chunk.Skip(2); ModCommand dummy{}; ROWINDEX row = 0; while(chunk.CanRead(1) && row < 64) { uint8 flag = chunk.ReadUint8(); if(!flag) { row++; continue; } CHANNELINDEX chn = (flag & 0x0F); ModCommand &m = (chn < GetNumChannels() ? *Patterns[patNum].GetpModCommand(row, chn) : dummy); if(flag & 0x80) { uint8 note = chunk.ReadUint8(); if(note) { if(note <= 12 * 9) note += 11 + NOTE_MIN; m.note = note; } } if(flag & 0x40) { m.instr = chunk.ReadUint8(); } if (flag & 0x20) { m.volcmd = VOLCMD_VOLUME; m.vol = std::min(chunk.ReadUint8(), uint8(64)); } if(flag & 0x10) { auto [command, param] = chunk.ReadArray(); ConvertModCommand(m, command, param); } } patNum++; } else if(!memcmp(chunkHeader.magic, "INST", 4) && CanAddMoreSamples()) { // Read sample m_nSamples++; ModSample &sample = Samples[m_nSamples]; DSMSampleHeader sampleHeader; chunk.ReadStruct(sampleHeader); sampleHeader.ConvertToMPT(sample); m_szNames[m_nSamples] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.sampleName); if(loadFlags & loadSampleData) { sampleHeader.GetSampleFormat().ReadSample(sample, chunk); } } } return true; } ///////////////////////////////////////////////////////////////////// // DSM (Dynamic Studio) loader struct DSmSampleHeader { char name[22]; uint8 type; uint16le length; uint8 finetune; uint8 volume; uint16le loopStart; uint16le loopLength; uint8 padding; void ConvertToMPT(ModSample &mptSmp) const { mptSmp.nVolume = std::min(volume, uint8(64)) * 4u; mptSmp.nFineTune = MOD2XMFineTune(finetune); mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopStart + loopLength; mptSmp.uFlags.set(CHN_LOOP, loopLength > 2); mptSmp.uFlags.set(CHN_16BIT, type == 16); } }; MPT_BINARY_STRUCT(DSmSampleHeader, 32) struct DSmFileHeader { char magic[4]; // "DSm\x1A" uint8 version; char title[20]; char artist[20]; uint8 numChannels; uint8 numSamples; uint8 numOrders; uint8 packInformation; uint8 globalVol; // 0...100 char padding[14]; bool IsValid() const noexcept { return !memcmp(magic, "DSm\x1A", 4) && version == 0x20 && numChannels >= 1 && numChannels <= 16 && numSamples > 0 && numOrders > 0 && globalVol <= 100; } uint32 GetHeaderMinimumAdditionalSize() const noexcept { return static_cast(numChannels + numOrders + numSamples * sizeof(DSmSampleHeader)); } }; MPT_BINARY_STRUCT(DSmFileHeader, 64) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDSm(MemoryFileReader file, const uint64 *pfilesize) { DSmFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadDSm(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); DSmFileHeader fileHeader; if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) return false; if(!file.CanRead(fileHeader.GetHeaderMinimumAdditionalSize())) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_MOD, fileHeader.numChannels); m_SongFlags = SONG_IMPORTED; static_assert(MAX_BASECHANNELS >= 32 && MAX_SAMPLES > 255); m_nSamples = fileHeader.numSamples; m_nDefaultGlobalVolume = Util::muldivr_unsigned(fileHeader.globalVol, MAX_GLOBAL_VOLUME, 100); m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.title); m_songArtist = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.artist)); for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = (file.ReadUint8() & 0x0F) * 0x11; } ReadOrderFromFile(Order(), file, fileHeader.numOrders); PATTERNINDEX numPatterns = 0; for(PATTERNINDEX pat : Order()) { numPatterns = std::max(pat, numPatterns); } numPatterns++; if(!file.CanRead((numPatterns * GetNumChannels() * 8) + (m_nSamples * sizeof(DSmSampleHeader)) + (numPatterns * GetNumChannels() * 64 * 4))) return false; // Track names for each pattern - we only read the track names of the first pattern for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].szName = mpt::String::ReadBuf(mpt::String::spacePadded, file.ReadArray()); } file.Skip((numPatterns - 1) * GetNumChannels() * 8); for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { DSmSampleHeader sampleHeader; file.ReadStruct(sampleHeader); sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); } Patterns.ResizeArray(numPatterns); for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { file.Skip(GetNumChannels() * 64 * 4); continue; } for(ModCommand &m : Patterns[pat]) { const auto data = file.ReadArray(); if(data[1] > 0 && data[1] <= 84 * 2) m.note = (data[1] >> 1) + NOTE_MIN + 35; m.instr = data[0]; m.param = data[3]; if(data[2] == 0x08) { switch(m.param & 0xF0) { case 0x00: // 4-bit panning m.command = CMD_MODCMDEX; m.param |= 0x80; break; case 0x10: // Default volume slide Up (should stop at sample's default volume) m.command = CMD_VOLUMESLIDE; m.param <<= 4; break; case 0x20: // Default fine volume slide Up (should stop at sample's default volume) m.command = CMD_MODCMDEX; m.param |= 0xA0; break; case 0x30: // Fine porta up (support all 5 octaves) case 0x40: // Fine porta down (support all 5 octaves) m.command = CMD_MODCMDEX; m.param -= 0x20; break; default: break; } } else if(data[2] == 0x13) { // 3D Simulate m.command = CMD_PANNING8; uint32 param = (m.param & 0x7F) * 2u; if(m.param <= 0x40) // 00 Front -> 40 Right param += 0x80; else if(m.param < 0x80) // 40 Right -> 80 Back param = 0x180 - param; else if(m.param < 0xC0) // 80 Back -> C0 Left param = 0x80 - param; else // C0 Left -> FF Front param -= 0x80; m.param = mpt::saturate_cast(param); } else if((data[2] & 0xF0) == 0x20) { // Offset + volume m.command = CMD_OFFSET; m.SetVolumeCommand(VOLCMD_VOLUME, static_cast((data[2] & 0x0F) * 4 + 4)); } else if(data[2] <= 0x0F || data[2] == 0x11 || data[2] == 0x12) { // 0x11 and 0x12 support the full 5-octave range, 0x01 and 0x02 presumably only the ProTracker 3-octave range ConvertModCommand(m, data[2] & 0x0F, data[3]); } } } if(loadFlags & loadSampleData) { for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { SampleIO(Samples[smp].uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM).ReadSample(Samples[smp], file); } } m_modFormat.formatName = UL_("Dynamic Studio"); m_modFormat.type = UL_("dsm"); m_modFormat.charset = mpt::Charset::CP437; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_xm.cpp0000644000175000017500000013770614735077030020210 00000000000000/* * Load_xm.cpp * ----------- * Purpose: XM (FastTracker II) module loader / saver * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "../common/version.h" #include "XMTools.h" #include "mod_specifications.h" #ifndef MODPLUG_NO_FILESAVE #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "../common/mptFileIO.h" #endif #include "OggStream.h" #include #ifdef MODPLUG_TRACKER #include "../mptrack/TrackerSettings.h" // For super smooth ramping option #endif // MODPLUG_TRACKER #include "mpt/audio/span.hpp" #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE) #include #endif #if defined(MPT_WITH_VORBIS) #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif // MPT_COMPILER_CLANG #include #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #endif #if defined(MPT_WITH_VORBISFILE) #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif // MPT_COMPILER_CLANG #include #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #include "openmpt/soundbase/Copy.hpp" #endif #ifdef MPT_WITH_STBVORBIS #include #include "openmpt/soundbase/Copy.hpp" #endif // MPT_WITH_STBVORBIS OPENMPT_NAMESPACE_BEGIN #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE) static size_t VorbisfileFilereaderRead(void *ptr, size_t size, size_t nmemb, void *datasource) { FileReader &file = *mpt::void_ptr(datasource); return file.ReadRaw(mpt::span(mpt::void_cast(ptr), size * nmemb)).size() / size; } static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int whence) { FileReader &file = *mpt::void_ptr(datasource); switch(whence) { case SEEK_SET: { if(!mpt::in_range(offset)) { return -1; } return file.Seek(mpt::saturate_cast(offset)) ? 0 : -1; } break; case SEEK_CUR: { if(offset < 0) { if(offset == std::numeric_limits::min()) { return -1; } if(!mpt::in_range(0-offset)) { return -1; } return file.SkipBack(mpt::saturate_cast(0 - offset)) ? 0 : -1; } else { if(!mpt::in_range(offset)) { return -1; } return file.Skip(mpt::saturate_cast(offset)) ? 0 : -1; } } break; case SEEK_END: { if(!mpt::in_range(offset)) { return -1; } if(!mpt::in_range(file.GetLength() + offset)) { return -1; } return file.Seek(mpt::saturate_cast(file.GetLength() + offset)) ? 0 : -1; } break; default: return -1; } } static long VorbisfileFilereaderTell(void *datasource) { FileReader &file = *mpt::void_ptr(datasource); FileReader::pos_type result = file.GetPosition(); if(!mpt::in_range(result)) { return -1; } return static_cast(result); } #endif // MPT_WITH_VORBIS && MPT_WITH_VORBISFILE // Allocate samples for an instrument static std::vector AllocateXMSamples(CSoundFile &sndFile, SAMPLEINDEX numSamples) { LimitMax(numSamples, SAMPLEINDEX(32)); std::vector foundSlots; foundSlots.reserve(numSamples); for(SAMPLEINDEX i = 0; i < numSamples; i++) { SAMPLEINDEX candidateSlot = sndFile.GetNumSamples() + 1; if(candidateSlot >= MAX_SAMPLES) { // If too many sample slots are needed, try to fill some empty slots first. for(SAMPLEINDEX j = 1; j <= sndFile.GetNumSamples(); j++) { if(sndFile.GetSample(j).HasSampleData()) { continue; } if(!mpt::contains(foundSlots, j)) { // Empty sample slot that is not occupied by the current instrument. Yay! candidateSlot = j; // Remove unused sample from instrument sample assignments for(INSTRUMENTINDEX ins = 1; ins <= sndFile.GetNumInstruments(); ins++) { if(sndFile.Instruments[ins] == nullptr) { continue; } for(auto &sample : sndFile.Instruments[ins]->Keyboard) { if(sample == candidateSlot) { sample = 0; } } } break; } } } if(candidateSlot >= MAX_SAMPLES) { // Still couldn't find any empty sample slots, so look out for existing but unused samples. std::vector usedSamples; SAMPLEINDEX unusedSampleCount = sndFile.DetectUnusedSamples(usedSamples); if(unusedSampleCount > 0) { sndFile.RemoveSelectedSamples(usedSamples); // Remove unused samples from instrument sample assignments for(INSTRUMENTINDEX ins = 1; ins <= sndFile.GetNumInstruments(); ins++) { if(sndFile.Instruments[ins] == nullptr) { continue; } for(auto &sample : sndFile.Instruments[ins]->Keyboard) { if(sample < usedSamples.size() && !usedSamples[sample]) { sample = 0; } } } // New candidate slot is first unused sample slot. candidateSlot = static_cast(std::find(usedSamples.begin() + 1, usedSamples.end(), false) - usedSamples.begin()); } else { // No unused sample slots: Give up :( break; } } if(candidateSlot < MAX_SAMPLES) { foundSlots.push_back(candidateSlot); if(candidateSlot > sndFile.GetNumSamples()) { sndFile.m_nSamples = candidateSlot; } } } return foundSlots; } // Read .XM patterns static void ReadXMPatterns(FileReader &file, const XMFileHeader &fileHeader, CSoundFile &sndFile) { // Reading patterns sndFile.Patterns.ResizeArray(fileHeader.patterns); for(PATTERNINDEX pat = 0; pat < fileHeader.patterns; pat++) { FileReader::pos_type curPos = file.GetPosition(); const uint32 headerSize = file.ReadUint32LE(); if(headerSize < 8 || !file.CanRead(headerSize - 4)) break; file.Skip(1); // Pack method (= 0) ROWINDEX numRows; if(fileHeader.version == 0x0102) numRows = file.ReadUint8() + 1; else numRows = file.ReadUint16LE(); // A packed size of 0 indicates a completely empty pattern. const uint16 packedSize = file.ReadUint16LE(); if(numRows == 0) numRows = 64; else if(numRows > MAX_PATTERN_ROWS) numRows = MAX_PATTERN_ROWS; file.Seek(curPos + headerSize); FileReader patternChunk = file.ReadChunk(packedSize); if(pat >= MAX_PATTERNS || !sndFile.Patterns.Insert(pat, numRows) || packedSize == 0) continue; enum PatternFlags { isPackByte = 0x80, allFlags = 0xFF, notePresent = 0x01, instrPresent = 0x02, volPresent = 0x04, commandPresent = 0x08, paramPresent = 0x10, }; for(auto &m : sndFile.Patterns[pat]) { if(!file.CanRead(1)) break; uint8 info = patternChunk.ReadUint8(); uint8 vol = 0, command = 0; if(info & isPackByte) { // Interpret byte as flag set. if(info & notePresent) m.note = patternChunk.ReadUint8(); } else { // Interpret byte as note, read all other pattern fields as well. m.note = info; info = allFlags; } if(info & instrPresent) m.instr = patternChunk.ReadUint8(); if(info & volPresent) vol = patternChunk.ReadUint8(); if(info & commandPresent) command = patternChunk.ReadUint8(); if(info & paramPresent) m.param = patternChunk.ReadUint8(); if(m.note == 97) { m.note = NOTE_KEYOFF; } else if(m.note > 0 && m.note < 97) { m.note += 12; } else { m.note = NOTE_NONE; } if(command | m.param) { CSoundFile::ConvertModCommand(m, command, m.param); } else { m.command = CMD_NONE; } if(m.instr == 0xFF) { m.instr = 0; } if(vol >= 0x10 && vol <= 0x50) { m.volcmd = VOLCMD_VOLUME; m.vol = vol - 0x10; } else if (vol >= 0x60) { // Volume commands 6-F translation. static constexpr ModCommand::VOLCMD volEffTrans[] = { VOLCMD_VOLSLIDEDOWN, VOLCMD_VOLSLIDEUP, VOLCMD_FINEVOLDOWN, VOLCMD_FINEVOLUP, VOLCMD_VIBRATOSPEED, VOLCMD_VIBRATODEPTH, VOLCMD_PANNING, VOLCMD_PANSLIDELEFT, VOLCMD_PANSLIDERIGHT, VOLCMD_TONEPORTAMENTO, }; m.volcmd = volEffTrans[(vol - 0x60) >> 4]; m.vol = vol & 0x0F; if(m.volcmd == VOLCMD_PANNING) { m.vol *= 4; // FT2 does indeed not scale panning symmetrically. } } } } } enum TrackerVersions { verUnknown = 0x00, // Probably not made with MPT verOldModPlug = 0x01, // Made with MPT Alpha / Beta verNewModPlug = 0x02, // Made with MPT (not Alpha / Beta) verModPlugBidiFlag = 0x04, // MPT up to v1.11 sets both normal loop and pingpong loop flags verOpenMPT = 0x08, // Made with OpenMPT verConfirmed = 0x10, // We are very sure that we found the correct tracker version. verFT2Generic = 0x20, // "FastTracker v2.00", but FastTracker has NOT been ruled out verOther = 0x40, // Something we don't know, testing for DigiTrakker. verFT2Clone = 0x80, // NOT FT2: itype changed between instruments, or \0 found in song title verPlayerPRO = 0x100, // Could be PlayerPRO verDigiTrakker = 0x200, // Probably DigiTrakker verUNMO3 = 0x400, // TODO: UNMO3-ed XMs are detected as MPT 1.16 verEmptyOrders = 0x800, // Allow empty order list like in OpenMPT (FT2 just plays pattern 0 if the order list is empty according to the header) }; DECLARE_FLAGSET(TrackerVersions) static bool ValidateHeader(const XMFileHeader &fileHeader) { if(fileHeader.channels == 0 || fileHeader.channels > MAX_BASECHANNELS || std::memcmp(fileHeader.signature, "Extended Module: ", 17) ) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const XMFileHeader &fileHeader) { return fileHeader.orders + 4 * (fileHeader.patterns + fileHeader.instruments); } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize) { XMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } static bool ReadSampleData(ModSample &sample, SampleIO sampleFlags, FileReader &sampleChunk, bool &isOXM) { bool unsupportedSample = false; bool isOGG = false; if(sampleChunk.CanRead(8)) { isOGG = true; sampleChunk.Skip(4); // In order to avoid false-detecting PCM as OggVorbis as much as possible, // we parse and verify the complete sample data and only assume OggVorbis, // if all Ogg checksums are correct a no single byte of non-Ogg data exists. // The fast-path for regular PCM will only check "OggS" magic and do no other work after failing that check. while(!sampleChunk.EndOfFile()) { if(!Ogg::ReadPage(sampleChunk)) { isOGG = false; break; } } } isOXM = isOXM || isOGG; sampleChunk.Rewind(); if(isOGG) { uint32 originalSize = sampleChunk.ReadInt32LE(); FileReader sampleData = sampleChunk.ReadChunk(sampleChunk.BytesLeft()); sample.uFlags.set(CHN_16BIT, sampleFlags.GetBitDepth() >= 16); sample.uFlags.set(CHN_STEREO, sampleFlags.GetChannelFormat() != SampleIO::mono); sample.nLength = originalSize / (sample.uFlags[CHN_16BIT] ? 2 : 1) / (sample.uFlags[CHN_STEREO] ? 2 : 1); #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE) ov_callbacks callbacks = { &VorbisfileFilereaderRead, &VorbisfileFilereaderSeek, NULL, &VorbisfileFilereaderTell }; OggVorbis_File vf; MemsetZero(vf); if(ov_open_callbacks(mpt::void_ptr(&sampleData), &vf, nullptr, 0, callbacks) == 0) { if(ov_streams(&vf) == 1) { // we do not support chained vorbis samples vorbis_info *vi = ov_info(&vf, -1); if(vi && vi->rate > 0 && vi->channels > 0) { sample.AllocateSample(); SmpLength offset = 0; int channels = vi->channels; int current_section = 0; long decodedSamples = 0; bool eof = false; while(!eof && offset < sample.nLength && sample.HasSampleData()) { float **output = nullptr; long ret = ov_read_float(&vf, &output, 1024, ¤t_section); if(ret == 0) { eof = true; } else if(ret < 0) { // stream error, just try to continue } else { decodedSamples = ret; LimitMax(decodedSamples, mpt::saturate_cast(sample.nLength - offset)); if(offset == 0 && channels == 1 && sample.GetNumChannels() == 2) { // oggmod doesn't know what stereo samples are, so it treats them as mono samples, but doesn't clear the unknown stereo flag. // We just take the left channel in this case, as it is difficult (if possible at all) to properly reconstruct the waveform of the right channel. // Due to XM's delta-encoding and Vorbis being a lossless codec, samples could distort easily even when the delta encoding was off by a very small amount. sample.uFlags.reset(CHN_STEREO); } if(decodedSamples > 0 && channels == sample.GetNumChannels()) { if(sample.uFlags[CHN_16BIT]) { CopyAudio(mpt::audio_span_interleaved(sample.sample16() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples)); } else { CopyAudio(mpt::audio_span_interleaved(sample.sample8() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples)); } } offset += static_cast(decodedSamples); } } } else { unsupportedSample = true; } } else { unsupportedSample = true; } ov_clear(&vf); } else { unsupportedSample = true; } #elif defined(MPT_WITH_STBVORBIS) // NOTE/TODO: stb_vorbis does not handle inferred negative PCM sample // position at stream start. (See // ). // This means that, for remuxed and re-aligned/cutted (at stream start) // Vorbis files, stb_vorbis will include superfluous samples at the // beginning. OXM files with this property are yet to be spotted in the // wild, thus, this behaviour is currently not problematic. int consumed = 0, error = 0; stb_vorbis *vorb = nullptr; FileReader::PinnedView sampleDataView = sampleData.GetPinnedView(); const std::byte* data = sampleDataView.data(); std::size_t dataLeft = sampleDataView.size(); vorb = stb_vorbis_open_pushdata(mpt::byte_cast(data), mpt::saturate_cast(dataLeft), &consumed, &error, nullptr); sampleData.Skip(consumed); data += consumed; dataLeft -= consumed; if(vorb) { // Header has been read, proceed to reading the sample data sample.AllocateSample(); SmpLength offset = 0; while((error == VORBIS__no_error || (error == VORBIS_need_more_data && dataLeft > 0)) && offset < sample.nLength && sample.HasSampleData()) { int channels = 0, decodedSamples = 0; float **output; consumed = stb_vorbis_decode_frame_pushdata(vorb, mpt::byte_cast(data), mpt::saturate_cast(dataLeft), &channels, &output, &decodedSamples); sampleData.Skip(consumed); data += consumed; dataLeft -= consumed; LimitMax(decodedSamples, mpt::saturate_cast(sample.nLength - offset)); if(decodedSamples > 0 && channels == sample.GetNumChannels()) { if(sample.uFlags[CHN_16BIT]) { CopyAudio(mpt::audio_span_interleaved(sample.sample16() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples)); } else { CopyAudio(mpt::audio_span_interleaved(sample.sample8() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples)); } } offset += decodedSamples; error = stb_vorbis_get_error(vorb); } stb_vorbis_close(vorb); } else { unsupportedSample = true; } #else // !VORBIS unsupportedSample = true; #endif // VORBIS } else { sampleFlags.ReadSample(sample, sampleChunk); } return !unsupportedSample; } bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); XMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } else if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_XM, fileHeader.channels); m_nMixLevels = MixLevels::Compatible; FlagSet madeWith(verUnknown); mpt::ustring madeWithTracker; bool isMadTracker = false; if(!memcmp(fileHeader.trackerName, "FastTracker v2.00 ", 20) && fileHeader.size == 276) { const std::string_view songName{fileHeader.songName, sizeof(fileHeader.songName)}; if(fileHeader.version < 0x0104) { madeWith = verFT2Generic | verConfirmed; } else if(const auto firstNull = songName.find('\0'); firstNull != std::string_view::npos) { // FT2 pads the song title with spaces, some other trackers use null chars // PlayerPRO filles the remaining buffer after the null terminator with space characters. // PlayerPRO does not support song restart position. if(fileHeader.restartPos) madeWith = verFT2Clone | verNewModPlug | verEmptyOrders; else if(firstNull == songName.size() - 1) madeWith = verFT2Clone | verNewModPlug | verPlayerPRO | verEmptyOrders; else if(songName.find_first_not_of(' ', firstNull + 1) == std::string_view::npos) madeWith = verPlayerPRO | verConfirmed; else madeWith = verFT2Clone | verNewModPlug | verEmptyOrders; } else { if(fileHeader.restartPos) madeWith = verFT2Generic | verNewModPlug; else madeWith = verFT2Generic | verNewModPlug | verPlayerPRO; } } else if(!memcmp(fileHeader.trackerName, "FastTracker v 2.00 ", 20)) { // MPT 1.0 (exact version to be determined later) madeWith = verOldModPlug; } else { // Something else! madeWith = verUnknown | verConfirmed; madeWithTracker = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.trackerName)); if(!memcmp(fileHeader.trackerName, "OpenMPT ", 8)) { madeWith = verOpenMPT | verConfirmed | verEmptyOrders; } else if(!memcmp(fileHeader.trackerName, "MilkyTracker ", 12)) { // MilkyTracker prior to version 0.90.87 doesn't set a version string. // Luckily, starting with v0.90.87, MilkyTracker also implements the FT2 panning scheme. if(memcmp(fileHeader.trackerName + 12, " ", 8)) { m_nMixLevels = MixLevels::CompatibleFT2; } } else if(!memcmp(fileHeader.trackerName, "Fasttracker II clone", 20)) { // 8bitbubsy's FT2 clone should be treated exactly like FT2 madeWith = verFT2Generic | verConfirmed; } else if(!memcmp(fileHeader.trackerName, "MadTracker 2.0\0", 15)) { // Fix channel 2 in m3_cha.xm m_playBehaviour.reset(kFT2PortaNoNote); // Fix arpeggios in kragle_-_happy_day.xm m_playBehaviour.reset(kFT2Arpeggio); isMadTracker = true; if(memcmp(fileHeader.trackerName + 15, "\0\0\0\0", 4)) madeWithTracker = UL_("MadTracker 2 (registered)"); else madeWithTracker = UL_("MadTracker 2"); } else if(!memcmp(fileHeader.trackerName, "Skale Tracker\0", 14) || !memcmp(fileHeader.trackerName, "Sk@le Tracker\0", 14)) { m_playBehaviour.reset(kFT2ST3OffsetOutOfRange); // Fix arpeggios in KAPTENFL.XM m_playBehaviour.reset(kFT2Arpeggio); } else if(!memcmp(fileHeader.trackerName, "*Converted ", 11) && !memcmp(fileHeader.trackerName + 14, "-File*", 6)) { madeWith = verDigiTrakker | verConfirmed; madeWithTracker = UL_("Digitrakker"); } } m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songName); m_nMinPeriod = 1; m_nMaxPeriod = 31999; Order().SetRestartPos(fileHeader.restartPos); m_nInstruments = std::min(static_cast(fileHeader.instruments), static_cast(MAX_INSTRUMENTS - 1)); if(fileHeader.speed) Order().SetDefaultSpeed(fileHeader.speed); if(fileHeader.tempo) Order().SetDefaultTempo(Clamp(TEMPO(fileHeader.tempo, 0), ModSpecs::xmEx.GetTempoMin(), ModSpecs::xmEx.GetTempoMax())); m_SongFlags.reset(); m_SongFlags.set(SONG_LINEARSLIDES, (fileHeader.flags & XMFileHeader::linearSlides) != 0); m_SongFlags.set(SONG_EXFILTERRANGE, (fileHeader.flags & XMFileHeader::extendedFilterRange) != 0); if(m_SongFlags[SONG_EXFILTERRANGE] && madeWith[verNewModPlug]) madeWith = verFT2Clone | verNewModPlug | verConfirmed | verEmptyOrders; ReadOrderFromFile(Order(), file, fileHeader.orders); if(fileHeader.orders == 0 && !madeWith[verEmptyOrders]) { // Fix lamb_-_dark_lighthouse.xm, which only contains one pattern and an empty order list Order().assign(1, 0); } file.Seek(fileHeader.size + 60); if(fileHeader.version >= 0x0104) { ReadXMPatterns(file, fileHeader, *this); } bool isOXM = false; // In case of XM versions < 1.04, we need to memorize the sample flags for all samples, as they are not stored immediately after the sample headers. std::vector sampleFlags; uint8 sampleReserved = 0; int16 lastInstrType = -1, lastSampleReserved = -1; int64 lastSampleHeaderSize = -1; bool unsupportedSamples = false; bool anyADPCM = false; bool instrumentWithSamplesEncountered = false; // Reading instruments for(INSTRUMENTINDEX instr = 1; instr <= m_nInstruments; instr++) { if(!AllocateInstrument(instr)) return false; if(!file.CanRead(4)) continue; // First, try to read instrument header length... uint32 headerSize = file.ReadUint32LE(); if(headerSize == 0) { headerSize = sizeof(XMInstrumentHeader); } // Now, read the complete struct. file.SkipBack(4); XMInstrumentHeader instrHeader; file.ReadStructPartial(instrHeader, headerSize); // Time for some version detection stuff. if(madeWith == verOldModPlug) { madeWith.set(verConfirmed); if(instrHeader.size == 245) { // ModPlug Tracker Alpha m_dwLastSavedWithVersion = MPT_V("1.00.00.A5"); madeWithTracker = UL_("ModPlug Tracker 1.0 alpha"); } else if(instrHeader.size == 263) { // ModPlug Tracker Beta (Beta 1 still behaves like Alpha, but Beta 3.3 does it this way) m_dwLastSavedWithVersion = MPT_V("1.00.00.B3"); madeWithTracker = UL_("ModPlug Tracker 1.0 beta"); } else { // WTF? madeWith = (verUnknown | verConfirmed); } } else if(instrHeader.numSamples == 0) { // Empty instruments make tracker identification pretty easy! if(instrHeader.size == 263 && instrHeader.sampleHeaderSize == 0 && madeWith[verNewModPlug]) madeWith.set(verConfirmed); else if(instrHeader.size != 29 && madeWith[verDigiTrakker]) madeWith.reset(verDigiTrakker); else if(madeWith[verFT2Clone | verFT2Generic] && instrHeader.size != 33) { // Sure isn't FT2. // 4-mat's eternity.xm has an empty instruments with a header size of 29. // Another module using that size is funky_dumbass.xm. Mysterious! // Note: This may happen when the XM Commenter by Aka (XMC.EXE) adds empty instruments at the end of the list, // which would explain the latter case, but in eternity.xm the empty slots are not at the end of the list. madeWith = verUnknown; } if(instrHeader.size != 33) { madeWith.reset(verPlayerPRO); } else if(instrHeader.sampleHeaderSize > sizeof(XMSample) && madeWith[verPlayerPRO]) { // Older PlayerPRO versions appear to write garbage in the sampleHeaderSize field, and it's different for each sample. // Note: FT2 NORMALLY writes sampleHeaderSize=40 for all samples, but for any instruments before the first // instrument that has numSamples != 0, sampleHeaderSize will be uninitialized. It will always be the same // value, though. if(instrumentWithSamplesEncountered || (lastSampleHeaderSize != -1 && instrHeader.sampleHeaderSize != lastSampleHeaderSize)) madeWith = verPlayerPRO | verConfirmed; lastSampleHeaderSize = instrHeader.sampleHeaderSize; } } instrHeader.ConvertToMPT(*Instruments[instr]); if(lastInstrType == -1) { lastInstrType = instrHeader.type; } else if(lastInstrType != instrHeader.type && madeWith[verFT2Generic]) { // FT2 writes some random junk for the instrument type field, // but it's always the SAME junk for every instrument saved. // Note: This may happen when running an FT2-made XM through PutInst and adding new instrument slots. madeWith.reset(verFT2Generic); madeWith.set(verFT2Clone); } if(instrHeader.numSamples > 0) { instrumentWithSamplesEncountered = true; // Yep, there are some samples associated with this instrument. // If MIDI settings are present, this is definitely not an old MPT or PlayerPRO. if((instrHeader.instrument.midiEnabled | instrHeader.instrument.midiChannel | instrHeader.instrument.midiProgram | instrHeader.instrument.muteComputer) != 0) madeWith.reset(verOldModPlug | verNewModPlug | verPlayerPRO); if(instrHeader.size != 263 || instrHeader.type != 0) madeWith.reset(verPlayerPRO); if(!madeWith[verConfirmed] && madeWith[verPlayerPRO]) { // Note: Earlier (?) PlayerPRO versions do not seem to set the loop points to 0xFF (george_megas_-_q.xm) if((!(instrHeader.instrument.volFlags & XMInstrument::envLoop) && instrHeader.instrument.volLoopStart == 0xFF && instrHeader.instrument.volLoopEnd == 0xFF) || (!(instrHeader.instrument.panFlags & XMInstrument::envLoop) && instrHeader.instrument.panLoopStart == 0xFF && instrHeader.instrument.panLoopEnd == 0xFF)) { madeWith.set(verConfirmed); madeWith.reset(verNewModPlug); } } // Read sample headers std::vector sampleSlots = AllocateXMSamples(*this, instrHeader.numSamples); // Update sample assignment map for(size_t k = 0 + 12; k < 96 + 12; k++) { if(Instruments[instr]->Keyboard[k] < sampleSlots.size()) { Instruments[instr]->Keyboard[k] = sampleSlots[Instruments[instr]->Keyboard[k]]; } } if(fileHeader.version >= 0x0104) { sampleFlags.clear(); } // Need to memorize those if we're going to skip any samples... std::vector sampleSize(instrHeader.numSamples); // Early versions of Sk@le Tracker set instrHeader.sampleHeaderSize = 0 (IFULOVE.XM) // cybernostra weekend has instrHeader.sampleHeaderSize = 0x12, which would leave out the sample name, but FT2 still reads the name. MPT_ASSERT(instrHeader.sampleHeaderSize == 0 || instrHeader.sampleHeaderSize == sizeof(XMSample)); for(SAMPLEINDEX sample = 0; sample < instrHeader.numSamples; sample++) { XMSample sampleHeader; file.ReadStruct(sampleHeader); sampleFlags.push_back(sampleHeader.GetSampleFormat()); sampleSize[sample] = sampleHeader.length; sampleReserved |= sampleHeader.reserved; if(sampleHeader.reserved != 0 && sampleHeader.reserved != 0xAD) madeWith.reset(verOldModPlug | verNewModPlug | verOpenMPT); if(lastSampleReserved == -1) lastSampleReserved = sampleHeader.reserved; else if(lastSampleReserved != sampleHeader.reserved) madeWith.reset(verPlayerPRO); if(sampleHeader.pan != 128) madeWith.reset(verPlayerPRO); if((sampleHeader.finetune & 0x0F) && sampleHeader.finetune != 127) madeWith.reset(verPlayerPRO); if(sample < sampleSlots.size()) { SAMPLEINDEX mptSample = sampleSlots[sample]; sampleHeader.ConvertToMPT(Samples[mptSample]); instrHeader.instrument.ApplyAutoVibratoToMPT(Samples[mptSample]); m_szNames[mptSample] = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); if(madeWith[verFT2Generic | verFT2Clone] && madeWith[verNewModPlug | verPlayerPRO] && !madeWith[verConfirmed] && (sampleHeader.reserved > 22 || std::find_if(std::begin(sampleHeader.name) + sampleHeader.reserved, std::end(sampleHeader.name), [](char c) { return c != ' '; }) != std::end(sampleHeader.name))) { // FT2 stores the sample name length here (it just copies the entire Pascal string, but that string might have ended with spaces even before space-padding it in the file, so we cannot do an exact length comparison) madeWith.reset(verFT2Generic); madeWith.set(verFT2Clone | verConfirmed); } if((sampleHeader.flags & 3) == 3 && madeWith[verNewModPlug]) madeWith.set(verModPlugBidiFlag); } if(sampleFlags.back().GetEncoding() == SampleIO::ADPCM) anyADPCM = true; } // Read samples if(fileHeader.version >= 0x0104) { for(SAMPLEINDEX sample = 0; sample < instrHeader.numSamples; sample++) { // Sample 15 in dirtysex.xm by J/M/T/M is a 16-bit sample with an odd size of 0x18B according to the header, while the real sample size would be 0x18A. // Always read as many bytes as specified in the header, even if the sample reader would probably read less bytes. FileReader sampleChunk = file.ReadChunk(sampleFlags[sample].GetEncoding() != SampleIO::ADPCM ? sampleSize[sample] : (16 + (sampleSize[sample] + 1) / 2)); if(sample < sampleSlots.size() && (loadFlags & loadSampleData)) { if(!ReadSampleData(Samples[sampleSlots[sample]], sampleFlags[sample], sampleChunk, isOXM)) { unsupportedSamples = true; } } } } } } if(sampleReserved == 0 && madeWith[verNewModPlug] && memchr(fileHeader.songName, '\0', sizeof(fileHeader.songName)) != nullptr) { // Null-terminated song name: Quite possibly MPT. (could really be an MPT-made file resaved in FT2, though) madeWith.set(verConfirmed); } if(fileHeader.version < 0x0104) { // Load Patterns and Samples (Version 1.02 and 1.03) if(loadFlags & (loadPatternData | loadSampleData)) { ReadXMPatterns(file, fileHeader, *this); } if(loadFlags & loadSampleData) { for(SAMPLEINDEX sample = 1; sample <= GetNumSamples(); sample++) { sampleFlags[sample - 1].ReadSample(Samples[sample], file); } } } if(unsupportedSamples) { AddToLog(LogWarning, U_("Some compressed samples could not be loaded because they use an unsupported codec.")); } // Read song comments: "text" if(file.ReadMagic("text")) { m_songMessage.Read(file, file.ReadUint32LE(), SongMessage::leCR); madeWith.set(verConfirmed); madeWith.reset(verPlayerPRO); } // Read midi config: "MIDI" bool hasMidiConfig = false; if(file.ReadMagic("MIDI")) { file.ReadStructPartial(m_MidiCfg, file.ReadUint32LE()); m_MidiCfg.Sanitize(); hasMidiConfig = true; madeWith.set(verConfirmed); madeWith.reset(verPlayerPRO); } // Read pattern names: "PNAM" if(file.ReadMagic("PNAM")) { const PATTERNINDEX namedPats = std::min(static_cast(file.ReadUint32LE() / MAX_PATTERNNAME), Patterns.Size()); for(PATTERNINDEX pat = 0; pat < namedPats; pat++) { char patName[MAX_PATTERNNAME]; file.ReadString(patName, MAX_PATTERNNAME); Patterns[pat].SetName(patName); } madeWith.set(verConfirmed); madeWith.reset(verPlayerPRO); } // Read channel names: "CNAM" if(file.ReadMagic("CNAM")) { const CHANNELINDEX namedChans = std::min(static_cast(file.ReadUint32LE() / MAX_CHANNELNAME), GetNumChannels()); for(CHANNELINDEX chn = 0; chn < namedChans; chn++) { file.ReadString(ChnSettings[chn].szName, MAX_CHANNELNAME); } madeWith.set(verConfirmed); madeWith.reset(verPlayerPRO); } // Read mix plugins information if(file.CanRead(8)) { FileReader::pos_type oldPos = file.GetPosition(); LoadMixPlugins(file); if(file.GetPosition() != oldPos) { madeWith.set(verConfirmed); madeWith.reset(verPlayerPRO); } } if(madeWith[verConfirmed]) { if(madeWith[verModPlugBidiFlag]) { m_dwLastSavedWithVersion = MPT_V("1.11"); madeWithTracker = UL_("ModPlug Tracker 1.0 - 1.11"); } else if(madeWith[verNewModPlug] && !madeWith[verPlayerPRO]) { m_dwLastSavedWithVersion = MPT_V("1.16"); madeWithTracker = UL_("ModPlug Tracker 1.0 - 1.16"); } else if(madeWith[verNewModPlug] && madeWith[verPlayerPRO]) { m_dwLastSavedWithVersion = MPT_V("1.16"); madeWithTracker = UL_("ModPlug Tracker 1.0 - 1.16 / PlayerPRO"); } else if(!madeWith[verNewModPlug] && madeWith[verPlayerPRO]) { madeWithTracker = UL_("PlayerPRO"); } } if(!memcmp(fileHeader.trackerName, "OpenMPT ", 8)) { // Hey, I know this tracker! std::string mptVersion(fileHeader.trackerName + 8, 12); m_dwLastSavedWithVersion = Version::Parse(mpt::ToUnicode(mpt::Charset::ASCII, mptVersion)); madeWith = verOpenMPT | verConfirmed; if(m_dwLastSavedWithVersion < MPT_V("1.22.07.19")) m_nMixLevels = MixLevels::Compatible; else m_nMixLevels = MixLevels::CompatibleFT2; } if(m_dwLastSavedWithVersion && !madeWith[verOpenMPT]) { m_nMixLevels = MixLevels::Original; m_playBehaviour.reset(); } if(madeWith[verFT2Generic]) { m_nMixLevels = MixLevels::CompatibleFT2; if(!hasMidiConfig) { // FT2 allows typing in arbitrary unsupported effect letters such as Zxx. // Prevent these commands from being interpreted as filter commands by erasing the default MIDI Config. m_MidiCfg.ClearZxxMacros(); } if(fileHeader.version >= 0x0104 // Old versions of FT2 didn't have (smooth) ramping. Disable it for those versions where we can be sure that there should be no ramping. #ifdef MODPLUG_TRACKER && TrackerSettings::Instance().autoApplySmoothFT2Ramping #endif // MODPLUG_TRACKER ) { // apply FT2-style super-soft volume ramping m_playBehaviour.set(kFT2VolumeRamping); } } if(madeWithTracker.empty()) { if(madeWith[verDigiTrakker] && sampleReserved == 0 && (lastInstrType ? lastInstrType : -1) == -1) { madeWithTracker = UL_("DigiTrakker"); } else if(madeWith[verFT2Generic]) { madeWithTracker = UL_("FastTracker 2 or compatible"); } else { madeWithTracker = UL_("Unknown"); } } bool isOpenMPTMade = false; // specific for OpenMPT 1.17+ if(GetNumInstruments()) { isOpenMPTMade = LoadExtendedInstrumentProperties(file); } LoadExtendedSongProperties(file, true, &isOpenMPTMade); if(isOpenMPTMade && m_dwLastSavedWithVersion < MPT_V("1.17")) { // Up to OpenMPT 1.17.02.45 (r165), it was possible that the "last saved with" field was 0 // when saving a file in OpenMPT for the first time. m_dwLastSavedWithVersion = MPT_V("1.17"); } if(m_dwLastSavedWithVersion >= MPT_V("1.17")) { madeWithTracker = UL_("OpenMPT ") + m_dwLastSavedWithVersion.ToUString(); } // We no longer allow any --- or +++ items in the order list now. if(m_dwLastSavedWithVersion && m_dwLastSavedWithVersion < MPT_V("1.22.02.02")) { if(!Patterns.IsValidPat(0xFE)) Order().RemovePattern(0xFE); if(!Patterns.IsValidPat(0xFF)) Order().Replace(0xFF, PATTERNINDEX_INVALID); } m_modFormat.formatName = MPT_UFORMAT("FastTracker 2 v{}.{}")(fileHeader.version >> 8, mpt::ufmt::hex0<2>(fileHeader.version & 0xFF)); m_modFormat.madeWithTracker = std::move(madeWithTracker); m_modFormat.charset = (m_dwLastSavedWithVersion || isMadTracker) ? mpt::Charset::Windows1252 : mpt::Charset::CP437; if(isOXM) { m_modFormat.originalFormatName = std::move(m_modFormat.formatName); m_modFormat.formatName = UL_("OggMod FastTracker 2"); m_modFormat.type = UL_("oxm"); m_modFormat.originalType = UL_("xm"); } else { m_modFormat.type = UL_("xm"); } if(anyADPCM) m_modFormat.madeWithTracker += UL_(" (ADPCM packed)"); return true; } #ifndef MODPLUG_NO_FILESAVE #if MPT_GCC_AT_LEAST(13, 0, 0) && MPT_GCC_BEFORE(15, 1, 0) // work-around massively confused GCC 13/14 optimizer: // /usr/include/c++/13/bits/stl_algobase.h:437:30: warning: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' writing between 3 and 9223372036854775806 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=] template static MPT_NOINLINE Tcont1 & gcc_append(Tcont1 & cont1, const Tcont2 & cont2) { cont1.insert(cont1.end(), cont2.begin(), cont2.end()); return cont1; } #endif bool CSoundFile::SaveXM(std::ostream &f, bool compatibilityExport) { bool addChannel = false; // avoid odd channel count for FT2 compatibility XMFileHeader fileHeader; MemsetZero(fileHeader); memcpy(fileHeader.signature, "Extended Module: ", 17); mpt::String::WriteBuf(mpt::String::spacePadded, fileHeader.songName) = m_songName; fileHeader.eof = 0x1A; const std::string openMptTrackerName = mpt::ToCharset(GetCharsetFile(), Version::Current().GetOpenMPTVersionString()); mpt::String::WriteBuf(mpt::String::spacePadded, fileHeader.trackerName) = openMptTrackerName; // Writing song header fileHeader.version = 0x0104; // XM Format v1.04 fileHeader.size = sizeof(XMFileHeader) - 60; // minus everything before this field fileHeader.restartPos = Order().GetRestartPos(); fileHeader.channels = GetNumChannels(); if((GetNumChannels() % 2u) && GetNumChannels() < 32) { // Avoid odd channel count for FT2 compatibility fileHeader.channels++; addChannel = true; } else if(compatibilityExport && fileHeader.channels > 32) { fileHeader.channels = 32; } // Find out number of orders and patterns used. // +++ and --- patterns are not taken into consideration as FastTracker does not support them. const ORDERINDEX trimmedLength = Order().GetLengthTailTrimmed(); std::vector orderList(trimmedLength); const ORDERINDEX orderLimit = compatibilityExport ? 256 : uint16_max; ORDERINDEX numOrders = 0; PATTERNINDEX numPatterns = Patterns.GetNumPatterns(); bool changeOrderList = false; for(ORDERINDEX ord = 0; ord < trimmedLength; ord++) { PATTERNINDEX pat = Order()[ord]; if(pat == PATTERNINDEX_SKIP || pat == PATTERNINDEX_INVALID || pat > uint8_max) { changeOrderList = true; } else if(numOrders < orderLimit) { orderList[numOrders++] = static_cast(pat); if(pat >= numPatterns) numPatterns = pat + 1; } } if(changeOrderList) { AddToLog(LogWarning, U_("Skip and stop order list items (+++ and ---) are not saved in XM files.")); } orderList.resize(compatibilityExport ? 256 : numOrders); fileHeader.orders = numOrders; fileHeader.patterns = numPatterns; fileHeader.size += static_cast(orderList.size()); uint16 writeInstruments; if(m_nInstruments > 0) fileHeader.instruments = writeInstruments = m_nInstruments; else fileHeader.instruments = writeInstruments = m_nSamples; if(m_SongFlags[SONG_LINEARSLIDES]) fileHeader.flags |= XMFileHeader::linearSlides; if(m_SongFlags[SONG_EXFILTERRANGE] && !compatibilityExport) fileHeader.flags |= XMFileHeader::extendedFilterRange; fileHeader.flags = fileHeader.flags; // Fasttracker 2 will happily accept any tempo faster than 255 BPM. XMPlay does also support this, great! fileHeader.tempo = mpt::saturate_cast(Order().GetDefaultTempo().GetInt()); fileHeader.speed = static_cast(Clamp(Order().GetDefaultSpeed(), 1u, 31u)); mpt::IO::Write(f, fileHeader); // Write processed order list mpt::IO::Write(f, orderList); // Writing patterns #define ASSERT_CAN_WRITE(x) \ if(len > s.size() - x) /*Buffer running out? Make it larger.*/ \ s.resize(s.size() + 10 * 1024, 0); std::vector s(64 * 64 * 5, 0); for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { uint8 patHead[9] = { 0 }; patHead[0] = 9; if(!Patterns.IsValidPat(pat)) { // There's nothing to write... chicken out. patHead[5] = 64; mpt::IO::Write(f, patHead); continue; } const uint16 numRows = mpt::saturate_cast(Patterns[pat].GetNumRows()); patHead[5] = static_cast(numRows & 0xFF); patHead[6] = static_cast(numRows >> 8); auto p = Patterns[pat].cbegin(); size_t len = 0; // Empty patterns are always loaded as 64-row patterns in FT2, regardless of their real size... bool emptyPattern = true; for(size_t j = GetNumChannels() * numRows; j > 0; j--, p++) { // Don't write more than 32 channels if(compatibilityExport && GetNumChannels() - ((j - 1) % GetNumChannels()) > 32) continue; uint8 note = p->note, command = 0, param = 0; ModSaveCommand(*p, command, param, true, compatibilityExport); if(note >= NOTE_MIN_SPECIAL) note = 97; else if(note < NOTE_MIN + 12 || note >= NOTE_MIN + 12 + 96) note = 0; else note -= 12; uint8 vol = 0; if (p->volcmd != VOLCMD_NONE) { switch(p->volcmd) { case VOLCMD_VOLUME: vol = 0x10 + p->vol; break; case VOLCMD_VOLSLIDEDOWN: vol = 0x60 + (p->vol & 0x0F); break; case VOLCMD_VOLSLIDEUP: vol = 0x70 + (p->vol & 0x0F); break; case VOLCMD_FINEVOLDOWN: vol = 0x80 + (p->vol & 0x0F); break; case VOLCMD_FINEVOLUP: vol = 0x90 + (p->vol & 0x0F); break; case VOLCMD_VIBRATOSPEED: vol = 0xA0 + (p->vol & 0x0F); break; case VOLCMD_VIBRATODEPTH: vol = 0xB0 + (p->vol & 0x0F); break; case VOLCMD_PANNING: vol = 0xC0 + (p->vol / 4); if (vol > 0xCF) vol = 0xCF; break; case VOLCMD_PANSLIDELEFT: vol = 0xD0 + (p->vol & 0x0F); break; case VOLCMD_PANSLIDERIGHT: vol = 0xE0 + (p->vol & 0x0F); break; case VOLCMD_TONEPORTAMENTO: vol = 0xF0 + (p->vol & 0x0F); break; default: break; } // Those values are ignored in FT2. Don't save them, also to avoid possible problems with other trackers (or MPT itself) if(compatibilityExport && p->vol == 0) { switch(p->volcmd) { case VOLCMD_VOLUME: case VOLCMD_PANNING: case VOLCMD_VIBRATODEPTH: case VOLCMD_TONEPORTAMENTO: case VOLCMD_PANSLIDELEFT: // Doesn't have memory, but does weird things with zero param. break; default: // no memory here. vol = 0; } } } // no need to fix non-empty patterns if(!p->IsEmpty()) emptyPattern = false; // Completely empty patterns are loaded as empty 64-row patterns in FT2, regardless of their original size. // We have to avoid this, so we add a "break to row 0" command in the last row. if(j == 1 && emptyPattern && numRows != 64) { command = 0x0D; param = 0; } if ((note) && (p->instr) && (vol > 0x0F) && (command) && (param)) { s[len++] = note; s[len++] = p->instr; s[len++] = vol; s[len++] = command; s[len++] = param; } else { uint8 b = 0x80; if (note) b |= 0x01; if (p->instr) b |= 0x02; if (vol >= 0x10) b |= 0x04; if (command) b |= 0x08; if (param) b |= 0x10; s[len++] = b; if (b & 1) s[len++] = note; if (b & 2) s[len++] = p->instr; if (b & 4) s[len++] = vol; if (b & 8) s[len++] = command; if (b & 16) s[len++] = param; } if(addChannel && (j % GetNumChannels() == 1 || GetNumChannels() == 1)) { ASSERT_CAN_WRITE(1); s[len++] = 0x80; } ASSERT_CAN_WRITE(5); } if(emptyPattern && numRows == 64) { // Be smart when saving empty patterns! len = 0; } // Reaching the limits of file format? if(len > uint16_max) { AddToLog(LogWarning, MPT_UFORMAT("Warning: File format limit was reached. Some pattern data may not get written to file. (pattern {})")(pat)); len = uint16_max; } patHead[7] = static_cast(len & 0xFF); patHead[8] = static_cast(len >> 8); mpt::IO::Write(f, patHead); if(len) mpt::IO::WriteRaw(f, s.data(), len); } #undef ASSERT_CAN_WRITE // Check which samples are referenced by which instruments (for assigning unreferenced samples to instruments) std::vector sampleAssigned(GetNumSamples() + 1, false); for(INSTRUMENTINDEX ins = 1; ins <= GetNumInstruments(); ins++) { if(Instruments[ins] != nullptr) { Instruments[ins]->GetSamples(sampleAssigned); } } // Writing instruments for(INSTRUMENTINDEX ins = 1; ins <= writeInstruments; ins++) { XMInstrumentHeader insHeader; std::vector samples; if(GetNumInstruments()) { if(Instruments[ins] != nullptr) { // Convert instrument auto sampleList = insHeader.ConvertToXM(*Instruments[ins], compatibilityExport); samples = std::move(sampleList.samples); if(sampleList.tooManySamples) AddToLog(LogInformation, MPT_UFORMAT("Instrument {} references too many samples, only the first {} will be exported.")(ins, samples.size())); if(samples.size() > 0 && samples[0] <= GetNumSamples()) { // Copy over auto-vibrato settings of first sample insHeader.instrument.ApplyAutoVibratoToXM(Samples[samples[0]], GetType()); } std::vector additionalSamples; // Try to save "instrument-less" samples as well by adding those after the "normal" samples of our sample. // We look for unassigned samples directly after the samples assigned to our current instrument, so if // e.g. sample 1 is assigned to instrument 1 and samples 2 to 10 aren't assigned to any instrument, // we will assign those to sample 1. Any samples before the first referenced sample are going to be lost, // but hey, I wrote this mostly for preserving instrument texts in existing modules, where we shouldn't encounter this situation... for(auto smp : samples) { while(++smp <= GetNumSamples() && !sampleAssigned[smp] && insHeader.numSamples < (compatibilityExport ? 16 : 32)) { sampleAssigned[smp] = true; // Don't want to add this sample again. additionalSamples.push_back(smp); insHeader.numSamples++; } } #if MPT_GCC_AT_LEAST(13, 0, 0) && MPT_GCC_BEFORE(15, 1, 0) gcc_append(samples, additionalSamples); #else mpt::append(samples, additionalSamples); #endif } else { MemsetZero(insHeader); } } else { // Convert samples to instruments MemsetZero(insHeader); insHeader.numSamples = 1; insHeader.instrument.ApplyAutoVibratoToXM(Samples[ins], GetType()); samples.push_back(ins); } insHeader.Finalise(); size_t insHeaderSize = insHeader.size; mpt::IO::WritePartial(f, insHeader, insHeaderSize); std::vector sampleFlags(samples.size()); // Write Sample Headers for(SAMPLEINDEX smp = 0; smp < samples.size(); smp++) { XMSample xmSample; if(samples[smp] <= GetNumSamples()) { xmSample.ConvertToXM(Samples[samples[smp]], GetType(), compatibilityExport); } else { MemsetZero(xmSample); } sampleFlags[smp] = xmSample.GetSampleFormat(); mpt::String::WriteBuf(mpt::String::spacePadded, xmSample.name) = m_szNames[samples[smp]]; mpt::IO::Write(f, xmSample); } // Write Sample Data for(SAMPLEINDEX smp = 0; smp < samples.size(); smp++) { if(samples[smp] <= GetNumSamples()) { sampleFlags[smp].WriteSample(f, Samples[samples[smp]]); } } } if(!compatibilityExport) { // Writing song comments if(!m_songMessage.empty()) { uint32 size = mpt::saturate_cast(m_songMessage.length()); mpt::IO::WriteRaw(f, "text", 4); mpt::IO::WriteIntLE(f, size); mpt::IO::WriteRaw(f, m_songMessage.c_str(), size); } // Writing midi cfg if(!m_MidiCfg.IsMacroDefaultSetupUsed()) { mpt::IO::WriteRaw(f, "MIDI", 4); mpt::IO::WriteIntLE(f, sizeof(MIDIMacroConfigData)); mpt::IO::Write(f, static_cast(m_MidiCfg)); } // Writing Pattern Names const PATTERNINDEX numNamedPats = Patterns.GetNumNamedPatterns(); if(numNamedPats > 0) { mpt::IO::WriteRaw(f, "PNAM", 4); mpt::IO::WriteIntLE(f, numNamedPats * MAX_PATTERNNAME); for(PATTERNINDEX pat = 0; pat < numNamedPats; pat++) { char name[MAX_PATTERNNAME]; mpt::String::WriteBuf(mpt::String::maybeNullTerminated, name) = Patterns[pat].GetName(); mpt::IO::Write(f, name); } } // Writing Channel Names { CHANNELINDEX numNamedChannels = 0; for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { if (ChnSettings[chn].szName[0]) numNamedChannels = chn + 1; } // Do it! if(numNamedChannels) { mpt::IO::WriteRaw(f, "CNAM", 4); mpt::IO::WriteIntLE(f, numNamedChannels * MAX_CHANNELNAME); for(CHANNELINDEX chn = 0; chn < numNamedChannels; chn++) { char name[MAX_CHANNELNAME]; mpt::String::WriteBuf(mpt::String::maybeNullTerminated, name) = ChnSettings[chn].szName; mpt::IO::Write(f, name); } } } //Save hacked-on extra info SaveMixPlugins(&f); if(GetNumInstruments()) { SaveExtendedInstrumentProperties(0, MOD_TYPE_XM, f); } SaveExtendedSongProperties(f); } return true; } #endif // MODPLUG_NO_FILESAVE OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_unic.cpp0000644000175000017500000001646414721715306020517 00000000000000/* * Load_unic.cpp * ------------- * Purpose: UNIC Tracker v1 loader * Notes : UNIC Tracker is actually a module packer, not a stand-alone tracker software. * Support is mostly included to avoid such modules being recognized as regular M.K. MODs. * UNIC files without file signature are not supported. * Authors: OpenMPT Devs * Based on ProWizard by Asle * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "MODTools.h" OPENMPT_NAMESPACE_BEGIN static bool ValidateUNICSampleHeader(const MODSampleHeader &sampleHeader) { if(CountInvalidChars(mpt::as_span(sampleHeader.name).subspan(0, 20))) return false; int16be finetune; memcpy(&finetune, &sampleHeader.name[20], sizeof(int16be)); if(finetune < -42 || finetune > 8) // African Dreams.unic has finetune = -42 return false; if(sampleHeader.finetune != 0 || sampleHeader.volume > 64) return false; if(sampleHeader.length >= 0x8000 || sampleHeader.loopStart >= 0x8000 || sampleHeader.loopLength >= 0x8000) return false; if(!sampleHeader.length && (sampleHeader.loopStart > 0 || sampleHeader.loopLength > 1 || finetune != 0)) return false; if(sampleHeader.length && sampleHeader.length < sampleHeader.loopStart + sampleHeader.loopLength) return false; return true; } static bool ValidateUNICPatternEntry(const std::array data, SAMPLEINDEX lastSample) { if(data[0] > 0x74) return false; if((data[0] & 0x3F) > 0x24) return false; const uint8 command = (data[1] & 0x0F), param = data[2]; if(command == 0x0C && param > 80) // Mastercoma.unic has values > 64 return false; if(command == 0x0B && param > 0x7F) return false; if(command == 0x0D && param > 0x40) return false; if(uint8 instr = ((data[0] >> 2) & 0x30) | ((data[1] >> 4) & 0x0F); instr > lastSample) return false; return true; } struct UNICFileHeader { using PatternData = std::array, 64 * 4>; std::array title; MODSampleHeader sampleHeaders[31]; MODFileHeader fileHeader; std::array magic; PatternData firstPattern; struct ValidationResult { uint32 totalSampleSize = 0; SAMPLEINDEX lastSample = 0; uint8 numPatterns = 0; }; ValidationResult IsValid() const noexcept { if(!IsMagic(magic.data(), "M.K.") && !IsMagic(magic.data(), "UNIC") && !IsMagic(magic.data(), "\0\0\0\0")) return {}; if(CountInvalidChars(title)) return {}; uint32 totalSampleSize = 0; SAMPLEINDEX lastSample = 0; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { const MODSampleHeader &sampleHeader = sampleHeaders[smp - 1]; if(!ValidateUNICSampleHeader(sampleHeader)) return {}; totalSampleSize += sampleHeader.length * 2; if(sampleHeader.length) lastSample = smp; } if(totalSampleSize < 256) return {}; if(!fileHeader.numOrders || fileHeader.numOrders >= 128) return {}; uint8 numPatterns = 0; for(uint8 pat = 0; pat < 128; pat++) { if(fileHeader.orderList[pat] >= 128 || (pat > fileHeader.numOrders + 1 && fileHeader.orderList[pat] != 0)) return {}; numPatterns = std::max(numPatterns, fileHeader.orderList[pat].get()); } numPatterns++; for(const auto data : firstPattern) { if(!ValidateUNICPatternEntry(data, lastSample)) return {}; } return {totalSampleSize, lastSample, numPatterns}; } }; MPT_BINARY_STRUCT(UNICFileHeader, 1084 + 768) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderUNIC(MemoryFileReader file, const uint64 *pfilesize) { UNICFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; const auto headerValidationResult = fileHeader.IsValid(); if(!headerValidationResult.totalSampleSize) return ProbeFailure; if(pfilesize && *pfilesize < 1084 + headerValidationResult.numPatterns * 64u * 4u * 3u + headerValidationResult.totalSampleSize) return ProbeFailure; return ProbeSuccess; } bool CSoundFile::ReadUNIC(FileReader &file, ModLoadingFlags loadFlags) { UNICFileHeader fileHeader; file.Rewind(); if(!file.ReadStruct(fileHeader)) return false; const auto headerValidationResult = fileHeader.IsValid(); if(!headerValidationResult.totalSampleSize) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_MOD, 4); // Reading patterns (done first to avoid doing unnecessary work if this is a real ProTracker M.K. file) file.Seek(1084); if(!file.CanRead(headerValidationResult.numPatterns * 64u * 4u * 3u)) return false; if(loadFlags & loadPatternData) Patterns.ResizeArray(headerValidationResult.numPatterns); uint16 numNotes = 0; ModCommand::INSTR allInstrs = 0; for(PATTERNINDEX pat = 0; pat < headerValidationResult.numPatterns; pat++) { if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { UNICFileHeader::PatternData pattern; if(!file.ReadArray(pattern)) return false; for(const auto data : pattern) { if(!ValidateUNICPatternEntry(data, headerValidationResult.lastSample)) return false; } continue; } for(ModCommand &m : Patterns[pat]) { const auto data = file.ReadArray(); if(!ValidateUNICPatternEntry(data, headerValidationResult.lastSample)) return false; if(data[0] & 0x3F) { m.note = NOTE_MIDDLEC - 13 + (data[0] & 0x3F); numNotes++; } m.instr = ((data[0] >> 2) & 0x30) | ((data[1] >> 4) & 0x0F); allInstrs |= m.instr; ConvertModCommand(m, data[1] & 0x0F, data[2]); } } if(numNotes < 16 || !allInstrs) return false; // Reading samples if(!file.CanRead(headerValidationResult.totalSampleSize)) return false; m_nSamples = 31; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { const MODSampleHeader &sampleHeader = fileHeader.sampleHeaders[smp - 1]; ModSample &mptSmp = Samples[smp]; sampleHeader.ConvertToMPT(mptSmp, true); int16be finetune; memcpy(&finetune, &sampleHeader.name[20], sizeof(int16be)); mptSmp.nFineTune = MOD2XMFineTune(-finetune); // Metal Jumpover.unic (and various other files) has incorrect loop starts expressed as DWORDs // But for the flute sample African Dreams.unic this fix doesn't seem to be quite right if(mptSmp.uFlags[CHN_LOOP] && mptSmp.nLoopStart > 0 && mptSmp.nLoopStart + mptSmp.nLoopEnd >= mptSmp.nLength - 2 && mptSmp.nLoopStart + mptSmp.nLoopEnd <= mptSmp.nLength) { mptSmp.nLoopEnd += mptSmp.nLoopStart; mptSmp.nLoopStart += mptSmp.nLoopStart; } m_szNames[smp] = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name, 20); if(!(loadFlags & loadSampleData)) continue; SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM).ReadSample(Samples[smp], file); } SetupMODPanning(true); Order().SetDefaultSpeed(6); Order().SetDefaultTempoInt(125); ReadOrderFromArray(Order(), fileHeader.fileHeader.orderList, headerValidationResult.numPatterns); m_nMinPeriod = 113 * 4; m_nMaxPeriod = 856 * 4; m_nSamplePreAmp = 64; m_SongFlags.set(SONG_PT_MODE | SONG_IMPORTED | SONG_FORMAT_NO_VOLCOL); m_playBehaviour.reset(kMODOneShotLoops); m_playBehaviour.set(kMODIgnorePanning); m_playBehaviour.set(kMODSampleSwap); // untested m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.title); m_modFormat.formatName = UL_("UNIC Tracker"); m_modFormat.type = UL_("unic"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/tuningCollection.cpp0000644000175000017500000002052314763564270022141 00000000000000/* * tuningCollection.cpp * -------------------- * Purpose: Alternative sample tuning collection class. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "tuningcollection.h" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "../common/serialization_utils.h" #include #include "Loaders.h" #ifdef MODPLUG_TRACKER #include "../common/mptFileIO.h" #include "mpt/fs/fs.hpp" #include "mpt/io_file/outputfile.hpp" #include "../mptrack/TrackerSettings.h" #endif //MODPLUG_TRACKER OPENMPT_NAMESPACE_BEGIN namespace Tuning { /* Version history: 2->3: Serialization revamp(August 2007) 1->2: Sizetypes of string serialisation from size_t(uint32) to uint8. (March 2007) */ namespace CTuningS11n { void ReadStr(std::istream &iStrm, mpt::ustring &ustr, const std::size_t dummy, mpt::Charset charset); void WriteStr(std::ostream &oStrm, const mpt::ustring &ustr); } // namespace CTuningS11n using namespace CTuningS11n; static void ReadTuning(std::istream &iStrm, CTuningCollection &Tc, const std::size_t dummy, mpt::Charset defaultCharset) { MPT_UNREFERENCED_PARAMETER(dummy); Tc.AddTuning(iStrm, defaultCharset); } static void WriteTuning(std::ostream& oStrm, const CTuning& t) { t.Serialize(oStrm); } CTuning* CTuningCollection::GetTuning(const mpt::ustring &name) { for(std::size_t i = 0; iGetName() == name) { return m_Tunings[i].get(); } } return nullptr; } const CTuning* CTuningCollection::GetTuning(const mpt::ustring &name) const { for(std::size_t i = 0; iGetName() == name) { return m_Tunings[i].get(); } } return nullptr; } const CTuning* CTuningCollection::FindIdenticalTuning(const CTuning &tuning) const { auto result = std::find_if(m_Tunings.begin(), m_Tunings.end(), [&tuning](const std::unique_ptr &other) { return other && tuning == *other; }); return (result != m_Tunings.end()) ? result->get() : nullptr; } CTuning* CTuningCollection::FindIdenticalTuning(const CTuning &tuning) { auto result = std::find_if(m_Tunings.begin(), m_Tunings.end(), [&tuning](const std::unique_ptr &other) { return other && tuning == *other; }); return (result != m_Tunings.end()) ? result->get() : nullptr; } Tuning::SerializationResult CTuningCollection::Serialize(std::ostream& oStrm, const mpt::ustring &name) const { srlztn::SsbWrite ssb(oStrm); ssb.BeginWrite("TC", 3); // version ssb.WriteItem(int8(1), "UTF8"); ssb.WriteItem(name, "0", &WriteStr); uint16 dummyEditMask = 0xffff; ssb.WriteItem(dummyEditMask, "1"); const size_t tcount = m_Tunings.size(); for(size_t i = 0; i(iStrm.tellg()); const Tuning::SerializationResult oldLoadingResult = DeserializeOLD(iStrm, name, defaultCharset); if(oldLoadingResult == Tuning::SerializationResult::NoMagic) { // An old version was not recognised - trying new version. iStrm.clear(); iStrm.seekg(startpos, std::ios::beg); srlztn::SsbRead ssb(iStrm); ssb.BeginRead("TC", 3); // version int8 use_utf8 = 0; ssb.ReadItem(use_utf8, "UTF8"); const mpt::Charset charset = use_utf8 ? mpt::Charset::UTF8 : defaultCharset; const srlztn::SsbRead::ReadIterator iterBeg = ssb.GetReadBegin(); const srlztn::SsbRead::ReadIterator iterEnd = ssb.GetReadEnd(); for(srlztn::SsbRead::ReadIterator iter = iterBeg; iter != iterEnd; iter++) { uint16 dummyEditMask = 0xffff; if(ssb.MatchesId(iter, "0")) ssb.ReadIterItem(iter, name, [charset](std::istream &iStrm, mpt::ustring &ustr, const std::size_t dummy){ return ReadStr(iStrm, ustr, dummy, charset); }); else if(ssb.MatchesId(iter, "1")) ssb.ReadIterItem(iter, dummyEditMask); else if(ssb.MatchesId(iter, "2")) ssb.ReadIterItem(iter, *this, [charset](std::istream &iStrm, CTuningCollection &Tc, const std::size_t dummy){ return ReadTuning(iStrm, Tc, dummy, charset); }); } if(ssb.HasFailed()) return Tuning::SerializationResult::Failure; else return Tuning::SerializationResult::Success; } else { return oldLoadingResult; } } Tuning::SerializationResult CTuningCollection::DeserializeOLD(std::istream &inStrm, mpt::ustring &uname, mpt::Charset defaultCharset) { //1. begin marker: uint32 beginMarker = 0; mpt::IO::ReadIntLE(inStrm, beginMarker); if(beginMarker != MagicBE("TCSH")) // Magic is reversed in file, hence BE return Tuning::SerializationResult::NoMagic; //2. version int32 version = 0; mpt::IO::ReadIntLE(inStrm, version); if(version > 2 || version < 1) return Tuning::SerializationResult::Failure; //3. Name if(version < 2) { std::string name; if(!mpt::IO::ReadSizedStringLE(inStrm, name, 256)) return Tuning::SerializationResult::Failure; uname = mpt::ToUnicode(defaultCharset, name); } else { std::string name; if(!mpt::IO::ReadSizedStringLE(inStrm, name)) return Tuning::SerializationResult::Failure; uname = mpt::ToUnicode(defaultCharset, name); } //4. Editmask int16 em = 0; mpt::IO::ReadIntLE(inStrm, em); //Not assigning the value yet, for if it sets some property const, //further loading might fail. //5. Tunings { uint32 s = 0; mpt::IO::ReadIntLE(inStrm, s); if(s > 50) return Tuning::SerializationResult::Failure; for(size_t i = 0; i(inStrm, endMarker); if(endMarker != MagicBE("TCSF")) // Magic is reversed in file, hence BE return Tuning::SerializationResult::Failure; return Tuning::SerializationResult::Success; } bool CTuningCollection::Remove(const CTuning *pT) { const auto it = std::find_if(m_Tunings.begin(), m_Tunings.end(), [&] (const std::unique_ptr & upT) -> bool { return upT.get() == pT; } ); if(it == m_Tunings.end()) { return false; } m_Tunings.erase(it); return true; } bool CTuningCollection::Remove(const std::size_t i) { if(i >= m_Tunings.size()) { return false; } m_Tunings.erase(m_Tunings.begin() + i); return true; } CTuning* CTuningCollection::AddTuning(std::unique_ptr pT) { if(m_Tunings.size() >= s_nMaxTuningCount) { return nullptr; } if(!pT) { return nullptr; } CTuning *result = pT.get(); m_Tunings.push_back(std::move(pT)); return result; } CTuning* CTuningCollection::AddTuning(std::istream &inStrm, mpt::Charset defaultCharset) { if(m_Tunings.size() >= s_nMaxTuningCount) { return nullptr; } if(!inStrm.good()) { return nullptr; } std::unique_ptr pT = CTuning::CreateDeserializeOLD(inStrm, defaultCharset); if(!pT) { pT = CTuning::CreateDeserialize(inStrm, defaultCharset); } if(!pT) { return nullptr; } CTuning *result = pT.get(); m_Tunings.push_back(std::move(pT)); return result; } #ifdef MODPLUG_TRACKER bool UnpackTuningCollection(const CTuningCollection &tc, const mpt::PathString &prefix) { bool error = false; auto numberFmt = mpt::format_simple_spec().Dec().FillNul().Width(1 + static_cast(std::log10(tc.GetNumTunings()))); for(std::size_t i = 0; i < tc.GetNumTunings(); ++i) { const CTuning & tuning = *(tc.GetTuning(i)); mpt::PathString fn; fn += prefix; mpt::ustring tuningName = tuning.GetName(); if(tuningName.empty()) { tuningName = U_("untitled"); } fn += mpt::PathString::FromUnicode(MPT_UFORMAT("{} - {}")(mpt::ufmt::fmt(i + 1, numberFmt), tuningName)).AsSanitizedComponent(); fn += mpt::PathString::FromUTF8(CTuning::s_FileExtension); if(mpt::native_fs{}.exists(fn)) { error = true; } else { mpt::IO::SafeOutputFile sfout(fn, std::ios::binary, mpt::IO::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave)); if(tuning.Serialize(sfout) != Tuning::SerializationResult::Success) { error = true; } } } return !error; } #endif } // namespace Tuning OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/modcommand.cpp0000644000175000017500000011064215005446366020734 00000000000000/* * modcommand.cpp * -------------- * Purpose: Various functions for writing effects to patterns, converting ModCommands, etc. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "modcommand.h" #include "mod_specifications.h" #include "Sndfile.h" #include "Tables.h" OPENMPT_NAMESPACE_BEGIN static constexpr EffectType effectTypes[] = { EffectType::Normal, EffectType::Normal, EffectType::Pitch, EffectType::Pitch, EffectType::Pitch, EffectType::Pitch, EffectType::Volume, EffectType::Volume, EffectType::Volume, EffectType::Panning, EffectType::Normal, EffectType::Volume, EffectType::Global, EffectType::Volume, EffectType::Global, EffectType::Normal, EffectType::Global, EffectType::Global, EffectType::Normal, EffectType::Normal, EffectType::Normal, EffectType::Volume, EffectType::Volume, EffectType::Global, EffectType::Global, EffectType::Normal, EffectType::Pitch, EffectType::Panning, EffectType::Pitch, EffectType::Panning, EffectType::Normal, EffectType::Normal, EffectType::Normal, EffectType::Normal, EffectType::Normal, EffectType::Pitch, EffectType::Pitch, EffectType::Normal, EffectType::Pitch, EffectType::Pitch, EffectType::Pitch, EffectType::Pitch, EffectType::Normal, EffectType::Normal, EffectType::Normal, EffectType::Normal, EffectType::Volume, EffectType::Normal, EffectType::Normal, EffectType::Volume, EffectType::Pitch, EffectType::Pitch, EffectType::Pitch, EffectType::Pitch, EffectType::Pitch, EffectType::Pitch, EffectType::Volume, EffectType::Volume, }; static_assert(std::size(effectTypes) == MAX_EFFECTS); static constexpr EffectType volumeEffectTypes[] = { EffectType::Normal, EffectType::Volume, EffectType::Panning, EffectType::Volume, EffectType::Volume, EffectType::Volume, EffectType::Volume, EffectType::Pitch, EffectType::Pitch, EffectType::Panning, EffectType::Panning, EffectType::Pitch, EffectType::Pitch, EffectType::Pitch, EffectType::Normal, EffectType::Normal, }; static_assert(std::size(volumeEffectTypes) == MAX_VOLCMDS); EffectType ModCommand::GetEffectType(COMMAND cmd) { if(cmd < std::size(effectTypes)) return effectTypes[cmd]; else return EffectType::Normal; } EffectType ModCommand::GetVolumeEffectType(VOLCMD volcmd) { if(volcmd < std::size(volumeEffectTypes)) return volumeEffectTypes[volcmd]; else return EffectType::Normal; } // Convert an Exx command (MOD) to Sxx command (S3M) void ModCommand::ExtendedMODtoS3MEffect() { if(command != CMD_MODCMDEX) return; command = CMD_S3MCMDEX; switch(param & 0xF0) { case 0x00: command = CMD_NONE; break; // No filter control case 0x10: command = CMD_PORTAMENTOUP; param |= 0xF0; break; case 0x20: command = CMD_PORTAMENTODOWN; param |= 0xF0; break; case 0x30: param = (param & 0x0F) | 0x10; break; case 0x40: param = (param & 0x03) | 0x30; break; case 0x50: param = (param ^ 0x58) | 0x20; break; case 0x60: param = (param & 0x0F) | 0xB0; break; case 0x70: param = (param & 0x03) | 0x40; break; case 0x90: command = CMD_RETRIG; param = (param & 0x0F); break; case 0xA0: if(param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command = CMD_NONE; break; case 0xB0: if(param & 0x0F) { command = CMD_VOLUMESLIDE; param = 0xF0 | static_cast(std::min(param & 0x0F, 0x0E)); } else command = CMD_NONE; break; case 0xC0: if(param == 0xC0) { command = CMD_NONE; note = NOTE_NOTECUT; } break; // this does different things in IT and ST3 case 0xD0: if(param == 0xD0) { command = CMD_NONE; } break; // ditto // rest are the same or handled elsewhere } } // Convert an Sxx command (S3M) to Exx command (MOD) void ModCommand::ExtendedS3MtoMODEffect() { if(command != CMD_S3MCMDEX) return; command = CMD_MODCMDEX; switch(param & 0xF0) { case 0x10: param = (param & 0x0F) | 0x30; break; case 0x20: param = (param ^ 0x28) | 0x50; break; case 0x30: param = (param & 0x0F) | 0x40; break; case 0x40: param = (param & 0x0F) | 0x70; break; case 0x50: command = CMD_XFINEPORTAUPDOWN; break; // map to unused X5x case 0x60: command = CMD_XFINEPORTAUPDOWN; break; // map to unused X6x case 0x80: command = CMD_PANNING8; param = (param & 0x0F) * 0x11; break; // FT2 does actually not support E8x case 0x90: command = CMD_XFINEPORTAUPDOWN; break; // map to unused X9x case 0xA0: command = CMD_XFINEPORTAUPDOWN; break; // map to unused XAx case 0xB0: param = (param & 0x0F) | 0x60; break; case 0x70: command = CMD_NONE; break; // No NNA / envelope control in MOD/XM format // rest are the same or handled elsewhere } } // Convert a mod command from one format to another. void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &sndFile) { if(fromType == toType) { return; } if(fromType == MOD_TYPE_MTM) { // Special MTM fixups. // Retrigger with param 0 if(command == CMD_MODCMDEX && param == 0x90) { command = CMD_NONE; } else if(command == CMD_VIBRATO) { // Vibrato is approximately half as deep compared to MOD/S3M. uint8 speed = (param & 0xF0); uint8 depth = (param & 0x0F) >> 1; param = speed | depth; } // Apart from these special fixups, do a regular conversion from MOD. fromType = MOD_TYPE_MOD; } if(command == CMD_DIGIREVERSESAMPLE && toType != MOD_TYPE_DIGI) { command = CMD_S3MCMDEX; param = 0x9F; } if(command == CMD_VOLUME8) { command = CMD_VOLUME; param = static_cast((param + 3u) / 4u); } // helper variables const bool oldTypeIsMOD = (fromType == MOD_TYPE_MOD), oldTypeIsXM = (fromType == MOD_TYPE_XM), oldTypeIsS3M = (fromType == MOD_TYPE_S3M), oldTypeIsIT = (fromType == MOD_TYPE_IT), oldTypeIsMPT = (fromType == MOD_TYPE_MPT), oldTypeIsMOD_XM = (oldTypeIsMOD || oldTypeIsXM), oldTypeIsS3M_IT_MPT = (oldTypeIsS3M || oldTypeIsIT || oldTypeIsMPT), oldTypeIsIT_MPT = (oldTypeIsIT || oldTypeIsMPT); const bool newTypeIsMOD = (toType == MOD_TYPE_MOD), newTypeIsXM = (toType == MOD_TYPE_XM), newTypeIsS3M = (toType == MOD_TYPE_S3M), newTypeIsIT = (toType == MOD_TYPE_IT), newTypeIsMPT = (toType == MOD_TYPE_MPT), newTypeIsMOD_XM = (newTypeIsMOD || newTypeIsXM), newTypeIsS3M_IT_MPT = (newTypeIsS3M || newTypeIsIT || newTypeIsMPT), newTypeIsIT_MPT = (newTypeIsIT || newTypeIsMPT); const CModSpecifications &newSpecs = CSoundFile::GetModSpecifications(toType); ////////////////////////// // Convert 8-bit Panning if(command == CMD_PANNING8) { if(newTypeIsS3M) { param = static_cast((param + 1u) >> 1); } else if(oldTypeIsS3M) { if(param == 0xA4) { // surround remap command = (toType & (MOD_TYPE_IT | MOD_TYPE_MPT)) ? CMD_S3MCMDEX : CMD_XFINEPORTAUPDOWN; param = 0x91; } else { param = mpt::saturate_cast(param * 2u); } } } // End if(command == CMD_PANNING8) // Re-map \xx to Zxx if the new format only knows the latter command. if(command == CMD_SMOOTHMIDI && !newSpecs.HasCommand(CMD_SMOOTHMIDI) && newSpecs.HasCommand(CMD_MIDI)) { command = CMD_MIDI; } /////////////////////////////////////////////////////////////////////////////////////// // MPTM to anything: Convert param control, extended envelope control, note delay+cut if(oldTypeIsMPT) { if(IsPcNote()) { COMMAND newCmd = (note == NOTE_PC) ? CMD_MIDI : CMD_SMOOTHMIDI; if(!newSpecs.HasCommand(newCmd)) { newCmd = CMD_MIDI; // assuming that this was CMD_SMOOTHMIDI if(!newSpecs.HasCommand(newCmd)) { newCmd = CMD_NONE; } } param = static_cast(std::min(static_cast(maxColumnValue), GetValueEffectCol()) * 0x7F / maxColumnValue); command = newCmd; // might be removed later volcmd = VOLCMD_NONE; note = NOTE_NONE; instr = 0; } if((command == CMD_S3MCMDEX) && ((param & 0xF0) == 0x70) && ((param & 0x0F) > 0x0C)) { // Extended pitch envelope control commands param = 0x7C; } else if(command == CMD_DELAYCUT) { command = CMD_S3MCMDEX; // When converting to MOD/XM, this will be converted to CMD_MODCMDEX later param = 0xD0 | (param >> 4); // Preserve delay nibble } else if(command == CMD_FINETUNE || command == CMD_FINETUNE_SMOOTH) { // Convert finetune from +/-128th of a semitone to (extra-)fine portamento (assumes linear slides, plus we're missing the actual pitch wheel depth of the instrument) if(param < 0x80) { command = CMD_PORTAMENTODOWN; param = 0x80 - param; } else if(param > 0x80) { command = CMD_PORTAMENTOUP; param -= 0x80; } if(param <= 30) param = static_cast(0xE0u | ((param + 1u) / 2u)); else param = static_cast(0xF0u | std::min(static_cast((param + 7u) / 8u), PARAM(15))); } } // End if(oldTypeIsMPT) ///////////////////////////////////////// // Convert MOD / XM to S3M / IT / MPTM if(!oldTypeIsS3M_IT_MPT && newTypeIsS3M_IT_MPT) { switch(command) { case CMD_ARPEGGIO: if(!param) command = CMD_NONE; // 000 does nothing in MOD/XM break; case CMD_MODCMDEX: ExtendedMODtoS3MEffect(); break; case CMD_VOLUME: // Effect column volume command overrides the volume column in XM. if(volcmd == VOLCMD_NONE || volcmd == VOLCMD_VOLUME) { volcmd = VOLCMD_VOLUME; vol = param; if(vol > 64) vol = 64; command = CMD_NONE; param = 0; } else if(volcmd == VOLCMD_PANNING) { std::swap(vol, param); volcmd = VOLCMD_VOLUME; if(vol > 64) vol = 64; command = CMD_S3MCMDEX; param = 0x80 | (param / 4); // XM volcol panning is actually 4-Bit, so we can use 4-Bit panning here. } break; case CMD_PORTAMENTOUP: if(param > 0xDF) param = 0xDF; break; case CMD_PORTAMENTODOWN: if(param > 0xDF) param = 0xDF; break; case CMD_XFINEPORTAUPDOWN: switch(param & 0xF0) { case 0x10: command = CMD_PORTAMENTOUP; param = (param & 0x0F) | 0xE0; break; case 0x20: command = CMD_PORTAMENTODOWN; param = (param & 0x0F) | 0xE0; break; case 0x50: case 0x60: case 0x70: case 0x90: case 0xA0: command = CMD_S3MCMDEX; // Surround remap (this is the "official" command) if(toType & MOD_TYPE_S3M && param == 0x91) { command = CMD_PANNING8; param = 0xA4; } break; } break; case CMD_KEYOFF: if(note == NOTE_NONE) { note = newTypeIsS3M ? NOTE_NOTECUT : NOTE_KEYOFF; command = CMD_S3MCMDEX; if(param == 0) instr = 0; param = 0xD0 | std::min(param, PARAM(0x0F)); } break; case CMD_PANNINGSLIDE: // swap L/R, convert to fine slide if(param & 0xF0) { param = 0xF0 | std::min(PARAM(0x0E), static_cast(param >> 4)); } else { param = 0x0F | (std::min(PARAM(0x0E), static_cast(param & 0x0F)) << 4); } break; case CMD_DUMMY: // Command "W" in XM, equivalent implementation in IT / S3M is command " ". // Don't convert this command, as it overwrites effect memory in S3M in particular - a feature not supported by all S3M players. command = CMD_NONE; break; default: break; } } // End if(!oldTypeIsS3M_IT_MPT && newTypeIsS3M_IT_MPT) ///////////////////////////////////////// // Convert S3M / IT / MPTM to MOD / XM else if(!oldTypeIsMOD_XM && newTypeIsMOD_XM) { if(note == NOTE_NOTECUT) { // convert note cut to C00 if possible or volume command otherwise (MOD/XM has no real way of cutting notes that cannot be "undone" by volume commands) note = NOTE_NONE; if(command == CMD_NONE || !newTypeIsXM) { command = CMD_VOLUME; param = 0; } else { volcmd = VOLCMD_VOLUME; vol = 0; } } else if(note == NOTE_FADE) { // convert note fade to note off note = NOTE_KEYOFF; } switch(command) { case CMD_S3MCMDEX: ExtendedS3MtoMODEffect(); break; case CMD_TONEPORTAVOL: // Can't do fine slides and portamento/vibrato at the same time :( case CMD_VIBRATOVOL: // ditto if(volcmd == VOLCMD_NONE && (((param & 0xF0) && ((param & 0x0F) == 0x0F)) || ((param & 0x0F) && ((param & 0xF0) == 0xF0)))) { // Try to salvage portamento/vibrato if(command == CMD_TONEPORTAVOL) volcmd = VOLCMD_TONEPORTAMENTO; else if(command == CMD_VIBRATOVOL) volcmd = VOLCMD_VIBRATODEPTH; vol = 0; } [[fallthrough]]; case CMD_VOLUMESLIDE: if((param & 0xF0) && ((param & 0x0F) == 0x0F)) { command = CMD_MODCMDEX; param = (param >> 4) | 0xA0; } else if((param & 0x0F) && ((param & 0xF0) == 0xF0)) { command = CMD_MODCMDEX; param = (param & 0x0F) | 0xB0; } break; case CMD_PORTAMENTOUP: if(param >= 0xF0) { command = CMD_MODCMDEX; param = (param & 0x0F) | 0x10; } else if(param >= 0xE0) { if(newTypeIsXM) { command = CMD_XFINEPORTAUPDOWN; param = 0x10 | (param & 0x0F); } else { command = CMD_MODCMDEX; param = static_cast((((param & 0x0Fu) + 3u) >> 2) | 0x10u); } } else { command = CMD_PORTAMENTOUP; } break; case CMD_PORTAMENTODOWN: if(param >= 0xF0) { command = CMD_MODCMDEX; param = (param & 0x0F) | 0x20; } else if(param >= 0xE0) { if(newTypeIsXM) { command = CMD_XFINEPORTAUPDOWN; param = 0x20 | (param & 0x0F); } else { command = CMD_MODCMDEX; param = static_cast((((param & 0x0Fu) + 3u) >> 2) | 0x20u); } } else { command = CMD_PORTAMENTODOWN; } break; case CMD_TEMPO: if(param < 0x20) command = CMD_NONE; // no tempo slides break; case CMD_PANNINGSLIDE: // swap L/R, convert fine slides to normal slides if((param & 0x0F) == 0x0F && (param & 0xF0)) { param = (param >> 4); } else if((param & 0xF0) == 0xF0 && (param & 0x0F)) { param = (param & 0x0F) << 4; } else if(param & 0x0F) { param = 0xF0; } else if(param & 0xF0) { param = 0x0F; } else { param = 0; } break; case CMD_RETRIG: // Retrig: Q0y doesn't change volume in IT/S3M, but R0y in XM takes the last x parameter if(param != 0 && (param & 0xF0) == 0) { param |= 0x80; } break; default: break; } } // End if(!oldTypeIsMOD_XM && newTypeIsMOD_XM) /////////////////////// // Convert IT to S3M else if(oldTypeIsIT_MPT && newTypeIsS3M) { if(note == NOTE_KEYOFF || note == NOTE_FADE) note = NOTE_NOTECUT; switch(command) { case CMD_S3MCMDEX: switch(param & 0xF0) { case 0x70: command = CMD_NONE; break; // No NNA / envelope control in S3M format case 0x90: if(param == 0x91) { // surround remap (this is the "official" command) command = CMD_PANNING8; param = 0xA4; } else if(param == 0x90) { command = CMD_PANNING8; param = 0x40; } break; } break; case CMD_GLOBALVOLUME: param = static_cast((std::min(PARAM(0x80), param) + 1u) / 2u); break; default: break; } } // End if(oldTypeIsIT_MPT && newTypeIsS3M) ////////////////////// // Convert IT to XM if(oldTypeIsIT_MPT && newTypeIsXM) { switch(command) { case CMD_VIBRATO: // With linear slides, strength is roughly doubled. param = static_cast((param & 0xF0u) | (((param & 0x0Fu) + 1u) / 2u)); break; case CMD_GLOBALVOLUME: param = static_cast((std::min(PARAM(0x80), param) + 1u) / 2u); break; default: break; } } // End if(oldTypeIsIT_MPT && newTypeIsXM) ////////////////////// // Convert XM to IT if(oldTypeIsXM && newTypeIsIT_MPT) { switch(command) { case CMD_VIBRATO: // With linear slides, strength is roughly halved. param = (param & 0xF0) | std::min(static_cast((param & 0x0F) * 2u), PARAM(15)); break; case CMD_GLOBALVOLUME: param = std::min(PARAM(0x40), param) * 2u; break; default: break; } } // End if(oldTypeIsIT_MPT && newTypeIsXM) /////////////////////////////////// // MOD / XM Speed/Tempo limits if(newTypeIsMOD_XM) { switch(command) { case CMD_SPEED: param = std::min(param, PARAM(0x1F)); break; break; case CMD_TEMPO: param = std::max(param, PARAM(0x20)); break; default: break; } } /////////////////////////////////////////////////////////////////////// // Convert MOD to anything - adjust effect memory, remove Invert Loop if(oldTypeIsMOD) { switch(command) { case CMD_TONEPORTAVOL: // lacks memory -> 500 is the same as 300 if(param == 0x00) command = CMD_TONEPORTAMENTO; break; case CMD_VIBRATOVOL: // lacks memory -> 600 is the same as 400 if(param == 0x00) command = CMD_VIBRATO; break; case CMD_PORTAMENTOUP: // lacks memory -> remove case CMD_PORTAMENTODOWN: case CMD_VOLUMESLIDE: if(param == 0x00) command = CMD_NONE; break; case CMD_MODCMDEX: // No effect memory if(param == 0x10 || param == 0x20 || param == 0xA0 || param == 0xB0) command = CMD_NONE; // This would turn into "Set Active Macro", so let's better remove it if((param & 0xF0) == 0xF0) command = CMD_NONE; break; case CMD_S3MCMDEX: if((param & 0xF0) == 0xF0) command = CMD_NONE; break; default: break; } } // End if(oldTypeIsMOD && newTypeIsXM) ///////////////////////////////////////////////////////////////////// // Convert anything to MOD - remove volume column, remove Set Macro if(newTypeIsMOD) { // convert note off events if(IsSpecialNote()) { note = NOTE_NONE; // no effect present, so just convert note off to volume 0 if(command == CMD_NONE) { command = CMD_VOLUME; param = 0; // EDx effect present, so convert it to ECx } else if((command == CMD_MODCMDEX) && ((param & 0xF0) == 0xD0)) { param = 0xC0 | (param & 0x0F); } } if(command != CMD_NONE) switch(command) { case CMD_RETRIG: // MOD only has E9x command = CMD_MODCMDEX; param = 0x90 | (param & 0x0F); break; case CMD_MODCMDEX: // This would turn into "Invert Loop", so let's better remove it if((param & 0xF0) == 0xF0) command = CMD_NONE; break; default: break; } if(command == CMD_NONE) switch(volcmd) { case VOLCMD_VOLUME: command = CMD_VOLUME; param = vol; break; case VOLCMD_PANNING: command = CMD_PANNING8; param = vol < 64 ? vol << 2 : 255; break; case VOLCMD_VOLSLIDEDOWN: command = CMD_VOLUMESLIDE; param = vol; break; case VOLCMD_VOLSLIDEUP: command = CMD_VOLUMESLIDE; param = vol << 4; break; case VOLCMD_FINEVOLDOWN: command = CMD_MODCMDEX; param = 0xB0 | vol; break; case VOLCMD_FINEVOLUP: command = CMD_MODCMDEX; param = 0xA0 | vol; break; case VOLCMD_PORTADOWN: command = CMD_PORTAMENTODOWN; param = vol << 2; break; case VOLCMD_PORTAUP: command = CMD_PORTAMENTOUP; param = vol << 2; break; case VOLCMD_TONEPORTAMENTO: command = CMD_TONEPORTAMENTO; param = vol << 2; break; case VOLCMD_VIBRATODEPTH: command = CMD_VIBRATO; param = vol; break; case VOLCMD_VIBRATOSPEED: command = CMD_VIBRATO; param = vol << 4; break; default: break; } volcmd = VOLCMD_NONE; } // End if(newTypeIsMOD) /////////////////////////////////////////////////// // Convert anything to S3M - adjust volume column if(newTypeIsS3M) { if(command == CMD_NONE) switch(volcmd) { case VOLCMD_VOLSLIDEDOWN: command = CMD_VOLUMESLIDE; param = vol; volcmd = VOLCMD_NONE; break; case VOLCMD_VOLSLIDEUP: command = CMD_VOLUMESLIDE; param = vol << 4; volcmd = VOLCMD_NONE; break; case VOLCMD_FINEVOLDOWN: command = CMD_VOLUMESLIDE; param = 0xF0 | vol; volcmd = VOLCMD_NONE; break; case VOLCMD_FINEVOLUP: command = CMD_VOLUMESLIDE; param = (vol << 4) | 0x0F; volcmd = VOLCMD_NONE; break; case VOLCMD_PORTADOWN: command = CMD_PORTAMENTODOWN; param = vol << 2; volcmd = VOLCMD_NONE; break; case VOLCMD_PORTAUP: command = CMD_PORTAMENTOUP; param = vol << 2; volcmd = VOLCMD_NONE; break; case VOLCMD_TONEPORTAMENTO: command = CMD_TONEPORTAMENTO; param = vol << 2; volcmd = VOLCMD_NONE; break; case VOLCMD_VIBRATODEPTH: command = CMD_VIBRATO; param = vol; volcmd = VOLCMD_NONE; break; case VOLCMD_VIBRATOSPEED: command = CMD_VIBRATO; param = vol << 4; volcmd = VOLCMD_NONE; break; case VOLCMD_PANSLIDELEFT: command = CMD_PANNINGSLIDE; param = vol << 4; volcmd = VOLCMD_NONE; break; case VOLCMD_PANSLIDERIGHT: command = CMD_PANNINGSLIDE; param = vol; volcmd = VOLCMD_NONE; break; default: break; } } // End if(newTypeIsS3M) //////////////////////////////////////////////////////////////////////// // Convert anything to XM - adjust volume column, breaking EDx command if(newTypeIsXM) { // remove EDx if no note is next to it, or it will retrigger the note in FT2 mode if(command == CMD_MODCMDEX && (param & 0xF0) == 0xD0 && note == NOTE_NONE) { command = CMD_NONE; param = 0; } if(IsSpecialNote()) { // Instrument numbers next to Note Off reset instrument settings instr = 0; if(command == CMD_MODCMDEX && (param & 0xF0) == 0xD0) { // Note Off + Note Delay does nothing when using envelopes. note = NOTE_NONE; command = CMD_KEYOFF; param &= 0x0F; } } // Convert some commands which behave differently or don't exist if(command == CMD_NONE) switch(volcmd) { case VOLCMD_PORTADOWN: command = CMD_PORTAMENTODOWN; param = vol << 2; volcmd = VOLCMD_NONE; break; case VOLCMD_PORTAUP: command = CMD_PORTAMENTOUP; param = vol << 2; volcmd = VOLCMD_NONE; break; case VOLCMD_TONEPORTAMENTO: command = CMD_TONEPORTAMENTO; param = ImpulseTrackerPortaVolCmd[vol & 0x0F]; volcmd = VOLCMD_NONE; break; default: break; } } // End if(newTypeIsXM) /////////////////////////////////////////////////// // Convert anything to IT - adjust volume column if(newTypeIsIT_MPT) { // Convert some commands which behave differently or don't exist if(!oldTypeIsIT_MPT && command == CMD_NONE) switch(volcmd) { case VOLCMD_PANSLIDELEFT: command = CMD_PANNINGSLIDE; param = vol << 4; volcmd = VOLCMD_NONE; break; case VOLCMD_PANSLIDERIGHT: command = CMD_PANNINGSLIDE; param = vol; volcmd = VOLCMD_NONE; break; case VOLCMD_VIBRATOSPEED: command = CMD_VIBRATO; param = vol << 4; volcmd = VOLCMD_NONE; break; case VOLCMD_TONEPORTAMENTO: command = CMD_TONEPORTAMENTO; param = vol << 4; volcmd = VOLCMD_NONE; break; default: break; } switch(volcmd) { case VOLCMD_VOLSLIDEDOWN: case VOLCMD_VOLSLIDEUP: case VOLCMD_FINEVOLDOWN: case VOLCMD_FINEVOLUP: case VOLCMD_PORTADOWN: case VOLCMD_PORTAUP: case VOLCMD_TONEPORTAMENTO: case VOLCMD_VIBRATODEPTH: // OpenMPT-specific commands case VOLCMD_OFFSET: vol = std::min(vol, VOL(9)); break; default: break; } } // End if(newTypeIsIT_MPT) // Fix volume column offset for formats that don't have it. if(volcmd == VOLCMD_OFFSET && !newSpecs.HasVolCommand(VOLCMD_OFFSET) && (command == CMD_NONE || command == CMD_OFFSET || !newSpecs.HasCommand(command))) { const ModCommand::PARAM oldOffset = (command == CMD_OFFSET) ? param : 0; command = CMD_OFFSET; volcmd = VOLCMD_NONE; SAMPLEINDEX smp = instr; if(smp > 0 && smp <= sndFile.GetNumInstruments() && IsNote() && sndFile.Instruments[smp] != nullptr) smp = sndFile.Instruments[smp]->Keyboard[note - NOTE_MIN]; if(smp > 0 && smp <= sndFile.GetNumSamples() && vol <= std::size(ModSample().cues)) { const ModSample &sample = sndFile.GetSample(smp); if(vol == 0) param = mpt::saturate_cast(Util::muldivr_unsigned(sample.nLength, oldOffset, 65536u)); else param = mpt::saturate_cast((sample.cues[vol - 1] + (oldOffset * 256u) + 128u) / 256u); } else { param = vol << 3; } } else if(volcmd == VOLCMD_PLAYCONTROL && (vol == 2 || vol == 3) && command == CMD_NONE && !newSpecs.HasVolCommand(VOLCMD_PLAYCONTROL) && (newSpecs.HasCommand(CMD_S3MCMDEX) || newSpecs.HasCommand(CMD_XFINEPORTAUPDOWN))) { volcmd = VOLCMD_NONE; param = vol - 2 + 0x9E; if(newSpecs.HasCommand(CMD_S3MCMDEX)) command = CMD_S3MCMDEX; else command = CMD_XFINEPORTAUPDOWN; } // Offset effect memory is only updated when the command is placed next to a note. if(oldTypeIsXM && command == CMD_OFFSET && !IsNote()) command = CMD_NONE; if((command == CMD_REVERSEOFFSET || command == CMD_OFFSETPERCENTAGE) && !newSpecs.HasCommand(command)) { command = CMD_OFFSET; } else if(command == CMD_HMN_MEGA_ARP && !newSpecs.HasCommand(CMD_HMN_MEGA_ARP)) { command = CMD_ARPEGGIO; param = (HisMastersNoiseMegaArp[param & 0x0F][1] << 4) | HisMastersNoiseMegaArp[param & 0x0F][2]; } if(!newSpecs.HasNote(note)) note = NOTE_NONE; // ensure the commands really exist in this format if(!newSpecs.HasCommand(command)) command = CMD_NONE; if(!newSpecs.HasVolCommand(volcmd)) volcmd = VOLCMD_NONE; } bool ModCommand::IsAnyPitchSlide() const { switch(command) { case CMD_PORTAMENTOUP: case CMD_PORTAMENTODOWN: case CMD_TONEPORTAMENTO: case CMD_TONEPORTAVOL: case CMD_NOTESLIDEUP: case CMD_NOTESLIDEDOWN: case CMD_NOTESLIDEUPRETRIG: case CMD_NOTESLIDEDOWNRETRIG: case CMD_AUTO_PORTAUP: case CMD_AUTO_PORTADOWN: case CMD_AUTO_PORTAUP_FINE: case CMD_AUTO_PORTADOWN_FINE: case CMD_AUTO_PORTAMENTO_FC: case CMD_TONEPORTA_DURATION: return true; case CMD_MODCMDEX: case CMD_XFINEPORTAUPDOWN: if(param >= 0x10 && param <= 0x2F) return true; break; default: break; } switch(volcmd) { case VOLCMD_TONEPORTAMENTO: case VOLCMD_PORTAUP: case VOLCMD_PORTADOWN: return true; default: break; } return false; } bool ModCommand::IsContinousCommand(const CSoundFile &sndFile) const { switch(command) { case CMD_ARPEGGIO: case CMD_TONEPORTAMENTO: case CMD_VIBRATO: case CMD_TREMOLO: case CMD_RETRIG: case CMD_TREMOR: case CMD_FINEVIBRATO: case CMD_PANBRELLO: case CMD_SMOOTHMIDI: case CMD_NOTESLIDEUP: case CMD_NOTESLIDEDOWN: case CMD_NOTESLIDEUPRETRIG: case CMD_NOTESLIDEDOWNRETRIG: case CMD_HMN_MEGA_ARP: case CMD_AUTO_VOLUMESLIDE: case CMD_AUTO_PORTAUP: case CMD_AUTO_PORTADOWN: case CMD_AUTO_PORTAUP_FINE: case CMD_AUTO_PORTADOWN_FINE: case CMD_AUTO_PORTAMENTO_FC: return true; case CMD_PORTAMENTOUP: case CMD_PORTAMENTODOWN: if(!param && sndFile.GetType() == MOD_TYPE_MOD) return false; if(sndFile.GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM)) return true; if(param >= 0xF0) return false; if(param >= 0xE0 && sndFile.GetType() != MOD_TYPE_DBM) return false; return true; case CMD_VOLUMESLIDE: case CMD_TONEPORTAVOL: case CMD_VIBRATOVOL: case CMD_GLOBALVOLSLIDE: case CMD_CHANNELVOLSLIDE: case CMD_PANNINGSLIDE: if(!param && sndFile.GetType() == MOD_TYPE_MOD) return false; if(sndFile.GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_AMF0 | MOD_TYPE_MED | MOD_TYPE_DIGI)) return true; if((param & 0xF0) == 0xF0 && (param & 0x0F)) return false; if((param & 0x0F) == 0x0F && (param & 0xF0)) return false; return true; case CMD_TEMPO: return (param < 0x20); default: return false; } } bool ModCommand::IsContinousVolColCommand() const { switch(volcmd) { case VOLCMD_VOLSLIDEUP: case VOLCMD_VOLSLIDEDOWN: case VOLCMD_VIBRATOSPEED: case VOLCMD_VIBRATODEPTH: case VOLCMD_PANSLIDELEFT: case VOLCMD_PANSLIDERIGHT: case VOLCMD_TONEPORTAMENTO: case VOLCMD_PORTAUP: case VOLCMD_PORTADOWN: return true; default: return false; } } bool ModCommand::IsSlideUpDownCommand() const { switch(command) { case CMD_VOLUMESLIDE: case CMD_TONEPORTAVOL: case CMD_VIBRATOVOL: case CMD_GLOBALVOLSLIDE: case CMD_CHANNELVOLSLIDE: case CMD_PANNINGSLIDE: case CMD_AUTO_VOLUMESLIDE: return true; default: return false; } } bool ModCommand::IsGlobalCommand(COMMAND command, PARAM param) { switch(command) { case CMD_POSITIONJUMP: case CMD_PATTERNBREAK: case CMD_SPEED: case CMD_TEMPO: case CMD_GLOBALVOLUME: case CMD_GLOBALVOLSLIDE: case CMD_MIDI: case CMD_SMOOTHMIDI: case CMD_DBMECHO: return true; case CMD_MODCMDEX: switch(param & 0xF0) { case 0x00: // LED Filter case 0x60: // Pattern Loop case 0xE0: // Row Delay return true; default: return false; } case CMD_XFINEPORTAUPDOWN: case CMD_S3MCMDEX: switch(param & 0xF0) { case 0x60: // Tick Delay case 0x90: // Sound Control case 0xB0: // Pattern Loop case 0xE0: // Row Delay return true; default: return false; } default: return false; } } bool ModCommand::CommandHasTwoNibbles(COMMAND command) { switch(command) { case CMD_ARPEGGIO: case CMD_VIBRATO: case CMD_TONEPORTAVOL: case CMD_VIBRATOVOL: case CMD_TREMOLO: case CMD_VOLUMESLIDE: case CMD_RETRIG: case CMD_TREMOR: case CMD_MODCMDEX: case CMD_S3MCMDEX: case CMD_CHANNELVOLSLIDE: case CMD_GLOBALVOLSLIDE: case CMD_FINEVIBRATO: case CMD_PANBRELLO: case CMD_XFINEPORTAUPDOWN: case CMD_PANNINGSLIDE: case CMD_DELAYCUT: case CMD_NOTESLIDEUP: case CMD_NOTESLIDEDOWN: case CMD_NOTESLIDEUPRETRIG: case CMD_NOTESLIDEDOWNRETRIG: case CMD_AUTO_VOLUMESLIDE: return true; default: return false; } } // "Importance" of every FX command. Table is used for importing from formats with multiple effect colums // and is approximately the same as in SchismTracker. size_t ModCommand::GetEffectWeight(COMMAND cmd) { // Effect weights, sorted from lowest to highest weight. static constexpr COMMAND weights[] = { CMD_NONE, CMD_DUMMY, CMD_XPARAM, CMD_SETENVPOSITION, CMD_MED_SYNTH_JUMP, CMD_KEYOFF, CMD_TREMOLO, CMD_FINEVIBRATO, CMD_VIBRATO, CMD_XFINEPORTAUPDOWN, CMD_FINETUNE, CMD_FINETUNE_SMOOTH, CMD_PANBRELLO, CMD_S3MCMDEX, CMD_MODCMDEX, CMD_DELAYCUT, CMD_MIDI, CMD_SMOOTHMIDI, CMD_PANNINGSLIDE, CMD_PANNING8, CMD_NOTESLIDEUPRETRIG, CMD_NOTESLIDEUP, CMD_NOTESLIDEDOWNRETRIG, CMD_NOTESLIDEDOWN, CMD_PORTAMENTOUP, CMD_AUTO_PORTAMENTO_FC, CMD_AUTO_PORTAUP_FINE, CMD_AUTO_PORTAUP, CMD_PORTAMENTODOWN, CMD_AUTO_PORTADOWN_FINE, CMD_AUTO_PORTADOWN, CMD_VOLUMESLIDE, CMD_AUTO_VOLUMESLIDE, CMD_VIBRATOVOL, CMD_VOLUME, CMD_VOLUME8, CMD_DIGIREVERSESAMPLE, CMD_REVERSEOFFSET, CMD_OFFSETPERCENTAGE, CMD_OFFSET, CMD_TREMOR, CMD_RETRIG, CMD_HMN_MEGA_ARP, CMD_ARPEGGIO, CMD_TONEPORTA_DURATION, CMD_TONEPORTAMENTO, CMD_TONEPORTAVOL, CMD_DBMECHO, CMD_VOLUMEDOWN_DURATION, CMD_VOLUMEDOWN_ETX, CMD_CHANNELVOLSLIDE, CMD_CHANNELVOLUME, CMD_GLOBALVOLSLIDE, CMD_GLOBALVOLUME, CMD_TEMPO, CMD_SPEED, CMD_POSITIONJUMP, CMD_PATTERNBREAK, }; static_assert(std::size(weights) == MAX_EFFECTS); for(size_t i = 0; i < std::size(weights); i++) { if(weights[i] == cmd) { return i; } } // Invalid / unknown command. MPT_ASSERT_NOTREACHED(); return 0; } // Try to convert a fx column command into a volume column command. // Returns the translated command if successful. // Some commands can only be converted by losing some precision. // If moving the command into the volume column is more important than accuracy, use force = true. // (Code translated from SchismTracker and mainly supposed to be used with loaders ported from this tracker) std::pair ModCommand::ConvertToVolCommand(const EffectCommand effect, ModCommand::PARAM param, bool force) { switch(effect) { case CMD_NONE: break; case CMD_VOLUME: return {VOLCMD_VOLUME, std::min(param, PARAM(64))}; case CMD_VOLUME8: if(!force && (param & 3)) break; return {VOLCMD_VOLUME, static_cast((param + 3u) / 4u)}; case CMD_PORTAMENTOUP: // if not force, reject when dividing causes loss of data in LSB, or if the final value is too // large to fit. (volume column Ex/Fx are four times stronger than effect column) if(!force && ((param & 3) || param >= 0xE0)) break; return {VOLCMD_PORTAUP, static_cast(param / 4u)}; case CMD_PORTAMENTODOWN: if(!force && ((param & 3) || param >= 0xE0)) break; return {VOLCMD_PORTADOWN, static_cast(param / 4u)}; case CMD_TONEPORTAMENTO: if(param >= 0xF0) { // hack for people who can't type F twice :) return {VOLCMD_TONEPORTAMENTO, VOL(9)}; } for(uint8 n = 0; n < 10; n++) { if(force ? (param <= ImpulseTrackerPortaVolCmd[n]) : (param == ImpulseTrackerPortaVolCmd[n])) { return {VOLCMD_TONEPORTAMENTO, n}; } } break; case CMD_VIBRATO: if(force) param = std::min(static_cast(param & 0x0F), PARAM(9)); else if((param & 0x0F) > 9 || (param & 0xF0) != 0) break; return {VOLCMD_VIBRATODEPTH, static_cast(param & 0x0F)}; case CMD_FINEVIBRATO: if(force) param = 0; else if(param) break; return {VOLCMD_VIBRATODEPTH, param}; case CMD_PANNING8: if(param == 255) param = 64; else param /= 4; return {VOLCMD_PANNING, param}; case CMD_VOLUMESLIDE: if(param == 0) break; if((param & 0x0F) == 0) // Dx0 / Cx return {VOLCMD_VOLSLIDEUP, static_cast(param >> 4)}; else if((param & 0xF0) == 0) // D0x / Dx return {VOLCMD_VOLSLIDEDOWN, param}; else if((param & 0x0F) == 0x0F) // DxF / Ax return {VOLCMD_FINEVOLUP, static_cast(param >> 4)}; else if((param & 0xF0) == 0xF0) // DFx / Bx return {VOLCMD_FINEVOLDOWN, static_cast(param & 0x0F)}; break; case CMD_S3MCMDEX: switch(param & 0xF0) { case 0x80: return {VOLCMD_PANNING, static_cast(((param & 0x0F) << 2) + 2)}; case 0x90: if(param >= 0x9E && force) return {VOLCMD_PLAYCONTROL, static_cast(param - 0x9E + 2)}; break; default: break; } break; case CMD_MODCMDEX: switch(param & 0xF0) { case 0x80: return {VOLCMD_PANNING, static_cast(((param & 0x0F) << 2) + 2)}; case 0xA0: return {VOLCMD_FINEVOLUP, static_cast(param & 0x0F)}; case 0xB0: return {VOLCMD_FINEVOLDOWN, static_cast(param & 0x0F)}; default: break; } break; default: break; } return {VOLCMD_NONE, VOL(0)}; } // Try to combine two commands into one. Returns true on success and the combined command is placed in eff1 / param1. bool ModCommand::CombineEffects(EffectCommand &eff1, uint8 ¶m1, EffectCommand &eff2, uint8 ¶m2) { if(eff1 == CMD_VOLUMESLIDE && (eff2 == CMD_VIBRATO || eff2 == CMD_TONEPORTAVOL) && param2 == 0) { // Merge commands if(eff2 == CMD_VIBRATO) { eff1 = CMD_VIBRATOVOL; } else { eff1 = CMD_TONEPORTAVOL; } eff2 = CMD_NONE; return true; } else if(eff2 == CMD_VOLUMESLIDE && (eff1 == CMD_VIBRATO || eff1 == CMD_TONEPORTAVOL) && param1 == 0) { // Merge commands if(eff1 == CMD_VIBRATO) { eff1 = CMD_VIBRATOVOL; } else { eff1 = CMD_TONEPORTAVOL; } param1 = param2; eff2 = CMD_NONE; return true; } else if(eff1 == CMD_OFFSET && eff2 == CMD_S3MCMDEX && param2 == 0x9F) { // Reverse offset eff1 = CMD_REVERSEOFFSET; eff2 = CMD_NONE; return true; } else if(eff1 == CMD_S3MCMDEX && param1 == 0x9F && eff2 == CMD_OFFSET) { // Reverse offset eff1 = CMD_REVERSEOFFSET; param1 = param2; eff2 = CMD_NONE; return true; } else { return false; } } std::pair ModCommand::FillInTwoCommands(EffectCommand effect1, uint8 param1, EffectCommand effect2, uint8 param2, bool allowLowResOffset) { if(effect1 == effect2) { // For non-sliding, absolute effects, it doesn't make sense to keep both commands switch(effect1) { case CMD_ARPEGGIO: case CMD_PANNING8: case CMD_OFFSET: case CMD_POSITIONJUMP: case CMD_VOLUME: case CMD_PATTERNBREAK: case CMD_SPEED: case CMD_TEMPO: case CMD_CHANNELVOLUME: case CMD_GLOBALVOLUME: case CMD_KEYOFF: case CMD_SETENVPOSITION: case CMD_MIDI: case CMD_SMOOTHMIDI: case CMD_DELAYCUT: case CMD_FINETUNE: case CMD_FINETUNE_SMOOTH: case CMD_DUMMY: case CMD_REVERSEOFFSET: case CMD_DBMECHO: case CMD_OFFSETPERCENTAGE: case CMD_DIGIREVERSESAMPLE: case CMD_VOLUME8: case CMD_HMN_MEGA_ARP: case CMD_MED_SYNTH_JUMP: effect2 = CMD_NONE; break; default: break; } } for(uint8 n = 0; n < 4; n++) { if(auto volCmd = ModCommand::ConvertToVolCommand(effect1, param1, (n > 1)); effect1 == CMD_NONE || volCmd.first != VOLCMD_NONE) { SetVolumeCommand(volCmd); SetEffectCommand(effect2, param2); return {CMD_NONE, ModCommand::PARAM(0)}; } std::swap(effect1, effect2); std::swap(param1, param2); } // Can only keep one command :( if(GetEffectWeight(effect1) > GetEffectWeight(effect2)) { std::swap(effect1, effect2); std::swap(param1, param2); } if(effect2 == CMD_OFFSET && (allowLowResOffset || param2 == 0)) { SetVolumeCommand(VOLCMD_OFFSET, static_cast(param2 ? std::max(param2 * 9 / 255, 1) : 0)); SetEffectCommand(effect1, param1); return {CMD_NONE, ModCommand::PARAM(0)}; } SetVolumeCommand(VOLCMD_NONE, 0); SetEffectCommand(effect2, param2); return {effect1, param1}; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/UpgradeModule.cpp0000644000175000017500000007553515022626104021353 00000000000000/* * UpdateModule.cpp * ---------------- * Purpose: Compensate for playback bugs of previous OpenMPT versions during import * by rewriting patterns / samples / instruments or enabling / disabling specific compatibility flags * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Sndfile.h" #include "plugins/PluginManager.h" #include "../common/mptStringBuffer.h" #include "../common/version.h" OPENMPT_NAMESPACE_BEGIN struct UpgradePatternData { UpgradePatternData(CSoundFile &sf) : sndFile(sf) , compatPlay(sf.m_playBehaviour[MSF_COMPATIBLE_PLAY]) { } void operator() (ModCommand &m) { const CHANNELINDEX curChn = chn; chn++; if(chn >= sndFile.GetNumChannels()) { chn = 0; } if(m.IsPcNote()) { return; } const auto version = sndFile.m_dwLastSavedWithVersion; const auto modType = sndFile.GetType(); if(modType == MOD_TYPE_S3M) { // Out-of-range global volume commands should be ignored in S3M. Fixed in OpenMPT 1.19 (r831). // So for tracks made with older versions of OpenMPT, we limit invalid global volume commands. if(version < MPT_V("1.19.00.00") && m.command == CMD_GLOBALVOLUME) { LimitMax(m.param, ModCommand::PARAM(64)); } } else if(modType & (MOD_TYPE_IT | MOD_TYPE_MPT)) { if(version < MPT_V("1.17.03.02") || (!compatPlay && version < MPT_V("1.20.00.00"))) { if(m.command == CMD_GLOBALVOLUME) { // Out-of-range global volume commands should be ignored in IT. // OpenMPT 1.17.03.02 fixed this in compatible mode, OpenMPT 1.20 fixes it in normal mode as well. // So for tracks made with older versions than OpenMPT 1.17.03.02 or tracks made with 1.17.03.02 <= version < 1.20, we limit invalid global volume commands. LimitMax(m.param, ModCommand::PARAM(128)); } // SC0 and SD0 should be interpreted as SC1 and SD1 in IT files. // OpenMPT 1.17.03.02 fixed this in compatible mode, OpenMPT 1.20 fixes it in normal mode as well. else if(m.command == CMD_S3MCMDEX) { if(m.param == 0xC0) { m.command = CMD_NONE; m.note = NOTE_NOTECUT; } else if(m.param == 0xD0) { m.command = CMD_NONE; } } } // In the IT format, slide commands with both nibbles set should be ignored. // For note volume slides, OpenMPT 1.18 fixes this in compatible mode, OpenMPT 1.20 fixes this in normal mode as well. const bool noteVolSlide = (version < MPT_V("1.18.00.00") || (!compatPlay && version < MPT_V("1.20.00.00"))) && (m.command == CMD_VOLUMESLIDE || m.command == CMD_VIBRATOVOL || m.command == CMD_TONEPORTAVOL || m.command == CMD_PANNINGSLIDE); // OpenMPT 1.20 also fixes this for global volume and channel volume slides. const bool chanVolSlide = (version < MPT_V("1.20.00.00")) && (m.command == CMD_GLOBALVOLSLIDE || m.command == CMD_CHANNELVOLSLIDE); if(noteVolSlide || chanVolSlide) { if((m.param & 0x0F) != 0x00 && (m.param & 0x0F) != 0x0F && (m.param & 0xF0) != 0x00 && (m.param & 0xF0) != 0xF0) { if(m.command == CMD_GLOBALVOLSLIDE) m.param &= 0xF0; else m.param &= 0x0F; } } if(version < MPT_V("1.22.01.04") && version != MPT_V("1.22.00.00")) // Ignore compatibility export { // OpenMPT 1.22.01.04 fixes illegal (out of range) instrument numbers; they should do nothing. In previous versions, they stopped the playing sample. if(sndFile.GetNumInstruments() && m.instr > sndFile.GetNumInstruments() && !compatPlay) { m.volcmd = VOLCMD_VOLUME; m.vol = 0; } } // Command I11 accidentally behaved the same as command I00 with compatible IT tremor and old effects disabled if(m.command == CMD_TREMOR && m.param == 0x11 && version < MPT_V("1.29.12.02") && sndFile.m_playBehaviour[kITTremor] && !sndFile.m_SongFlags[SONG_ITOLDEFFECTS]) { m.param = 0; } } else if(modType == MOD_TYPE_XM) { // Something made be believe that out-of-range global volume commands are ignored in XM // just like they are ignored in IT, but apparently they are not. Aaaaaargh! if(((version >= MPT_V("1.17.03.02") && compatPlay) || (version >= MPT_V("1.20.00.00"))) && version < MPT_V("1.24.02.02") && m.command == CMD_GLOBALVOLUME && m.param > 64) { m.command = CMD_NONE; } if(version < MPT_V("1.19.00.00") || (!compatPlay && version < MPT_V("1.20.00.00"))) { if(m.command == CMD_OFFSET && m.volcmd == VOLCMD_TONEPORTAMENTO) { // If there are both a portamento and an offset effect, the portamento should be preferred in XM files. // OpenMPT 1.19 fixed this in compatible mode, OpenMPT 1.20 fixes it in normal mode as well. m.command = CMD_NONE; } } if(version < MPT_V("1.20.01.10") && m.volcmd == VOLCMD_TONEPORTAMENTO && m.command == CMD_TONEPORTAMENTO && (m.vol != 0 || compatPlay) && m.param != 0) { // Mx and 3xx on the same row does weird things in FT2: 3xx is completely ignored and the Mx parameter is doubled. Fixed in revision 1312 / OpenMPT 1.20.01.10 // Previously the values were just added up, so let's fix this! m.volcmd = VOLCMD_NONE; const uint16 param = static_cast(m.param) + static_cast(m.vol << 4); m.param = mpt::saturate_cast(param); } if(version < MPT_V("1.22.07.09") && m.command == CMD_SPEED && m.param == 0) { // OpenMPT can emulate FT2's F00 behaviour now. m.command = CMD_NONE; } } if(version < MPT_V("1.20.00.00")) { // Pattern Delay fixes const bool fixS6x = (m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0x60); // We also fix X6x commands in hacked XM files, since they are treated identically to the S6x command in IT/S3M files. // We don't treat them in files made with OpenMPT 1.18+ that have compatible play enabled, though, since they are ignored there anyway. const bool fixX6x = (m.command == CMD_XFINEPORTAUPDOWN && (m.param & 0xF0) == 0x60 && (!(compatPlay && modType == MOD_TYPE_XM) || version < MPT_V("1.18.00.00"))); if(fixS6x || fixX6x) { // OpenMPT 1.20 fixes multiple fine pattern delays on the same row. Previously, only the last command was considered, // but all commands should be added up. Since Scream Tracker 3 itself doesn't support S6x, we also use Impulse Tracker's behaviour here, // since we can assume that most S3Ms that make use of S6x were composed with Impulse Tracker. for(ModCommand *fixCmd = (&m) - curChn; fixCmd < &m; fixCmd++) { if((fixCmd->command == CMD_S3MCMDEX || fixCmd->command == CMD_XFINEPORTAUPDOWN) && (fixCmd->param & 0xF0) == 0x60) { fixCmd->command = CMD_NONE; } } } if(m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0xE0) { // OpenMPT 1.20 fixes multiple pattern delays on the same row. Previously, only the *last* command was considered, // but Scream Tracker 3 and Impulse Tracker only consider the *first* command. for(ModCommand *fixCmd = (&m) - curChn; fixCmd < &m; fixCmd++) { if(fixCmd->command == CMD_S3MCMDEX && (fixCmd->param & 0xF0) == 0xE0) { fixCmd->command = CMD_NONE; } } } } if(m.volcmd == VOLCMD_VIBRATODEPTH && version < MPT_V("1.27.00.37") && version != MPT_V("1.27.00.00")) { // Fix handling of double vibrato commands - previously only one of them was applied at a time if(m.command == CMD_VIBRATOVOL && m.vol > 0) { m.command = CMD_VOLUMESLIDE; } else if((m.command == CMD_VIBRATO || m.command == CMD_FINEVIBRATO) && (m.param & 0x0F) == 0) { m.command = CMD_VIBRATO; m.param |= (m.vol & 0x0F); m.volcmd = VOLCMD_NONE; } else if(m.command == CMD_VIBRATO || m.command == CMD_VIBRATOVOL || m.command == CMD_FINEVIBRATO) { m.volcmd = VOLCMD_NONE; } } // Volume column offset in IT/XM is bad, mkay? if(modType != MOD_TYPE_MPT && m.volcmd == VOLCMD_OFFSET && m.command == CMD_NONE) { m.command = CMD_OFFSET; m.param = m.vol << 3; m.volcmd = VOLCMD_NONE; } // Previously CMD_OFFSET simply overrode VOLCMD_OFFSET, now they work together as a combined command if(m.volcmd == VOLCMD_OFFSET && m.command == CMD_OFFSET && version < MPT_V("1.30.00.14")) { if(m.param != 0 || m.vol == 0) m.volcmd = VOLCMD_NONE; else m.command = CMD_NONE; } } const CSoundFile &sndFile; CHANNELINDEX chn = 0; const bool compatPlay; }; void CSoundFile::UpgradeModule() { if(m_dwLastSavedWithVersion < MPT_V("1.17.02.46") && m_dwLastSavedWithVersion != MPT_V("1.17.00.00")) { // Compatible playback mode didn't exist in earlier versions, so definitely disable it. m_playBehaviour.reset(MSF_COMPATIBLE_PLAY); } const bool compatModeIT = m_playBehaviour[MSF_COMPATIBLE_PLAY] && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)); const bool compatModeXM = m_playBehaviour[MSF_COMPATIBLE_PLAY] && GetType() == MOD_TYPE_XM; if(m_dwLastSavedWithVersion < MPT_V("1.20.00.00")) { for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { ModInstrument *ins = Instruments[i]; if(!ins) continue; // Previously, volume swing values ranged from 0 to 64. They should reach from 0 to 100 instead. ins->nVolSwing = static_cast(std::min(static_cast(ins->nVolSwing * 100 / 64), uint32(100))); if(!compatModeIT || m_dwLastSavedWithVersion < MPT_V("1.18.00.00")) { // Previously, Pitch/Pan Separation was only half depth (plot twist: it was actually only quarter depth). // This was corrected in compatible mode in OpenMPT 1.18, and in OpenMPT 1.20 it is corrected in normal mode as well. ins->nPPS = static_cast((ins->nPPS + (ins->nPPS >= 0 ? 1 : -1)) / 2); } if(!compatModeIT || m_dwLastSavedWithVersion < MPT_V("1.17.03.02")) { // IT compatibility 24. Short envelope loops // Previously, the pitch / filter envelope loop handling was broken, the loop was shortened by a tick (like in XM). // This was corrected in compatible mode in OpenMPT 1.17.03.02, and in OpenMPT 1.20 it is corrected in normal mode as well. ins->GetEnvelope(ENV_PITCH).Convert(MOD_TYPE_XM, GetType()); } if(m_dwLastSavedWithVersion >= MPT_V("1.17.00.00") && m_dwLastSavedWithVersion < MPT_V("1.17.02.50")) { // If there are any plugins that can receive volume commands, enable volume bug emulation. if(ins->nMixPlug && ins->HasValidMIDIChannel()) { m_playBehaviour.set(kMIDICCBugEmulation); } } if(m_dwLastSavedWithVersion < MPT_V("1.17.02.50") && (ins->nVolSwing | ins->nPanSwing | ins->nCutSwing | ins->nResSwing)) { // If there are any instruments with random variation, enable the old random variation behaviour. m_playBehaviour.set(kMPTOldSwingBehaviour); break; } } if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (m_dwLastSavedWithVersion < MPT_V("1.17.03.02") || !compatModeIT)) { // In the IT format, a sweep value of 0 shouldn't apply vibrato at all. Previously, a value of 0 was treated as "no sweep". // In OpenMPT 1.17.03.02, this was corrected in compatible mode, in OpenMPT 1.20 it is corrected in normal mode as well, // so we have to fix the setting while loading. for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++) { if(Samples[i].nVibSweep == 0 && (Samples[i].nVibDepth | Samples[i].nVibRate)) { Samples[i].nVibSweep = 255; } } } // Fix old nasty broken (non-standard) MIDI configs in files. m_MidiCfg.UpgradeMacros(); } if(m_dwLastSavedWithVersion < MPT_V("1.20.02.10") && m_dwLastSavedWithVersion != MPT_V("1.20.00.00") && (GetType() & (MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT))) { bool instrPlugs = false; // Old pitch wheel commands were closest to sample pitch bend commands if the PWD is 13. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { if(Instruments[i] != nullptr && Instruments[i]->nMidiChannel != MidiNoChannel) { Instruments[i]->midiPWD = 13; instrPlugs = true; } } if(instrPlugs) { m_playBehaviour.set(kOldMIDIPitchBends); } } if(m_dwLastSavedWithVersion < MPT_V("1.22.03.12") && m_dwLastSavedWithVersion != MPT_V("1.22.00.00") && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (m_playBehaviour[MSF_COMPATIBLE_PLAY] || m_playBehaviour[kMPTOldSwingBehaviour])) { // The "correct" pan swing implementation did nothing if the instrument also had a pan envelope. // If there's a pan envelope, disable pan swing for such modules. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { if(Instruments[i] != nullptr && Instruments[i]->nPanSwing != 0 && Instruments[i]->PanEnv.dwFlags[ENV_ENABLED]) { Instruments[i]->nPanSwing = 0; } } } bool hasAnyPlugins = false; if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM)) { for(auto &plugin : m_MixPlugins) { if(plugin.IsValidPlugin()) { hasAnyPlugins = true; break; } } } #ifndef NO_PLUGINS if(m_dwLastSavedWithVersion < MPT_V("1.22.07.01") && hasAnyPlugins) { // Convert ANSI plugin path names to UTF-8 (irrelevant in probably 99% of all cases anyway, I think I've never seen a VST plugin with a non-ASCII file name) for(auto &plugin : m_MixPlugins) { #if defined(MODPLUG_TRACKER) const std::string name = mpt::ToCharset(mpt::Charset::UTF8, mpt::Charset::Locale, plugin.Info.szLibraryName); #else const std::string name = mpt::ToCharset(mpt::Charset::UTF8, mpt::Charset::Windows1252, plugin.Info.szLibraryName); #endif plugin.Info.szLibraryName = name; } } #endif // NO_PLUGINS // Starting from OpenMPT 1.22.07.19, FT2-style panning was applied in compatible mix mode. // Starting from OpenMPT 1.23.01.04, FT2-style panning has its own mix mode instead. if(GetType() == MOD_TYPE_XM) { if(m_dwLastSavedWithVersion >= MPT_V("1.22.07.19") && m_dwLastSavedWithVersion < MPT_V("1.23.01.04") && GetMixLevels() == MixLevels::Compatible) { SetMixLevels(MixLevels::CompatibleFT2); } } if(m_dwLastSavedWithVersion < MPT_V("1.25.00.07") && m_dwLastSavedWithVersion != MPT_V("1.25.00.00")) { // Instrument plugins can now receive random volume variation. // For old instruments, disable volume swing in case there was no sample associated. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { if(Instruments[i] != nullptr && Instruments[i]->nVolSwing != 0 && Instruments[i]->nMidiChannel != MidiNoChannel) { bool hasSample = false; for(auto smp : Instruments[i]->Keyboard) { if(smp != 0) { hasSample = true; break; } } if(!hasSample) { Instruments[i]->nVolSwing = 0; } } } } if(m_dwLastSavedWithVersion < MPT_V("1.26.00.00")) { for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { ModInstrument *ins = Instruments[i]; if(!ins) continue; // Even after fixing it in OpenMPT 1.18, instrument PPS was only half the depth. ins->nPPS = static_cast((ins->nPPS + (ins->nPPS >= 0 ? 1 : -1)) / 2); // OpenMPT 1.18 fixed the depth of random pan in compatible mode. // OpenMPT 1.26 fixes it in normal mode too. if(!compatModeIT || m_dwLastSavedWithVersion < MPT_V("1.18.00.00")) ins->nPanSwing = static_cast((ins->nPanSwing + 3) / 4u); // Before OpenMPT 1.26 (r6129), it was possible to trigger MIDI notes using channel plugins if the instrument had a valid MIDI channel. if(!ins->nMixPlug && ins->HasValidMIDIChannel() && m_dwLastSavedWithVersion >= MPT_V("1.17.00.00")) m_playBehaviour.set(kMIDINotesFromChannelPlugin); } } if(m_dwLastSavedWithVersion < MPT_V("1.28.00.12")) { for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { if(Instruments[i] != nullptr && Instruments[i]->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET) { m_playBehaviour.set(kLegacyReleaseNode); break; } } } if(m_dwLastSavedWithVersion < MPT_V("1.28.03.04")) { for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { if(Instruments[i] != nullptr && (Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_MIDI || Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_DRYWET)) { m_playBehaviour.set(kMIDIVolumeOnNoteOffBug); break; } } } if(m_dwLastSavedWithVersion < MPT_V("1.30.00.54")) { for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++) { if(Samples[i].HasSampleData() && Samples[i].uFlags[CHN_PINGPONGLOOP | CHN_PINGPONGSUSTAIN]) { m_playBehaviour.set(kImprecisePingPongLoops); break; } } } Patterns.ForEachModCommand(UpgradePatternData(*this)); // Convert compatibility flags // NOTE: Some of these version numbers are just approximations. // Sometimes a quirk flag is shared by several code locations which might have been fixed at different times. // Sometimes the quirk behaviour has been revised over time, in which case the first version that emulated the quirk enables it. struct PlayBehaviourVersion { PlayBehaviour behaviour; Version version; }; if(compatModeIT && m_dwLastSavedWithVersion < MPT_V("1.26.00.00")) { // Pre-1.26: Detailed compatibility flags did not exist. static constexpr PlayBehaviourVersion behaviours[] = { { kTempoClamp, MPT_V("1.17.03.02") }, { kPerChannelGlobalVolSlide, MPT_V("1.17.03.02") }, { kPanOverride, MPT_V("1.17.03.02") }, { kITInstrWithoutNote, MPT_V("1.17.02.46") }, { kITVolColFinePortamento, MPT_V("1.17.02.49") }, { kITArpeggio, MPT_V("1.17.02.49") }, { kITOutOfRangeDelay, MPT_V("1.17.02.49") }, { kITPortaMemoryShare, MPT_V("1.17.02.49") }, { kITPatternLoopTargetReset, MPT_V("1.17.02.49") }, { kITFT2PatternLoop, MPT_V("1.17.02.49") }, { kITPingPongNoReset, MPT_V("1.17.02.51") }, { kITEnvelopeReset, MPT_V("1.17.02.51") }, { kITClearOldNoteAfterCut, MPT_V("1.17.02.52") }, { kITVibratoTremoloPanbrello, MPT_V("1.17.03.02") }, { kITTremor, MPT_V("1.17.03.02") }, { kITRetrigger, MPT_V("1.17.03.02") }, { kITMultiSampleBehaviour, MPT_V("1.17.03.02") }, { kITPortaTargetReached, MPT_V("1.17.03.02") }, { kITPatternLoopBreak, MPT_V("1.17.03.02") }, { kITOffset, MPT_V("1.17.03.02") }, { kITSwingBehaviour, MPT_V("1.18.00.00") }, { kITNNAReset, MPT_V("1.18.00.00") }, { kITSCxStopsSample, MPT_V("1.18.00.01") }, { kITEnvelopePositionHandling, MPT_V("1.18.01.00") }, { kITPortamentoInstrument, MPT_V("1.19.00.01") }, { kITPingPongMode, MPT_V("1.19.00.21") }, { kITRealNoteMapping, MPT_V("1.19.00.30") }, { kITHighOffsetNoRetrig, MPT_V("1.20.00.14") }, { kITFilterBehaviour, MPT_V("1.20.00.35") }, { kITNoSurroundPan, MPT_V("1.20.00.53") }, { kITShortSampleRetrig, MPT_V("1.20.00.54") }, { kITPortaNoNote, MPT_V("1.20.00.56") }, { kRowDelayWithNoteDelay, MPT_V("1.20.00.76") }, { kITFT2DontResetNoteOffOnPorta, MPT_V("1.20.02.06") }, { kITVolColMemory, MPT_V("1.21.01.16") }, { kITPortamentoSwapResetsPos, MPT_V("1.21.01.25") }, { kITEmptyNoteMapSlot, MPT_V("1.21.01.25") }, { kITFirstTickHandling, MPT_V("1.22.07.09") }, { kITSampleAndHoldPanbrello, MPT_V("1.22.07.19") }, { kITClearPortaTarget, MPT_V("1.23.04.03") }, { kITPanbrelloHold, MPT_V("1.24.01.06") }, { kITPanningReset, MPT_V("1.24.01.06") }, { kITPatternLoopWithJumpsOld, MPT_V("1.25.00.19") }, }; for(const auto &b : behaviours) { m_playBehaviour.set(b.behaviour, (m_dwLastSavedWithVersion >= b.version || m_dwLastSavedWithVersion == b.version.Masked(0xFFFF0000u))); } } else if(compatModeXM && m_dwLastSavedWithVersion < MPT_V("1.26.00.00")) { // Pre-1.26: Detailed compatibility flags did not exist. static constexpr PlayBehaviourVersion behaviours[] = { { kTempoClamp, MPT_V("1.17.03.02") }, { kPerChannelGlobalVolSlide, MPT_V("1.17.03.02") }, { kPanOverride, MPT_V("1.17.03.02") }, { kITFT2PatternLoop, MPT_V("1.17.03.02") }, { kFT2Arpeggio, MPT_V("1.17.03.02") }, { kFT2Retrigger, MPT_V("1.17.03.02") }, { kFT2VolColVibrato, MPT_V("1.17.03.02") }, { kFT2PortaNoNote, MPT_V("1.17.03.02") }, { kFT2KeyOff, MPT_V("1.17.03.02") }, { kFT2PanSlide, MPT_V("1.17.03.02") }, { kFT2ST3OffsetOutOfRange, MPT_V("1.17.03.02") }, { kFT2RestrictXCommand, MPT_V("1.18.00.00") }, { kFT2RetrigWithNoteDelay, MPT_V("1.18.00.00") }, { kFT2SetPanEnvPos, MPT_V("1.18.00.00") }, { kFT2PortaIgnoreInstr, MPT_V("1.18.00.01") }, { kFT2VolColMemory, MPT_V("1.18.01.00") }, { kFT2LoopE60Restart, MPT_V("1.18.02.01") }, { kFT2ProcessSilentChannels, MPT_V("1.18.02.01") }, { kFT2ReloadSampleSettings, MPT_V("1.20.00.36") }, { kFT2PortaDelay, MPT_V("1.20.00.40") }, { kFT2Transpose, MPT_V("1.20.00.62") }, { kFT2PatternLoopWithJumps, MPT_V("1.20.00.69") }, { kFT2PortaTargetNoReset, MPT_V("1.20.00.69") }, { kFT2EnvelopeEscape, MPT_V("1.20.00.77") }, { kFT2Tremor, MPT_V("1.20.01.11") }, { kFT2OutOfRangeDelay, MPT_V("1.20.02.02") }, { kFT2Periods, MPT_V("1.22.03.01") }, { kFT2PanWithDelayedNoteOff, MPT_V("1.22.03.02") }, { kFT2VolColDelay, MPT_V("1.22.07.19") }, { kFT2FinetunePrecision, MPT_V("1.22.07.19") }, }; for(const auto &b : behaviours) { m_playBehaviour.set(b.behaviour, m_dwLastSavedWithVersion >= b.version); } } if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) { // The following behaviours were added in/after OpenMPT 1.26, so are not affected by the upgrade mechanism above. static constexpr PlayBehaviourVersion behaviours[] = { { kITInstrWithNoteOff, MPT_V("1.26.00.01") }, { kITMultiSampleInstrumentNumber, MPT_V("1.27.00.27") }, { kITInstrWithNoteOffOldEffects, MPT_V("1.28.02.06") }, { kITDoNotOverrideChannelPan, MPT_V("1.29.00.22") }, { kITPatternLoopWithJumps, MPT_V("1.29.00.32") }, { kITDCTBehaviour, MPT_V("1.29.00.57") }, { kITPitchPanSeparation, MPT_V("1.30.00.53") }, { kITResetFilterOnPortaSmpChange, MPT_V("1.30.08.02") }, { kITInitialNoteMemory, MPT_V("1.31.00.25") }, { kITNoSustainOnPortamento, MPT_V("1.32.00.13") }, { kITEmptyNoteMapSlotIgnoreCell, MPT_V("1.32.00.13") }, { kITOffsetWithInstrNumber, MPT_V("1.32.00.15") }, { kITDoublePortamentoSlides, MPT_V("1.32.00.27") }, { kITCarryAfterNoteOff, MPT_V("1.32.00.40") }, { kITNoteCutWithPorta, MPT_V("1.32.01.02") }, }; for(const auto &b : behaviours) { if(m_dwLastSavedWithVersion < b.version.Masked(0xFFFF0000u)) m_playBehaviour.reset(b.behaviour); // Full version information available, i.e. not compatibility-exported. else if(m_dwLastSavedWithVersion > b.version.Masked(0xFFFF0000u) && m_dwLastSavedWithVersion < b.version) m_playBehaviour.reset(b.behaviour); } } else if(GetType() == MOD_TYPE_XM) { // The following behaviours were added after OpenMPT 1.26, so are not affected by the upgrade mechanism above. static constexpr PlayBehaviourVersion behaviours[] = { { kFT2NoteOffFlags, MPT_V("1.27.00.27") }, { kRowDelayWithNoteDelay, MPT_V("1.27.00.37") }, { kFT2MODTremoloRampWaveform, MPT_V("1.27.00.37") }, { kFT2PortaUpDownMemory, MPT_V("1.27.00.37") }, { kFT2PanSustainRelease, MPT_V("1.28.00.09") }, { kFT2NoteDelayWithoutInstr, MPT_V("1.28.00.44") }, { kITFT2DontResetNoteOffOnPorta, MPT_V("1.29.00.34") }, { kFT2PortaResetDirection, MPT_V("1.30.00.40") }, { kFT2AutoVibratoAbortSweep, MPT_V("1.32.00.29") }, { kFT2OffsetMemoryRequiresNote, MPT_V("1.32.00.43") }, }; for(const auto &b : behaviours) { if(m_dwLastSavedWithVersion < b.version) m_playBehaviour.reset(b.behaviour); } } else if(GetType() == MOD_TYPE_S3M) { // We do not store any of these flags in S3M files. static constexpr PlayBehaviourVersion behaviours[] = { { kST3NoMutedChannels, MPT_V("1.18.00.00") }, { kST3EffectMemory, MPT_V("1.20.00.00") }, { kRowDelayWithNoteDelay, MPT_V("1.20.00.00") }, { kST3PortaSampleChange, MPT_V("1.22.00.00") }, { kST3VibratoMemory, MPT_V("1.26.00.00") }, { kITPanbrelloHold, MPT_V("1.26.00.00") }, { KST3PortaAfterArpeggio, MPT_V("1.27.00.00") }, { kST3OffsetWithoutInstrument, MPT_V("1.28.00.00") }, { kST3RetrigAfterNoteCut, MPT_V("1.29.00.00") }, { kFT2ST3OffsetOutOfRange, MPT_V("1.29.00.00") }, { kApplyUpperPeriodLimit, MPT_V("1.30.00.45") }, { kST3TonePortaWithAdlibNote, MPT_V("1.31.00.13") }, }; for(const auto &b : behaviours) { if(m_dwLastSavedWithVersion < b.version) m_playBehaviour.reset(b.behaviour); } } if(GetType() == MOD_TYPE_XM && m_dwLastSavedWithVersion < MPT_V("1.19.00.00")) { // This bug was introduced sometime between 1.18.03.00 and 1.19.01.00 m_playBehaviour.set(kFT2NoteDelayWithoutInstr); } if(m_dwLastSavedWithVersion >= MPT_V("1.27.00.27") && m_dwLastSavedWithVersion < MPT_V("1.27.00.49")) { // OpenMPT 1.27 inserted some IT/FT2 flags before the S3M flags that are never saved to files anyway, to keep the flag IDs a bit more compact. // However, it was overlooked that these flags would still be read by OpenMPT 1.26 and thus S3M-specific behaviour would be enabled in IT/XM files. // Hence, in OpenMPT 1.27.00.49 the flag IDs got remapped to no longer conflict with OpenMPT 1.26. // Files made with the affected pre-release versions of OpenMPT 1.27 are upgraded here to use the new IDs. for(int i = 0; i < 5; i++) { m_playBehaviour.set(kFT2NoteOffFlags + i, m_playBehaviour[kST3NoMutedChannels + i]); m_playBehaviour.reset(kST3NoMutedChannels + i); } } if(m_dwLastSavedWithVersion < MPT_V("1.17.00.00")) { // MPT 1.16 has a maximum tempo of 255. m_playBehaviour.set(kTempoClamp); } else if(m_dwLastSavedWithVersion >= MPT_V("1.17.00.00") && m_dwLastSavedWithVersion <= MPT_V("1.20.01.03") && m_dwLastSavedWithVersion != MPT_V("1.20.00.00")) { // OpenMPT introduced some "fixes" that execute regular portamentos also at speed 1. m_playBehaviour.set(kSlidesAtSpeed1); } if(m_SongFlags[SONG_LINEARSLIDES]) { if(m_dwLastSavedWithVersion < MPT_V("1.24.00.00")) { // No frequency slides in Hz before OpenMPT 1.24 m_playBehaviour.reset(kPeriodsAreHertz); } else if(m_dwLastSavedWithVersion >= MPT_V("1.24.00.00") && m_dwLastSavedWithVersion < MPT_V("1.26.00.00") && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) { // Frequency slides were always in Hz rather than periods in this version range. m_playBehaviour.set(kPeriodsAreHertz); } } else { if(m_dwLastSavedWithVersion < MPT_V("1.30.00.36") && m_dwLastSavedWithVersion != MPT_V("1.30.00.00")) { // No frequency slides in Hz before OpenMPT 1.30 m_playBehaviour.reset(kPeriodsAreHertz); } } if(m_playBehaviour[kITEnvelopePositionHandling] && m_dwLastSavedWithVersion >= MPT_V("1.23.01.02") && m_dwLastSavedWithVersion < MPT_V("1.28.00.43")) { // Bug that effectively clamped the release node to the sustain end for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { if(Instruments[i] != nullptr && Instruments[i]->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET && Instruments[i]->VolEnv.dwFlags[ENV_SUSTAIN] && Instruments[i]->VolEnv.nReleaseNode > Instruments[i]->VolEnv.nSustainEnd) { m_playBehaviour.set(kReleaseNodePastSustainBug); break; } } } if(GetType() & (MOD_TYPE_MPT | MOD_TYPE_S3M)) { for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++) { if(Samples[i].uFlags[CHN_ADLIB]) { if(GetType() == MOD_TYPE_MPT && GetNumInstruments() && m_dwLastSavedWithVersion >= MPT_V("1.28.00.20") && m_dwLastSavedWithVersion <= MPT_V("1.29.00.55")) m_playBehaviour.set(kOPLNoResetAtEnvelopeEnd); if(m_dwLastSavedWithVersion <= MPT_V("1.30.00.34") && m_dwLastSavedWithVersion != MPT_V("1.30")) m_playBehaviour.reset(kOPLNoteOffOnNoteChange); if(GetType() == MOD_TYPE_S3M && m_dwLastSavedWithVersion < MPT_V("1.29")) m_playBehaviour.set(kOPLRealRetrig); else if(GetType() != MOD_TYPE_S3M) m_playBehaviour.reset(kOPLRealRetrig); break; } } } #ifndef NO_PLUGINS if(m_dwLastSavedWithVersion >= MPT_V("1.27.00.42") && m_dwLastSavedWithVersion < MPT_V("1.30.00.46") && hasAnyPlugins) { // The Flanger DMO plugin is almost identical to the Chorus... but only almost. // The effect implementation was the same in OpenMPT 1.27-1.29, now it isn't anymore. // As the old implementation continues to exist for the Chorus plugin, there is a legacy wrapper for the Flanger plugin. for(auto &plugin : m_MixPlugins) { if(plugin.Info.dwPluginId1 == kDmoMagic && plugin.Info.dwPluginId2 == int32(0xEFCA3D92) && plugin.pluginData.size() == 32) plugin.Info.szLibraryName = "Flanger (Legacy)"; } } if(m_dwLastSavedWithVersion < MPT_V("1.30.00.54") && hasAnyPlugins) { // Currently active program and bank is assumed to be 1 when starting playback for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { if(Instruments[i] && (Instruments[i]->nMidiProgram == 1 || Instruments[i]->wMidiBank == 1)) { m_playBehaviour.set(kPluginDefaultProgramAndBank1); break; } } } if(m_dwLastSavedWithVersion < MPT_V("1.31.00.09") && hasAnyPlugins) { // Old-style plugin tone portamento m_playBehaviour.set(kPluginIgnoreTonePortamento); } if(m_dwLastSavedWithVersion >= MPT_V("1.27") && m_dwLastSavedWithVersion < MPT_V("1.30.06.00") && hasAnyPlugins) { // Fix off-by-one delay length in older Echo DMO emulation for(auto &plugin : m_MixPlugins) { if(plugin.Info.dwPluginId1 == kDmoMagic && plugin.Info.dwPluginId2 == int32(0xEF3E932C) && plugin.pluginData.size() == 24) { float32le leftDelay, rightDelay; memcpy(&leftDelay, plugin.pluginData.data() + 12, 4); memcpy(&rightDelay, plugin.pluginData.data() + 16, 4); leftDelay = float32le{mpt::safe_clamp(((leftDelay * 2000.0f) - 1.0f) / 1999.0f, 0.0f, 1.0f)}; rightDelay = float32le{mpt::safe_clamp(((rightDelay * 2000.0f) - 1.0f) / 1999.0f, 0.0f, 1.0f)}; memcpy(plugin.pluginData.data() + 12, &leftDelay, 4); memcpy(plugin.pluginData.data() + 16, &rightDelay, 4); } } } if(m_dwLastSavedWithVersion >= MPT_V("1.17") && m_dwLastSavedWithVersion < MPT_V("1.32.00.30") && hasAnyPlugins) { for(const auto &plugin : m_MixPlugins) { if(plugin.Info.dwPluginId1 == PLUGMAGIC('V', 's', 't', 'P')) { m_playBehaviour.set(kLegacyPPQpos); break; } } } if(m_dwLastSavedWithVersion < MPT_V("1.32.00.38") && hasAnyPlugins) { for(const auto &plugin : m_MixPlugins) { if(plugin.Info.dwPluginId1 == PLUGMAGIC('V', 's', 't', 'P')) { m_playBehaviour.set(kLegacyPluginNNABehaviour); break; } } } #endif } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_mid.cpp0000644000175000017500000011404014770032272020315 00000000000000/* * Load_mid.cpp * ------------ * Purpose: MIDI file loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "Dlsbank.h" #include "MIDIEvents.h" #include "mod_specifications.h" #ifdef MODPLUG_TRACKER #include "../mptrack/TrackerSettings.h" #include "../mptrack/Moddoc.h" #include "../mptrack/Mptrack.h" #include "mpt/io_file/inputfile.hpp" #include "mpt/io_file_read/inputfile_filecursor.hpp" #include "../common/mptFileIO.h" #include "mpt/fs/fs.hpp" #endif // MODPLUG_TRACKER OPENMPT_NAMESPACE_BEGIN #if defined(MODPLUG_TRACKER) || defined(MPT_FUZZ_TRACKER) #ifdef LIBOPENMPT_BUILD struct CDLSBank { static int32 DLSMidiVolumeToLinear(uint32) { return 256; } }; #endif // LIBOPENMPT_BUILD #define MIDI_DRUMCHANNEL 10 const char *szMidiGroupNames[17] = { "Piano", "Chromatic Percussion", "Organ", "Guitar", "Bass", "Strings", "Ensemble", "Brass", "Reed", "Pipe", "Synth Lead", "Synth Pad", "Synth Effects", "Ethnic", "Percussive", "Sound Effects", "Percussions" }; const char *szMidiProgramNames[128] = { // 1-8: Piano "Acoustic Grand Piano", "Bright Acoustic Piano", "Electric Grand Piano", "Honky-tonk Piano", "Electric Piano 1", "Electric Piano 2", "Harpsichord", "Clavi", // 9-16: Chromatic Percussion "Celesta", "Glockenspiel", "Music Box", "Vibraphone", "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", // 17-24: Organ "Drawbar Organ", "Percussive Organ", "Rock Organ", "Church Organ", "Reed Organ", "Accordion", "Harmonica", "Tango Accordion", // 25-32: Guitar "Acoustic Guitar (nylon)", "Acoustic Guitar (steel)", "Electric Guitar (jazz)", "Electric Guitar (clean)", "Electric Guitar (muted)", "Overdriven Guitar", "Distortion Guitar", "Guitar harmonics", // 33-40 Bass "Acoustic Bass", "Electric Bass (finger)", "Electric Bass (pick)", "Fretless Bass", "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2", // 41-48 Strings "Violin", "Viola", "Cello", "Contrabass", "Tremolo Strings", "Pizzicato Strings", "Orchestral Harp", "Timpani", // 49-56 Ensemble "String Ensemble 1", "String Ensemble 2", "SynthStrings 1", "SynthStrings 2", "Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit", // 57-64 Brass "Trumpet", "Trombone", "Tuba", "Muted Trumpet", "French Horn", "Brass Section", "SynthBrass 1", "SynthBrass 2", // 65-72 Reed "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax", "Oboe", "English Horn", "Bassoon", "Clarinet", // 73-80 Pipe "Piccolo", "Flute", "Recorder", "Pan Flute", "Blown Bottle", "Shakuhachi", "Whistle", "Ocarina", // 81-88 Synth Lead "Lead 1 (square)", "Lead 2 (sawtooth)", "Lead 3 (calliope)", "Lead 4 (chiff)", "Lead 5 (charang)", "Lead 6 (voice)", "Lead 7 (fifths)", "Lead 8 (bass + lead)", // 89-96 Synth Pad "Pad 1 (new age)", "Pad 2 (warm)", "Pad 3 (polysynth)", "Pad 4 (choir)", "Pad 5 (bowed)", "Pad 6 (metallic)", "Pad 7 (halo)", "Pad 8 (sweep)", // 97-104 Synth Effects "FX 1 (rain)", "FX 2 (soundtrack)", "FX 3 (crystal)", "FX 4 (atmosphere)", "FX 5 (brightness)", "FX 6 (goblins)", "FX 7 (echoes)", "FX 8 (sci-fi)", // 105-112 Ethnic "Sitar", "Banjo", "Shamisen", "Koto", "Kalimba", "Bag pipe", "Fiddle", "Shanai", // 113-120 Percussive "Tinkle Bell", "Agogo", "Steel Drums", "Woodblock", "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal", // 121-128 Sound Effects "Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet", "Telephone Ring", "Helicopter", "Applause", "Gunshot" }; // Notes 25-85 const char *szMidiPercussionNames[61] = { "Seq Click", "Brush Tap", "Brush Swirl", "Brush Slap", "Brush Swirl W/Attack", "Snare Roll", "Castanet", "Snare Lo", "Sticks", "Bass Drum Lo", "Open Rim Shot", "Acoustic Bass Drum", "Bass Drum 1", "Side Stick", "Acoustic Snare", "Hand Clap", "Electric Snare", "Low Floor Tom", "Closed Hi-Hat", "High Floor Tom", "Pedal Hi-Hat", "Low Tom", "Open Hi-Hat", "Low-Mid Tom", "Hi Mid Tom", "Crash Cymbal 1", "High Tom", "Ride Cymbal 1", "Chinese Cymbal", "Ride Bell", "Tambourine", "Splash Cymbal", "Cowbell", "Crash Cymbal 2", "Vibraslap", "Ride Cymbal 2", "Hi Bongo", "Low Bongo", "Mute Hi Conga", "Open Hi Conga", "Low Conga", "High Timbale", "Low Timbale", "High Agogo", "Low Agogo", "Cabasa", "Maracas", "Short Whistle", "Long Whistle", "Short Guiro", "Long Guiro", "Claves", "Hi Wood Block", "Low Wood Block", "Mute Cuica", "Open Cuica", "Mute Triangle", "Open Triangle", "Shaker", "Jingle Bell", "Bell Tree", }; static constexpr uint8 NUM_MIDI_CHANNELS = 32; //////////////////////////////////////////////////////////////////////////////// // Maps a midi instrument - returns the instrument number in the file uint32 CSoundFile::MapMidiInstrument(uint8 program, uint16 bank, uint8 midiChannel, uint8 note, bool isXG, std::bitset drumChns) { ModInstrument *pIns; program &= 0x7F; bank &= 0x3FFF; note &= 0x7F; // In XG mode, extra drums are on banks with MSB 7F const bool isDrum = drumChns[midiChannel - 1] || (bank >= 0x3F80 && isXG); for (uint32 i = 1; i <= m_nInstruments; i++) if (Instruments[i]) { ModInstrument *p = Instruments[i]; // Drum Kit? if (isDrum) { if (note == p->nMidiDrumKey && bank + 1 == p->wMidiBank) return i; } else // Melodic Instrument { if (program + 1 == p->nMidiProgram && bank + 1 == p->wMidiBank && p->nMidiDrumKey == 0) return i; } } if(!CanAddMoreInstruments() || !CanAddMoreSamples()) return 0; pIns = AllocateInstrument(m_nInstruments + 1); if(pIns == nullptr) { return 0; } m_nSamples++; pIns->wMidiBank = bank + 1; pIns->nMidiProgram = program + 1; pIns->nFadeOut = 1024; pIns->nNNA = NewNoteAction::NoteOff; pIns->nDCT = isDrum ? DuplicateCheckType::Sample : DuplicateCheckType::Note; pIns->nDNA = DuplicateNoteAction::NoteFade; if(isDrum) { pIns->nMidiChannel = MIDI_DRUMCHANNEL; pIns->nMidiDrumKey = note; for(auto &key : pIns->NoteMap) { key = NOTE_MIDDLEC; } } pIns->VolEnv.dwFlags.set(ENV_ENABLED); if (!isDrum) pIns->VolEnv.dwFlags.set(ENV_SUSTAIN); pIns->VolEnv.reserve(4); pIns->VolEnv.push_back(EnvelopeNode(0, ENVELOPE_MAX)); pIns->VolEnv.push_back(EnvelopeNode(10, ENVELOPE_MAX)); pIns->VolEnv.push_back(EnvelopeNode(15, (ENVELOPE_MAX + ENVELOPE_MID) / 2)); pIns->VolEnv.push_back(EnvelopeNode(20, ENVELOPE_MIN)); pIns->VolEnv.nSustainStart = pIns->VolEnv.nSustainEnd = 1; // Set GM program / drum name if (!isDrum) { pIns->name = szMidiProgramNames[program]; } else { if (note >= 24 && note <= 84) pIns->name = szMidiPercussionNames[note - 24]; else pIns->name = "Percussions"; } return m_nInstruments; } struct MThd { uint32be headerLength; uint16be format; // 0 = single-track, 1 = multi-track, 2 = multi-song uint16be numTracks; // Number of track chunks uint16be division; // Delta timing value: positive = units/beat; negative = smpte compatible units }; MPT_BINARY_STRUCT(MThd, 10) using tick_t = uint32; struct TrackState { FileReader track; tick_t nextEvent = 0; uint8 command = 0; uint8 midiBaseChannel = 0; bool finished = false; }; struct ModChannelState { static constexpr uint8 NOMIDI = 0xFF; // No MIDI channel assigned. tick_t age = 0; // At which MIDI tick the channel was triggered int32 porta = 0; // Current portamento position in extra-fine slide units (1/64th of a semitone) uint8 vol = 100; // MIDI note volume (0...127) uint8 pan = 128; // MIDI channel panning (0...256) uint8 midiCh = NOMIDI; // MIDI channel that was last played on this channel ModCommand::NOTE note = NOTE_NONE; // MIDI note that was last played on this channel bool sustained = false; // If true, the note was already released by a note-off event, but sustain pedal CC is still active }; struct MidiChannelState { int32 pitchbendMod = 0; // Pre-computed pitchbend in extra-fine slide units (1/64th of a semitone) int16 pitchbend = MIDIEvents::pitchBendCentre; // 0...16383 uint16 bank = 0; // 0...16383 uint8 program = 0; // 0...127 // -- Controllers ---------------- function ---------- CC# --- range ---- init (midi) --- uint8 pan = 128; // Channel Panning 10 [0-255] 128 (64) uint8 expression = 128; // Channel Expression 11 0-128 128 (127) uint8 volume = 80; // Channel Volume 7 0-128 80 (100) uint16 rpn = 0x3FFF; // Currently selected RPN 100/101 n/a uint8 pitchBendRange = 2; // Pitch Bend Range 2 int8 transpose = 0; // Channel transpose 0 bool monoMode = false; // Mono/Poly operation 126/127 n/a Poly bool sustain = false; // Sustain pedal 64 on/off off std::array noteOn; // Value != CHANNELINDEX_INVALID: Note is active and mapped to mod channel in value MidiChannelState() { noteOn.fill(CHANNELINDEX_INVALID); } void SetPitchbend(uint16 value) { pitchbend = value; // Convert from arbitrary MIDI pitchbend to 64th of semitone pitchbendMod = Util::muldiv(pitchbend - MIDIEvents::pitchBendCentre, pitchBendRange * 64, MIDIEvents::pitchBendCentre); } void ResetAllControllers() { expression = 128; pitchBendRange = 2; SetPitchbend(MIDIEvents::pitchBendCentre); transpose = 0; rpn = 0x3FFF; monoMode = false; sustain = false; // Should also reset modulation, pedals (40h-43h), aftertouch } void SetRPN(uint8 value) { switch(rpn) { case 0: // Pitch Bend Range pitchBendRange = std::max(value, uint8(1)); SetPitchbend(pitchbend); break; case 2: // Coarse Tune transpose = static_cast(value) - 64; break; } } void SetRPNRelative(int8 value) { switch(rpn) { case 0: // Pitch Bend Range pitchBendRange = static_cast(std::clamp(pitchBendRange + value, 1, 0x7F)); break; case 2: // Coarse Tune transpose = mpt::saturate_cast(transpose + value); break; } } }; static CHANNELINDEX FindUnusedChannel(uint8 midiCh, ModCommand::NOTE note, const std::vector &channels, bool monoMode, mpt::span patRow) { for(size_t i = 0; i < channels.size(); i++) { // Check if this note is already playing, or find any note of the same MIDI channel in case of mono mode if(channels[i].midiCh == midiCh && (channels[i].note == note || (monoMode && channels[i].note != NOTE_NONE))) { return static_cast(i); } } CHANNELINDEX anyUnusedChannel = CHANNELINDEX_INVALID; CHANNELINDEX anyFreeChannel = CHANNELINDEX_INVALID; CHANNELINDEX oldsetMidiCh = CHANNELINDEX_INVALID; tick_t oldestMidiChAge = std::numeric_limits::max(); CHANNELINDEX oldestAnyCh = 0; tick_t oldestAnyChAge = std::numeric_limits::max(); for(size_t i = 0; i < channels.size(); i++) { if(channels[i].note == NOTE_NONE && !patRow[i].IsNote()) { // Recycle channel previously used by the same MIDI channel if(channels[i].midiCh == midiCh) return static_cast(i); // If we cannot find a channel that was already used for the same MIDI channel, try a completely unused channel next else if(channels[i].midiCh == ModChannelState::NOMIDI && anyUnusedChannel == CHANNELINDEX_INVALID) anyUnusedChannel = static_cast(i); // And if that fails, try any channel that currently doesn't play a note. if(anyFreeChannel == CHANNELINDEX_INVALID) anyFreeChannel = static_cast(i); } // If we can't find any free channels, look for the oldest channels if(channels[i].midiCh == midiCh && channels[i].age < oldestMidiChAge) { // Oldest channel matching this MIDI channel oldestMidiChAge = channels[i].age; oldsetMidiCh = static_cast(i); } else if(channels[i].age < oldestAnyChAge) { // Any oldest channel oldestAnyChAge = channels[i].age; oldestAnyCh = static_cast(i); } } if(anyUnusedChannel != CHANNELINDEX_INVALID) return anyUnusedChannel; if(anyFreeChannel != CHANNELINDEX_INVALID) return anyFreeChannel; if(oldsetMidiCh != CHANNELINDEX_INVALID) return oldsetMidiCh; return oldestAnyCh; } static void MIDINoteOff(MidiChannelState &midiChn, std::vector &modChnStatus, uint8 note, uint8 delay, mpt::span patRow, std::bitset drumChns) { CHANNELINDEX chn = midiChn.noteOn[note]; if(chn == CHANNELINDEX_INVALID) return; if(midiChn.sustain) { // Turn this off later modChnStatus[chn].sustained = true; return; } uint8 midiCh = modChnStatus[chn].midiCh; modChnStatus[chn].note = NOTE_NONE; modChnStatus[chn].sustained = false; midiChn.noteOn[note] = CHANNELINDEX_INVALID; ModCommand &m = patRow[chn]; if(m.note == NOTE_NONE) { m.note = NOTE_KEYOFF; if(delay != 0) { m.command = CMD_S3MCMDEX; m.param = 0xD0 | delay; } } else if(m.IsNote() && !drumChns[midiCh]) { // Only do note cuts for melodic instruments - they sound weird on drums which should fade out naturally. if(m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0xD0) { // Already have a note delay m.command = CMD_DELAYCUT; m.param = (m.param << 4) | (delay - (m.param & 0x0F)); } else if(m.command == CMD_NONE || m.command == CMD_PANNING8) { m.command = CMD_S3MCMDEX; m.param = 0xC0 | delay; } } } static void EnterMIDIVolume(ModCommand &m, ModChannelState &modChn, const MidiChannelState &midiChn) { m.volcmd = VOLCMD_VOLUME; int32 vol = CDLSBank::DLSMidiVolumeToLinear(modChn.vol) >> 8; vol = (vol * midiChn.volume * midiChn.expression) >> 13; Limit(vol, 4, 256); m.vol = static_cast(vol / 4); } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMID(MemoryFileReader file, const uint64 *pfilesize) { MPT_UNREFERENCED_PARAMETER(pfilesize); char magic[4]; file.ReadArray(magic); if(!memcmp(magic, "MThd", 4)) return ProbeSuccess; if(!memcmp(magic, "RIFF", 4) && file.Skip(4) && file.ReadMagic("RMID")) return ProbeSuccess; return ProbeFailure; } bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); // Microsoft MIDI files bool isRIFF = false; if(file.ReadMagic("RIFF")) { file.Skip(4); if(!file.ReadMagic("RMID")) { return false; } else if(loadFlags == onlyVerifyHeader) { return true; } do { char id[4]; file.ReadArray(id); uint32 length = file.ReadUint32LE(); if(memcmp(id, "data", 4)) { file.Skip(length); } else { isRIFF = true; break; } } while(file.CanRead(8)); } MThd fileHeader; if(!file.ReadMagic("MThd") || !file.ReadStruct(fileHeader) || fileHeader.numTracks == 0 || fileHeader.headerLength < 6 || !file.Skip(fileHeader.headerLength - 6)) { return false; } else if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_MID, GetModSpecifications(MOD_TYPE_MPT).channelsMax); #ifdef MODPLUG_TRACKER const uint32 quantize = Clamp(TrackerSettings::Instance().midiImportQuantize.Get(), 4u, 256u); const ROWINDEX patternLen = Clamp(TrackerSettings::Instance().midiImportPatternLen.Get(), GetModSpecifications().patternRowsMin, GetModSpecifications().patternRowsMax); const uint8 ticksPerRow = Clamp(TrackerSettings::Instance().midiImportTicks.Get(), uint8(2), uint8(16)); #else const uint32 quantize = 32; // Must be 4 or higher const ROWINDEX patternLen = 128; const uint8 ticksPerRow = 16; // Must be in range 2...16 #endif #ifdef MPT_FUZZ_TRACKER // Avoid generating test cases that take overly long to evaluate const ORDERINDEX MPT_MIDI_IMPORT_MAX_ORDERS = 64; #else const ORDERINDEX MPT_MIDI_IMPORT_MAX_ORDERS = MAX_ORDERS; #endif m_songArtist = UL_("MIDI Conversion"); m_modFormat.formatName = UL_("Standard MIDI File"); m_modFormat.type = isRIFF ? UL_("rmi") : UL_("mid"); m_modFormat.madeWithTracker = UL_("Standard MIDI File"); m_modFormat.charset = mpt::Charset::ISO8859_1; SetMixLevels(MixLevels::v1_17RC3); m_nTempoMode = TempoMode::Modern; m_SongFlags = SONG_LINEARSLIDES; TEMPO tempo{120, 0}; Order().SetDefaultTempo(tempo); Order().SetDefaultSpeed(ticksPerRow); m_nDefaultRowsPerBeat = quantize / 4; m_nDefaultRowsPerMeasure = 4 * m_nDefaultRowsPerBeat; m_nSamplePreAmp = m_nVSTiVolume = 32; uint16 ppqn = fileHeader.division; if(ppqn & 0x8000) { // SMPTE compatible units (approximation) int frames = 256 - (ppqn >> 8), subFrames = (ppqn & 0xFF); ppqn = static_cast(frames * subFrames / 2); } if(!ppqn) ppqn = 96; Order().clear(); std::array midiChnStatus; const CHANNELINDEX tempoChannel = GetNumChannels() - 2, globalVolChannel = GetNumChannels() - 1; const uint16 numTracks = fileHeader.numTracks; std::vector tracks(numTracks); std::vector modChnStatus(GetNumChannels()); std::bitset drumChns; drumChns.set(MIDI_DRUMCHANNEL - 1); drumChns.set(MIDI_DRUMCHANNEL + 15); tick_t timeShift = 0; for(auto &track : tracks) { if(!file.ReadMagic("MTrk")) return false; track.track = file.ReadChunk(file.ReadUint32BE()); tick_t delta = 0; track.track.ReadVarInt(delta); // Work-around for some MID files that assume that negative deltas exist (they don't according to the standard) if(delta > int32_max) timeShift = std::max(static_cast(~delta + 1), timeShift); track.nextEvent = delta; } if(timeShift != 0) { for(auto &track : tracks) { if(track.nextEvent > int32_max) track.nextEvent = timeShift - static_cast(~track.nextEvent + 1); else track.nextEvent += timeShift; } } uint16 finishedTracks = 0; PATTERNINDEX emptyPattern = PATTERNINDEX_INVALID; ORDERINDEX lastOrd = 0, loopEndOrd = ORDERINDEX_INVALID; ROWINDEX lastRow = 0, loopEndRow = ROWINDEX_INVALID; ROWINDEX restartRow = ROWINDEX_INVALID; int8 masterTranspose = 0; bool isXG = false; bool isEMIDI = false; bool isEMIDILoop = false; const bool isType2 = (fileHeader.format == 2); const auto ModPositionFromTick = [&](const tick_t tick, const tick_t offset = 0) { tick_t modTicks = Util::muldivr_unsigned(tick, quantize * ticksPerRow, ppqn * 4u) - offset; ORDERINDEX ord = static_cast((modTicks / ticksPerRow) / patternLen); ROWINDEX row = (modTicks / ticksPerRow) % patternLen; uint8 delay = static_cast(modTicks % ticksPerRow); return std::make_tuple(ord, row, delay); }; while(finishedTracks < numTracks) { uint16 t = 0; tick_t tick = std::numeric_limits::max(); for(uint16 track = 0; track < numTracks; track++) { if(!tracks[track].finished && tracks[track].nextEvent < tick) { tick = tracks[track].nextEvent; t = track; if(isType2) break; } } FileReader &track = tracks[t].track; const auto [ord, row, delay] = ModPositionFromTick(tick); if(ord >= Order().GetLength()) { if(ord > MPT_MIDI_IMPORT_MAX_ORDERS) break; ORDERINDEX curSize = Order().GetLength(); // If we need to extend the order list by more than one pattern, this means that we // will be filling in empty patterns. Just recycle one empty pattern for this job. // We read events in chronological order, so it is never possible for the loader to // "jump back" to one of those empty patterns and write into it. if(ord > curSize && emptyPattern == PATTERNINDEX_INVALID) { if((emptyPattern = Patterns.InsertAny(patternLen)) == PATTERNINDEX_INVALID) break; } Order().resize(ord + 1, emptyPattern); if((Order()[ord] = Patterns.InsertAny(patternLen)) == PATTERNINDEX_INVALID) break; } // Keep track of position of last event for resizing the last pattern if(ord > lastOrd) { lastOrd = ord; lastRow = row; } else if(ord == lastOrd) { lastRow = std::max(lastRow, row); } PATTERNINDEX pat = Order()[ord]; auto patRow = Patterns[pat].GetRow(row); uint8 data1 = track.ReadUint8(); if(data1 == 0xFF) { // Meta events data1 = track.ReadUint8(); size_t len = 0; track.ReadVarInt(len); FileReader chunk = track.ReadChunk(len); switch(data1) { case 1: // Text case 2: // Copyright m_songMessage.Read(chunk, len, SongMessage::leAutodetect); break; case 3: // Track Name if(len > 0) { std::string s; chunk.ReadString(s, len); if(!m_songMessage.empty()) m_songMessage.append(1, SongMessage::InternalLineEnding); m_songMessage += s; if(m_songName.empty()) m_songName = s; } break; case 4: // Instrument case 5: // Lyric break; case 6: // Marker case 7: // Cue point { std::string s; chunk.ReadString(s, len); Patterns[pat].SetName(s); if(!mpt::CompareNoCaseAscii(s, "loopStart")) { Order().SetRestartPos(ord); restartRow = row; } else if(!mpt::CompareNoCaseAscii(s, "loopEnd")) { std::tie(loopEndOrd, loopEndRow, std::ignore) = ModPositionFromTick(tick, 1); } } break; case 8: // Patch name case 9: // Port name break; case 0x21: // MIDI port tracks[t].midiBaseChannel = chunk.ReadUint8() * 16u; break; case 0x2F: // End Of Track tracks[t].finished = true; break; case 0x51: // Tempo { uint32 tempoInt = chunk.ReadUint24BE(); if(tempoInt == 0) break; TEMPO newTempo(60000000.0 / tempoInt); if(!tick) { Order().SetDefaultTempo(newTempo); } else if(newTempo != tempo) { patRow[tempoChannel].command = CMD_TEMPO; patRow[tempoChannel].param = mpt::saturate_round(std::max(32.0, newTempo.ToDouble())); } tempo = newTempo; } break; case 0x7F: // Sequencer specific { // Yamaha MIDI port selection uint32 data = chunk.ReadUint32BE(); if(chunk.LengthIs(4) && (data & 0xFFFFFF00) == 0x43000100) tracks[t].midiBaseChannel = static_cast((data & 0xFF) * 16u); } break; default: break; } } else { uint8 command = tracks[t].command; if(data1 & 0x80) { // Command byte (if not present, use running status for channel messages) command = data1; if(data1 < 0xF0) { tracks[t].command = data1; data1 = track.ReadUint8(); } } const uint8 midiCh = ((command & 0x0F) + tracks[t].midiBaseChannel) % NUM_MIDI_CHANNELS; switch(command & 0xF0) { case 0x80: // Note Off case 0x90: // Note On { data1 &= 0x7F; ModCommand::NOTE note = static_cast(Clamp(data1 + NOTE_MIN, NOTE_MIN, NOTE_MAX)); uint8 data2 = track.ReadUint8(); if(data2 > 0 && (command & 0xF0) == 0x90) { // Note On CHANNELINDEX chn = FindUnusedChannel(midiCh, note, modChnStatus, midiChnStatus[midiCh].monoMode, patRow); if(chn != CHANNELINDEX_INVALID) { modChnStatus[chn].age = tick; modChnStatus[chn].note = note; modChnStatus[chn].midiCh = midiCh; modChnStatus[chn].vol = data2; modChnStatus[chn].sustained = false; midiChnStatus[midiCh].noteOn[data1] = chn; int32 pitchOffset = 0; if(midiChnStatus[midiCh].pitchbendMod != 0) { pitchOffset = (midiChnStatus[midiCh].pitchbendMod + (midiChnStatus[midiCh].pitchbendMod > 0 ? 32 : -32)) / 64; modChnStatus[chn].porta = pitchOffset * 64; } else { modChnStatus[chn].porta = 0; } patRow[chn].note = static_cast(Clamp(note + pitchOffset + midiChnStatus[midiCh].transpose + masterTranspose, NOTE_MIN, NOTE_MAX)); patRow[chn].instr = mpt::saturate_cast(MapMidiInstrument(midiChnStatus[midiCh].program, midiChnStatus[midiCh].bank, midiCh + 1, data1, isXG, drumChns)); EnterMIDIVolume(patRow[chn], modChnStatus[chn], midiChnStatus[midiCh]); if(patRow[chn].command == CMD_PORTAMENTODOWN || patRow[chn].command == CMD_PORTAMENTOUP) { patRow[chn].command = CMD_NONE; } if(delay != 0) { patRow[chn].command = CMD_S3MCMDEX; patRow[chn].param = 0xD0 | delay; } if(modChnStatus[chn].pan != midiChnStatus[midiCh].pan && patRow[chn].command == CMD_NONE) { patRow[chn].command = CMD_PANNING8; patRow[chn].param = midiChnStatus[midiCh].pan; modChnStatus[chn].pan = midiChnStatus[midiCh].pan; } } } else { // Note Off MIDINoteOff(midiChnStatus[midiCh], modChnStatus, data1, delay, patRow, drumChns); } } break; case 0xA0: // Note Aftertouch { track.Skip(1); } break; case 0xB0: // Controller { uint8 data2 = track.ReadUint8(); switch(data1) { case MIDIEvents::MIDICC_Panposition_Coarse: midiChnStatus[midiCh].pan = data2 * 2u; for(auto chn : midiChnStatus[midiCh].noteOn) { if(chn != CHANNELINDEX_INVALID && modChnStatus[chn].pan != midiChnStatus[midiCh].pan) { if(Patterns[pat].WriteEffect(EffectWriter(CMD_PANNING8, midiChnStatus[midiCh].pan).Channel(chn).Row(row))) { modChnStatus[chn].pan = midiChnStatus[midiCh].pan; } } } break; case MIDIEvents::MIDICC_DataEntry_Coarse: midiChnStatus[midiCh].SetRPN(data2); break; case MIDIEvents::MIDICC_Volume_Coarse: midiChnStatus[midiCh].volume = (uint8)(CDLSBank::DLSMidiVolumeToLinear(data2) >> 9); for(auto chn : midiChnStatus[midiCh].noteOn) { if(chn != CHANNELINDEX_INVALID) { EnterMIDIVolume(patRow[chn], modChnStatus[chn], midiChnStatus[midiCh]); } } break; case MIDIEvents::MIDICC_Expression_Coarse: midiChnStatus[midiCh].expression = (uint8)(CDLSBank::DLSMidiVolumeToLinear(data2) >> 9); for(auto chn : midiChnStatus[midiCh].noteOn) { if(chn != CHANNELINDEX_INVALID) { EnterMIDIVolume(patRow[chn], modChnStatus[chn], midiChnStatus[midiCh]); } } break; case MIDIEvents::MIDICC_BankSelect_Coarse: midiChnStatus[midiCh].bank &= 0x7F; midiChnStatus[midiCh].bank |= (data2 << 7); break; case MIDIEvents::MIDICC_BankSelect_Fine: midiChnStatus[midiCh].bank &= (0x7F << 7); midiChnStatus[midiCh].bank |= data2; break; case MIDIEvents::MIDICC_HoldPedal_OnOff: midiChnStatus[midiCh].sustain = (data2 >= 0x40); if(data2 < 0x40) { // Release notes that are still being held after note-off for(const auto &chnState : modChnStatus) { if(chnState.midiCh == midiCh && chnState.sustained && chnState.note != NOTE_NONE) { MIDINoteOff(midiChnStatus[midiCh], modChnStatus, chnState.note - NOTE_MIN, delay, patRow, drumChns); } } } break; case MIDIEvents::MIDICC_DataButtonincrement: case MIDIEvents::MIDICC_DataButtondecrement: midiChnStatus[midiCh].SetRPNRelative((data1 == MIDIEvents::MIDICC_DataButtonincrement) ? 1 : -1); break; case MIDIEvents::MIDICC_NonRegisteredParameter_Fine: case MIDIEvents::MIDICC_NonRegisteredParameter_Coarse: midiChnStatus[midiCh].rpn = 0x3FFF; break; case MIDIEvents::MIDICC_RegisteredParameter_Fine: midiChnStatus[midiCh].rpn &= (0x7F << 7); midiChnStatus[midiCh].rpn |= data2; break; case MIDIEvents::MIDICC_RegisteredParameter_Coarse: midiChnStatus[midiCh].rpn &= 0x7F; midiChnStatus[midiCh].rpn |= (data2 << 7); break; case 110: isEMIDI = true; break; case 111: // Non-standard MIDI loop point. May conflict with Apogee EMIDI CCs (110/111), which is why we also check if CC 110 is ever used. if(data2 == 0 && !isEMIDI) { Order().SetRestartPos(ord); restartRow = row; } break; case 118: // EMIDI Global Loop Start isEMIDI = true; isEMIDILoop = false; Order().SetRestartPos(ord); restartRow = row; break; case 119: // EMIDI Global Loop End if(data2 == 0x7F) { isEMIDILoop = true; isEMIDI = true; std::tie(loopEndOrd, loopEndRow, std::ignore) = ModPositionFromTick(tick, 1); } break; case MIDIEvents::MIDICC_AllControllersOff: midiChnStatus[midiCh].ResetAllControllers(); break; // Bn.78.00: All Sound Off (GS) // Bn.7B.00: All Notes Off (GM) case MIDIEvents::MIDICC_AllSoundOff: case MIDIEvents::MIDICC_AllNotesOff: // All Notes Off midiChnStatus[midiCh].sustain = false; for(uint8 note = 0; note < 128; note++) { MIDINoteOff(midiChnStatus[midiCh], modChnStatus, note, delay, patRow, drumChns); } break; case MIDIEvents::MIDICC_MonoOperation: if(data2 == 0) { midiChnStatus[midiCh].monoMode = true; } break; case MIDIEvents::MIDICC_PolyOperation: if(data2 == 0) { midiChnStatus[midiCh].monoMode = false; } break; } } break; case 0xC0: // Program Change midiChnStatus[midiCh].program = data1 & 0x7F; break; case 0xD0: // Channel aftertouch break; case 0xE0: // Pitch bend midiChnStatus[midiCh].SetPitchbend(data1 | (track.ReadUint8() << 7)); break; case 0xF0: // General / Immediate switch(command & 0x0F) { case MIDIEvents::sysExStart: // SysEx case MIDIEvents::sysExEnd: // SysEx (continued) { uint32 len; track.ReadVarInt(len); FileReader sysex = track.ReadChunk(len); if(midiCh == MIDIEvents::sysExEnd) break; if(sysex.ReadMagic("\x7F\x7F\x04\x01")) { // Master volume uint8 volumeRaw[2]; sysex.ReadArray(volumeRaw); uint16 globalVol = volumeRaw[0] | (volumeRaw[1] << 7); if(tick == 0) { m_nDefaultGlobalVolume = Util::muldivr_unsigned(globalVol, MAX_GLOBAL_VOLUME, 16383); } else { patRow[globalVolChannel].command = CMD_GLOBALVOLUME; patRow[globalVolChannel].param = static_cast(Util::muldivr_unsigned(globalVol, 128, 16383)); } } else { uint8 xg[7]; sysex.ReadArray(xg); if(!memcmp(xg, "\x43\x10\x4C\x00\x00\x7E\x00", 7)) { // XG System On isXG = true; } else if(!memcmp(xg, "\x43\x10\x4C\x00\x00\x06", 6)) { // XG Master Transpose masterTranspose = static_cast(xg[6]) - 64; } else if(!memcmp(xg, "\x41\x10\x42\x12\x40", 5) && (xg[5] & 0xF0) == 0x10 && xg[6] == 0x15) { // GS Drum Kit uint8 chn = xg[5] & 0x0F; if(chn == 0) chn = 9; else if(chn < 10) chn--; drumChns.set(chn, sysex.ReadUint8() != 0); } } } break; case MIDIEvents::sysQuarterFrame: track.Skip(1); break; case MIDIEvents::sysPositionPointer: track.Skip(2); break; case MIDIEvents::sysSongSelect: track.Skip(1); break; case MIDIEvents::sysTuneRequest: case MIDIEvents::sysMIDIClock: case MIDIEvents::sysMIDITick: case MIDIEvents::sysStart: case MIDIEvents::sysContinue: case MIDIEvents::sysStop: case MIDIEvents::sysActiveSense: case MIDIEvents::sysReset: break; default: break; } break; default: break; } } // Pitch bend any channels that haven't reached their target yet // TODO: This is currently not called on any rows without events! for(size_t chn = 0; chn < modChnStatus.size(); chn++) { ModChannelState &chnState = modChnStatus[chn]; ModCommand &m = patRow[chn]; uint8 midiCh = chnState.midiCh; if(chnState.note == NOTE_NONE || m.command == CMD_S3MCMDEX || m.command == CMD_DELAYCUT || midiCh == ModChannelState::NOMIDI) continue; int32 diff = midiChnStatus[midiCh].pitchbendMod - chnState.porta; if(diff == 0) continue; if(m.command == CMD_PORTAMENTODOWN || m.command == CMD_PORTAMENTOUP) { // First, undo the effect of an existing portamento command int32 porta = 0; if(m.param < 0xE0) porta = m.param * 4 * (ticksPerRow - 1); else if(m.param < 0xF0) porta = (m.param & 0x0F); else porta = (m.param & 0x0F) * 4; if(m.command == CMD_PORTAMENTODOWN) porta = -porta; diff += porta; chnState.porta -= porta; if(diff == 0) { m.command = CMD_NONE; continue; } } m.command = (diff < 0) ? CMD_PORTAMENTODOWN : CMD_PORTAMENTOUP; int32 absDiff = std::abs(diff); int32 realDiff = 0; if(absDiff < 16) { // Extra-fine slides can do this. m.param = 0xE0 | static_cast(absDiff); realDiff = absDiff; } else if(absDiff < 64) { // Fine slides can do this. absDiff = std::min((absDiff + 3) / 4, 0x0F); m.param = 0xF0 | static_cast(absDiff); realDiff = absDiff * 4; } else { // Need a normal slide. absDiff /= 4 * (ticksPerRow - 1); LimitMax(absDiff, 0xDF); m.param = static_cast(absDiff); realDiff = absDiff * 4 * (ticksPerRow - 1); } chnState.porta += realDiff * mpt::signum(diff); } tick_t delta = 0; if(track.ReadVarInt(delta) && track.CanRead(1)) { tracks[t].nextEvent += delta; } else { finishedTracks++; tracks[t].nextEvent = Util::MaxValueOfType(delta); tracks[t].finished = true; // Add another sub-song for type-2 files if(isType2 && finishedTracks < numTracks) { if(Order.AddSequence() == SEQUENCEINDEX_INVALID) break; Order().clear(); } } } if(isEMIDILoop) isEMIDI = false; if(isEMIDI) { Order().SetRestartPos(0); } if(loopEndOrd == ORDERINDEX_INVALID) loopEndOrd = lastOrd; if(loopEndRow == ROWINDEX_INVALID) loopEndRow = lastRow; if(Order().IsValidPat(loopEndOrd)) { PATTERNINDEX lastPat = Order()[loopEndOrd]; if(loopEndOrd == lastOrd) Patterns[lastPat].Resize(loopEndRow + 1); if(restartRow != ROWINDEX_INVALID && !isEMIDI) { Patterns[lastPat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, mpt::saturate_cast(restartRow)).Row(loopEndRow)); if(ORDERINDEX restartPos = Order().GetRestartPos(); loopEndOrd != lastOrd || restartPos <= std::numeric_limits::max()) Patterns[lastPat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, mpt::saturate_cast(restartPos)).Row(loopEndRow)); } } Order.SetSequence(0); std::vector channels; channels.reserve(GetNumChannels()); for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { if(modChnStatus[i].midiCh != ModChannelState::NOMIDI #ifdef MODPLUG_TRACKER || (GetpModDoc() != nullptr && !GetpModDoc()->IsChannelUnused(i)) #endif // MODPLUG_TRACKER ) { channels.push_back(i); if(modChnStatus[i].midiCh != ModChannelState::NOMIDI) ChnSettings[i].szName = MPT_AFORMAT("MIDI Ch {}")(1 + modChnStatus[i].midiCh); else if(i == tempoChannel) ChnSettings[i].szName = "Tempo"; else if(i == globalVolChannel) ChnSettings[i].szName = "Global Volume"; } } if(channels.empty()) return false; #ifdef MODPLUG_TRACKER if(GetpModDoc() != nullptr) { // Keep MIDI channels in patterns neatly grouped std::sort(channels.begin(), channels.end(), [&modChnStatus] (CHANNELINDEX c1, CHANNELINDEX c2) { if(modChnStatus[c1].midiCh == modChnStatus[c2].midiCh) return c1 < c2; return modChnStatus[c1].midiCh < modChnStatus[c2].midiCh; }); GetpModDoc()->ReArrangeChannels(channels, false); GetpModDoc()->m_ShowSavedialog = true; } std::unique_ptr cachedBank, embeddedBank; FileReader *bankFile = nullptr; if(CDLSBank::IsDLSBank(file)) { // Soundfont embedded in MIDI file embeddedBank = std::make_unique(); embeddedBank->Open(file); bankFile = &file; } else { // Soundfont with same name as MIDI file for(const auto &ext : { P_(".sf2"), P_(".sf3"), P_(".sf4"), P_(".sbk"), P_(".dls") }) { mpt::PathString filename = file.GetOptionalFileName().value_or(P_("")).ReplaceExtension(ext); if(mpt::native_fs{}.is_file(filename)) { embeddedBank = std::make_unique(); if(embeddedBank->Open(filename)) break; } } } ChangeModTypeTo(MOD_TYPE_MPT); const MidiLibrary &midiLib = CTrackApp::GetMidiLibrary(); mpt::PathString cachedBankName; // Load Instruments for (INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++) if (Instruments[ins]) { ModInstrument *pIns = Instruments[ins]; uint32 midiCode = 0; if(pIns->nMidiChannel == MIDI_DRUMCHANNEL) midiCode = 0x80 | (pIns->nMidiDrumKey & 0x7F); else if(pIns->nMidiProgram) midiCode = (pIns->nMidiProgram - 1) & 0x7F; if(embeddedBank && embeddedBank->FindAndExtract(*this, ins, midiCode >= 0x80, bankFile)) { continue; } const mpt::PathString &midiMapName = midiLib[midiCode].value_or(P_("")); if(!midiMapName.empty()) { // Load from DLS/SF2 Bank if(CDLSBank::IsDLSBank(midiMapName)) { CDLSBank *dlsBank = nullptr; if(cachedBank != nullptr && !mpt::PathCompareNoCase(cachedBankName, midiMapName)) { dlsBank = cachedBank.get(); } else { cachedBank = std::make_unique(); cachedBankName = midiMapName; if(cachedBank->Open(midiMapName)) dlsBank = cachedBank.get(); } if(dlsBank) { dlsBank->FindAndExtract(*this, ins, midiCode >= 0x80); } } else { // Load from Instrument or Sample file mpt::IO::InputFile f(midiMapName, SettingCacheCompleteFileBeforeLoading()); if(f.IsValid()) { FileReader insFile = GetFileReader(f); if(ReadInstrumentFromFile(ins, insFile, false)) { mpt::PathString filename = midiMapName.GetFilename(); pIns = Instruments[ins]; if(!pIns->filename[0]) pIns->filename = filename.ToLocale(); if(!pIns->name[0]) { if(midiCode < 0x80) { pIns->name = szMidiProgramNames[midiCode]; } else { uint32 key = midiCode & 0x7F; if((key >= 24) && (key < 24 + std::size(szMidiPercussionNames))) pIns->name = szMidiPercussionNames[key - 24]; } } } } } } } #endif // MODPLUG_TRACKER return true; } #else // !MODPLUG_TRACKER && !MPT_FUZZ_TRACKER bool CSoundFile::ReadMID(FileReader &/*file*/, ModLoadingFlags /*loadFlags*/) { return false; } #endif OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_ptm.cpp0000644000175000017500000002002514674116012020341 00000000000000/* * Load_ptm.cpp * ------------ * Purpose: PTM (PolyTracker) module loader * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct PTMFileHeader { char songname[28]; // Name of song, asciiz string uint8le dosEOF; // 26 uint8le versionLo; // 03 version of file, currently 0203h uint8le versionHi; // 02 uint8le reserved1; // Reserved, set to 0 uint16le numOrders; // Number of orders (0..256) uint16le numSamples; // Number of instruments (1..255) uint16le numPatterns; // Number of patterns (1..128) uint16le numChannels; // Number of channels (voices) used (1..32) uint16le flags; // Set to 0 uint8le reserved2[2]; // Reserved, set to 0 char magic[4]; // Song identification, 'PTMF' uint8le reserved3[16]; // Reserved, set to 0 uint8le chnPan[32]; // Channel panning settings, 0..15, 0 = left, 7 = middle, 15 = right uint8le orders[256]; // Order list, valid entries 0..nOrders-1 uint16le patOffsets[128]; // Pattern offsets (*16) }; MPT_BINARY_STRUCT(PTMFileHeader, 608) struct PTMSampleHeader { enum SampleFlags { smpTypeMask = 0x03, smpPCM = 0x01, smpLoop = 0x04, smpPingPong = 0x08, smp16Bit = 0x10, }; uint8le flags; // Sample type (see SampleFlags) char filename[12]; // Name of external sample file uint8le volume; // Default volume uint16le c4speed; // C-4 speed (yep, not C-5) uint8le smpSegment[2]; // Sample segment (used internally) uint32le dataOffset; // Offset of sample data uint32le length; // Sample size (in bytes) uint32le loopStart; // Start of loop uint32le loopEnd; // End of loop uint8le gusdata[14]; char samplename[28]; // Name of sample, ASCIIZ char magic[4]; // Sample identification, 'PTMS' // Convert an PTM sample header to OpenMPT's internal sample header. SampleIO ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(MOD_TYPE_S3M); mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4; mptSmp.nC5Speed = c4speed * 2; mptSmp.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, filename); SampleIO sampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::deltaPCM); if((flags & smpTypeMask) == smpPCM) { mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopEnd; if(mptSmp.nLoopEnd > mptSmp.nLoopStart) mptSmp.nLoopEnd--; if(flags & smpLoop) mptSmp.uFlags.set(CHN_LOOP); if(flags & smpPingPong) mptSmp.uFlags.set(CHN_PINGPONGLOOP); if(flags & smp16Bit) { sampleIO |= SampleIO::_16bit; sampleIO |= SampleIO::PTM8Dto16; mptSmp.nLength /= 2; mptSmp.nLoopStart /= 2; mptSmp.nLoopEnd /= 2; } } return sampleIO; } }; MPT_BINARY_STRUCT(PTMSampleHeader, 80) static bool ValidateHeader(const PTMFileHeader &fileHeader) { if(std::memcmp(fileHeader.magic, "PTMF", 4) || fileHeader.dosEOF != 26 || fileHeader.versionHi > 2 || fileHeader.flags != 0 || !fileHeader.numChannels || fileHeader.numChannels > 32 || !fileHeader.numOrders || fileHeader.numOrders > 256 || !fileHeader.numSamples || fileHeader.numSamples > 255 || !fileHeader.numPatterns || fileHeader.numPatterns > 128 ) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const PTMFileHeader &fileHeader) { return fileHeader.numSamples * sizeof(PTMSampleHeader); } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPTM(MemoryFileReader file, const uint64 *pfilesize) { PTMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); PTMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_PTM, fileHeader.numChannels); m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songname); m_modFormat.formatName = UL_("PolyTracker"); m_modFormat.type = UL_("ptm"); m_modFormat.madeWithTracker = MPT_UFORMAT("PolyTracker {}.{}")(fileHeader.versionHi.get(), mpt::ufmt::hex0<2>(fileHeader.versionLo.get())); m_modFormat.charset = mpt::Charset::CP437; SetMixLevels(MixLevels::CompatibleFT2); m_SongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS; m_nSamples = std::min(static_cast(fileHeader.numSamples), static_cast(MAX_SAMPLES - 1)); ReadOrderFromArray(Order(), fileHeader.orders, fileHeader.numOrders, 0xFF, 0xFE); // Reading channel panning for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = ((fileHeader.chnPan[chn] & 0x0F) << 4) + 4; } // Reading samples FileReader sampleHeaderChunk = file.ReadChunk(fileHeader.numSamples * sizeof(PTMSampleHeader)); for(SAMPLEINDEX smp = 0; smp < m_nSamples; smp++) { PTMSampleHeader sampleHeader; sampleHeaderChunk.ReadStruct(sampleHeader); ModSample &sample = Samples[smp + 1]; m_szNames[smp + 1] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.samplename); SampleIO sampleIO = sampleHeader.ConvertToMPT(sample); if((loadFlags & loadSampleData) && sample.nLength && file.Seek(sampleHeader.dataOffset)) { sampleIO.ReadSample(sample, file); } } // Reading Patterns if(!(loadFlags & loadPatternData)) { return true; } Patterns.ResizeArray(fileHeader.numPatterns); for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++) { if(!Patterns.Insert(pat, 64) || fileHeader.patOffsets[pat] == 0 || !file.Seek(fileHeader.patOffsets[pat] << 4)) { continue; } ModCommand *rowBase = Patterns[pat].GetpModCommand(0, 0); ROWINDEX row = 0; while(row < 64 && file.CanRead(1)) { uint8 b = file.ReadUint8(); if(b == 0) { row++; rowBase += GetNumChannels(); continue; } CHANNELINDEX chn = (b & 0x1F); ModCommand dummy = ModCommand(); ModCommand &m = chn < GetNumChannels() ? rowBase[chn] : dummy; if(b & 0x20) { const auto [note, instr] = file.ReadArray(); m.note = note; m.instr = instr; if(m.note == 254) m.note = NOTE_NOTECUT; else if(!m.note || m.note > 120) m.note = NOTE_NONE; } if(b & 0x40) { const auto [command, param] = file.ReadArray(); m.param = param; static constexpr EffectCommand effTrans[] = { CMD_GLOBALVOLUME, CMD_RETRIG, CMD_FINEVIBRATO, CMD_NOTESLIDEUP, CMD_NOTESLIDEDOWN, CMD_NOTESLIDEUPRETRIG, CMD_NOTESLIDEDOWNRETRIG, CMD_REVERSEOFFSET }; if(command < 0x10) { // Beware: Effect letters are as in MOD, but portamento and volume slides behave like in S3M (i.e. fine slides share the same effect letters) ConvertModCommand(m, command, param); } else if(command < 0x10 + std::size(effTrans)) { m.command = effTrans[command - 0x10]; } else { m.command = CMD_NONE; } switch(m.command) { case CMD_PANNING8: // Don't be surprised about the strange formula, this is directly translated from original disassembly... m.SetEffectCommand(CMD_S3MCMDEX, static_cast(0x80 | ((std::max(m.param >> 3, 1u) - 1u) & 0x0F))); break; case CMD_GLOBALVOLUME: m.param = std::min(m.param, uint8(0x40)) * 2u; break; #ifdef MODPLUG_TRACKER case CMD_OFFSET: case CMD_REVERSEOFFSET: if(m.instr && m.instr <= GetNumSamples() && Samples[m.instr].uFlags[CHN_16BIT]) m.param /= 2; break; #endif // MODPLUG_TRACKER default: break; } } if(b & 0x80) { m.SetVolumeCommand(VOLCMD_VOLUME, file.ReadUint8()); } } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_s3m.cpp0000644000175000017500000012337515017401256020256 00000000000000/* * Load_s3m.cpp * ------------ * Purpose: S3M (ScreamTracker 3) module loader / saver * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "S3MTools.h" #include "ITTools.h" #ifndef MODPLUG_NO_FILESAVE #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "../common/mptFileIO.h" #ifdef MODPLUG_TRACKER #include "../mptrack/Moddoc.h" #include "../mptrack/TrackerSettings.h" #endif // MODPLUG_TRACKER #endif // MODPLUG_NO_FILESAVE #include "../common/version.h" OPENMPT_NAMESPACE_BEGIN void CSoundFile::S3MConvert(ModCommand &m, const uint8 command, const uint8 param, const bool fromIT) { m.param = param; switch(command | 0x40) { case '@': m.command = (m.param ? CMD_DUMMY : CMD_NONE); break; case 'A': m.command = CMD_SPEED; break; case 'B': m.command = CMD_POSITIONJUMP; break; case 'C': m.command = CMD_PATTERNBREAK; if(!fromIT) m.param = static_cast((m.param >> 4) * 10 + (m.param & 0x0F)); break; case 'D': m.command = CMD_VOLUMESLIDE; break; case 'E': m.command = CMD_PORTAMENTODOWN; break; case 'F': m.command = CMD_PORTAMENTOUP; break; case 'G': m.command = CMD_TONEPORTAMENTO; break; case 'H': m.command = CMD_VIBRATO; break; case 'I': m.command = CMD_TREMOR; break; case 'J': m.command = CMD_ARPEGGIO; break; case 'K': m.command = CMD_VIBRATOVOL; break; case 'L': m.command = CMD_TONEPORTAVOL; break; case 'M': m.command = CMD_CHANNELVOLUME; break; case 'N': m.command = CMD_CHANNELVOLSLIDE; break; case 'O': m.command = CMD_OFFSET; break; case 'P': m.command = CMD_PANNINGSLIDE; break; case 'Q': m.command = CMD_RETRIG; break; case 'R': m.command = CMD_TREMOLO; break; case 'S': m.command = CMD_S3MCMDEX; break; case 'T': m.command = CMD_TEMPO; break; case 'U': m.command = CMD_FINEVIBRATO; break; case 'V': m.command = CMD_GLOBALVOLUME; break; case 'W': m.command = CMD_GLOBALVOLSLIDE; break; case 'X': m.command = CMD_PANNING8; break; case 'Y': m.command = CMD_PANBRELLO; break; case 'Z': m.command = CMD_MIDI; break; case '\\': m.command = fromIT ? CMD_SMOOTHMIDI : CMD_MIDI; break; // Chars under 0x40 don't save properly, so the following commands don't map to their pattern editor representations case ']': m.command = fromIT ? CMD_DELAYCUT : CMD_NONE; break; case '[': m.command = fromIT ? CMD_XPARAM : CMD_NONE; break; case '^': m.command = fromIT ? CMD_FINETUNE : CMD_NONE; break; case '_': m.command = fromIT ? CMD_FINETUNE_SMOOTH : CMD_NONE; break; // BeRoTracker extensions case '1' + 0x41: m.command = fromIT ? CMD_KEYOFF : CMD_NONE; break; case '2' + 0x41: m.command = fromIT ? CMD_SETENVPOSITION : CMD_NONE; break; default: m.command = CMD_NONE; } } #ifndef MODPLUG_NO_FILESAVE void CSoundFile::S3MSaveConvert(const ModCommand &source, uint8 &command, uint8 ¶m, const bool toIT, const bool compatibilityExport) const { command = 0; param = source.param; const bool extendedIT = !compatibilityExport && toIT; switch(source.command) { case CMD_DUMMY: command = (param ? '@' : 0); break; case CMD_SPEED: command = 'A'; break; case CMD_POSITIONJUMP: command = 'B'; break; case CMD_PATTERNBREAK: command = 'C'; if(!toIT) param = static_cast(((param / 10) << 4) + (param % 10)); break; case CMD_VOLUMESLIDE: command = 'D'; break; case CMD_PORTAMENTODOWN: command = 'E'; if(param >= 0xE0 && (GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) param = 0xDF; break; case CMD_PORTAMENTOUP: command = 'F'; if(param >= 0xE0 && (GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) param = 0xDF; break; case CMD_TONEPORTAMENTO: command = 'G'; break; case CMD_VIBRATO: command = 'H'; break; case CMD_TREMOR: command = 'I'; break; case CMD_ARPEGGIO: command = 'J'; break; case CMD_VIBRATOVOL: command = 'K'; break; case CMD_TONEPORTAVOL: command = 'L'; break; case CMD_CHANNELVOLUME: command = 'M'; break; case CMD_CHANNELVOLSLIDE: command = 'N'; break; case CMD_OFFSETPERCENTAGE: case CMD_OFFSET: command = 'O'; break; case CMD_PANNINGSLIDE: command = 'P'; break; case CMD_RETRIG: command = 'Q'; break; case CMD_TREMOLO: command = 'R'; break; case CMD_S3MCMDEX: command = 'S'; break; case CMD_TEMPO: command = 'T'; break; case CMD_FINEVIBRATO: command = 'U'; break; case CMD_GLOBALVOLUME: command = 'V'; break; case CMD_GLOBALVOLSLIDE: command = 'W'; break; case CMD_PANNING8: command = 'X'; if(toIT && !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM | MOD_TYPE_MOD))) { if(param == 0xA4) { command = 'S'; param = 0x91; } else if(param == 0x80) { param = 0xFF; } else if(param < 0x80) { param <<= 1; } else command = 0; } else if(!toIT && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM | MOD_TYPE_MOD))) { param >>= 1; } break; case CMD_PANBRELLO: command = 'Y'; break; case CMD_MIDI: command = 'Z'; break; case CMD_SMOOTHMIDI: if(extendedIT) command = '\\'; else command = 'Z'; break; case CMD_XFINEPORTAUPDOWN: switch(param & 0xF0) { case 0x10: command = 'F'; param = (param & 0x0F) | 0xE0; break; case 0x20: command = 'E'; param = (param & 0x0F) | 0xE0; break; case 0x90: command = 'S'; break; default: command = 0; } break; case CMD_MODCMDEX: { ModCommand mConv; mConv.command = CMD_MODCMDEX; mConv.param = param; mConv.ExtendedMODtoS3MEffect(); S3MSaveConvert(mConv, command, param, toIT, compatibilityExport); } return; // Chars under 0x40 don't save properly, so map : to ] and # to [. case CMD_DELAYCUT: command = extendedIT ? ']' : 0; break; case CMD_XPARAM: command = extendedIT ? '[' : 0; break; case CMD_FINETUNE: command = extendedIT ? '^' : 0; break; case CMD_FINETUNE_SMOOTH: command = extendedIT ? '_' : 0; break; default: command = 0; } if(command == 0) { param = 0; } command &= ~0x40; } #endif // MODPLUG_NO_FILESAVE static bool ValidateHeader(const S3MFileHeader &fileHeader) { if(std::memcmp(fileHeader.magic, "SCRM", 4) || fileHeader.fileType != S3MFileHeader::idS3MType || (fileHeader.formatVersion != S3MFileHeader::oldVersion && fileHeader.formatVersion != S3MFileHeader::newVersion) ) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const S3MFileHeader &fileHeader) { return fileHeader.ordNum + (fileHeader.smpNum + fileHeader.patNum) * 2; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderS3M(MemoryFileReader file, const uint64 *pfilesize) { S3MFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); // Is it a valid S3M file? S3MFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_S3M, fileHeader.GetNumChannels()); m_nMinPeriod = 64; m_nMaxPeriod = 32767; ReadOrderFromFile(Order(), file, fileHeader.ordNum, 0xFF, 0xFE); // Read sample header offsets std::vector sampleOffsets; file.ReadVector(sampleOffsets, fileHeader.smpNum); // Read pattern offsets std::vector patternOffsets; file.ReadVector(patternOffsets, fileHeader.patNum); // ST3 ignored Zxx commands, so if we find that a file was made with ST3, we should erase all MIDI macros. bool keepMidiMacros = false; mpt::ustring madeWithTracker; bool formatTrackerStr = false; bool nonCompatTracker = false; bool isST3 = false; bool isSchism = false; const bool usePanningTable = fileHeader.usePanningTable == S3MFileHeader::idPanning; const bool offsetsAreCanonical = !patternOffsets.empty() && !sampleOffsets.empty() && patternOffsets[0] > sampleOffsets[0]; const int32 schismDateVersion = SchismTrackerEpoch + ((fileHeader.cwtv == 0x4FFF) ? fileHeader.reserved2 : (fileHeader.cwtv - 0x4050)); uint32 editTimer = 0; switch(fileHeader.cwtv & S3MFileHeader::trackerMask) { case S3MFileHeader::trkAkord & S3MFileHeader::trackerMask: if(fileHeader.cwtv == S3MFileHeader::trkAkord) madeWithTracker = UL_("Akord"); break; case S3MFileHeader::trkScreamTracker: if(!memcmp(&fileHeader.reserved2, "SCLUB2.0", 8)) { madeWithTracker = UL_("Sound Club 2"); } else if(fileHeader.cwtv == S3MFileHeader::trkST3_20 && fileHeader.special == 0 && (fileHeader.ordNum & 0x01) == 0 && fileHeader.ultraClicks == 0 && (fileHeader.flags & ~0x50) == 0 && usePanningTable && offsetsAreCanonical) { // Canonical offset check avoids mis-detection of an automatic conversion of Vic's "Paper" demo track if((fileHeader.ordNum & 0x0F) == 0) { // MPT and OpenMPT before 1.17.03.02 - Simply keep default (filter) MIDI macros if((fileHeader.masterVolume & 0x80) != 0) { m_dwLastSavedWithVersion = MPT_V("1.16"); madeWithTracker = UL_("ModPlug Tracker / OpenMPT 1.17"); } else { // MPT 1.0 alpha5 doesn't set the stereo flag, but MPT 1.0 alpha6 does. m_dwLastSavedWithVersion = MPT_V("1.00.00.A0"); madeWithTracker = UL_("ModPlug Tracker 1.0 alpha"); } } else if((fileHeader.masterVolume & 0x80) != 0) { madeWithTracker = UL_("Schism Tracker"); } keepMidiMacros = true; nonCompatTracker = true; m_playBehaviour.set(kST3LimitPeriod); } else if(fileHeader.cwtv == S3MFileHeader::trkST3_20 && fileHeader.special == 0 && fileHeader.ultraClicks == 0 && fileHeader.flags == 0 && !usePanningTable) { if(fileHeader.globalVol == 64 && fileHeader.masterVolume == 48) madeWithTracker = UL_("PlayerPRO"); else // Always stereo madeWithTracker = UL_("Velvet Studio"); } else if(fileHeader.cwtv == S3MFileHeader::trkST3_20 && fileHeader.special == 0 && fileHeader.ultraClicks == 0 && fileHeader.flags == 8 && !usePanningTable) { madeWithTracker = UL_("Impulse Tracker < 1.03"); // Not sure if 1.02 saves like this as I don't have it } else { // ST3.20 should only ever write ultra-click values 16, 24 and 32 (corresponding to 8, 12 and 16 in the GUI), ST3.01/3.03 should only write 0, // though several ST3.01/3.03 files with ultra-click values of 16 have been found as well. // However, we won't fingerprint these values here as it's unlikely that there is any other tracker out there disguising as ST3 and using a strange ultra-click value. // Also, re-saving a file with a strange ultra-click value in ST3 doesn't fix this value unless the user manually changes it, or if it's below 16. isST3 = true; if(fileHeader.cwtv == S3MFileHeader::trkST3_20) { // 3.21 writes the version number as 3.20. There is no known way to differentiate between the two. madeWithTracker = UL_("Scream Tracker 3.20 - 3.21"); } else { madeWithTracker = UL_("Scream Tracker"); formatTrackerStr = true; } } break; case S3MFileHeader::trkImagoOrpheus: formatTrackerStr = (fileHeader.cwtv != S3MFileHeader::trkPlayerPRO); if(formatTrackerStr) madeWithTracker = UL_("Imago Orpheus"); else madeWithTracker = UL_("PlayerPRO"); nonCompatTracker = true; break; case S3MFileHeader::trkImpulseTracker: if(fileHeader.cwtv == S3MFileHeader::trkIT1_old) madeWithTracker = UL_("Impulse Tracker 1.03"); // Could also be 1.02, maybe? I don't have that one else madeWithTracker = GetImpulseTrackerVersion(fileHeader.cwtv, 0); if(fileHeader.cwtv >= S3MFileHeader::trkIT2_07 && fileHeader.reserved3 != 0) { // Starting from version 2.07, IT stores the total edit time of a module in the "reserved" field editTimer = DecodeITEditTimer(fileHeader.cwtv, fileHeader.reserved3); } nonCompatTracker = true; m_playBehaviour.set(kPeriodsAreHertz); m_playBehaviour.set(kITRetrigger); m_playBehaviour.set(kITShortSampleRetrig); m_playBehaviour.set(kST3SampleSwap); // Not exactly like ST3, but close enough m_playBehaviour.set(kITPortaNoNote); m_playBehaviour.set(kITPortamentoSwapResetsPos); m_nMinPeriod = 1; break; case S3MFileHeader::trkSchismTracker: if(fileHeader.cwtv == S3MFileHeader::trkBeRoTrackerOld) { madeWithTracker = UL_("BeRoTracker"); m_playBehaviour.set(kST3LimitPeriod); } else { madeWithTracker = GetSchismTrackerVersion(fileHeader.cwtv, fileHeader.reserved2); m_nMinPeriod = 1; isSchism = true; if(schismDateVersion >= SchismVersionFromDate<2021, 05, 02>::date) m_playBehaviour.set(kPeriodsAreHertz); if(schismDateVersion >= SchismVersionFromDate<2016, 05, 13>::date) m_playBehaviour.set(kITShortSampleRetrig); m_playBehaviour.reset(kST3TonePortaWithAdlibNote); if(fileHeader.cwtv == (S3MFileHeader::trkSchismTracker | 0xFFF) && fileHeader.reserved3 != 0) { // Added in commit 6c4b71f10d4e0bf202dddfa8bd781de510b8bc0b editTimer = fileHeader.reserved3; } } nonCompatTracker = true; break; case S3MFileHeader::trkOpenMPT: if((fileHeader.cwtv & 0xFF00) == S3MFileHeader::trkNESMusa) { madeWithTracker = UL_("NESMusa"); formatTrackerStr = true; } else if(fileHeader.reserved2 == 0 && fileHeader.ultraClicks == 16 && fileHeader.channels[1] != 1) { // Liquid Tracker's ID clashes with OpenMPT's. // OpenMPT started writing full version information with OpenMPT 1.29 and later changed the ultraClicks value from 8 to 16. // Liquid Tracker writes an ultraClicks value of 16. // So we assume that a file was saved with Liquid Tracker if the reserved fields are 0 and ultraClicks is 16. madeWithTracker = UL_("Liquid Tracker"); formatTrackerStr = true; } else if(fileHeader.cwtv != S3MFileHeader::trkGraoumfTracker) { uint32 mptVersion = (fileHeader.cwtv & S3MFileHeader::versionMask) << 16; if(mptVersion >= 0x01'29'00'00) { mptVersion |= fileHeader.reserved2; // Added in OpenMPT 1.32.00.31 if(fileHeader.reserved3 != 0) editTimer = fileHeader.reserved3; } m_dwLastSavedWithVersion = Version(mptVersion); madeWithTracker = UL_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion); } else { madeWithTracker = UL_("Graoumf Tracker"); } break; case S3MFileHeader::trkBeRoTracker: madeWithTracker = UL_("BeRoTracker"); m_playBehaviour.set(kST3LimitPeriod); break; case S3MFileHeader::trkCreamTracker: madeWithTracker = UL_("CreamTracker"); break; default: if(fileHeader.cwtv == S3MFileHeader::trkCamoto) madeWithTracker = UL_("Camoto"); break; } if(formatTrackerStr) { madeWithTracker = MPT_UFORMAT("{} {}.{}")(madeWithTracker, (fileHeader.cwtv & 0xF00) >> 8, mpt::ufmt::hex0<2>(fileHeader.cwtv & 0xFF)); } // IT edit timer if(editTimer != 0) { FileHistory hist; hist.openTime = static_cast(editTimer * (HISTORY_TIMER_PRECISION / 18.2)); m_FileHistory.push_back(hist); } m_modFormat.formatName = UL_("Scream Tracker 3"); m_modFormat.type = UL_("s3m"); m_modFormat.madeWithTracker = std::move(madeWithTracker); m_modFormat.charset = m_dwLastSavedWithVersion ? mpt::Charset::Windows1252 : mpt::Charset::CP437; if(nonCompatTracker) { m_playBehaviour.reset(kST3NoMutedChannels); m_playBehaviour.reset(kST3EffectMemory); m_playBehaviour.reset(kST3PortaSampleChange); m_playBehaviour.reset(kST3VibratoMemory); m_playBehaviour.reset(KST3PortaAfterArpeggio); m_playBehaviour.reset(kST3OffsetWithoutInstrument); m_playBehaviour.reset(kApplyUpperPeriodLimit); } if(fileHeader.cwtv <= S3MFileHeader::trkST3_01) { // This broken behaviour is not present in ST3.01 m_playBehaviour.reset(kST3TonePortaWithAdlibNote); } if((fileHeader.cwtv & S3MFileHeader::trackerMask) > S3MFileHeader::trkScreamTracker) { if((fileHeader.cwtv & S3MFileHeader::trackerMask) != S3MFileHeader::trkImpulseTracker || fileHeader.cwtv >= S3MFileHeader::trkIT2_14) { // Keep MIDI macros if this is not an old IT version (BABYLON.S3M by Necros has Zxx commands and was saved with IT 2.05) keepMidiMacros = true; } } m_MidiCfg.Reset(); if(!keepMidiMacros) { // Remove macros so they don't interfere with tunes made in trackers that don't support Zxx m_MidiCfg.ClearZxxMacros(); } m_songName = mpt::String::ReadBuf(mpt::String::nullTerminated, fileHeader.name); if(fileHeader.flags & S3MFileHeader::amigaLimits) m_SongFlags.set(SONG_AMIGALIMITS); if(fileHeader.flags & S3MFileHeader::st2Vibrato) m_SongFlags.set(SONG_S3MOLDVIBRATO); if(fileHeader.cwtv == S3MFileHeader::trkST3_00 || (fileHeader.flags & S3MFileHeader::fastVolumeSlides) != 0) { m_SongFlags.set(SONG_FASTVOLSLIDES); } // Even though ST3 accepts the command AFF as expected, it mysteriously fails to load a default speed of 255... if(fileHeader.speed == 0 || (fileHeader.speed == 255 && isST3)) Order().SetDefaultSpeed(6); else Order().SetDefaultSpeed(fileHeader.speed); // ST3 also fails to load an otherwise valid default tempo of 32... if(fileHeader.tempo < 33) Order().SetDefaultTempoInt(isST3 ? 125 : 32); else Order().SetDefaultTempoInt(fileHeader.tempo); // Global Volume m_nDefaultGlobalVolume = std::min(fileHeader.globalVol.get(), uint8(64)) * 4u; // The following check is probably not very reliable, but it fixes a few tunes, e.g. // DARKNESS.S3M by Purple Motion (ST 3.00) and "Image of Variance" by C.C.Catch (ST 3.01). // Note that even ST 3.01b imports these files with a global volume of 0, // so it's not clear if these files ever played "as intended" in any ST3 versions (I don't have any older ST3 versions). if(m_nDefaultGlobalVolume == 0 && fileHeader.cwtv < S3MFileHeader::trkST3_20) { m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; } if(fileHeader.formatVersion == S3MFileHeader::oldVersion && fileHeader.masterVolume < 8) m_nSamplePreAmp = std::min((fileHeader.masterVolume + 1) * 0x10, 0x7F); // These changes were probably only supposed to be done for older format revisions, where supposedly 0x10 was the stereo flag. // However, this version check is missing in ST3, so any mono file with a master volume of 18 will be converted to a stereo file with master volume 32. else if(fileHeader.masterVolume == 2 || fileHeader.masterVolume == (2 | 0x10)) m_nSamplePreAmp = 0x20; else if(!(fileHeader.masterVolume & 0x7F)) m_nSamplePreAmp = 48; else m_nSamplePreAmp = std::max(fileHeader.masterVolume & 0x7F, 0x10); // Bit 7 = Stereo (we always use stereo) // Approximately as loud as in DOSBox and a real SoundBlaster 16 m_nVSTiVolume = 36; if(isSchism && schismDateVersion < SchismVersionFromDate<2018, 11, 12>::date) m_nVSTiVolume = 64; const bool isStereo = (fileHeader.masterVolume & 0x80) != 0 || m_dwLastSavedWithVersion; if(!isStereo) { m_nSamplePreAmp = Util::muldivr_unsigned(m_nSamplePreAmp, 8, 11); m_nVSTiVolume = Util::muldivr_unsigned(m_nVSTiVolume, 8, 11); } // Channel setup std::bitset<32> isAdlibChannel; for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { uint8 ctype = fileHeader.channels[i] & ~0x80; if(fileHeader.channels[i] != 0xFF && isStereo) ChnSettings[i].nPan = (ctype & 8) ? 0xCC : 0x33; // 200 : 56 if(fileHeader.channels[i] & 0x80) ChnSettings[i].dwFlags = CHN_MUTE; if(ctype >= 16 && ctype <= 29) { // Adlib channel - except for OpenMPT 1.19 and older, which would write wrong channel types for PCM channels 16-32. // However, MPT/OpenMPT always wrote the extra panning table, so there is no need to consider this here. ChnSettings[i].nPan = 128; isAdlibChannel[i] = true; } } // Read extended channel panning if(usePanningTable) { bool hasChannelsWithoutPanning = false; const auto pan = file.ReadArray(); for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { if((pan[i] & 0x20) != 0 && (!isST3 || !isAdlibChannel[i])) ChnSettings[i].nPan = static_cast((static_cast(pan[i] & 0x0F) * 256 + 8) / 15u); else if(pan[i] < 0x10) hasChannelsWithoutPanning = true; } if(GetNumChannels() < 32 && m_dwLastSavedWithVersion == MPT_V("1.16")) { // MPT 1.0 alpha 6 up to 1.16.203 set the panning bit for all channels, regardless of whether they are used or not. // Note: Schism Tracker fixed the same bug in git commit f21fe8bcae8b6dde2df27ede4ac9fe563f91baff if(hasChannelsWithoutPanning) m_modFormat.madeWithTracker = UL_("ModPlug Tracker 1.16 / OpenMPT 1.17"); else m_modFormat.madeWithTracker = UL_("ModPlug Tracker"); } } // Reading sample headers m_nSamples = std::min(static_cast(fileHeader.smpNum), static_cast(MAX_SAMPLES - 1)); bool anySamples = false, anyADPCM = false; uint16 gusAddresses = 0; for(SAMPLEINDEX smp = 0; smp < m_nSamples; smp++) { S3MSampleHeader sampleHeader; if(!file.Seek(sampleOffsets[smp] * 16) || !file.ReadStruct(sampleHeader)) { continue; } sampleHeader.ConvertToMPT(Samples[smp + 1], isST3); // Old ModPlug Tracker allowed to write into the last byte reserved for the null terminator m_szNames[smp + 1] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name); if(sampleHeader.sampleType < S3MSampleHeader::typeAdMel) { if(sampleHeader.length != 0) { SampleIO sampleIO = sampleHeader.GetSampleFormat((fileHeader.formatVersion == S3MFileHeader::oldVersion)); if((loadFlags & loadSampleData) && file.Seek(sampleHeader.GetSampleOffset())) sampleIO.ReadSample(Samples[smp + 1], file); anySamples = true; if(sampleIO.GetEncoding() == SampleIO::ADPCM) anyADPCM = true; } gusAddresses |= sampleHeader.gusAddress; } } const bool useGUS = gusAddresses > 1; if(isST3 && anySamples && !gusAddresses && fileHeader.cwtv != S3MFileHeader::trkST3_00) { // All Scream Tracker versions except for some probably early revisions of Scream Tracker 3.00 write GUS addresses. GUS support might not have existed at that point (1992). // Hence if a file claims to be written with ST3 (but not ST3.00), but has no GUS addresses, we deduce that it must be written by some other software (e.g. some PSM -> S3M conversions) isST3 = false; m_modFormat.madeWithTracker = UL_("Unknown"); // Check these only after we are certain that it can't be ST3.01 because that version doesn't sanitize the ultraClicks value yet if(fileHeader.cwtv == S3MFileHeader::trkST3_01 && fileHeader.ultraClicks == 0) { if(!(fileHeader.flags & ~(S3MFileHeader::fastVolumeSlides | S3MFileHeader::amigaLimits)) && (fileHeader.masterVolume & 0x80) && usePanningTable) m_modFormat.madeWithTracker = UL_("UNMO3"); else if(!fileHeader.flags && fileHeader.globalVol == 48 && fileHeader.masterVolume == 176 && fileHeader.tempo == 150 && !usePanningTable) m_modFormat.madeWithTracker = UL_("deMODifier"); // SoundSmith to S3M converter else if(!fileHeader.flags && fileHeader.globalVol == 64 && (fileHeader.masterVolume & 0x7F) == 48 && fileHeader.speed == 6 && fileHeader.tempo == 125 && !usePanningTable) m_modFormat.madeWithTracker = UL_("Kosmic To-S3M"); // MTM to S3M converter by Zab/Kosmic } } else if(isST3) { // Saving an S3M file in ST3 with the Gravis Ultrasound driver loaded will write a unique GUS memory address for each non-empty sample slot (and 0 for unused slots). // Re-saving that file in ST3 with the SoundBlaster driver loaded will reset the GUS address for all samples to 0 (unused) or 1 (used). // The first used sample will also have an address of 1 with the GUS driver. // So this is a safe way of telling if the file was last saved with the GUS driver loaded or not if there's more than one sample. m_playBehaviour.set(kST3PortaSampleChange, useGUS); m_playBehaviour.set(kST3SampleSwap, !useGUS); m_playBehaviour.set(kITShortSampleRetrig, !useGUS); // Only half the truth but close enough for now m_modFormat.madeWithTracker += useGUS ? UL_(" (GUS)") : UL_(" (SB)"); // ST3's GUS driver doesn't use this value. Ignoring it fixes the balance between FM and PCM samples (e.g. in Rotagilla by Manwe) if(useGUS) m_nSamplePreAmp = 48; } if(isST3) m_playBehaviour.set(kS3MIgnoreCombinedFineSlides); if(anyADPCM) m_modFormat.madeWithTracker += UL_(" (ADPCM packed)"); // Try to find out if Zxx commands are supposed to be panning commands (PixPlay). // Actually I am only aware of one module that uses this panning style, namely "Crawling Despair" by $volkraq // and I have no idea what PixPlay is, so this code is solely based on the sample text of that module. // We won't convert if there are not enough Zxx commands, too "high" Zxx commands // or there are only "left" or "right" pannings (we assume that stereo should be somewhat balanced), // and modules not made with an old version of ST3 were probably made in a tracker that supports panning anyway. bool pixPlayPanning = (fileHeader.cwtv < S3MFileHeader::trkST3_20); int zxxCountRight = 0, zxxCountLeft = 0; // Reading patterns if(!(loadFlags & loadPatternData)) { return true; } // Order list cannot contain pattern indices > 255, so do not even try to load higher patterns const PATTERNINDEX readPatterns = std::min(static_cast(fileHeader.patNum), static_cast(uint8_max)); Patterns.ResizeArray(readPatterns); for(PATTERNINDEX pat = 0; pat < readPatterns; pat++) { // A zero parapointer indicates an empty pattern. if(!Patterns.Insert(pat, 64) || patternOffsets[pat] == 0 || !file.Seek(patternOffsets[pat] * 16)) { continue; } // Skip pattern length indication. // Some modules, for example http://aminet.net/mods/8voic/s3m_hunt.lha seem to have a wrong pattern length - // If you strictly adhere the pattern length, you won't read some patterns (e.g. 17) correctly in that module. // It's most likely a broken copy because there are other versions of the track which don't have this issue. // Still, we don't really need this information, so we just ignore it. file.Skip(2); // Read pattern data ROWINDEX row = 0; auto rowBase = Patterns[pat].GetRow(0); ModCommand dummy; while(row < 64) { uint8 info = file.ReadUint8(); if(info == s3mEndOfRow) { // End of row if(++row < 64) { rowBase = Patterns[pat].GetRow(row); } continue; } CHANNELINDEX channel = (info & s3mChannelMask); ModCommand &m = (channel < GetNumChannels()) ? rowBase[channel] : dummy; if(info & s3mNotePresent) { const auto [note, instr] = file.ReadArray(); if(note < 0xF0) m.note = static_cast(Clamp((note & 0x0F) + 12 * (note >> 4) + 12 + NOTE_MIN, NOTE_MIN, NOTE_MAX)); else if(note == s3mNoteOff) m.note = NOTE_NOTECUT; else if(note == s3mNoteNone) m.note = NOTE_NONE; m.instr = instr; } if(info & s3mVolumePresent) { uint8 volume = file.ReadUint8(); if(volume >= 128 && volume <= 192) { m.volcmd = VOLCMD_PANNING; m.vol = volume - 128; } else { m.volcmd = VOLCMD_VOLUME; m.vol = std::min(volume, uint8(64)); } } if(info & s3mEffectPresent) { const auto [command, param] = file.ReadArray(); S3MConvert(m, command, param, false); if(m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0xA0 && fileHeader.cwtv < S3MFileHeader::trkST3_20) { // Convert the old messy SoundBlaster stereo control command (or an approximation of it, anyway) const uint8 ctype = fileHeader.channels[channel] & 0x7F; if(useGUS || ctype >= 0x10) m.command = CMD_DUMMY; else if(m.param == 0xA0 || m.param == 0xA2) // Normal panning m.param = (ctype & 8) ? 0x8C : 0x83; else if(m.param == 0xA1 || m.param == 0xA3) // Swap left / right channel m.param = (ctype & 8) ? 0x83 : 0x8C; else if(m.param <= 0xA7) // Center m.param = 0x88; else m.command = CMD_DUMMY; } else if(m.command == CMD_MIDI) { // PixPlay panning test if(m.param > 0x0F) { // PixPlay has Z00 to Z0F panning, so we ignore this. pixPlayPanning = false; } else { if(m.param < 0x08) zxxCountLeft++; else if(m.param > 0x08) zxxCountRight++; } } else if(m.command == CMD_OFFSET && m.param == 0 && isST3 && fileHeader.cwtv <= S3MFileHeader::trkST3_01) { // Offset command didn't have effect memory in ST3.01; fixed in ST3.03 m.command = CMD_DUMMY; } } } } if(pixPlayPanning && zxxCountLeft + zxxCountRight >= GetNumChannels() && (-zxxCountLeft + zxxCountRight) < static_cast(GetNumChannels())) { // There are enough Zxx commands, so let's assume this was made to be played with PixPlay Patterns.ForEachModCommand([](ModCommand &m) { if(m.command == CMD_MIDI) { m.command = CMD_S3MCMDEX; m.param |= 0x80; } }); } return true; } #ifndef MODPLUG_NO_FILESAVE bool CSoundFile::SaveS3M(std::ostream &f) const { static constexpr uint8 filler[16] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, }; if(GetNumChannels() == 0) { return false; } const bool saveMuteStatus = #ifdef MODPLUG_TRACKER TrackerSettings::Instance().MiscSaveChannelMuteStatus; #else true; #endif S3MFileHeader fileHeader; MemsetZero(fileHeader); mpt::String::WriteBuf(mpt::String::nullTerminated, fileHeader.name) = m_songName; fileHeader.dosEof = S3MFileHeader::idEOF; fileHeader.fileType = S3MFileHeader::idS3MType; // Orders ORDERINDEX writeOrders = Order().GetLengthTailTrimmed(); if(writeOrders < 2) { writeOrders = 2; } else if((writeOrders % 2u) != 0) { // Number of orders should be even writeOrders++; } LimitMax(writeOrders, static_cast(256)); fileHeader.ordNum = static_cast(writeOrders); // Samples SAMPLEINDEX writeSamples = static_cast(GetNumInstruments()); if(writeSamples == 0) { writeSamples = GetNumSamples(); } writeSamples = Clamp(writeSamples, static_cast(1), static_cast(99)); fileHeader.smpNum = static_cast(writeSamples); // Patterns PATTERNINDEX writePatterns = std::min(Patterns.GetNumPatterns(), PATTERNINDEX(100)); fileHeader.patNum = static_cast(writePatterns); // Flags if(m_SongFlags[SONG_FASTVOLSLIDES]) { fileHeader.flags |= S3MFileHeader::fastVolumeSlides; } if(m_nMaxPeriod < 20000 || m_SongFlags[SONG_AMIGALIMITS]) { fileHeader.flags |= S3MFileHeader::amigaLimits; } if(m_SongFlags[SONG_S3MOLDVIBRATO]) { fileHeader.flags |= S3MFileHeader::st2Vibrato; } // Version info following: ST3.20 = 0x1320 // Most significant nibble = Tracker ID, see S3MFileHeader::S3MTrackerVersions // Following: One nibble = Major version, one byte = Minor version (hex) const uint32 mptVersion = Version::Current().GetRawVersion(); fileHeader.cwtv = S3MFileHeader::trkOpenMPT | static_cast((mptVersion >> 16) & S3MFileHeader::versionMask); fileHeader.reserved2 = static_cast(mptVersion); fileHeader.formatVersion = S3MFileHeader::newVersion; memcpy(fileHeader.magic, "SCRM", 4); // Song Variables fileHeader.globalVol = static_cast(std::min(m_nDefaultGlobalVolume / 4u, uint32(64))); fileHeader.speed = static_cast(Clamp(Order().GetDefaultSpeed(), 1u, 254u)); fileHeader.tempo = static_cast(Clamp(Order().GetDefaultTempo().GetInt(), 33u, 255u)); fileHeader.masterVolume = static_cast(Clamp(m_nSamplePreAmp, 16u, 127u) | 0x80); fileHeader.ultraClicks = 16; fileHeader.usePanningTable = S3MFileHeader::idPanning; // IT edit timer uint64 editTimer = 0; for(const auto &mptHistory : GetFileHistory()) { editTimer += static_cast(mptHistory.openTime * HISTORY_TIMER_PRECISION / 18.2); } #ifdef MODPLUG_TRACKER if(const auto modDoc = GetpModDoc(); modDoc != nullptr) { auto creationTime = modDoc->GetCreationTime(); editTimer += mpt::saturate_round((mpt::Date::UnixAsSeconds(mpt::Date::UnixNow()) - mpt::Date::UnixAsSeconds(creationTime)) * HISTORY_TIMER_PRECISION); } #endif // MODPLUG_TRACKER fileHeader.reserved3 = mpt::saturate_cast(editTimer); mpt::IO::Write(f, fileHeader); Order().WriteAsByte(f, writeOrders); // Comment about parapointers stolen from Schism Tracker: // The sample data parapointers are 24+4 bits, whereas pattern data and sample headers are only 16+4 // bits -- so while the sample data can be written up to 268 MB within the file (starting at 0xffffff0), // the pattern data and sample headers are restricted to the first 1 MB (starting at 0xffff0). In effect, // this practically requires the sample data to be written last in the file, as it is entirely possible // (and quite easy, even) to write more than 1 MB of sample data in a file. // The "practical standard order" listed in TECH.DOC is sample headers, patterns, then sample data. // Calculate offset of first sample header... mpt::IO::Offset sampleHeaderOffset = mpt::IO::TellWrite(f) + (writeSamples + writePatterns) * 2 + 32; // ...which must be a multiple of 16, because parapointers omit the lowest 4 bits. sampleHeaderOffset = (sampleHeaderOffset + 15) & ~15; std::vector sampleOffsets(writeSamples); for(SAMPLEINDEX smp = 0; smp < writeSamples; smp++) { static_assert((sizeof(S3MSampleHeader) % 16) == 0); sampleOffsets[smp] = static_cast((sampleHeaderOffset + smp * sizeof(S3MSampleHeader)) / 16); } mpt::IO::Write(f, sampleOffsets); mpt::IO::Offset patternPointerOffset = mpt::IO::TellWrite(f); mpt::IO::Offset firstPatternOffset = sampleHeaderOffset + writeSamples * sizeof(S3MSampleHeader); std::vector patternOffsets(writePatterns); // Need to calculate the real offsets later. mpt::IO::Write(f, patternOffsets); // Write channel panning uint8 chnPan[32]; for(CHANNELINDEX chn = 0; chn < 32; chn++) { if(chn < GetNumChannels()) chnPan[chn] = static_cast(((ChnSettings[chn].nPan * 15 + 128) / 256) | 0x20); else chnPan[chn] = 0x08; } mpt::IO::Write(f, chnPan); // Do we need to fill up the file with some padding bytes for 16-Byte alignment? mpt::IO::Offset curPos = mpt::IO::TellWrite(f); if(curPos < sampleHeaderOffset) { MPT_ASSERT(sampleHeaderOffset - curPos < 16); mpt::IO::WriteRaw(f, filler, static_cast(sampleHeaderOffset - curPos)); } // Don't write sample headers for now, we are lacking the sample offset data. mpt::IO::SeekAbsolute(f, firstPatternOffset); // Write patterns enum class S3MChannelType : uint8 { kUnused = 0, kPCM = 1, kAdlib = 2 }; std::array, 32> channelType; channelType.fill(S3MChannelType::kUnused); bool globalCmdOnMutedChn = false; for(PATTERNINDEX pat = 0; pat < writePatterns; pat++) { if(Patterns.IsPatternEmpty(pat)) { patternOffsets[pat] = 0; continue; } mpt::IO::Offset patOffset = mpt::IO::TellWrite(f); if(patOffset > 0xFFFF0) { AddToLog(LogError, MPT_UFORMAT("Too much pattern data! Writing patterns failed starting from pattern {}.")(pat)); break; } MPT_ASSERT((patOffset % 16) == 0); patternOffsets[pat] = static_cast(patOffset / 16); std::vector buffer; buffer.reserve(5 * 1024); // Reserve space for length bytes buffer.resize(2, 0); if(Patterns.IsValidPat(pat)) { for(ROWINDEX row = 0; row < 64; row++) { if(row >= Patterns[pat].GetNumRows()) { // Invent empty row buffer.push_back(s3mEndOfRow); continue; } const auto rowBase = Patterns[pat].GetRow(row); CHANNELINDEX writeChannels = std::min(CHANNELINDEX(32), GetNumChannels()); bool writePatternBreak = (Patterns[pat].GetNumRows() < 64 && row + 1 == Patterns[pat].GetNumRows() && !Patterns[pat].RowHasJump(row)); for(CHANNELINDEX chn = 0; chn < writeChannels; chn++) { const ModCommand &m = rowBase[chn]; uint8 info = static_cast(chn); uint8 note = m.note; if(note != NOTE_NONE || m.instr != 0) { info |= s3mNotePresent; if(ModCommand::IsSpecialNote(note)) { // Note Cut note = s3mNoteOff; } else if(note >= NOTE_MIN + 12 && note <= NOTE_MIN + 107) { note -= NOTE_MIN + 12; note = static_cast((note % 12) + ((note / 12) << 4)); } else { note = s3mNoteNone; } if(m.instr > 0 && m.instr <= GetNumSamples()) { const ModSample &smp = Samples[m.instr]; if(smp.uFlags[CHN_ADLIB]) channelType[chn].set(S3MChannelType::kAdlib); else if(smp.HasSampleData()) channelType[chn].set(S3MChannelType::kPCM); } } uint8 vol = std::min(m.vol, ModCommand::VOL(64)); if(m.volcmd == VOLCMD_VOLUME) { info |= s3mVolumePresent; } else if(m.volcmd == VOLCMD_PANNING) { info |= s3mVolumePresent; vol |= 0x80; } else if(m.command == CMD_VOLUME) { info |= s3mVolumePresent; vol = std::min(m.param, ModCommand::PARAM(64)); } uint8 command = 0, param = 0; if(m.command != CMD_NONE && m.command != CMD_VOLUME) { S3MSaveConvert(m, command, param, false, true); if(command || param) { info |= s3mEffectPresent; if(saveMuteStatus && ChnSettings[chn].dwFlags[CHN_MUTE] && m.IsGlobalCommand()) { globalCmdOnMutedChn = true; } } } if(writePatternBreak && !(info & s3mEffectPresent)) { info |= s3mEffectPresent; command = 'C' ^ 0x40; writePatternBreak = false; } if(info & s3mAnyPresent) { buffer.push_back(info); if(info & s3mNotePresent) { buffer.push_back(note); buffer.push_back(m.instr); } if(info & s3mVolumePresent) { buffer.push_back(vol); } if(info & s3mEffectPresent) { buffer.push_back(command); buffer.push_back(param); } } } buffer.push_back(s3mEndOfRow); } } else { // Invent empty pattern buffer.insert(buffer.end(), 64, s3mEndOfRow); } uint16 length = mpt::saturate_cast(buffer.size()); buffer[0] = static_cast(length & 0xFF); buffer[1] = static_cast((length >> 8) & 0xFF); if((buffer.size() % 16u) != 0) { // Add padding bytes buffer.insert(buffer.end(), 16 - (buffer.size() % 16u), 0); } mpt::IO::Write(f, buffer); } if(globalCmdOnMutedChn) { //AddToLog(LogWarning, U_("Global commands on muted channels are interpreted only by some S3M players.")); } mpt::IO::Offset sampleDataOffset = mpt::IO::TellWrite(f); // Write samples std::vector sampleHeader(writeSamples); for(SAMPLEINDEX smp = 0; smp < writeSamples; smp++) { SAMPLEINDEX realSmp = smp + 1; if(GetNumInstruments() != 0 && Instruments[smp] != nullptr) { // Find some valid sample associated with this instrument. for(SAMPLEINDEX keySmp : Instruments[smp]->Keyboard) { if(keySmp > 0 && keySmp <= GetNumSamples()) { realSmp = keySmp; break; } } } if(realSmp > GetNumSamples()) { continue; } const SmpLength smpLength = sampleHeader[smp].ConvertToS3M(Samples[realSmp]); mpt::String::WriteBuf(mpt::String::nullTerminated, sampleHeader[smp].name) = m_szNames[realSmp]; if(smpLength != 0) { // Write sample data if(sampleDataOffset > 0xFFFFFF0) { AddToLog(LogError, MPT_UFORMAT("Too much sample data! Writing samples failed starting from sample {}.")(realSmp)); break; } sampleHeader[smp].dataPointer[1] = static_cast((sampleDataOffset >> 4) & 0xFF); sampleHeader[smp].dataPointer[2] = static_cast((sampleDataOffset >> 12) & 0xFF); sampleHeader[smp].dataPointer[0] = static_cast((sampleDataOffset >> 20) & 0xFF); size_t writtenLength = sampleHeader[smp].GetSampleFormat(false).WriteSample(f, Samples[realSmp], smpLength); sampleDataOffset += writtenLength; if((writtenLength % 16u) != 0) { size_t fillSize = 16 - (writtenLength % 16u); mpt::IO::WriteRaw(f, filler, fillSize); sampleDataOffset += fillSize; } } } // Channel Table uint8 sampleCh = 0, adlibCh = 0; for(CHANNELINDEX chn = 0; chn < 32; chn++) { if(chn < GetNumChannels()) { if(channelType[chn][S3MChannelType::kPCM] && channelType[chn][S3MChannelType::kAdlib]) { AddToLog(LogWarning, MPT_UFORMAT("Pattern channel {} constains both samples and OPL instruments, which is not supported by Scream Tracker 3.")(chn + 1)); } // ST3 only supports 16 PCM channels, so if channels 17-32 are used, // they must be mapped to the same "internal channels" as channels 1-16. // The channel indices determine in which order channels are evaluated in ST3. // First, the "left" channels (0...7) are evaluated, then the "right" channels (8...15). // Previously, an alternating LRLR scheme was written, which would lead to a different // effect processing in ST3 than LLL...RRR, but since OpenMPT doesn't care about the // channel order and always parses them left to right as they appear in the pattern, // we should just write in the LLL...RRR manner. uint8 ch = sampleCh % 16u; // If there are neither PCM nor AdLib instruments on this channel, just fall back a regular sample-based channel for maximum compatibility. if(channelType[chn][S3MChannelType::kPCM]) ch = (sampleCh++) % 16u; else if(channelType[chn][S3MChannelType::kAdlib]) ch = 16 + ((adlibCh++) % 9u); if(saveMuteStatus && ChnSettings[chn].dwFlags[CHN_MUTE]) { ch |= 0x80; } fileHeader.channels[chn] = ch; } else { fileHeader.channels[chn] = 0xFF; } } if(sampleCh > 16) { AddToLog(LogWarning, MPT_UFORMAT("This module has more than 16 ({}) sample channels, which is not supported by Scream Tracker 3.")(sampleCh)); } if(adlibCh > 9) { AddToLog(LogWarning, MPT_UFORMAT("This module has more than 9 ({}) OPL channels, which is not supported by Scream Tracker 3.")(adlibCh)); } mpt::IO::SeekAbsolute(f, 0); mpt::IO::Write(f, fileHeader); // Now we know where the patterns are. if(writePatterns != 0) { mpt::IO::SeekAbsolute(f, patternPointerOffset); mpt::IO::Write(f, patternOffsets); } // And we can finally write the sample headers. if(writeSamples != 0) { mpt::IO::SeekAbsolute(f, sampleHeaderOffset); mpt::IO::Write(f, sampleHeader); } return true; } #endif // MODPLUG_NO_FILESAVE OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_ice.cpp0000644000175000017500000001215614721715306020313 00000000000000/* * Load_ice.cpp * ------------ * Purpose: ST26 (SoundTracker 2.6 / Ice Tracker) loader * Notes : The only real difference to other SoundTracker formats is the way patterns are stored: * Every pattern consists of four independent, re-usable tracks. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "MODTools.h" OPENMPT_NAMESPACE_BEGIN CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize) { if(!file.CanRead(1464 + 4)) return ProbeWantMoreData; file.Seek(1464); char magic[4]; file.ReadArray(magic); if(!IsMagic(magic, "MTN\0") && !IsMagic(magic, "IT10")) return ProbeFailure; file.Seek(20); uint32 invalidBytes = 0; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { MODSampleHeader sampleHeader; file.ReadStruct(sampleHeader); invalidBytes += sampleHeader.GetInvalidByteScore(); if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) return ProbeFailure; } const auto [numOrders, numTracks] = file.ReadArray(); if(numOrders > 128) { return ProbeFailure; } std::array tracks; file.ReadArray(tracks); for(auto track : tracks) { if(track > numTracks) return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags) { char magic[4]; if(!file.Seek(1464) || !file.ReadArray(magic)) { return false; } if(IsMagic(magic, "MTN\0")) { InitializeGlobals(MOD_TYPE_MOD, 4); m_modFormat.formatName = UL_("MnemoTroN SoundTracker"); m_modFormat.type = UL_("st26"); m_modFormat.madeWithTracker = UL_("SoundTracker 2.6"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; } else if(IsMagic(magic, "IT10")) { InitializeGlobals(MOD_TYPE_MOD, 4); m_modFormat.formatName = UL_("Ice Tracker"); m_modFormat.type = UL_("ice"); m_modFormat.madeWithTracker = UL_("Ice Tracker 1.0 / 1.1"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; } else { return false; } // Reading song title file.Seek(0); file.ReadString(m_songName, 20); // Load Samples m_nSamples = 31; uint32 invalidBytes = 0; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { MODSampleHeader sampleHeader; file.ReadStruct(sampleHeader); invalidBytes += ReadMODSample(sampleHeader, Samples[smp], m_szNames[smp], true); if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) return false; } const auto [numOrders, numTracks] = file.ReadArray(); if(numOrders > 128) return false; std::array tracks; file.ReadArray(tracks); for(auto track : tracks) { if(track > numTracks) return false; } if(loadFlags == onlyVerifyHeader) return true; // Now we can be pretty sure that this is a valid ICE file. Set up default song settings. SetupMODPanning(true); Order().SetDefaultSpeed(6); Order().SetDefaultTempoInt(125); m_nMinPeriod = 14 * 4; m_nMaxPeriod = 3424 * 4; m_nSamplePreAmp = 64; m_SongFlags.set(SONG_PT_MODE | SONG_IMPORTED | SONG_FORMAT_NO_VOLCOL); m_playBehaviour.reset(kMODOneShotLoops); m_playBehaviour.set(kMODIgnorePanning); m_playBehaviour.set(kMODSampleSwap); // untested // Reading patterns Order().resize(numOrders); uint8 speed = 0; if(loadFlags & loadPatternData) Patterns.ResizeArray(numOrders); for(PATTERNINDEX pat = 0; pat < numOrders; pat++) { Order()[pat] = pat; if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) break; for(CHANNELINDEX chn = 0; chn < 4; chn++) { file.Seek(1468 + tracks[pat * 4 + chn] * 64u * 4u); ModCommand *m = Patterns[pat].GetpModCommand(0, chn); for(ROWINDEX row = 0; row < 64; row++, m += 4) { const auto [command, param] = ReadMODPatternEntry(file, *m); if((command || param) && !(command == 0x0E && param >= 0x10) // Exx only sets filter && !(command >= 0x05 && command <= 0x09)) // These don't exist in ST2.6 { ConvertModCommand(*m, command, param); } else { m->command = CMD_NONE; } } } // Handle speed command with both nibbles set - this enables auto-swing (alternates between the two nibbles) auto m = Patterns[pat].begin(); for(ROWINDEX row = 0; row < 64; row++) { for(CHANNELINDEX chn = 0; chn < 4; chn++, m++) { if(m->command == CMD_SPEED || m->command == CMD_TEMPO) { m->command = CMD_SPEED; if(m->param & 0xF0) { if((m->param >> 4) != (m->param & 0x0F) && (m->param & 0x0F) != 0) { // Both nibbles set speed = m->param; } m->param >>= 4; } } } if(speed) { speed = mpt::rotr(speed, 4); Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, speed & 0x0F).Row(row)); } } } // Reading samples if(loadFlags & loadSampleData) { file.Seek(1468 + numTracks * 64u * 4u); for(SAMPLEINDEX smp = 1; smp <= 31; smp++) if(Samples[smp].nLength) { SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(Samples[smp], file); } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_wav.cpp0000644000175000017500000001454614657606142020362 00000000000000/* * Load_wav.cpp * ------------ * Purpose: WAV importer * Notes : This loader converts each WAV channel into a separate mono sample. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "WAVTools.h" #include "openmpt/soundbase/SampleConvert.hpp" #include "openmpt/soundbase/SampleDecode.hpp" #include "SampleCopy.h" OPENMPT_NAMESPACE_BEGIN ///////////////////////////////////////////////////////////// // WAV file support template static bool CopyWavChannel(ModSample &sample, const FileReader &file, size_t channelIndex, size_t numChannels, SampleConversion conv = SampleConversion()) { MPT_ASSERT(sample.GetNumChannels() == 1); MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t)); const size_t offset = channelIndex * sizeof(typename SampleConversion::input_t) * SampleConversion::input_inc; if(sample.AllocateSample() == 0 || !file.CanRead(offset)) { return false; } FileReader::PinnedView inData = file.GetPinnedView(file.BytesLeft()); CopySample(sample.template sample(), sample.nLength, 1, inData.data() + offset, inData.size() - offset, numChannels, conv); return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderWAV(MemoryFileReader file, const uint64 *pfilesize) { RIFFHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if((fileHeader.magic != RIFFHeader::idRIFF && fileHeader.magic != RIFFHeader::idLIST) || (fileHeader.type != RIFFHeader::idWAVE && fileHeader.type != RIFFHeader::idwave)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadWAV(FileReader &file, ModLoadingFlags loadFlags) { WAVReader wavFile(file); if(!wavFile.IsValid() || wavFile.GetNumChannels() == 0 || wavFile.GetNumChannels() > MAX_BASECHANNELS || wavFile.GetNumChannels() >= MAX_SAMPLES || wavFile.GetBitsPerSample() == 0 || wavFile.GetBitsPerSample() > 64 || (wavFile.GetBitsPerSample() < 32 && wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat) || (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat)) { return false; } else if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_MPT, std::max(wavFile.GetNumChannels(), uint16(2))); m_ContainerType = ModContainerType::WAV; Patterns.ResizeArray(2); if(!Patterns.Insert(0, 64) || !Patterns.Insert(1, 64)) { return false; } m_modFormat.formatName = UL_("RIFF WAVE"); m_modFormat.type = UL_("wav"); m_modFormat.charset = mpt::Charset::Windows1252; const SmpLength sampleLength = wavFile.GetSampleLength(); // Setting up module length // Calculate sample length in ticks at tempo 125 const uint32 sampleRate = std::max(uint32(1), wavFile.GetSampleRate()); const uint32 sampleTicks = mpt::saturate_cast(((sampleLength * 50) / sampleRate) + 1); uint32 ticksPerRow = std::max((sampleTicks + 63u) / 63u, uint32(1)); Order().assign(1, 0); ORDERINDEX numOrders = 1; while(ticksPerRow >= 32 && numOrders < MAX_ORDERS) { numOrders++; ticksPerRow = (sampleTicks + (64 * numOrders - 1)) / (64 * numOrders); } Order().resize(numOrders, 1); m_nSamples = wavFile.GetNumChannels(); m_nInstruments = 0; Order().SetDefaultSpeed(ticksPerRow); Order().SetDefaultTempoInt(125); m_SongFlags = SONG_LINEARSLIDES; for(CHANNELINDEX channel = 0; channel < GetNumChannels(); channel++) { ChnSettings[channel].nPan = (channel % 2u) ? 256 : 0; } // Setting up pattern auto row = Patterns[0].GetRow(0); row[0].note = row[1].note = NOTE_MIDDLEC; row[0].instr = row[1].instr = 1; const FileReader sampleChunk = wavFile.GetSampleData(); // Read every channel into its own sample lot. for(SAMPLEINDEX channel = 0; channel < GetNumSamples(); channel++) { row[channel].note = row[0].note; row[channel].instr = static_cast(channel + 1); ModSample &sample = Samples[channel + 1]; sample.Initialize(); sample.uFlags = CHN_PANNING; sample.nLength = sampleLength; sample.nC5Speed = wavFile.GetSampleRate(); m_szNames[channel + 1] = ""; wavFile.ApplySampleSettings(sample, GetCharsetInternal(), m_szNames[channel + 1]); if(wavFile.GetNumChannels() > 1) { // Pan all samples appropriately switch(channel) { case 0: sample.nPan = 0; break; case 1: sample.nPan = 256; break; case 2: sample.nPan = (wavFile.GetNumChannels() == 3 ? 128u : 64u); row[channel].command = CMD_S3MCMDEX; row[channel].param = 0x91; break; case 3: sample.nPan = 192; row[channel].command = CMD_S3MCMDEX; row[channel].param = 0x91; break; default: sample.nPan = 128; break; } } if(wavFile.GetBitsPerSample() > 8) { sample.uFlags.set(CHN_16BIT); } if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat) { if(wavFile.GetBitsPerSample() <= 32) CopyWavChannel, SC::DecodeFloat32>>(sample, sampleChunk, channel, wavFile.GetNumChannels()); else CopyWavChannel, SC::DecodeFloat64>>(sample, sampleChunk, channel, wavFile.GetNumChannels()); } else { if(wavFile.GetBitsPerSample() <= 8) CopyWavChannel(sample, sampleChunk, channel, wavFile.GetNumChannels()); else if(wavFile.GetBitsPerSample() <= 16) CopyWavChannel>(sample, sampleChunk, channel, wavFile.GetNumChannels()); else if(wavFile.GetBitsPerSample() <= 24) CopyWavChannel, SC::DecodeInt24<0, littleEndian24>>>(sample, sampleChunk, channel, wavFile.GetNumChannels()); else if(wavFile.GetBitsPerSample() <= 32) CopyWavChannel, SC::DecodeInt32<0, littleEndian32>>>(sample, sampleChunk, channel, wavFile.GetNumChannels()); else if(wavFile.GetBitsPerSample() <= 64) CopyWavChannel, SC::DecodeInt64<0, littleEndian64>>>(sample, sampleChunk, channel, wavFile.GetNumChannels()); } sample.PrecomputeLoops(*this, false); } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/S3MTools.h0000644000175000017500000001261614644275460017713 00000000000000/* * S3MTools.h * ---------- * Purpose: Definition of S3M file structures and helper functions * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/base/Endian.hpp" #include "Snd_defs.h" OPENMPT_NAMESPACE_BEGIN struct ModSample; class SampleIO; // S3M File Header struct S3MFileHeader { // Magic Bytes enum S3MMagic { idEOF = 0x1A, idS3MType = 0x10, idPanning = 0xFC, }; // Tracker Versions in the cwtv field enum S3MTrackerVersions { trackerMask = 0xF000, versionMask = 0x0FFF, trkScreamTracker = 0x1000, trkImagoOrpheus = 0x2000, trkImpulseTracker = 0x3000, trkSchismTracker = 0x4000, trkOpenMPT = 0x5000, trkBeRoTracker = 0x6000, trkCreamTracker = 0x7000, trkAkord = 0x0208, trkST3_00 = 0x1300, trkST3_01 = 0x1301, trkST3_20 = 0x1320, trkIT1_old = 0x3320, trkIT2_07 = 0x3207, trkIT2_14 = 0x3214, trkBeRoTrackerOld = 0x4100, // Used from 2004 to 2012 trkGraoumfTracker = 0x5447, trkNESMusa = 0x5700, trkCamoto = 0xCA00, trkPlayerPRO = 0x2013, // PlayerPRO on Intel doesn't byte-swap the tracker ID bytes }; // Flags enum S3MHeaderFlags { st2Vibrato = 0x01, // Vibrato is twice as deep. Cannot be enabled from UI. zeroVolOptim = 0x08, // Volume 0 optimisations amigaLimits = 0x10, // Enforce Amiga limits fastVolumeSlides = 0x40, // Fast volume slides (like in ST3.00) }; // S3M Format Versions enum S3MFormatVersion { oldVersion = 0x01, // Old Version, signed samples newVersion = 0x02, // New Version, unsigned samples }; char name[28]; // Song Title uint8le dosEof; // Supposed to be 0x1A, but even ST3 seems to ignore this sometimes (see STRSHINE.S3M by Purple Motion) uint8le fileType; // File Type, 0x10 = ST3 module char reserved1[2]; // Reserved uint16le ordNum; // Number of order items uint16le smpNum; // Number of sample parapointers uint16le patNum; // Number of pattern parapointers uint16le flags; // Flags, see S3MHeaderFlags uint16le cwtv; // "Made With" Tracker ID, see S3MTrackerVersions uint16le formatVersion; // Format Version, see S3MFormatVersion char magic[4]; // "SCRM" magic bytes uint8le globalVol; // Default Global Volume (0...64) uint8le speed; // Default Speed (1...254) uint8le tempo; // Default Tempo (33...255) uint8le masterVolume; // Sample Volume (0...127, stereo if high bit is set) uint8le ultraClicks; // Number of channels used for ultra click removal uint8le usePanningTable; // 0xFC => read extended panning table uint16le reserved2; // Schism Tracker and OpenMPT use this for their extended version information uint32le reserved3; // Impulse Tracker hides its edit timer here uint16le reserved4; uint16le special; // Pointer to special custom data (unused) uint8le channels[32]; // Channel setup uint8 GetNumChannels() const { uint8 numChannels = 4; for(uint8 i = 0; i < 32; i++) { if(channels[i] != 0xFF) numChannels = i + 1; } return numChannels; } }; MPT_BINARY_STRUCT(S3MFileHeader, 96) // S3M Sample Header struct S3MSampleHeader { enum SampleType { typeNone = 0, typePCM = 1, typeAdMel = 2, }; enum SampleFlags { smpLoop = 0x01, smpStereo = 0x02, smp16Bit = 0x04, }; enum SamplePacking { pUnpacked = 0x00, // PCM pDP30ADPCM = 0x01, // Unused packing type pADPCM = 0x04, // MODPlugin ADPCM :( }; uint8le sampleType; // Sample type, see SampleType char filename[12]; // Sample filename uint8le dataPointer[3]; // Pointer to sample data (divided by 16) uint32le length; // Sample length, in samples uint32le loopStart; // Loop start, in samples uint32le loopEnd; // Loop end, in samples uint8le defaultVolume; // Default volume (0...64) char reserved1; // Reserved uint8le pack; // Packing algorithm, SamplePacking uint8le flags; // Sample flags uint32le c5speed; // Middle-C frequency char reserved2[4]; // Reserved uint16le gusAddress; // Sample address in GUS memory (used for fingerprinting) uint16le sb512; // SoundBlaster loop expansion stuff uint32le lastUsedPos; // More SoundBlaster stuff char name[28]; // Sample name char magic[4]; // "SCRS" magic bytes ("SCRI" for Adlib instruments) // Convert an S3M sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp, bool isST3 = false) const; // Convert OpenMPT's internal sample header to an S3M sample header. SmpLength ConvertToS3M(const ModSample &mptSmp); // Retrieve the internal sample format flags for this sample. SampleIO GetSampleFormat(bool signedSamples) const; // Calculate the sample position in file uint32 GetSampleOffset() const; }; MPT_BINARY_STRUCT(S3MSampleHeader, 80) // Pattern decoding flags enum S3MPattern { s3mEndOfRow = 0x00, s3mChannelMask = 0x1F, s3mNotePresent = 0x20, s3mVolumePresent = 0x40, s3mEffectPresent = 0x80, s3mAnyPresent = 0xE0, s3mNoteOff = 0xFE, s3mNoteNone = 0xFF, }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/patternContainer.h0000644000175000017500000001113214610011735021562 00000000000000/* * PatternContainer.h * ------------------ * Purpose: Container class for managing patterns. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "pattern.h" #include OPENMPT_NAMESPACE_BEGIN class CSoundFile; class CPatternContainer { public: CPattern& operator[](const int pat) { return m_Patterns[pat]; } const CPattern& operator[](const int pat) const { return m_Patterns[pat]; } public: CPatternContainer(CSoundFile &sndFile) : m_rSndFile{sndFile} { } CPatternContainer(const CPatternContainer &) = default; CPatternContainer(CPatternContainer &&) noexcept = default; CPatternContainer &operator=(const CPatternContainer &other); CPatternContainer &operator=(CPatternContainer &&other) noexcept; // Delete all patterns. void DestroyPatterns(); // Insert (default)pattern to given position. If pattern already exists at that position, // ignoring request. Returns true on success, false otherwise. bool Insert(const PATTERNINDEX index, const ROWINDEX rows); // Insert pattern to position with the lowest index, and return that index, PATTERNINDEX_INVALID on failure. // If respectQtyLimits is true, inserting patterns will fail if the resulting pattern index would exceed the current format's pattern quantity limits. PATTERNINDEX InsertAny(const ROWINDEX rows, bool respectQtyLimits = false); // Duplicate an existing pattern. Returns new pattern index on success, or PATTERNINDEX_INVALID on failure. // If respectQtyLimits is true, inserting patterns will fail if the resulting pattern index would exceed the current format's pattern quantity limits. PATTERNINDEX Duplicate(PATTERNINDEX from, bool respectQtyLimits = false); //Remove pattern from given position. Currently it actually makes the pattern //'invisible' - the pattern data is cleared but the actual pattern object won't get removed. void Remove(const PATTERNINDEX index); // Applies function object for modcommands in all patterns. template void ForEachModCommand(Func func); template void ForEachModCommand(Func func) const; std::vector::iterator begin() noexcept { return m_Patterns.begin(); } std::vector::const_iterator begin() const noexcept { return m_Patterns.begin(); } std::vector::const_iterator cbegin() const noexcept { return m_Patterns.cbegin(); } std::vector::iterator end() noexcept { return m_Patterns.end(); } std::vector::const_iterator end() const noexcept { return m_Patterns.end(); } std::vector::const_iterator cend() const noexcept { return m_Patterns.cend(); } PATTERNINDEX Size() const noexcept { return static_cast(m_Patterns.size()); } CSoundFile& GetSoundFile() noexcept { return m_rSndFile; } const CSoundFile& GetSoundFile() const noexcept { return m_rSndFile; } // Return true if pattern can be accessed with operator[](iPat), false otherwise. bool IsValidIndex(const PATTERNINDEX iPat) const noexcept { return (iPat < Size()); } // Return true if IsValidIndex() is true and the corresponding pattern has allocated modcommand array, false otherwise. bool IsValidPat(const PATTERNINDEX iPat) const noexcept { return IsValidIndex(iPat) && m_Patterns[iPat].IsValid(); } // Returns true if the pattern is empty, i.e. there are no notes/effects in this pattern bool IsPatternEmpty(const PATTERNINDEX nPat) const noexcept; void ResizeArray(const PATTERNINDEX newSize); void OnModTypeChanged(const MODTYPE oldtype); // Returns index of last valid pattern + 1, zero if no such pattern exists. PATTERNINDEX GetNumPatterns() const noexcept; // Returns index of highest pattern with pattern named + 1. PATTERNINDEX GetNumNamedPatterns() const noexcept; // Number of patterns that can still be added, respecting the current format's limitations PATTERNINDEX GetRemainingCapacity() const noexcept; private: std::vector m_Patterns; CSoundFile &m_rSndFile; }; template void CPatternContainer::ForEachModCommand(Func func) { for(auto &pattern : m_Patterns) std::for_each(pattern.begin(), pattern.end(), func); } template void CPatternContainer::ForEachModCommand(Func func) const { for(const auto &pattern : m_Patterns) std::for_each(pattern.cbegin(), pattern.cend(), func); } const char FileIdPatterns[] = "mptPc"; void ReadModPatterns(std::istream& iStrm, CPatternContainer& patc, const size_t nSize = 0); void WriteModPatterns(std::ostream& oStrm, const CPatternContainer& patc); OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/PlayState.cpp0000644000175000017500000000436614723412114020517 00000000000000/* * PlayState.cpp * ------------- * Purpose: This class represents all of the playback state of a module. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "PlayState.h" #include "MIDIMacros.h" #include "Mixer.h" #include "Sndfile.h" OPENMPT_NAMESPACE_BEGIN PlayState::PlayState() { Chn.fill({}); m_midiMacroScratchSpace.reserve(kMacroLength); // Note: If macros ever become variable-length, the scratch space needs to be at least one byte longer than the longest macro in the file for end-of-SysEx insertion to stay allocation-free in the mixer! } void PlayState::ResetGlobalVolumeRamping() noexcept { m_lHighResRampingGlobalVolume = m_nGlobalVolume << VOLUMERAMPPRECISION; m_nGlobalVolumeDestination = m_nGlobalVolume; m_nSamplesToGlobalVolRampDest = 0; m_nGlobalVolumeRampAmount = 0; } void PlayState::UpdateTimeSignature(const CSoundFile &sndFile) noexcept { if(!sndFile.Patterns.IsValidIndex(m_nPattern) || !sndFile.Patterns[m_nPattern].GetOverrideSignature()) { m_nCurrentRowsPerBeat = sndFile.m_nDefaultRowsPerBeat; m_nCurrentRowsPerMeasure = sndFile.m_nDefaultRowsPerMeasure; } else { m_nCurrentRowsPerBeat = sndFile.Patterns[m_nPattern].GetRowsPerBeat(); m_nCurrentRowsPerMeasure = sndFile.Patterns[m_nPattern].GetRowsPerMeasure(); } } void PlayState::UpdatePPQ(bool patternTransition) noexcept { ROWINDEX rpm = m_nCurrentRowsPerMeasure ? m_nCurrentRowsPerMeasure : DEFAULT_ROWS_PER_MEASURE; ROWINDEX rpb = m_nCurrentRowsPerBeat ? m_nCurrentRowsPerBeat : DEFAULT_ROWS_PER_BEAT; if(m_lTotalSampleCount > 0 && (patternTransition || !(m_nRow % rpm))) { // Pattern end = end of measure, so round up PPQ to the next full measure m_ppqPosBeat += (rpm + (rpb - 1)) / rpb; m_ppqPosFract = 0; } } mpt::span PlayState::PatternChannels(const CSoundFile &sndFile) noexcept { return mpt::as_span(Chn).subspan(0, std::min(Chn.size(), static_cast(sndFile.GetNumChannels()))); } mpt::span PlayState::BackgroundChannels(const CSoundFile &sndFile) noexcept { return mpt::as_span(Chn).subspan(std::min(Chn.size(), static_cast(sndFile.GetNumChannels()))); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Sndfile.h0000644000175000017500000016172614754160672017663 00000000000000/* * Sndfile.h * --------- * Purpose: Core class of the playback engine. Every song is represented by a CSoundFile object. * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "SoundFilePlayConfig.h" #include "MixerSettings.h" #include "../common/misc_util.h" #include "../common/mptFileType.h" #include "../common/mptRandom.h" #include "../common/version.h" #include "Snd_defs.h" #include "tuningbase.h" #include "MIDIMacros.h" #ifdef MODPLUG_TRACKER #include "../mptrack/MIDIMapping.h" #endif // MODPLUG_TRACKER #include "Mixer.h" #include "Resampler.h" #ifndef NO_REVERB #include "../sounddsp/Reverb.h" #endif #ifndef NO_AGC #include "../sounddsp/AGC.h" #endif #ifndef NO_DSP #include "../sounddsp/DSP.h" #endif #ifndef NO_EQ #include "../sounddsp/EQ.h" #endif #include "Message.h" #include "ModChannel.h" #include "modcommand.h" #include "ModInstrument.h" #include "ModSample.h" #include "ModSequence.h" #include "pattern.h" #include "patternContainer.h" #include "PlayState.h" #include "plugins/PluginStructs.h" #include "RowVisitor.h" #include "mpt/audio/span.hpp" #include "../common/FileReaderFwd.h" #include #include #include OPENMPT_NAMESPACE_BEGIN bool SettingCacheCompleteFileBeforeLoading(); // Sample decompression routines in format-specific source files void AMSUnpack(mpt::const_byte_span source, mpt::byte_span dest, int8 packCharacter); uintptr_t DMFUnpack(FileReader &file, uint8 *psample, uint32 maxlen); #ifdef LIBOPENMPT_BUILD #ifndef NO_PLUGINS class CVstPluginManager; #endif #endif using PlayBehaviourSet = std::bitset; #ifdef MODPLUG_TRACKER // For WAV export (writing pattern positions to file) struct PatternCuePoint { uint64 offset; // offset in the file (in samples) ORDERINDEX order; // which order is this? bool processed; // has this point been processed by the main WAV render function yet? }; #endif // MODPLUG_TRACKER // Return values for GetLength() struct GetLengthType { double duration = 0.0; // Total time in seconds ROWINDEX restartRow = ROWINDEX_INVALID; // First row to play after module loops (or last parsed row if target is specified; equal to target if it was found) ROWINDEX endRow = ROWINDEX_INVALID; // Last row played before module loops (UNDEFINED if a target is specified) ROWINDEX startRow = 0; // First row of parsed subsong ORDERINDEX restartOrder = ORDERINDEX_INVALID; // First row to play after module loops (see restartRow remark) ORDERINDEX endOrder = ORDERINDEX_INVALID; // Last order played before module loops (UNDEFINED if a target is specified) ORDERINDEX startOrder = 0; // First order of parsed subsong bool targetReached = false; // True if the specified order/row combination or duration has been reached while going through the module }; struct SubSong { double duration; ROWINDEX startRow, endRow, loopStartRow; ORDERINDEX startOrder, endOrder, loopStartOrder; SEQUENCEINDEX sequence; }; // Target seek mode for GetLength() struct GetLengthTarget { ROWINDEX startRow; ORDERINDEX startOrder; SEQUENCEINDEX sequence; struct pos_type { ROWINDEX row; ORDERINDEX order; }; union { double time; pos_type pos; }; enum Mode { NoTarget, // Don't seek, i.e. return complete length of the first subsong. GetAllSubsongs, // Same as NoTarget (i.e. get complete length), but returns the length of all sub songs SeekPosition, // Seek to given pattern position. SeekSeconds, // Seek to given time. } mode; // Don't seek, i.e. return complete module length. GetLengthTarget(bool allSongs = false) { mode = allSongs ? GetAllSubsongs : NoTarget; sequence = SEQUENCEINDEX_INVALID; startOrder = 0; startRow = 0; } // Seek to given pattern position if position is valid. GetLengthTarget(ORDERINDEX order, ROWINDEX row) { mode = NoTarget; sequence = SEQUENCEINDEX_INVALID; startOrder = 0; startRow = 0; if(order != ORDERINDEX_INVALID && row != ROWINDEX_INVALID) { mode = SeekPosition; pos.row = row; pos.order = order; } } // Seek to given time if t is valid (i.e. not negative). GetLengthTarget(double t) { mode = NoTarget; sequence = SEQUENCEINDEX_INVALID; startOrder = 0; startRow = 0; if(t >= 0.0) { mode = SeekSeconds; time = t; } } // Set start position from which seeking should begin. GetLengthTarget &StartPos(SEQUENCEINDEX seq, ORDERINDEX order, ROWINDEX row) { sequence = seq; startOrder = order; startRow = row; return *this; } }; // Reset mode for GetLength() enum enmGetLengthResetMode { // Never adjust global variables / mod parameters eNoAdjust = 0x00, // Mod parameters (such as global volume, speed, tempo, etc...) will always be memorized if the target was reached (i.e. they won't be reset to the previous values). If target couldn't be reached, they are reset to their default values. eAdjust = 0x01, // Same as above, but global variables will only be memorized if the target could be reached. This does *NOT* influence the visited rows vector - it will *ALWAYS* be adjusted in this mode. eAdjustOnSuccess = 0x02 | eAdjust, // Same as previous option, but will also try to emulate sample playback so that voices from previous patterns will sound when continuing playback at the target position. eAdjustSamplePositions = 0x04 | eAdjustOnSuccess, // Only adjust the visited rows state eAdjustOnlyVisitedRows = 0x08, }; // Delete samples assigned to instrument enum deleteInstrumentSamples { deleteAssociatedSamples, doNoDeleteAssociatedSamples, }; namespace Tuning { class CTuningCollection; } // namespace Tuning using CTuningCollection = Tuning::CTuningCollection; struct CModSpecifications; class OPL; class PlaybackTest; class CModDoc; ///////////////////////////////////////////////////////////////////////// // File edit history #define HISTORY_TIMER_PRECISION 18.2 struct FileHistory { // Date when the file was loaded in the the tracker or created. mpt::Date::AnyGregorian loadDate = {}; // Time the file was open in the editor, in 1/18.2th seconds (frequency of a standard DOS timer, to keep compatibility with Impulse Tracker easy). uint32 openTime = 0; // Return the date as a (possibly truncated if not enough precision is available) ISO 8601 formatted date. mpt::ustring AsISO8601(mpt::Date::LogicalTimezone internalTimezone) const; // Returns true if the date component is valid. Some formats only store edit time, not edit date. bool HasValidDate() const { return loadDate != mpt::Date::AnyGregorian{}; } bool operator==(const FileHistory &other) const noexcept { return std::tie(loadDate, openTime) == std::tie(other.loadDate, other.openTime); } bool operator!=(const FileHistory &other) const noexcept { return std::tie(loadDate, openTime) != std::tie(other.loadDate, other.openTime); } bool operator<(const FileHistory &other) const noexcept { return std::tie(loadDate, openTime) < std::tie(other.loadDate, other.openTime); } }; struct TimingInfo { double InputLatency = 0.0; // seconds double OutputLatency = 0.0; // seconds int64 StreamFrames = 0; uint64 SystemTimestamp = 0; // nanoseconds double Speed = 1.0; }; enum class ModMessageHeuristicOrder { Instruments, Samples, InstrumentsSamples, SamplesInstruments, BothInstrumentsSamples, BothSamplesInstruments, Default = InstrumentsSamples, }; struct ModFormatDetails { mpt::ustring formatName; // "FastTracker 2" mpt::ustring type; // "xm" mpt::ustring madeWithTracker; // "OpenMPT 1.28.01.00" mpt::ustring originalFormatName; // "FastTracker 2" in the case of converted formats like MO3 or GDM mpt::ustring originalType; // "xm" in the case of converted formats like MO3 or GDM mpt::Charset charset = mpt::Charset::UTF8; mpt::Date::LogicalTimezone timezone = mpt::Date::LogicalTimezone::Unspecified; }; class IAudioTarget { protected: virtual ~IAudioTarget() = default; public: virtual void Process(mpt::audio_span_interleaved buffer) = 0; virtual void Process(mpt::audio_span_interleaved buffer) = 0; }; class IAudioSource { public: virtual ~IAudioSource() = default; public: virtual void Process(mpt::audio_span_planar buffer) = 0; virtual void Process(mpt::audio_span_planar buffer) = 0; }; class IMonitorInput { public: virtual ~IMonitorInput() = default; public: virtual void Process(mpt::audio_span_planar buffer) = 0; virtual void Process(mpt::audio_span_planar buffer) = 0; }; class IMonitorOutput { public: virtual ~IMonitorOutput() = default; public: virtual void Process(mpt::audio_span_interleaved buffer) = 0; virtual void Process(mpt::audio_span_interleaved buffer) = 0; }; class AudioSourceNone : public IAudioSource { public: void Process(mpt::audio_span_planar buffer) override { for(std::size_t channel = 0; channel < buffer.size_channels(); ++channel) { for(std::size_t frame = 0; frame < buffer.size_frames(); ++frame) { buffer(channel, frame) = 0; } } } void Process(mpt::audio_span_planar buffer) override { for(std::size_t channel = 0; channel < buffer.size_channels(); ++channel) { for(std::size_t frame = 0; frame < buffer.size_frames(); ++frame) { buffer(channel, frame) = MixSampleFloat(0.0); } } } }; using NoteName = mpt::uchar[4]; struct PlaybackTestSettings { uint32 mixingFreq = 48000; uint32 outputChannels = 2; uint32 mixerChannels = MAX_CHANNELS; ResamplingMode srcMode = SRCMODE_CUBIC; void Sanitize() { if(mixingFreq < 1000) { mixingFreq = 48000; } if(outputChannels != 1 && outputChannels != 2 && outputChannels != 4) { outputChannels = 2; } if(mixerChannels < 1) { mixerChannels = MAX_CHANNELS; } } }; class CSoundFile { friend class GetLengthMemory; friend class MIDIMacroParser; public: #ifdef MODPLUG_TRACKER void ChangeModTypeTo(const MODTYPE newType, bool adjust = true); #endif // MODPLUG_TRACKER // Returns value in seconds. If given position won't be played at all, returns -1. // If updateVars is true, the state of various playback variables will be updated according to the playback position. // If updateSamplePos is also true, the sample positions of samples still playing from previous patterns will be kept in sync. double GetPlaybackTimeAt(ORDERINDEX ord, ROWINDEX row, bool updateVars, bool updateSamplePos); std::vector GetAllSubSongs(); //Tuning--> public: static std::unique_ptr CreateTuning12TET(const mpt::ustring &name); CTuningCollection& GetTuneSpecificTunings() {return *m_pTuningsTuneSpecific;} mpt::ustring GetNoteName(const ModCommand::NOTE note, const INSTRUMENTINDEX inst, const NoteName *noteNames = nullptr) const; mpt::ustring GetNoteName(const ModCommand::NOTE note) const; static mpt::ustring GetNoteName(const ModCommand::NOTE note, const NoteName *noteNames); #ifdef MODPLUG_TRACKER public: static void SetDefaultNoteNames(); static const NoteName *GetDefaultNoteNames(); static mpt::ustring GetDefaultNoteName(int note) // note = [0..11] { return m_NoteNames[note]; } private: static const NoteName *m_NoteNames; #else private: const NoteName *m_NoteNames; #endif private: CTuningCollection* m_pTuningsTuneSpecific = nullptr; private: //Misc data const CModSpecifications *m_pModSpecs; private: // Interleaved Front Mix Buffer (Also room for interleaved rear mix) mixsample_t MixSoundBuffer[MIXBUFFERSIZE * 4]; mixsample_t MixRearBuffer[MIXBUFFERSIZE * 2]; // Non-interleaved plugin processing buffer float MixFloatBuffer[2][MIXBUFFERSIZE]; mixsample_t MixInputBuffer[NUMMIXINPUTBUFFERS][MIXBUFFERSIZE]; // End-of-sample pop reduction tail level mixsample_t m_dryLOfsVol = 0, m_dryROfsVol = 0; mixsample_t m_surroundLOfsVol = 0, m_surroundROfsVol = 0; public: MixerSettings m_MixerSettings; CResampler m_Resampler; #ifndef NO_REVERB mixsample_t ReverbSendBuffer[MIXBUFFERSIZE * 2]; mixsample_t m_RvbROfsVol = 0, m_RvbLOfsVol = 0; CReverb m_Reverb; #endif #ifndef NO_DSP CSurround m_Surround; CMegaBass m_MegaBass; #endif #ifndef NO_EQ CEQ m_EQ; #endif #ifndef NO_AGC CAGC m_AGC; #endif #ifndef NO_DSP BitCrush m_BitCrush; #endif static constexpr uint32 TICKS_ROW_FINISHED = uint32_max - 1u; private: #ifdef MODPLUG_TRACKER CModDoc *m_pModDoc = nullptr; // Can be a null pointer for example when previewing samples from the treeview. #endif // MODPLUG_TRACKER Enum m_nType; ModContainerType m_ContainerType = ModContainerType::None; public: SAMPLEINDEX m_nSamples = 0; INSTRUMENTINDEX m_nInstruments = 0; uint32 m_nDefaultGlobalVolume; FlagSet m_SongFlags; CHANNELINDEX m_nMixChannels = 0; private: CHANNELINDEX m_nMixStat; public: ROWINDEX m_nDefaultRowsPerBeat, m_nDefaultRowsPerMeasure; // default rows per beat and measure for this module TempoMode m_nTempoMode = TempoMode::Classic; #ifdef MODPLUG_TRACKER // Lock playback between two rows. Lock is active if lock start != ROWINDEX_INVALID). ROWINDEX m_lockRowStart = ROWINDEX_INVALID, m_lockRowEnd = ROWINDEX_INVALID; // Lock playback between two orders. Lock is active if lock start != ORDERINDEX_INVALID). ORDERINDEX m_lockOrderStart = ORDERINDEX_INVALID, m_lockOrderEnd = ORDERINDEX_INVALID; #endif // MODPLUG_TRACKER uint32 m_nSamplePreAmp, m_nVSTiVolume; uint32 m_OPLVolumeFactor; // 16.16 static constexpr uint32 m_OPLVolumeFactorScale = 1 << 16; constexpr bool IsGlobalVolumeUnset() const noexcept { return IsFirstTick(); } #ifndef MODPLUG_TRACKER uint32 m_nFreqFactor = 65536; // Pitch shift factor (65536 = no pitch shifting). Only used in libopenmpt (openmpt::ext::interactive::set_pitch_factor) uint32 m_nTempoFactor = 65536; // Tempo factor (65536 = no tempo adjustment). Only used in libopenmpt (openmpt::ext::interactive::set_tempo_factor) #endif // Row swing factors for modern tempo mode TempoSwing m_tempoSwing; // Min Period = highest possible frequency, Max Period = lowest possible frequency for current format // Note: Period is an Amiga metric that is inverse to frequency. // Periods in MPT are 4 times as fine as Amiga periods because of extra fine frequency slides (introduced in the S3M format). int32 m_nMinPeriod, m_nMaxPeriod; ResamplingMode m_nResampling; // Resampling mode (if overriding the globally set resampling) int32 m_nRepeatCount = 0; // -1 means repeat infinitely. ORDERINDEX m_restartOverridePos = 0, m_maxOrderPosition = 0; std::vector ChnSettings; // Initial channels settings CPatternContainer Patterns; ModSequenceSet Order; // Pattern sequences (order lists) protected: ModSample Samples[MAX_SAMPLES]; public: ModInstrument *Instruments[MAX_INSTRUMENTS]; // Instrument Headers InstrumentSynth::Events m_globalScript; MIDIMacroConfig m_MidiCfg; // MIDI Macro config table #ifndef NO_PLUGINS std::array m_MixPlugins; // Mix plugins uint32 m_loadedPlugins = 0; // Not a PLUGINDEX because number of loaded plugins may exceed MAX_MIXPLUGINS during MIDI conversion #endif mpt::charbuf m_szNames[MAX_SAMPLES]; // Sample names Version m_dwCreatedWithVersion; Version m_dwLastSavedWithVersion; PlayBehaviourSet m_playBehaviour; protected: mpt::fast_prng m_PRNG; inline mpt::fast_prng & AccessPRNG() const { return const_cast(this)->m_PRNG; } inline mpt::fast_prng & AccessPRNG() { return m_PRNG; } protected: // Mix level stuff CSoundFilePlayConfig m_PlayConfig; MixLevels m_nMixLevels; public: PlayState m_PlayState; protected: // For handling backwards jumps and stuff to prevent infinite loops when counting the mod length or rendering to wav. RowVisitor m_visitedRows; public: #ifdef MODPLUG_TRACKER std::bitset m_bChannelMuteTogglePending; std::bitset m_pluginDryWetRatioChanged; // Dry/Wet ratio was changed by playback code (e.g. through MIDI macro), need to update UI std::vector *m_PatternCuePoints = nullptr; // For WAV export (writing pattern positions to file) std::vector *m_SamplePlayLengths = nullptr; // For storing the maximum play length of each sample for automatic sample trimming #endif // MODPLUG_TRACKER std::unique_ptr m_opl; #ifdef MODPLUG_TRACKER public: CMIDIMapper& GetMIDIMapper() { return m_MIDIMapper; } const CMIDIMapper& GetMIDIMapper() const { return m_MIDIMapper; } private: CMIDIMapper m_MIDIMapper; #endif // MODPLUG_TRACKER public: #if defined(LIBOPENMPT_BUILD) && !defined(NO_PLUGINS) std::unique_ptr m_PluginManager; #endif public: std::string m_songName; mpt::ustring m_songArtist; SongMessage m_songMessage; ModFormatDetails m_modFormat; protected: std::vector m_FileHistory; // File edit history public: std::vector &GetFileHistory() { return m_FileHistory; } const std::vector &GetFileHistory() const { return m_FileHistory; } #ifdef MPT_EXTERNAL_SAMPLES // MPTM external on-disk sample paths protected: std::vector m_samplePaths; public: void SetSamplePath(SAMPLEINDEX smp, mpt::PathString filename) { if(m_samplePaths.size() < smp) m_samplePaths.resize(smp); m_samplePaths[smp - 1] = std::move(filename); } void ResetSamplePath(SAMPLEINDEX smp) { if(m_samplePaths.size() >= smp) m_samplePaths[smp - 1] = mpt::PathString(); Samples[smp].uFlags.reset(SMP_KEEPONDISK | SMP_MODIFIED);} mpt::PathString GetSamplePath(SAMPLEINDEX smp) const { if(m_samplePaths.size() >= smp) return m_samplePaths[smp - 1]; else return mpt::PathString(); } bool SampleHasPath(SAMPLEINDEX smp) const { if(m_samplePaths.size() >= smp) return !m_samplePaths[smp - 1].empty(); else return false; } bool IsExternalSampleMissing(SAMPLEINDEX smp) const { return Samples[smp].uFlags[SMP_KEEPONDISK] && !Samples[smp].HasSampleData(); } bool LoadExternalSample(SAMPLEINDEX smp, const mpt::PathString &filename); #endif // MPT_EXTERNAL_SAMPLES bool m_bIsRendering = false; TimingInfo m_TimingInfo; // only valid if !m_bIsRendering private: // logging ILog *m_pCustomLog = nullptr; public: CSoundFile(); CSoundFile(const CSoundFile &) = delete; CSoundFile & operator=(const CSoundFile &) = delete; ~CSoundFile(); public: // logging void SetCustomLog(ILog *pLog) { m_pCustomLog = pLog; } void AddToLog(LogLevel level, const mpt::ustring &text) const; public: enum ModLoadingFlags { loadPatternData = 0x01, // If unset, advise loaders to not process any pattern data (if possible) loadSampleData = 0x02, // If unset, advise loaders to not process any sample data (if possible) loadPluginData = 0x04, // If unset, plugin data is not loaded (and as a consequence, plugins are not instantiated). loadPluginInstance = 0x08, // If unset, plugins are not instantiated. skipContainer = 0x10, skipModules = 0x20, onlyVerifyHeader = 0x40, // Do not combine with other flags! // Shortcuts loadCompleteModule = loadSampleData | loadPatternData | loadPluginData | loadPluginInstance, loadNoPatternOrPluginData = loadSampleData, loadNoPluginInstance = loadSampleData | loadPatternData | loadPluginData, }; #define PROBE_RECOMMENDED_SIZE 2048u static constexpr std::size_t ProbeRecommendedSize = PROBE_RECOMMENDED_SIZE; enum ProbeFlags { ProbeModules = 0x1, ProbeContainers = 0x2, ProbeFlagsDefault = ProbeModules | ProbeContainers, ProbeFlagsNone = 0 }; enum ProbeResult { ProbeSuccess = 1, ProbeFailure = 0, ProbeWantMoreData = -1 }; static ProbeResult ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize); static ProbeResult Probe(ProbeFlags flags, mpt::span data, const uint64 *pfilesize); public: #ifdef MODPLUG_TRACKER // Get parent CModDoc. Can be nullptr if previewing from tree view, and is always nullptr if we're not actually compiling OpenMPT. CModDoc *GetpModDoc() const noexcept { return m_pModDoc; } #endif // MODPLUG_TRACKER void Create(MODTYPE type, CHANNELINDEX numChannels, CModDoc *pModDoc = nullptr); bool Create(FileReader file, ModLoadingFlags loadFlags = loadCompleteModule, CModDoc *pModDoc = nullptr); private: bool CreateInternal(FileReader file, ModLoadingFlags loadFlags); public: bool Destroy(); Enum GetType() const noexcept { return m_nType; } ModContainerType GetContainerType() const noexcept { return m_ContainerType; } // rough heuristic, could be improved mpt::Charset GetCharsetFile() const // 8bit string encoding of strings in the on-disk file { return m_modFormat.charset; } mpt::Charset GetCharsetInternal() const // 8bit string encoding of strings internal in CSoundFile { #if defined(MODPLUG_TRACKER) return mpt::Charset::Locale; #else // MODPLUG_TRACKER return GetCharsetFile(); #endif // MODPLUG_TRACKER } mpt::Date::LogicalTimezone GetTimezoneInternal() const { return m_modFormat.timezone; } ModMessageHeuristicOrder GetMessageHeuristic() const; void SetPreAmp(uint32 vol); uint32 GetPreAmp() const noexcept { return m_MixerSettings.m_nPreAmp; } void SetMixLevels(MixLevels levels); MixLevels GetMixLevels() const noexcept { return m_nMixLevels; } const CSoundFilePlayConfig &GetPlayConfig() const noexcept { return m_PlayConfig; } constexpr INSTRUMENTINDEX GetNumInstruments() const noexcept { return m_nInstruments; } constexpr SAMPLEINDEX GetNumSamples() const noexcept { return m_nSamples; } constexpr PATTERNINDEX GetCurrentPattern() const noexcept { return m_PlayState.m_nPattern; } constexpr ORDERINDEX GetCurrentOrder() const noexcept { return m_PlayState.m_nCurrentOrder; } MPT_FORCEINLINE CHANNELINDEX GetNumChannels() const noexcept { return static_cast(ChnSettings.size()); } constexpr bool CanAddMoreSamples(SAMPLEINDEX amount = 1) const noexcept { return (amount < MAX_SAMPLES) && m_nSamples < (MAX_SAMPLES - amount); } constexpr bool CanAddMoreInstruments(INSTRUMENTINDEX amount = 1) const noexcept { return (amount < MAX_INSTRUMENTS) && m_nInstruments < (MAX_INSTRUMENTS - amount); } #ifndef NO_PLUGINS IMixPlugin* GetInstrumentPlugin(INSTRUMENTINDEX instr) const noexcept; #endif const CModSpecifications& GetModSpecifications() const {return *m_pModSpecs;} static const CModSpecifications& GetModSpecifications(const MODTYPE type); static ChannelFlags GetChannelMuteFlag(); #ifdef MODPLUG_TRACKER void PatternTranstionChnSolo(const CHANNELINDEX first, const CHANNELINDEX last); void PatternTransitionChnUnmuteAll(); protected: void HandleRowTransitionEvents(bool nextPattern); const ModSample *m_metronomeMeasure = nullptr; const ModSample *m_metronomeBeat = nullptr; ModChannel m_metronomeChn{}; public: void SetMetronomeSamples(const ModSample *measure, const ModSample *beat) { m_metronomeMeasure = measure; m_metronomeBeat = beat; m_metronomeChn.pModSample = nullptr; m_metronomeChn.pCurrentSample = nullptr; } constexpr bool IsMetronomeEnabled() const noexcept { return m_metronomeMeasure || m_metronomeBeat; } #endif // MODPLUG_TRACKER public: double GetCurrentBPM() const; void DontLoopPattern(PATTERNINDEX nPat, ROWINDEX nRow = 0); CHANNELINDEX GetMixStat() const { return m_nMixStat; } void ResetMixStat() { m_nMixStat = 0; } void ResetPlayPos(); void SetCurrentOrder(ORDERINDEX nOrder); std::string GetTitle() const { return m_songName; } bool SetTitle(const std::string &newTitle); // Return true if title was changed. const char *GetSampleName(SAMPLEINDEX nSample) const; const char *GetInstrumentName(INSTRUMENTINDEX nInstr) const; uint32 GetMusicSpeed() const { return m_PlayState.m_nMusicSpeed; } TEMPO GetMusicTempo() const { return m_PlayState.m_nMusicTempo; } constexpr bool IsFirstTick() const noexcept { return (m_PlayState.m_lTotalSampleCount == 0); } // Get song duration in various cases: total length, length to specific order & row, etc. std::vector GetLength(enmGetLengthResetMode adjustMode, GetLengthTarget target = GetLengthTarget()); public: void RecalculateSamplesPerTick(); double GetRowDuration(TEMPO tempo, uint32 speed) const; uint32 GetTickDuration(PlayState &playState) const; // A repeat count value of -1 means infinite loop void SetRepeatCount(int n) { m_nRepeatCount = n; } int GetRepeatCount() const { return m_nRepeatCount; } bool IsPaused() const { return m_PlayState.m_flags[SONG_PAUSED | SONG_STEP]; } // Added SONG_STEP as it seems to be desirable in most cases to check for this as well. void LoopPattern(PATTERNINDEX nPat, ROWINDEX nRow = 0); void InitAmigaResampler(); void InitOPL(); static constexpr bool SupportsOPL(MODTYPE type) noexcept { return type & (MOD_TYPE_S3M | MOD_TYPE_MPT); } bool SupportsOPL() const noexcept { return SupportsOPL(m_nType); } #if !defined(MPT_WITH_ANCIENT) static ProbeResult ProbeFileHeaderMMCMP(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderPP20(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderXPK(MemoryFileReader file, const uint64 *pfilesize); #endif // !MPT_WITH_ANCIENT static ProbeResult ProbeFileHeaderUMX(MemoryFileReader file, const uint64* pfilesize); static ProbeResult ProbeFileHeader667(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderAMS(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderAMS2(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderC67(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderCBA(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderDBM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderDTM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderDSm(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderDSym(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderETX(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderFC(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderFMT(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderFTM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderGMC(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderGT2(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderGTK(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderIMS(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderKRIS(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderMUS_KM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderSTK(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderMTM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderPLM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderPSM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderPSM16(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderPTM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderPuma(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderRTM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderS3M(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderSTM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderSTX(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderSymMOD(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderTCB(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderUNIC(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderXMF(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderMID(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderUAX(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderWAV(MemoryFileReader file, const uint64 *pfilesize); // Module Loaders bool Read667(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool Read669(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadAM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadAMS(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadAMS2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadC67(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadCBA(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadDBM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadDTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadDIGI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadDMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadDSM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadDSm(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadDSym(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadETX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadFAR(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadFC(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadFMT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadFTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadGDM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadGMC(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadGT2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadGTK(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadICE(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadIMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadIMS(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadIT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadITP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadJ2B(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadKRIS(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMUS_KM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadSTK(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMDL(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMED(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMO3(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMOD(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMT2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadOKT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadPLM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadPSM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadPSM16(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadPT36(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadPTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadPuma(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadRTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadS3M(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadSFX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadSTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadSTP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadSTX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadTCB(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadUNIC(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadULT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadXM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadXMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadUAX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadWAV(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); static std::vector GetSupportedExtensions(bool otherFormats); static bool IsExtensionSupported(std::string_view ext); // UTF8, casing of ext is ignored static mpt::ustring ModContainerTypeToString(ModContainerType containertype); static mpt::ustring ModContainerTypeToTracker(ModContainerType containertype); // Repair non-standard stuff in modules saved with previous ModPlug versions void UpgradeModule(); // Save Functions #ifndef MODPLUG_NO_FILESAVE bool SaveXM(std::ostream &f, bool compatibilityExport = false); bool SaveS3M(std::ostream &f) const; bool SaveMod(std::ostream &f) const; bool SaveIT(std::ostream &f, const mpt::PathString &filename, bool compatibilityExport = false); uint32 SaveMixPlugins(std::ostream *file=nullptr, bool bUpdate=true); void SaveExtendedInstrumentProperties(INSTRUMENTINDEX instr, MODTYPE forceType, std::ostream &f) const; static void SaveExtendedInstrumentProperties(mpt::span instruments, MODTYPE forceType, std::ostream &f, bool allInstruments); void SaveExtendedSongProperties(std::ostream &f) const; #endif // MODPLUG_NO_FILESAVE static void ReadExtendedInstrumentProperty(mpt::span instruments, const uint32 code, FileReader &file); bool LoadExtendedSongProperties(FileReader &file, bool ignoreChannelCount, bool* pInterpretMptMade = nullptr); void LoadMPTMProperties(FileReader &file, uint16 cwtv); static mpt::ustring GetImpulseTrackerVersion(uint16 cwtv, uint16 cmwt); static mpt::ustring GetSchismTrackerVersion(uint16 cwtv, uint32 reserved); // Reads extended instrument properties(XM/IT/MPTM/ITI/XI). // Returns true if extended instrument properties were found. bool LoadExtendedInstrumentProperties(FileReader &file) { return LoadExtendedInstrumentProperties(mpt::as_span(Instruments).subspan(1, GetNumInstruments()), file); } static bool LoadExtendedInstrumentProperties(mpt::span instruments, FileReader &file); void SetDefaultPlaybackBehaviour(MODTYPE type); static PlayBehaviourSet GetSupportedPlaybackBehaviour(MODTYPE type); static PlayBehaviourSet GetDefaultPlaybackBehaviour(MODTYPE type); // MOD Convert function MODTYPE GetBestSaveFormat() const; static void ConvertModCommand(ModCommand &m, const uint8 command, const uint8 param); static void S3MConvert(ModCommand &m, const uint8 command, const uint8 param, const bool fromIT); void S3MSaveConvert(const ModCommand &source, uint8 &command, uint8 ¶m, const bool toIT, const bool compatibilityExport = false) const; void ModSaveCommand(const ModCommand &source, uint8 &command, uint8 ¶m, const bool toXM, const bool compatibilityExport = false) const; // Reads 4 bytes formatted like SoundTracker/NoiseTracker/ProTracker pattern data, converts the period to a note, fills the instrument number and returns the effect command and parameter bytes. static std::pair ReadMODPatternEntry(FileReader &file, ModCommand &m); // Converts 4 bytes formatted like SoundTracker/NoiseTracker/ProTracker pattern data by converting the period to a note and filling the instrument number, and returns the effect command and parameter bytes. static std::pair ReadMODPatternEntry(const std::array data, ModCommand &m); void SetupMODPanning(bool forceSetup = false); // Setup LRRL panning public: // Real-time sound functions void SuspendPlugins(); void ResumePlugins(); void UpdatePluginPositions(); void StopAllVsti(); void RecalculateGainForAllPlugs(); void ResetChannels(); samplecount_t Read(samplecount_t count, IAudioTarget &target) { AudioSourceNone source; return Read(count, target, source); } samplecount_t Read( samplecount_t count, IAudioTarget &target, IAudioSource &source, std::optional> outputMonitor = std::nullopt, std::optional> inputMonitor = std::nullopt ); samplecount_t ReadOneTick(); private: void CreateStereoMix(int count); bool MixChannel(int count, ModChannel &chn, CHANNELINDEX channel, bool doMix); public: bool FadeSong(uint32 msec); private: void ProcessDSP(uint32 countChunk); void ProcessPlugins(uint32 nCount); void ProcessInputChannels(IAudioSource &source, std::size_t countChunk); public: samplecount_t GetTotalSampleCount() const { return m_PlayState.m_lTotalSampleCount; } bool HasPositionChanged() { bool b = m_PlayState.m_flags[SONG_POSITIONCHANGED]; m_PlayState.m_flags.reset(SONG_POSITIONCHANGED); return b; } bool IsRenderingToDisc() const { return m_bIsRendering; } void PrecomputeSampleLoops(bool updateChannels = false); void UpdateInstrumentFilter(const ModInstrument &ins, bool updateMode, bool updateCutoff, bool updateResonance); public: // Mixer Config void SetMixerSettings(const MixerSettings &mixersettings); void SetResamplerSettings(const CResamplerSettings &resamplersettings); void InitPlayer(bool bReset=false); void SetDspEffects(uint32 DSPMask); uint32 GetSampleRate() const { return m_MixerSettings.gdwMixingFreq; } #ifndef NO_EQ void SetEQGains(const uint32 *pGains, const uint32 *pFreqs, bool bReset = false) { m_EQ.SetEQGains(pGains, pFreqs, bReset, m_MixerSettings.gdwMixingFreq); } // 0=-12dB, 32=+12dB #endif // NO_EQ public: bool ReadNote(); bool ProcessRow(); bool ProcessEffects(); std::pair NextRow(PlayState &playState, const bool breakRow) const; void SetupNextRow(PlayState &playState, const bool patternLoop) const; CHANNELINDEX GetNNAChannel(CHANNELINDEX nChn) const; CHANNELINDEX CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, bool forceCut); void StopOldNNA(ModChannel &chn, CHANNELINDEX channel); void NoteChange(ModChannel &chn, int note, bool bPorta = false, bool bResetEnv = true, bool bManual = false, CHANNELINDEX channelHint = CHANNELINDEX_INVALID) const; void InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta = false, bool bUpdVol = true, bool bResetEnv = true) const; void ApplyInstrumentPanning(ModChannel &chn, const ModInstrument *instr, const ModSample *smp) const; uint32 CalculateXParam(PATTERNINDEX pat, ROWINDEX row, CHANNELINDEX chn, uint32 *extendedRows = nullptr) const; // Channel Effects void KeyOff(ModChannel &chn) const; // Global Effects void SetTempo(TEMPO param, bool setAsNonModcommand = false) { SetTempo(m_PlayState, param, setAsNonModcommand); } void SetTempo(PlayState &playState, TEMPO param, bool setAsNonModcommand = false) const; void SetSpeed(PlayState &playState, uint32 param) const; static TEMPO ConvertST2Tempo(uint8 tempo); void ProcessRamping(ModChannel &chn) const; void ProcessFinetune(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel, bool isSmooth); protected: // Global variable initializer for loader functions void SetType(MODTYPE type); void InitializeGlobals(MODTYPE type, CHANNELINDEX numChannels); // Channel effect processing int GetVibratoDelta(int type, int position) const; void ProcessVolumeSwing(ModChannel &chn, int &vol) const; void ProcessPanningSwing(ModChannel &chn) const; void ProcessTremolo(ModChannel &chn, int &vol) const; void ProcessTremor(CHANNELINDEX nChn, int &vol); bool IsEnvelopeProcessed(const ModChannel &chn, EnvelopeType env) const; void ProcessVolumeEnvelope(ModChannel &chn, int &vol) const; void ProcessPanningEnvelope(ModChannel &chn) const; int ProcessPitchFilterEnvelope(ModChannel &chn, int32 &period) const; void IncrementEnvelopePosition(ModChannel &chn, EnvelopeType envType) const; void IncrementEnvelopePositions(ModChannel &chn) const; void ProcessInstrumentFade(ModChannel &chn, int &vol) const; static void ProcessPitchPanSeparation(int32 &pan, int note, const ModInstrument &instr); void ProcessPanbrello(ModChannel &chn) const; void ProcessArpeggio(CHANNELINDEX nChn, int32 &period, Tuning::NOTEINDEXTYPE &arpeggioSteps); void ProcessVibrato(CHANNELINDEX nChn, int32 &period, Tuning::RATIOTYPE &vibratoFactor); void ProcessSampleAutoVibrato(ModChannel &chn, int32 &period, Tuning::RATIOTYPE &vibratoFactor, int &nPeriodFrac) const; std::pair GetChannelIncrement(const ModChannel &chn, uint32 period, int periodFrac) const; protected: // Type of panning command enum PanningType { Pan4bit = 4, Pan6bit = 6, Pan8bit = 8, }; // Channel Effects void ResetAutoSlides(ModChannel &chn) const; void ProcessAutoSlides(PlayState &playState, CHANNELINDEX channel); void UpdateS3MEffectMemory(ModChannel &chn, ModCommand::PARAM param) const; void PortamentoFC(ModChannel &chn) const; void PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular); void PortamentoUp(PlayState &playState, CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) const; void PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular); void PortamentoDown(PlayState &playState, CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) const; void MidiPortamento(CHANNELINDEX nChn, int param, const bool doFineSlides); void FinePortamentoUp(ModChannel &chn, ModCommand::PARAM param) const; void FinePortamentoDown(ModChannel &chn, ModCommand::PARAM param) const; void ExtraFinePortamentoUp(ModChannel &chn, ModCommand::PARAM param) const; void ExtraFinePortamentoDown(ModChannel &chn, ModCommand::PARAM param) const; void PortamentoMPT(ModChannel &chn, int param) const; void PortamentoFineMPT(PlayState &playState, CHANNELINDEX nChn, int param) const; void PortamentoExtraFineMPT(ModChannel &chn, int param) const; void SetFinetune(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel, PlayState &playState, bool isSmooth) const; int16 CalculateFinetuneTarget(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel) const; void NoteSlide(ModChannel &chn, uint32 param, bool slideUp, bool retrig) const; std::pair GetVolCmdTonePorta(const ModCommand &m, uint32 startTick) const; bool TonePortamentoSharesEffectMemory() const; void InitTonePortamento(ModChannel &chn, uint16 param) const; void TonePortamento(CHANNELINDEX chn, uint16 param); int32 TonePortamento(PlayState &playState, CHANNELINDEX nChn, uint16 param) const; void TonePortamentoWithDuration(ModChannel &chn, uint16 param = uint16_max) const; void Vibrato(ModChannel &chn, uint32 param) const; void FineVibrato(ModChannel &chn, uint32 param) const; void AutoVolumeSlide(ModChannel &chn, ModCommand::PARAM param) const; void VolumeDownETX(const PlayState &playState, ModChannel &chn, ModCommand::PARAM param) const; void VolumeSlide(ModChannel &chn, ModCommand::PARAM param) const; void PanningSlide(ModChannel &chn, ModCommand::PARAM param, bool memory = true) const; void ChannelVolSlide(ModChannel &chn, ModCommand::PARAM param) const; void ChannelVolumeDownWithDuration(ModChannel &chn, uint16 param = uint16_max) const; void FineVolumeUp(ModChannel &chn, ModCommand::PARAM param, bool volCol) const; void FineVolumeDown(ModChannel &chn, ModCommand::PARAM param, bool volCol) const; void Tremolo(ModChannel &chn, uint32 param) const; void Panbrello(ModChannel &chn, uint32 param) const; void Panning(ModChannel &chn, uint32 param, PanningType panBits) const; void RetrigNote(CHANNELINDEX nChn, int param, int offset = 0); void ProcessSampleOffset(ModChannel &chn, CHANNELINDEX nChn, const PlayState &playState) const; void SampleOffset(ModChannel &chn, SmpLength param) const; void ReverseSampleOffset(ModChannel &chn, ModCommand::PARAM param) const; void DigiBoosterSampleReverse(ModChannel &chn, ModCommand::PARAM param) const; void HandleDigiSamplePlayDirection(PlayState &state, CHANNELINDEX chn) const; void NoteCut(CHANNELINDEX nChn, uint32 nTick, bool cutSample); void PatternLoop(PlayState &state, CHANNELINDEX nChn, ModCommand::PARAM param) const; bool HandleNextRow(PlayState &state, const ModSequence &order, bool honorPatternLoop) const; void ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param); void ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param); void ExtendedChannelEffect(ModChannel &chn, uint32 param, PlayState &playState) const; void InvertLoop(ModChannel &chn); void PositionJump(PlayState &state, CHANNELINDEX chn) const; ROWINDEX PatternBreak(PlayState &state, CHANNELINDEX chn, uint8 param) const; void GlobalVolSlide(PlayState &playState, ModCommand::PARAM param, CHANNELINDEX chn) const; void ProcessMacroOnChannel(CHANNELINDEX nChn); void ProcessMIDIMacro(PlayState &playState, CHANNELINDEX nChn, bool isSmooth, const MIDIMacroConfigData::Macro ¯o, uint8 param = 0, PLUGINDEX plugin = 0); void SendMIDIData(PlayState &playState, CHANNELINDEX nChn, bool isSmooth, const mpt::span macro, PLUGINDEX plugin); void SendMIDINote(CHANNELINDEX chn, uint16 note, uint16 volume, IMixPlugin *plugin = nullptr); int SetupChannelFilter(ModChannel &chn, bool bReset, int envModifier = 256) const; int HandleNoteChangeFilter(ModChannel &chn) const; public: static float CalculateSmoothParamChange(const PlayState &playState, float currentValue, float param); void DoFreqSlide(ModChannel &chn, int32 &period, int32 amount, bool isTonePorta = false) const; // Convert frequency to IT cutoff (0...127) uint8 FrequencyToCutOff(double frequency) const; // Convert IT cutoff (0...127 + modifier) to frequency float CutOffToFrequency(uint32 nCutOff, int envModifier = 256) const; // Returns true if periods are actually plain frequency values in Hz. bool PeriodsAreFrequencies() const noexcept { return m_playBehaviour[kPeriodsAreHertz] && !UseFinetuneAndTranspose(); } // Returns true if the format uses transpose+finetune rather than frequency in Hz to specify middle-C. static constexpr bool UseFinetuneAndTranspose(MODTYPE type) noexcept { return (type & (MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_MTM | MOD_TYPE_OKT | MOD_TYPE_SFX | MOD_TYPE_STP | MOD_TYPE_XM)); } bool UseFinetuneAndTranspose() const noexcept { return UseFinetuneAndTranspose(GetType()); } // Returns true if the format uses combined commands for fine and regular portamento slides static constexpr bool UseCombinedPortamentoCommands(MODTYPE type) noexcept { return !(type & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM)); } bool UseCombinedPortamentoCommands() const noexcept { return UseCombinedPortamentoCommands(GetType()); } uint32 GlobalVolumeRange() const noexcept { return !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_IMF | MOD_TYPE_J2B | MOD_TYPE_MID | MOD_TYPE_AMS | MOD_TYPE_DBM | MOD_TYPE_PTM | MOD_TYPE_MDL | MOD_TYPE_DTM)) ? 64 : 128; } bool DestroySample(SAMPLEINDEX nSample); bool DestroySampleThreadsafe(SAMPLEINDEX nSample); // Find an unused sample slot. If it is going to be assigned to an instrument, targetInstrument should be specified. // SAMPLEINDEX_INVLAID is returned if no free sample slot could be found. SAMPLEINDEX GetNextFreeSample(INSTRUMENTINDEX targetInstrument = INSTRUMENTINDEX_INVALID, SAMPLEINDEX start = 1) const; // Find an unused instrument slot. // INSTRUMENTINDEX_INVALID is returned if no free instrument slot could be found. INSTRUMENTINDEX GetNextFreeInstrument(INSTRUMENTINDEX start = 1) const; // Check whether a given sample is used by a given instrument. bool IsSampleReferencedByInstrument(SAMPLEINDEX sample, INSTRUMENTINDEX instr) const; ModInstrument *AllocateInstrument(INSTRUMENTINDEX instr, SAMPLEINDEX assignedSample = 0); bool DestroyInstrument(INSTRUMENTINDEX nInstr, deleteInstrumentSamples removeSamples); bool RemoveInstrumentSamples(INSTRUMENTINDEX nInstr, SAMPLEINDEX keepSample = SAMPLEINDEX_INVALID); SAMPLEINDEX DetectUnusedSamples(std::vector &sampleUsed) const; SAMPLEINDEX RemoveSelectedSamples(const std::vector &keepSamples); // Set the autovibrato settings for all samples associated to the given instrument. void PropagateXMAutoVibrato(INSTRUMENTINDEX ins, VibratoType type, uint8 sweep, uint8 depth, uint8 rate); // Samples file I/O bool ReadSampleFromFile(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false, bool includeInstrumentFormats = true); bool ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false, FileReader *wsmpChunk = nullptr); protected: bool ReadW64Sample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false); bool ReadPATSample(SAMPLEINDEX nSample, FileReader &file); bool ReadS3ISample(SAMPLEINDEX nSample, FileReader &file); bool ReadSBISample(SAMPLEINDEX sample, FileReader &file); bool ReadCAFSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false); bool ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false); bool ReadAUSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false); bool ReadXISample(SAMPLEINDEX nSample, FileReader &file); bool ReadITSSample(SAMPLEINDEX nSample, FileReader &file, bool rewind = true); bool ReadITISample(SAMPLEINDEX nSample, FileReader &file); bool ReadIFFSample(SAMPLEINDEX sample, FileReader &file, bool allowLittleEndian = true, uint8 octave = uint8_max); bool ReadBRRSample(SAMPLEINDEX sample, FileReader &file); bool ReadFLACSample(SAMPLEINDEX sample, FileReader &file); bool ReadOpusSample(SAMPLEINDEX sample, FileReader &file); bool ReadVorbisSample(SAMPLEINDEX sample, FileReader &file); bool ReadMP3Sample(SAMPLEINDEX sample, FileReader &file, bool raw = false, bool mo3Decode = false); // raw: ignore all encoder-/decodr-delays, decode just raw frames ; mod3Decode: skip metadata and loop-precompute bool ReadMediaFoundationSample(SAMPLEINDEX sample, FileReader &file, bool mo3Decode = false); // mod3Decode: skip metadata and loop-precompute public: #ifdef MODPLUG_TRACKER static std::vector GetMediaFoundationFileTypes(); #endif // MODPLUG_TRACKER #ifndef MODPLUG_NO_FILESAVE bool SaveWAVSample(SAMPLEINDEX nSample, std::ostream &f) const; bool SaveRAWSample(SAMPLEINDEX nSample, std::ostream &f) const; bool SaveFLACSample(SAMPLEINDEX nSample, std::ostream &f) const; bool SaveS3ISample(SAMPLEINDEX smp, std::ostream &f) const; bool SaveIFFSample(SAMPLEINDEX smp, std::ostream &f) const; #endif // Instrument file I/O bool ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize = false); bool ReadSampleAsInstrument(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize = false); protected: bool ReadXIInstrument(INSTRUMENTINDEX nInstr, FileReader &file); bool ReadITIInstrument(INSTRUMENTINDEX nInstr, FileReader &file); bool ReadPATInstrument(INSTRUMENTINDEX nInstr, FileReader &file); bool ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file); public: #ifndef MODPLUG_NO_FILESAVE bool SaveXIInstrument(INSTRUMENTINDEX nInstr, std::ostream &f) const; bool SaveITIInstrument(INSTRUMENTINDEX nInstr, std::ostream &f, const mpt::PathString &filename, bool compress, bool allowExternal) const; bool SaveSFZInstrument(INSTRUMENTINDEX nInstr, std::ostream &f, const mpt::PathString &filename, bool useFLACsamples) const; #endif // I/O from another sound file bool ReadInstrumentFromSong(INSTRUMENTINDEX targetInstr, const CSoundFile &srcSong, INSTRUMENTINDEX sourceInstr); bool ReadSampleFromSong(SAMPLEINDEX targetSample, const CSoundFile &srcSong, SAMPLEINDEX sourceSample); // Period/Note functions uint32 GetNoteFromPeriod(uint32 period, int32 nFineTune = 0, uint32 nC5Speed = 0) const; uint32 GetPeriodFromNote(uint32 note, int32 nFineTune, uint32 nC5Speed) const; uint32 GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPeriodFrac = 0) const; // Misc functions ModSample &GetSample(SAMPLEINDEX sample) { MPT_ASSERT(sample <= m_nSamples && sample < std::size(Samples)); return Samples[sample]; } const ModSample &GetSample(SAMPLEINDEX sample) const { MPT_ASSERT(sample <= m_nSamples && sample < std::size(Samples)); return Samples[sample]; } // Resolve note/instrument combination to real sample index. Return value is guaranteed to be in [0, GetNumSamples()]. SAMPLEINDEX GetSampleIndex(ModCommand::NOTE note, uint32 instr) const noexcept; uint32 MapMidiInstrument(uint8 program, uint16 bank, uint8 midiChannel, uint8 note, bool isXG, std::bitset<32> drumChns); size_t ITInstrToMPT(FileReader &file, ModInstrument &ins, uint16 trkvers); std::pair LoadMixPlugins(FileReader &file, bool ignoreChannelCount = true); #ifndef NO_PLUGINS static void ReadMixPluginChunk(FileReader &file, SNDMIXPLUGIN &plugin); void ProcessMidiOut(CHANNELINDEX nChn); #endif // NO_PLUGINS void ProcessGlobalVolume(samplecount_t countChunk); void ProcessStereoSeparation(samplecount_t countChunk); private: PLUGINDEX GetChannelPlugin(const ModChannel &channel, CHANNELINDEX nChn, PluginMutePriority respectMutes) const; static PLUGINDEX GetActiveInstrumentPlugin(const ModChannel &chn, PluginMutePriority respectMutes); IMixPlugin *GetChannelInstrumentPlugin(const ModChannel &chn) const; public: PLUGINDEX GetBestPlugin(const ModChannel &channel, CHANNELINDEX nChn, PluginPriority priority, PluginMutePriority respectMutes) const; #if defined(MPT_ENABLE_PLAYBACK_TRACE) PlaybackTest CreatePlaybackTest(PlaybackTestSettings settings); #endif // MPT_ENABLE_PLAYBACK_TRACE }; #ifndef NO_PLUGINS inline IMixPlugin* CSoundFile::GetInstrumentPlugin(INSTRUMENTINDEX instr) const noexcept { if(instr > 0 && instr <= GetNumInstruments() && Instruments[instr] && Instruments[instr]->nMixPlug && Instruments[instr]->nMixPlug <= MAX_MIXPLUGINS) return m_MixPlugins[Instruments[instr]->nMixPlug - 1].pMixPlugin; else return nullptr; } #endif // NO_PLUGINS #define FADESONGDELAY 100 MPT_CONSTEXPRINLINE int8 MOD2XMFineTune(int v) { return static_cast(static_cast(v) << 4); } MPT_CONSTEXPRINLINE int8 XM2MODFineTune(int v) { return static_cast(static_cast(v) >> 4); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/PlaybackTest.cpp0000644000175000017500000006700114754313154021202 00000000000000/* * PlaybackTest.cpp * ---------------- * Purpose: Tools for verifying correct playback of modules * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "PlaybackTest.h" #include "../common/mptBaseMacros.h" #if defined(MPT_ENABLE_PLAYBACK_TRACE) #include "../common/FileReader.h" #include "OPL.h" #include "SampleIO.h" #include "Sndfile.h" #include "mpt/base/bit.hpp" #include "mpt/binary/hex.hpp" #include "mpt/crc/crc.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/random/seed.hpp" #include "openmpt/base/Endian.hpp" #include #include #endif // MPT_ENABLE_PLAYBACK_TRACE OPENMPT_NAMESPACE_BEGIN #if defined(MPT_ENABLE_PLAYBACK_TRACE) struct TestDataHeader { static constexpr char TestDataHeaderMagic[] = "OpenMPT Test Data\r\n\x1A"; char magic[std::size(TestDataHeaderMagic) - 1]; uint8 fileVersion; uint8 isAmiga; uint8 positionPrecisionBits; uint8 filterPrecisionBits; uint8 srcMode; uint8 outputChannels; uint16le mixerChannels; uint16le numSamples; uint16le synthVolume; int32le globalVolumeUnity; int32le channelVolumeUnity; uint32le mixingFreq; uint32le mptVersion; }; MPT_BINARY_STRUCT(TestDataHeader, 48) struct TestDataRow { uint32le order; uint32le row; int32le globalVolume; uint32le tickLength; uint8 isFirstTick; uint16le activeChannels; }; MPT_BINARY_STRUCT(TestDataRow, 19) struct TestDataChannel { enum Flags : uint8 { kFilterNone = 0x00, kSurround = 0x01, kOPL = 0x02, kAmigaFilter = 0x04, kFilterLowPass = 0x08, kFilterHighPass = 0x10, kFilterMask = 0x18, }; int16le channel; // Negative = NNA channel (-1 = NNA of first channel, -2 = NNA of second channel, etc.) uint16le nnaAge; // Generation of NNA channels uint8 flags; uint8 srcMode; uint16le sample; int32le leftVol; int32le rightVol; int64le increment; int64le position; int32le filterA0; int32le filterB0; int32le filterB1; bool operator<(const TestDataChannel &other) const noexcept { if(channel == -other.channel) // One is an NNA channel of the other return channel > 0; else if(channel != other.channel) // Completely unrelated channels return std::abs(channel) < std::abs(other.channel); else // Both are NNA channels of the same source channel return nnaAge < other.nnaAge; } }; MPT_BINARY_STRUCT(TestDataChannel, 44) using SampleDataHashAlgorithm = mpt::crc64_jones; using SampleDataHash = mpt::packed; struct PlaybackTestData { struct Row { TestDataRow header; std::vector channels; std::vector oplRegisters; }; TestDataHeader header; std::vector sampleDataHashes; std::vector rows; PlaybackTestSettings GetSettings() const { PlaybackTestSettings result; result.mixingFreq = header.mixingFreq; result.outputChannels = header.outputChannels; result.mixerChannels = header.mixerChannels; result.srcMode = Resampling::ToKnownMode(header.srcMode); return result; } }; class OPLPlaybackLog final : public OPL::IRegisterLogger { public: using OPLData = std::vector; OPLPlaybackLog(const PlayState &playState) : m_playState{playState} {} void Reset() { m_registers.clear(); m_prevRegisters.clear(); m_keyOnToggle.clear(); m_globalRegisters.clear(); m_chnRegisters.clear(); m_prevChnRegisters.clear(); } OPLData DumpRegisters() { OPLData dump; // Dump registers for all channels for(const auto &[chn, registerDump] : m_chnRegisters) { bool first = true; const auto prevRegisters = m_prevChnRegisters.find(chn); for(const auto &[reg, value] : registerDump) { if(prevRegisters != m_prevChnRegisters.end()) { const auto prevRegister = prevRegisters->second.find(reg); if(prevRegister != prevRegisters->second.end() && prevRegister->second == value) continue; } m_prevChnRegisters[chn][reg] = value; if(first) { const auto [sourceChn, nnaGeneration] = chn; MPT_ASSERT(sourceChn < uint8_max); // nnaGeneration may be truncated but it doesn't matter, as it is purely for informational purposes dump.insert(dump.end(), {static_cast(sourceChn), static_cast(nnaGeneration)}); // Was key-on toggled on this channel? dump.push_back(static_cast(m_keyOnToggle.count(chn.first))); first = false; } dump.insert(dump.end(), {reg, value}); } if(!first) dump.push_back(uint8_max); } // Dump global register updates bool first = true; for(const auto reg : m_globalRegisters) { if(!m_prevRegisters.count(reg) || m_registers[reg] != m_prevRegisters[reg]) { if(first) { dump.insert(dump.end(), {uint8_max, uint8_max}); first = false; } dump.insert(dump.end(), {static_cast(reg & 0xFF), static_cast(reg >> 8), m_registers[reg]}); } } for(const auto &[reg, value] : m_registers) { m_prevRegisters[reg] = value; } m_chnRegisters.clear(); m_globalRegisters.clear(); m_registers.clear(); m_keyOnToggle.clear(); return dump; } #if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) // Work-around / // . #pragma GCC push_options #if defined(__OPTIMIZE__) #pragma GCC optimize("O1") #endif #endif static std::string Format(const OPLData &data) { FileReader file(mpt::as_span(data)); std::string result; while(file.CanRead(3)) { const auto [chn, generation] = file.ReadArray(); if(chn == uint8_max && generation == uint8_max) break; result += "[Ch " + mpt::afmt::val(chn); if(generation) result += ":" + mpt::afmt::val(generation); result += "] "; if(file.ReadUint8()) result += "[Toggle] "; while(file.CanRead(2)) { const uint8 reg = file.ReadUint8(); if(reg == uint8_max) break; const uint8 value = file.ReadUint8(); result += mpt::afmt::HEX0<2>(reg) + "=" + mpt::afmt::HEX0<2>(value) + " "; } } if(!file.CanRead(3)) return result; result += "[Global] "; while(file.CanRead(3)) { const uint16 reg = file.ReadUint16LE(); const uint8 value = file.ReadUint8(); result += mpt::afmt::HEX0<2>(reg) + "=" + mpt::afmt::HEX0<2>(value) + " "; } return result; } #if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) #pragma GCC diagnostic pop #pragma GCC pop_options #endif protected: void Port(CHANNELINDEX c, OPL::Register reg, OPL::Value value) override { MPT_ASSERT((OPL::RegisterToVoice(reg) == 0xFF) == (c == CHANNELINDEX_INVALID)); if(c != CHANNELINDEX_INVALID) { if((reg & 0xF0) == OPL::KEYON_BLOCK) { const auto prev = m_prevRegisters.find(reg); const auto current = m_registers.find(reg); if(prev != m_prevRegisters.end() && current != m_registers.end() && (prev->second & OPL::KEYON_BIT) == (value & OPL::KEYON_BIT) && (prev->second & OPL::KEYON_BIT) != (current->second & OPL::KEYON_BIT)) { // Key-On was toggled off and on again within a single frame, which retriggers the note. This needs to be recorded. m_keyOnToggle.insert(c); m_prevRegisters.erase(reg); } } const auto voiceReg = OPL::StripVoiceFromRegister(reg); MPT_ASSERT(voiceReg <= uint8_max); std::pair key{c, uint16(0)}; if(m_playState.Chn[c].nMasterChn) key = {static_cast(m_playState.Chn[c].nMasterChn - 1), m_playState.Chn[c].nnaGeneration}; m_chnRegisters[key][static_cast(voiceReg)] = value; } else { m_globalRegisters.insert(reg); } m_registers[reg] = value; } void MoveChannel(CHANNELINDEX from, CHANNELINDEX to) override { m_prevChnRegisters[{from, m_playState.Chn[to].nnaGeneration}] = std::move(m_prevChnRegisters[{from, uint16(0)}]); } std::map m_registers; // All registers that have been updated in the current tick std::map m_prevRegisters; // Previous state of all registers that have been set so far std::set m_keyOnToggle; // Set of channels on which a key-on -> key-off -> key-on transition was made on this tick std::set m_globalRegisters; // Set of all global registers that have been modified in the current tick std::map, std::map> m_chnRegisters; // Maps [source channel, age] to [voice register, voice value] std::map, std::map> m_prevChnRegisters; // Previous state of registers for this channel const PlayState &m_playState; }; PlaybackTest::PlaybackTest(FileReader file) noexcept(false) { Deserialize(file); } PlaybackTest::PlaybackTest(PlaybackTestData &&testData) : m_testData{std::make_unique(std::move(testData))} { } PlaybackTest::PlaybackTest(PlaybackTest &&other) noexcept : m_testData{std::move(other.m_testData)} { } PlaybackTest::~PlaybackTest() { // This destructor is put here so that we can forward-declare the PlaybackTestData class. } PlaybackTest& PlaybackTest::operator=(PlaybackTest &&other) noexcept { m_testData = std::move(other.m_testData); return *this; } void PlaybackTest::Deserialize(FileReader file) noexcept(false) { file.Rewind(); m_testData = std::make_unique(); auto &header = m_testData->header; file.Read(header); if(memcmp(header.magic, TestDataHeader::TestDataHeaderMagic, sizeof(header.magic))) throw std::runtime_error{"Invalid test data file"}; if(header.fileVersion != 0) throw std::runtime_error{"Invalid test data file version"}; if(!Resampling::IsKnownMode(header.srcMode)) throw std::runtime_error{"Invalid test data: SRC mode"}; if(header.outputChannels <= 0) throw std::runtime_error{"Invalid test data: number of output channels"}; if(header.mixerChannels <= 0) throw std::runtime_error{"Invalid test data: number of mixer channels"}; if(header.mixingFreq <= 0) throw std::runtime_error{"Invalid test data: mixing frequency"}; if(header.globalVolumeUnity <= 0) throw std::runtime_error{"Invalid test data: global volume unity"}; if(header.channelVolumeUnity <= 0) throw std::runtime_error{"Invalid test data: channel volume unity"}; file.ReadVector(m_testData->sampleDataHashes, header.numSamples); while(!file.EndOfFile()) { auto &row = m_testData->rows.emplace_back(); file.Read(row.header); file.ReadVector(row.channels, row.header.activeChannels); uint32 oplDataSize = 0; file.ReadVarInt(oplDataSize); file.ReadVector(row.oplRegisters, oplDataSize); } } void PlaybackTest::Serialize(std::ostream &output) const noexcept(false) { mpt::IO::Write(output, m_testData->header); mpt::IO::Write(output, m_testData->sampleDataHashes); for(const auto &row : m_testData->rows) { mpt::IO::Write(output, row.header); mpt::IO::Write(output, row.channels); mpt::IO::WriteVarInt(output, row.oplRegisters.size()); mpt::IO::Write(output, row.oplRegisters); } } void PlaybackTest::ToTSV(std::ostream &output) const noexcept(false) { const auto &header = m_testData->header; const auto positionPrecision = 1.0 / (int64(1) << header.positionPrecisionBits); const auto filterPrecision = 1.0 / (int64(1) << header.filterPrecisionBits); static constexpr int floatPrecision = 10; const auto floatFormat = mpt::format_simple_spec().SetPrecision(floatPrecision); output << std::setprecision(floatPrecision); output << "OpenMPT Test Data version " << mpt::afmt::val(header.fileVersion) << "\n" "Created by OpenMPT " << mpt::ToCharset(mpt::Charset::UTF8, Version::Current().ToUString()) << "\n" "isAmiga\t" << mpt::afmt::val(header.isAmiga) << "\n" "srcMode\t" << mpt::afmt::val(header.srcMode) << "\n" "outputChannels\t" << mpt::afmt::val(header.outputChannels) << "\n" "mixerChannels\t" << header.mixerChannels << "\n" "synthVolume\t" << header.synthVolume << "\n" "mixingFreq\t" << header.mixingFreq << "\n" "\nSample data hashes:\n"; for(SAMPLEINDEX smp = 1; smp <= header.numSamples; smp++) output << mpt::ToCharset(mpt::Charset::UTF8, mpt::encode_hex(mpt::as_raw_memory(m_testData->sampleDataHashes[smp - 1]))) << "\t" << smp << "\n"; output << "\nChannel data:\n" "index\torder\trow\ttick\tglobalVolume\ttickLength\tchannel\tsample\tleftVol\trightVol\tsurround\tspeed\tposition\tfilterType\tfilterA0\tfilterB0\tfilterB1\tsrcMode\toplRegisters\n"; uint32 tick = 0, rowIndex = 0; for(const auto &row : m_testData->rows) { if(row.header.isFirstTick) tick = 0; const auto headerFormat = MPT_AFORMAT("{}\t{}\t{}\t{}\t{}\t{}\t"); const auto channelHeaderFirst = headerFormat(rowIndex, row.header.order, row.header.row, tick, row.header.globalVolume, Util::muldivr_unsigned(row.header.tickLength, 100000, header.mixingFreq)); const auto channelHeaderFollow = headerFormat("", "", "", "", "", ""); tick++; rowIndex++; bool first = true; if(!row.oplRegisters.empty()) { output << channelHeaderFirst << "\t\t\t\t\t\t\t\t\t\t\t\t" << OPLPlaybackLog::Format(row.oplRegisters); output << "\n"; first = false; } else if(row.channels.empty()) { output << channelHeaderFirst << "--\n"; } for(const auto &channel : row.channels) { output << (first ? channelHeaderFirst : channelHeaderFollow); first = false; const char *filterType; switch(channel.flags & TestDataChannel::kFilterMask) { case TestDataChannel::kFilterNone: filterType = "--"; break; case TestDataChannel::kFilterLowPass: filterType = "LP"; break; case TestDataChannel::kFilterHighPass: filterType = "HP"; break; default: throw std::runtime_error{"Unknown filter type in test data"}; } output << std::abs(channel.channel) << (channel.channel < 0 ? "[NNA]" : "") << "\t" << channel.sample << "\t" << channel.leftVol << "\t" << channel.rightVol << "\t" << ((channel.flags & TestDataChannel::kSurround) ? "yes" : "no") << "\t" << (static_cast(channel.increment) * positionPrecision * header.mixingFreq) << "\t" << ((channel.flags & TestDataChannel::kOPL) ? "OPL" : mpt::afmt::fmt(static_cast(channel.position) * positionPrecision, floatFormat)) << "\t" << filterType << "\t" << channel.filterA0 * filterPrecision << "\t" << channel.filterB0 * filterPrecision << "\t" << channel.filterB1 * filterPrecision << "\t" << mpt::afmt::val(channel.srcMode) << "\n"; } } } PlaybackTestSettings PlaybackTest::GetSettings() const noexcept { return m_testData->GetSettings(); } static bool FuzzyEquals(const double left, const double right, const double epsilon) noexcept { return std::abs(left - right) <= std::min(std::abs(left), std::abs(right)) * epsilon; } #define MPT_LOG_TEST(propName, left, right) \ errors.push_back(mpt::ToUnicode(mpt::Charset::UTF8, MPT_AFORMAT("{} differs: {} vs {}") \ (propName, left, right))); #define MPT_LOG_TEST_WITH_ROW(propName, left, right) \ errors.push_back(mpt::ToUnicode(mpt::Charset::UTF8, MPT_AFORMAT("{} differs in test row {} (order {}, row {}, tick {}): {} vs {}") \ (propName, row, lRow.header.order, lRow.header.row, lTick, left, right))); #define MPT_LOG_TEST_WITH_ROW_CHN(propName, left, right) \ errors.push_back(mpt::ToUnicode(mpt::Charset::UTF8, MPT_AFORMAT("{} differs in test row {} (order {}, row {}, tick {}), channel {}: {} vs {}") \ (propName, row, lRow.header.order, lRow.header.row, lTick, chn, left, right))); std::vector PlaybackTest::Compare(const PlaybackTest &lhs, const PlaybackTest &rhs) { return lhs.Compare(rhs); } std::vector PlaybackTest::Compare(const PlaybackTest &otherTest) const { const auto &other = *otherTest.m_testData; const auto &header = m_testData->header; std::vector errors; if(header.mixingFreq != other.header.mixingFreq) return {MPT_UFORMAT("Mixing frequency differs ({} vs {}), not even going to try to compare them")(header.mixingFreq, other.header.mixingFreq)}; if(header.outputChannels != other.header.outputChannels) return {MPT_UFORMAT("Output channel layout differs ({} vs {} channels), not even going to try to compare them")(header.outputChannels, other.header.outputChannels)}; if(header.mixerChannels != other.header.mixerChannels) errors.push_back(MPT_UFORMAT("Mixer channel limit differs ({} vs {} channels), results may differ in case of channel starvation")(header.mixerChannels, other.header.mixerChannels)); if(header.srcMode != other.header.srcMode) errors.push_back(MPT_UFORMAT("Default SRC mode differs ({} vs {} channels), results may differ")(header.srcMode, other.header.srcMode)); const auto lPositionPrecision = 1.0 / (int64(1) << header.positionPrecisionBits); const auto rPositionPrecision = 1.0 / (int64(1) << other.header.positionPrecisionBits); const auto lFilterPrecision = 1.0 / (int64(1) << header.filterPrecisionBits); const auto rFilterPrecision = 1.0 / (int64(1) << other.header.filterPrecisionBits); const auto lGlobalVolumeScale = 1.0 / header.globalVolumeUnity; const auto rGlobalVolumeScale = 1.0 / other.header.globalVolumeUnity; const auto lChannelVolumeScale = 1.0 / header.channelVolumeUnity; const auto rChannelVolumeScale = 1.0 / other.header.channelVolumeUnity; const auto epsilon = 0.000001; if(header.isAmiga != other.header.isAmiga) MPT_LOG_TEST("Amiga mode", header.isAmiga, other.header.isAmiga); if(header.synthVolume != other.header.synthVolume) MPT_LOG_TEST("Synth volume", header.synthVolume, other.header.synthVolume); if(m_testData->sampleDataHashes.size() != other.sampleDataHashes.size()) MPT_LOG_TEST("Number of sample slots", m_testData->sampleDataHashes.size(), other.sampleDataHashes.size()); for(size_t smp = 0; smp < std::min(m_testData->sampleDataHashes.size(), other.sampleDataHashes.size()); smp++) { if(m_testData->sampleDataHashes[smp] != other.sampleDataHashes[smp]) errors.push_back(MPT_UFORMAT("Sample hash in slot {} differs: {} vs {}")(smp + 1, mpt::encode_hex(mpt::as_raw_memory(m_testData->sampleDataHashes[smp])), mpt::encode_hex(mpt::as_raw_memory(other.sampleDataHashes[smp])))); } uint64 lDuration = 0, rDuration = 0; uint32 lTick = 0, rTick = 0; if(m_testData->rows.size() != other.rows.size()) MPT_LOG_TEST("Number of test rows", m_testData->rows.size(), other.rows.size()); for(size_t row = 0; row < std::min(m_testData->rows.size(), other.rows.size()); row++) { const auto &lRow = m_testData->rows[row], &rRow = other.rows[row]; if(lRow.header.isFirstTick) lTick = 0; if(rRow.header.isFirstTick) rTick = 0; if(lRow.header.order != rRow.header.order || lRow.header.row != rRow.header.row || lRow.header.isFirstTick != rRow.header.isFirstTick) errors.push_back(MPT_UFORMAT("Play position differs in test row {} (order {}, row {}, tick {} vs order {}, row {}, tick {})")(row, lRow.header.order, lRow.header.row, lTick, rRow.header.order, rRow.header.row, rTick)); if(const auto l = lRow.header.globalVolume * lGlobalVolumeScale, r = rRow.header.globalVolume * rGlobalVolumeScale; !FuzzyEquals(l, r, epsilon)) MPT_LOG_TEST_WITH_ROW("Global volume", l, r); if(std::abs(static_cast(lRow.header.tickLength) - static_cast(rRow.header.tickLength)) > 1) { const auto lTickLength = Util::muldivr_unsigned(lRow.header.tickLength, 1'000'000, header.mixingFreq); const auto rTickLength = Util::muldivr_unsigned(rRow.header.tickLength, 1'000'000, other.header.mixingFreq); MPT_LOG_TEST_WITH_ROW("Tick length", mpt::afmt::val(lTickLength) + "us", mpt::afmt::val(rTickLength) + "us"); } if(lRow.oplRegisters != rRow.oplRegisters) { MPT_LOG_TEST_WITH_ROW("OPL register log", OPLPlaybackLog::Format(lRow.oplRegisters), OPLPlaybackLog::Format(rRow.oplRegisters)) } if(lRow.channels.size() != rRow.channels.size()) MPT_LOG_TEST_WITH_ROW("Number of active voices", lRow.channels.size(), rRow.channels.size()); for(size_t chn = 0; chn < std::min(lRow.channels.size(), rRow.channels.size()); chn++) { const auto &lChn = lRow.channels[chn], &rChn = rRow.channels[chn]; if(lChn.channel != rChn.channel) MPT_LOG_TEST_WITH_ROW_CHN("Source channel", lChn.channel, rChn.channel); if(lChn.flags != rChn.flags) MPT_LOG_TEST_WITH_ROW_CHN("Flags", lChn.flags, rChn.flags); if(lChn.srcMode != rChn.srcMode) MPT_LOG_TEST_WITH_ROW_CHN("SRC mode", lChn.srcMode, rChn.srcMode); if(lChn.sample != rChn.sample) MPT_LOG_TEST_WITH_ROW_CHN("Sample", lChn.sample, rChn.sample); if(const auto l = lChn.leftVol * lChannelVolumeScale, r = rChn.leftVol * rChannelVolumeScale; !FuzzyEquals(l, r, epsilon)) MPT_LOG_TEST_WITH_ROW_CHN("Left volume", l, r); if(const auto l = lChn.rightVol * lChannelVolumeScale, r = rChn.rightVol * rChannelVolumeScale; !FuzzyEquals(l, r, epsilon)) MPT_LOG_TEST_WITH_ROW_CHN("Right volume", l, r); if(const auto l = static_cast(lChn.increment) * lPositionPrecision * header.mixingFreq, r = static_cast(rChn.increment) * rPositionPrecision * other.header.mixingFreq; !FuzzyEquals(l, r, epsilon)) MPT_LOG_TEST_WITH_ROW_CHN("Speed", l, r); if(const auto l = static_cast(lChn.position) * lPositionPrecision, r = static_cast(rChn.position) * rPositionPrecision; !FuzzyEquals(l, r, epsilon)) MPT_LOG_TEST_WITH_ROW_CHN("Position", l, r); if(const auto l = lChn.filterA0 * lFilterPrecision, r = rChn.filterA0 * rFilterPrecision; !FuzzyEquals(l, r, epsilon)) MPT_LOG_TEST_WITH_ROW_CHN("Filter A0", l, r); if(const auto l = lChn.filterB0 * lFilterPrecision, r = rChn.filterB0 * rFilterPrecision; !FuzzyEquals(l, r, epsilon)) MPT_LOG_TEST_WITH_ROW_CHN("Filter B0", l, r); if(const auto l = lChn.filterB1 * lFilterPrecision, r = rChn.filterB1 * rFilterPrecision; !FuzzyEquals(l, r, epsilon)) MPT_LOG_TEST_WITH_ROW_CHN("Filter B1", l, r); } lDuration += lRow.header.tickLength; rDuration += rRow.header.tickLength; lTick++; rTick++; } if(const auto l = static_cast(lDuration) / header.mixingFreq, r = static_cast(rDuration) / other.header.mixingFreq; !FuzzyEquals(l, r, epsilon)) MPT_LOG_TEST("Total duration", mpt::afmt::val(l) + "s", mpt::afmt::val(r) + "s"); return errors; } PlaybackTest CSoundFile::CreatePlaybackTest(PlaybackTestSettings settings) { settings.Sanitize(); PlaybackTestData testData{}; m_bIsRendering = true; const auto origResamplerSettings = m_Resampler.m_Settings; m_Resampler.m_Settings.SrcMode = settings.srcMode; m_Resampler.m_Settings.emulateAmiga = m_SongFlags[SONG_ISAMIGA] ? Resampling::AmigaFilter::A1200 : Resampling::AmigaFilter::Off; const auto origMixerSettings = m_MixerSettings; MixerSettings testSettings; testSettings.gdwMixingFreq = settings.mixingFreq; testSettings.gnChannels = settings.outputChannels; testSettings.m_nMaxMixChannels = settings.mixerChannels; testSettings.VolumeRampUpMicroseconds = 0; testSettings.VolumeRampDownMicroseconds = 0; SetMixerSettings(testSettings); const auto origRepeatCount = GetRepeatCount(); SetRepeatCount(0); auto origPRNG = std::move(m_PRNG); mpt::deterministic_random_device rd; m_PRNG = mpt::make_prng(rd); auto origPlayState = std::make_unique(std::move(m_PlayState)); mpt::reconstruct(m_PlayState); ResetPlayPos(); auto origOPL = std::move(m_opl); OPLPlaybackLog oplLogger{m_PlayState}; auto &header = testData.header; memcpy(header.magic, TestDataHeader::TestDataHeaderMagic, sizeof(header.magic)); header.fileVersion = 0; header.isAmiga = m_SongFlags[SONG_ISAMIGA] ? 1 : 0; header.positionPrecisionBits = static_cast(mpt::bit_width(static_cast::type>(SamplePosition{1, 0}.GetRaw())) - 1); header.filterPrecisionBits = MIXING_FILTER_PRECISION; header.srcMode = m_Resampler.m_Settings.SrcMode; header.outputChannels = static_cast(m_MixerSettings.gnChannels); header.mixerChannels = static_cast(m_MixerSettings.m_nMaxMixChannels); header.synthVolume = static_cast(m_nVSTiVolume); header.globalVolumeUnity = MAX_GLOBAL_VOLUME; header.channelVolumeUnity = 16384; header.mixingFreq = m_MixerSettings.gdwMixingFreq; header.mptVersion = Version::Current().GetRawVersion(); header.numSamples = GetNumSamples(); testData.sampleDataHashes.reserve(GetNumSamples()); for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { SampleDataHashAlgorithm hasher; const ModSample &sample = Samples[smp]; if(sample.uFlags[CHN_ADLIB]) { hasher.process(mpt::as_raw_memory(sample.adlib)); } else { std::ostringstream ss{std::ios::out | std::ios::binary}; SampleIO{sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, sample.uFlags[CHN_STEREO] ? SampleIO::stereoInterleaved : SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM} .WriteSample(ss, sample); const auto s = std::move(ss).str(); hasher.process(mpt::byte_cast(mpt::as_span(s))); } SampleDataHash result; result.set(hasher.result()); testData.sampleDataHashes.push_back(result); } for(const auto &song : GetAllSubSongs()) { oplLogger.Reset(); m_opl = std::make_unique(oplLogger); ResetPlayPos(); GetLength(eAdjust, GetLengthTarget(song.startOrder, song.startRow).StartPos(song.sequence, 0, 0)); m_PlayState.m_flags.reset(); while(ReadOneTick()) { auto &row = testData.rows.emplace_back(); row.header.order = m_PlayState.m_nCurrentOrder; row.header.row = m_PlayState.m_nRow; row.header.globalVolume = m_PlayState.m_nGlobalVolume; row.header.tickLength = m_PlayState.m_nSamplesPerTick; row.header.isFirstTick = m_PlayState.m_nTickCount ? 0 : 1; row.header.activeChannels = static_cast(std::count_if(std::begin(m_PlayState.Chn), std::end(m_PlayState.Chn), [](const auto &chn) { return chn.nLength != 0; })); row.channels.reserve(row.header.activeChannels); for(CHANNELINDEX chn = 0; chn < MAX_CHANNELS; chn++) { if(!m_PlayState.Chn[chn].nLength) continue; auto &channel = m_PlayState.Chn[chn]; auto &channelData = row.channels.emplace_back(); channelData.channel = static_cast(channel.nMasterChn ? -static_cast(channel.nMasterChn) : (chn + 1)); channelData.nnaAge = channel.nnaGeneration; if(channel.dwFlags[CHN_SURROUND]) channelData.flags |= TestDataChannel::kSurround; if(channel.dwFlags[CHN_ADLIB]) channelData.flags |= TestDataChannel::kOPL; if(channel.dwFlags[CHN_AMIGAFILTER]) channelData.flags |= TestDataChannel::kAmigaFilter; channelData.srcMode = channel.resamplingMode; channelData.sample = static_cast(std::distance(&static_cast(Samples[0]), channel.pModSample)); channelData.leftVol = channel.newLeftVol; channelData.rightVol = channel.newRightVol; channelData.increment = channel.increment.GetRaw(); channelData.position = channel.position.GetRaw(); if(channel.dwFlags[CHN_FILTER]) channelData.flags |= (channel.nFilter_HP ? TestDataChannel::kFilterHighPass : TestDataChannel::kFilterLowPass); channelData.filterA0 = channel.nFilter_A0; channelData.filterB0 = channel.nFilter_B0; channelData.filterB1 = channel.nFilter_B1; } std::sort(row.channels.begin(), row.channels.end()); row.oplRegisters = oplLogger.DumpRegisters(); } } m_opl = std::move(origOPL); m_PlayState = std::move(*origPlayState); m_PRNG = std::move(origPRNG); SetRepeatCount(origRepeatCount); SetMixerSettings(origMixerSettings); m_Resampler.m_Settings = origResamplerSettings; m_bIsRendering = false; return PlaybackTest{std::move(testData)}; } #else // !MPT_ENABLE_PLAYBACK_TRACE MPT_MSVC_WORKAROUND_LNK4221(PlaybackTest) #endif // MPT_ENABLE_PLAYBACK_TRACE OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/tuning.h0000644000175000017500000001745514716716436017605 00000000000000/* * tuning.h * -------- * Purpose: Alternative sample tuning. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include #include "tuningbase.h" OPENMPT_NAMESPACE_BEGIN namespace Tuning { class CTuning { public: static constexpr char s_FileExtension[5] = ".tun"; static constexpr RATIOTYPE s_DefaultFallbackRatio = 1.0f; static constexpr NOTEINDEXTYPE s_NoteMinDefault = -64; static constexpr UNOTEINDEXTYPE s_RatioTableSizeDefault = 128; static constexpr USTEPINDEXTYPE s_RatioTableFineSizeMaxDefault = 1000; public: CTuning(CTuning &) = default; CTuning(CTuning &&) noexcept = default; bool operator==(const CTuning &other) const noexcept; bool operator!=(const CTuning &other) const noexcept { return !(*this == other); } // To return ratio of certain note. RATIOTYPE GetRatio(const NOTEINDEXTYPE note) const; // To return ratio from a 'step'(noteindex + stepindex) RATIOTYPE GetRatio(const NOTEINDEXTYPE baseNote, const STEPINDEXTYPE baseFineSteps) const; //Tuning might not be valid for arbitrarily large range, //so this can be used to ask where it is valid. Tells the lowest and highest //note that are valid. MPT_FORCEINLINE NoteRange GetNoteRange() const { return NoteRange{m_NoteMin, static_cast(m_NoteMin + static_cast(m_RatioTable.size()) - 1)}; } // Return true if note is within note range MPT_FORCEINLINE bool IsValidNote(const NOTEINDEXTYPE n) const { return (GetNoteRange().first <= n && n <= GetNoteRange().last); } MPT_FORCEINLINE UNOTEINDEXTYPE GetGroupSize() const { return m_GroupSize; } RATIOTYPE GetGroupRatio() const {return m_GroupRatio;} // To return (fine)stepcount between two consecutive mainsteps. MPT_FORCEINLINE USTEPINDEXTYPE GetFineStepCount() const { return m_FineStepCount; } //To return 'directed distance' between given notes. STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& from, const NOTEINDEXTYPE& to) const {return (to - from)*(static_cast(GetFineStepCount())+1);} //To return 'directed distance' between given steps. STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& noteFrom, const STEPINDEXTYPE& stepDistFrom, const NOTEINDEXTYPE& noteTo, const STEPINDEXTYPE& stepDistTo) const {return GetStepDistance(noteFrom, noteTo) + stepDistTo - stepDistFrom;} //To set finestepcount between two consecutive mainsteps. //Finestep count == 0 means that //stepdistances become the same as note distances. void SetFineStepCount(const USTEPINDEXTYPE& fs); // Multiply all ratios by given number. bool Multiply(const RATIOTYPE r); bool SetRatio(const NOTEINDEXTYPE& s, const RATIOTYPE& r); MPT_FORCEINLINE Tuning::Type GetType() const { return m_TuningType; } mpt::ustring GetNoteName(const NOTEINDEXTYPE &x, bool addOctave = true) const; void SetNoteName(const NOTEINDEXTYPE &, const mpt::ustring &); static std::unique_ptr CreateDeserialize(std::istream &f, mpt::Charset defaultCharset) { std::unique_ptr pT = std::unique_ptr(new CTuning()); if(pT->InitDeserialize(f, defaultCharset) != SerializationResult::Success) { return nullptr; } return pT; } //Try to read old version (v.3) and return pointer to new instance if succesfull, else nullptr. static std::unique_ptr CreateDeserializeOLD(std::istream &f, mpt::Charset defaultCharset) { std::unique_ptr pT = std::unique_ptr(new CTuning()); if(pT->InitDeserializeOLD(f, defaultCharset) != SerializationResult::Success) { return nullptr; } return pT; } static std::unique_ptr CreateGeneral(const mpt::ustring &name) { std::unique_ptr pT = std::unique_ptr(new CTuning()); pT->SetName(name); return pT; } static std::unique_ptr CreateGroupGeometric(const mpt::ustring &name, UNOTEINDEXTYPE groupsize, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount) { std::unique_ptr pT = std::unique_ptr(new CTuning()); pT->SetName(name); if(!pT->CreateGroupGeometric(groupsize, groupratio, 0)) { return nullptr; } pT->SetFineStepCount(finestepcount); return pT; } static std::unique_ptr CreateGroupGeometric(const mpt::ustring &name, const std::vector &ratios, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount) { std::unique_ptr pT = std::unique_ptr(new CTuning()); pT->SetName(name); NoteRange range = NoteRange{s_NoteMinDefault, static_cast(s_NoteMinDefault + s_RatioTableSizeDefault - 1)}; range.last = std::max(range.last, mpt::saturate_cast(ratios.size() - 1)); range.first = 0 - range.last - 1; if(!pT->CreateGroupGeometric(ratios, groupratio, range, 0)) { return nullptr; } pT->SetFineStepCount(finestepcount); return pT; } static std::unique_ptr CreateGeometric(const mpt::ustring &name, UNOTEINDEXTYPE groupsize, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount) { std::unique_ptr pT = std::unique_ptr(new CTuning()); pT->SetName(name); if(!pT->CreateGeometric(groupsize, groupratio)) { return nullptr; } pT->SetFineStepCount(finestepcount); return pT; } Tuning::SerializationResult Serialize(std::ostream& out) const; #ifdef MODPLUG_TRACKER bool WriteSCL(std::ostream &f, const mpt::PathString &filename) const; #endif bool ChangeGroupsize(const NOTEINDEXTYPE&); bool ChangeGroupRatio(const RATIOTYPE&); void SetName(const mpt::ustring &s) { m_TuningName = s; } mpt::ustring GetName() const { return m_TuningName; } private: CTuning(); SerializationResult InitDeserialize(std::istream &inStrm, mpt::Charset defaultCharset); //Try to read old version (v.3) and return pointer to new instance if succesfull, else nullptr. SerializationResult InitDeserializeOLD(std::istream &inStrm, mpt::Charset defaultCharset); //Create GroupGeometric tuning of *this using virtual ProCreateGroupGeometric. bool CreateGroupGeometric(const std::vector &v, const RATIOTYPE &r, const NoteRange &range, const NOTEINDEXTYPE &ratiostartpos); //Create GroupGeometric of *this using ratios from 'itself' and ratios starting from //position given as third argument. bool CreateGroupGeometric(const NOTEINDEXTYPE &s, const RATIOTYPE &r, const NOTEINDEXTYPE &startindex); //Create geometric tuning of *this using ratio(0) = 1. bool CreateGeometric(const UNOTEINDEXTYPE &p, const RATIOTYPE &r); bool CreateGeometric(const UNOTEINDEXTYPE &s, const RATIOTYPE &r, const NoteRange &range); void UpdateFineStepTable(); // GroupPeriodic-specific. // Get the corresponding note in [0, period-1]. // For example GetRefNote(-1) is to return note :'groupsize-1'. MPT_FORCEINLINE NOTEINDEXTYPE GetRefNote(NOTEINDEXTYPE note) const { MPT_ASSERT(GetType() == Type::GROUPGEOMETRIC || GetType() == Type::GEOMETRIC); return static_cast(mpt::wrapping_modulo(note, GetGroupSize())); } static bool IsValidRatio(RATIOTYPE ratio) { // Arbitrary epsilon > 0 to avoid NaNs and infinite values in ratio calculation return (ratio > static_cast(0.02f)); } private: Tuning::Type m_TuningType = Type::GENERAL; //Noteratios std::vector m_RatioTable; //'Fineratios' std::vector m_RatioTableFine; // The lowest index of note in the table NOTEINDEXTYPE m_NoteMin = s_NoteMinDefault; //For groupgeometric tunings, tells the 'group size' and 'group ratio' //m_GroupSize should always be >= 0. NOTEINDEXTYPE m_GroupSize = 0; RATIOTYPE m_GroupRatio = 0; USTEPINDEXTYPE m_FineStepCount = 0; // invariant: 0 <= m_FineStepCount <= FINESTEPCOUNT_MAX mpt::ustring m_TuningName; std::map m_NoteNameMap; }; // class CTuning } // namespace Tuning OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/XMTools.cpp0000644000175000017500000003130014726355054020156 00000000000000/* * XMTools.cpp * ----------- * Purpose: Definition of XM file structures and helper functions * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "XMTools.h" #include "Loaders.h" #include "Sndfile.h" #include "../common/version.h" #include OPENMPT_NAMESPACE_BEGIN // Convert OpenMPT's internal envelope representation to XM envelope data. void XMInstrument::ConvertEnvelopeToXM(const InstrumentEnvelope &mptEnv, uint8le &numPoints, uint8le &flags, uint8le &sustain, uint8le &loopStart, uint8le &loopEnd, EnvType env) { numPoints = static_cast(std::min(std::size_t(12), static_cast(mptEnv.size()))); // Envelope Data for(uint8 i = 0; i < numPoints; i++) { switch(env) { case EnvTypeVol: volEnv[i * 2] = std::min(mptEnv[i].tick, uint16_max); volEnv[i * 2 + 1] = std::min(mptEnv[i].value, uint8(64)); break; case EnvTypePan: panEnv[i * 2] = std::min(mptEnv[i].tick, uint16_max); panEnv[i * 2 + 1] = std::min(mptEnv[i].value, uint8(63)); break; } } // Envelope Flags if(mptEnv.dwFlags[ENV_ENABLED]) flags |= XMInstrument::envEnabled; if(mptEnv.dwFlags[ENV_SUSTAIN]) flags |= XMInstrument::envSustain; if(mptEnv.dwFlags[ENV_LOOP]) flags |= XMInstrument::envLoop; // Envelope Loops sustain = std::min(uint8(12), mptEnv.nSustainStart); loopStart = std::min(uint8(12), mptEnv.nLoopStart); loopEnd = std::min(uint8(12), mptEnv.nLoopEnd); } // Convert OpenMPT's internal sample representation to an XMInstrument. XMInstrument::SampleList XMInstrument::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport) { MemsetZero(*this); // FFF is maximum in the FT2 GUI, but it can also accept other values. MilkyTracker just allows 0...4095 and 32767 ("cut") volFade = static_cast(std::min(mptIns.nFadeOut, uint32(32767))); // Convert envelopes ConvertEnvelopeToXM(mptIns.VolEnv, volPoints, volFlags, volSustain, volLoopStart, volLoopEnd, EnvTypeVol); ConvertEnvelopeToXM(mptIns.PanEnv, panPoints, panFlags, panSustain, panLoopStart, panLoopEnd, EnvTypePan); if(mptIns.nMidiChannel != MidiNoChannel) { midiEnabled = 1; midiChannel = (mptIns.nMidiChannel != MidiMappedChannel ? (mptIns.nMidiChannel - MidiFirstChannel) : 0); } midiProgram = (mptIns.nMidiProgram != 0 ? mptIns.nMidiProgram - 1 : 0); pitchWheelRange = std::min(mptIns.midiPWD, int8(36)); // Create sample assignment table const auto sampleList = GetSampleList(mptIns, compatibilityExport); for(std::size_t i = 0; i < std::size(sampleMap); i++) { if(mptIns.Keyboard[i + 12] > 0) { auto sample = std::find(sampleList.samples.begin(), sampleList.samples.end(), mptIns.Keyboard[i + 12]); if(sample != sampleList.samples.end()) { // Yep, we want to export this sample. sampleMap[i] = static_cast(std::distance(sampleList.samples.begin(), sample)); } } } return sampleList; } // Get a list of samples that should be written to the file. XMInstrument::SampleList XMInstrument::GetSampleList(const ModInstrument &mptIns, bool compatibilityExport) const { SampleList sampleList; // List of samples associated with this instrument std::vector addedToList; // Which samples did we already add to the sample list? for(std::size_t i = 0; i < std::size(sampleMap); i++) { const SAMPLEINDEX smp = mptIns.Keyboard[i + 12]; if(smp == 0) continue; if(smp > addedToList.size()) addedToList.resize(smp, false); if(addedToList[smp - 1]) continue; // We haven't considered this sample yet. addedToList[smp - 1] = true; if(sampleList.samples.size() < (compatibilityExport ? 16u : 32u)) sampleList.samples.push_back(smp); else sampleList.tooManySamples = true; } // FT2 completely ignores MIDI settings (and also the less important stuff) if not at least one (empty) sample is assigned to this instrument! if(sampleList.samples.empty() && compatibilityExport && midiEnabled) sampleList.samples.assign(1, 0); return sampleList; } // Convert XM envelope data to an OpenMPT's internal envelope representation. void XMInstrument::ConvertEnvelopeToMPT(InstrumentEnvelope &mptEnv, uint8 numPoints, uint8 flags, uint8 sustain, uint8 loopStart, uint8 loopEnd, EnvType env) const { mptEnv.resize(std::min(numPoints, uint8(12))); // Envelope Data for(uint32 i = 0; i < mptEnv.size(); i++) { switch(env) { case EnvTypeVol: mptEnv[i].tick = volEnv[i * 2]; mptEnv[i].value = static_cast(volEnv[i * 2 + 1]); break; case EnvTypePan: mptEnv[i].tick = panEnv[i * 2]; mptEnv[i].value = static_cast(panEnv[i * 2 + 1]); break; } if(i > 0 && mptEnv[i].tick < mptEnv[i - 1].tick && !(mptEnv[i].tick & 0xFF00)) { // libmikmod code says: "Some broken XM editing program will only save the low byte of the position // value. Try to compensate by adding the missing high byte." // Note: MPT 1.07's XI instrument saver omitted the high byte of envelope nodes. // This might be the source for some broken envelopes in IT and XM files. mptEnv[i].tick |= static_cast(mptEnv[i - 1].tick & 0xFF00u); if(mptEnv[i].tick < mptEnv[i - 1].tick) mptEnv[i].tick += 0x100; } } // Envelope Flags mptEnv.dwFlags.reset(); if((flags & XMInstrument::envEnabled) != 0 && !mptEnv.empty()) mptEnv.dwFlags.set(ENV_ENABLED); // Envelope Loops if(sustain < 12) { if((flags & XMInstrument::envSustain) != 0) mptEnv.dwFlags.set(ENV_SUSTAIN); mptEnv.nSustainStart = mptEnv.nSustainEnd = sustain; } if(loopEnd < 12 && loopEnd >= loopStart) { if((flags & XMInstrument::envLoop) != 0) mptEnv.dwFlags.set(ENV_LOOP); mptEnv.nLoopStart = loopStart; mptEnv.nLoopEnd = loopEnd; } } // Convert an XMInstrument to OpenMPT's internal instrument representation. void XMInstrument::ConvertToMPT(ModInstrument &mptIns) const { mptIns.nFadeOut = volFade; // Convert envelopes ConvertEnvelopeToMPT(mptIns.VolEnv, volPoints, volFlags, volSustain, volLoopStart, volLoopEnd, EnvTypeVol); ConvertEnvelopeToMPT(mptIns.PanEnv, panPoints, panFlags, panSustain, panLoopStart, panLoopEnd, EnvTypePan); // Create sample assignment table for(std::size_t i = 0; i < std::size(sampleMap); i++) { mptIns.Keyboard[i + 12] = sampleMap[i]; } if(midiEnabled) { mptIns.nMidiChannel = midiChannel + MidiFirstChannel; Limit(mptIns.nMidiChannel, uint8(MidiFirstChannel), uint8(MidiLastChannel)); mptIns.nMidiProgram = static_cast(std::min(static_cast(midiProgram), uint16(127)) + 1); } mptIns.midiPWD = static_cast(pitchWheelRange); } // Apply auto-vibrato settings from sample to file. void XMInstrument::ApplyAutoVibratoToXM(const ModSample &mptSmp, MODTYPE fromType) { vibType = mptSmp.nVibType; vibSweep = mptSmp.nVibSweep; vibDepth = mptSmp.nVibDepth; vibRate = mptSmp.nVibRate; if((vibDepth | vibRate) != 0 && !(fromType & MOD_TYPE_XM)) { if(mptSmp.nVibSweep != 0) vibSweep = mpt::saturate_cast(Util::muldivr_unsigned(mptSmp.nVibDepth, 256, mptSmp.nVibSweep)); else vibSweep = 255; } } // Apply auto-vibrato settings from file to a sample. void XMInstrument::ApplyAutoVibratoToMPT(ModSample &mptSmp) const { mptSmp.nVibType = static_cast(vibType.get()); mptSmp.nVibSweep = vibSweep; mptSmp.nVibDepth = vibDepth; mptSmp.nVibRate = vibRate; } // Write stuff to the header that's always necessary (also for empty instruments) void XMInstrumentHeader::Finalise() { size = sizeof(XMInstrumentHeader); if(numSamples > 0) { sampleHeaderSize = sizeof(XMSample); } else { if(!instrument.midiEnabled) size -= sizeof(XMInstrument); sampleHeaderSize = 0; } } // Convert OpenMPT's internal sample representation to an XMInstrumentHeader. XMInstrument::SampleList XMInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport) { const auto sampleList = instrument.ConvertToXM(mptIns, compatibilityExport); numSamples = static_cast(sampleList.samples.size()); mpt::String::WriteBuf(mpt::String::spacePadded, name) = mptIns.name; type = mptIns.nMidiProgram; // If FT2 writes crap here, we can do so, too! (we probably shouldn't, though. This is just for backwards compatibility with old MPT versions.) return sampleList; } // Convert an XMInstrumentHeader to OpenMPT's internal instrument representation. void XMInstrumentHeader::ConvertToMPT(ModInstrument &mptIns) const { instrument.ConvertToMPT(mptIns); // Create sample assignment table for(std::size_t i = 0; i < std::size(instrument.sampleMap); i++) { if(instrument.sampleMap[i] < numSamples) { mptIns.Keyboard[i + 12] = instrument.sampleMap[i]; } else { mptIns.Keyboard[i + 12] = 0; } } mptIns.name = mpt::String::ReadBuf(mpt::String::spacePadded, name); // Old MPT backwards compatibility if(!instrument.midiEnabled) { mptIns.nMidiProgram = type; } } // Convert OpenMPT's internal sample representation to an XIInstrumentHeader. XMInstrument::SampleList XIInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport) { const auto sampleList = instrument.ConvertToXM(mptIns, compatibilityExport); numSamples = static_cast(sampleList.samples.size()); memcpy(signature, "Extended Instrument: ", 21); mpt::String::WriteBuf(mpt::String::spacePadded, name) = mptIns.name; eof = 0x1A; const std::string openMptTrackerName = mpt::ToCharset(mpt::Charset::CP437, Version::Current().GetOpenMPTVersionString()); mpt::String::WriteBuf(mpt::String::spacePadded, trackerName) = openMptTrackerName; version = 0x102; return sampleList; } // Convert an XIInstrumentHeader to OpenMPT's internal instrument representation. void XIInstrumentHeader::ConvertToMPT(ModInstrument &mptIns) const { instrument.ConvertToMPT(mptIns); // Fix sample assignment table for(std::size_t i = 12; i < std::size(instrument.sampleMap) + 12; i++) { if(mptIns.Keyboard[i] >= numSamples) { mptIns.Keyboard[i] = 0; } } mptIns.name = mpt::String::ReadBuf(mpt::String::spacePadded, name); } // Convert OpenMPT's internal sample representation to an XMSample. void XMSample::ConvertToXM(const ModSample &mptSmp, MODTYPE fromType, bool compatibilityExport) { MemsetZero(*this); // Volume / Panning vol = static_cast(std::min(mptSmp.nVolume / 4u, 64u)); pan = static_cast(std::min(mptSmp.nPan, uint16(255))); // Sample Frequency if((fromType & (MOD_TYPE_MOD | MOD_TYPE_XM))) { finetune = mptSmp.nFineTune; relnote = mptSmp.RelativeTone; } else { std::tie(relnote, finetune) = ModSample::FrequencyToTranspose(mptSmp.nC5Speed); } flags = 0; if(mptSmp.uFlags[CHN_PINGPONGLOOP]) flags |= XMSample::sampleBidiLoop; else if(mptSmp.uFlags[CHN_LOOP]) flags |= XMSample::sampleLoop; // Sample Length and Loops length = mpt::saturate_cast(mptSmp.nLength); loopStart = mpt::saturate_cast(mptSmp.nLoopStart); loopLength = mpt::saturate_cast(mptSmp.nLoopEnd - mptSmp.nLoopStart); if(mptSmp.uFlags[CHN_16BIT]) { flags |= XMSample::sample16Bit; length *= 2; loopStart *= 2; loopLength *= 2; } if(mptSmp.uFlags[CHN_STEREO] && !compatibilityExport) { flags |= XMSample::sampleStereo; length *= 2; loopStart *= 2; loopLength *= 2; } } // Convert an XMSample to OpenMPT's internal sample representation. void XMSample::ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(MOD_TYPE_XM); // Volume mptSmp.nVolume = vol * 4; LimitMax(mptSmp.nVolume, uint16(256)); // Panning mptSmp.nPan = pan; mptSmp.uFlags = CHN_PANNING; // Sample Frequency mptSmp.nFineTune = finetune; mptSmp.RelativeTone = relnote; // Sample Length and Loops mptSmp.nLength = length; mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = mptSmp.nLoopStart + loopLength; if((flags & XMSample::sample16Bit)) { mptSmp.nLength /= 2; mptSmp.nLoopStart /= 2; mptSmp.nLoopEnd /= 2; } if((flags & XMSample::sampleStereo)) { mptSmp.nLength /= 2; mptSmp.nLoopStart /= 2; mptSmp.nLoopEnd /= 2; } if((flags & (XMSample::sampleLoop | XMSample::sampleBidiLoop)) && mptSmp.nLoopEnd > mptSmp.nLoopStart) { mptSmp.uFlags.set(CHN_LOOP); if((flags & XMSample::sampleBidiLoop)) { mptSmp.uFlags.set(CHN_PINGPONGLOOP); } } mptSmp.filename = ""; } // Retrieve the internal sample format flags for this instrument. SampleIO XMSample::GetSampleFormat() const { if(reserved == sampleADPCM && !(flags & (XMSample::sample16Bit | XMSample::sampleStereo))) { // MODPlugin :( return SampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::ADPCM); } return SampleIO( (flags & XMSample::sample16Bit) ? SampleIO::_16bit : SampleIO::_8bit, (flags & XMSample::sampleStereo) ? SampleIO::stereoSplit : SampleIO::mono, SampleIO::littleEndian, SampleIO::deltaPCM); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MixerSettings.cpp0000644000175000017500000000254613605114473021421 00000000000000/* * MixerSettings.cpp * ----------------- * Purpose: A struct containing settings for the mixer of soundlib. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "MixerSettings.h" #include "Snd_defs.h" #include "../common/misc_util.h" OPENMPT_NAMESPACE_BEGIN MixerSettings::MixerSettings() { // SNDMIX: These are global flags for playback control m_nStereoSeparation = 128; m_nMaxMixChannels = MAX_CHANNELS; DSPMask = 0; MixerFlags = 0; // Mixing Configuration gnChannels = 2; gdwMixingFreq = 48000; m_nPreAmp = 128; VolumeRampUpMicroseconds = 363; // 16 @44100 VolumeRampDownMicroseconds = 952; // 42 @44100 NumInputChannels = 0; } int32 MixerSettings::GetVolumeRampUpSamples() const { return Util::muldivr(VolumeRampUpMicroseconds, gdwMixingFreq, 1000000); } int32 MixerSettings::GetVolumeRampDownSamples() const { return Util::muldivr(VolumeRampDownMicroseconds, gdwMixingFreq, 1000000); } void MixerSettings::SetVolumeRampUpSamples(int32 rampUpSamples) { VolumeRampUpMicroseconds = Util::muldivr(rampUpSamples, 1000000, gdwMixingFreq); } void MixerSettings::SetVolumeRampDownSamples(int32 rampDownSamples) { VolumeRampDownMicroseconds = Util::muldivr(rampDownSamples, 1000000, gdwMixingFreq); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/modcommand.h0000644000175000017500000002552314717445260020405 00000000000000/* * modcommand.h * ------------ * Purpose: ModCommand declarations and helpers. One ModCommand corresponds to one pattern cell. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" #include "mpt/base/algorithm.hpp" OPENMPT_NAMESPACE_BEGIN class CSoundFile; // Note definitions enum : uint8 // ModCommand::NOTE { NOTE_NONE = 0, // Empty note cell NOTE_MIN = 1, // Minimum note value NOTE_MAX = 128, // Maximum note value NOTE_MIDDLEC = (5 * 12 + NOTE_MIN), NOTE_KEYOFF = 0xFF, // === (Note Off, releases envelope / fades samples, stops plugin note) NOTE_NOTECUT = 0xFE, // ^^^ (Cuts sample / stops all plugin notes) NOTE_FADE = 0xFD, // ~~~ (Fades samples, stops plugin note) NOTE_PC = 0xFC, // Param Control 'note'. Changes param value on first tick. NOTE_PCS = 0xFB, // Param Control (Smooth) 'note'. Interpolates param value during the whole row. NOTE_MIN_SPECIAL = NOTE_PCS, NOTE_MAX_SPECIAL = NOTE_KEYOFF, }; // Volume Column commands enum VolumeCommand : uint8 { VOLCMD_NONE = 0, VOLCMD_VOLUME = 1, VOLCMD_PANNING = 2, VOLCMD_VOLSLIDEUP = 3, VOLCMD_VOLSLIDEDOWN = 4, VOLCMD_FINEVOLUP = 5, VOLCMD_FINEVOLDOWN = 6, VOLCMD_VIBRATOSPEED = 7, VOLCMD_VIBRATODEPTH = 8, VOLCMD_PANSLIDELEFT = 9, VOLCMD_PANSLIDERIGHT = 10, VOLCMD_TONEPORTAMENTO = 11, VOLCMD_PORTAUP = 12, VOLCMD_PORTADOWN = 13, VOLCMD_PLAYCONTROL = 14, VOLCMD_OFFSET = 15, MAX_VOLCMDS }; // Effect column commands enum EffectCommand : uint8 { CMD_NONE = 0, CMD_ARPEGGIO = 1, CMD_PORTAMENTOUP = 2, CMD_PORTAMENTODOWN = 3, CMD_TONEPORTAMENTO = 4, CMD_VIBRATO = 5, CMD_TONEPORTAVOL = 6, CMD_VIBRATOVOL = 7, CMD_TREMOLO = 8, CMD_PANNING8 = 9, CMD_OFFSET = 10, CMD_VOLUMESLIDE = 11, CMD_POSITIONJUMP = 12, CMD_VOLUME = 13, CMD_PATTERNBREAK = 14, CMD_RETRIG = 15, CMD_SPEED = 16, CMD_TEMPO = 17, CMD_TREMOR = 18, CMD_MODCMDEX = 19, CMD_S3MCMDEX = 20, CMD_CHANNELVOLUME = 21, CMD_CHANNELVOLSLIDE = 22, CMD_GLOBALVOLUME = 23, CMD_GLOBALVOLSLIDE = 24, CMD_KEYOFF = 25, CMD_FINEVIBRATO = 26, CMD_PANBRELLO = 27, CMD_XFINEPORTAUPDOWN = 28, CMD_PANNINGSLIDE = 29, CMD_SETENVPOSITION = 30, CMD_MIDI = 31, CMD_SMOOTHMIDI = 32, CMD_DELAYCUT = 33, CMD_XPARAM = 34, CMD_FINETUNE = 35, CMD_FINETUNE_SMOOTH = 36, CMD_DUMMY = 37, CMD_NOTESLIDEUP = 38, // IMF Gxy / PTM Jxy (Slide y notes up every x ticks) CMD_NOTESLIDEDOWN = 39, // IMF Hxy / PTM Kxy (Slide y notes down every x ticks) CMD_NOTESLIDEUPRETRIG = 40, // PTM Lxy (Slide y notes up every x ticks + retrigger note) CMD_NOTESLIDEDOWNRETRIG = 41, // PTM Mxy (Slide y notes down every x ticks + retrigger note) CMD_REVERSEOFFSET = 42, // PTM Nxx Revert sample + offset CMD_DBMECHO = 43, // DBM enable/disable echo CMD_OFFSETPERCENTAGE = 44, // PLM Percentage Offset CMD_DIGIREVERSESAMPLE = 45, // DIGI reverse sample CMD_VOLUME8 = 46, // 8-bit volume CMD_HMN_MEGA_ARP = 47, // His Master's Noise "mega-arp" CMD_MED_SYNTH_JUMP = 48, // MED synth jump / MIDI panning CMD_AUTO_VOLUMESLIDE = 49, CMD_AUTO_PORTAUP = 50, CMD_AUTO_PORTADOWN = 51, CMD_AUTO_PORTAUP_FINE = 52, CMD_AUTO_PORTADOWN_FINE = 53, CMD_AUTO_PORTAMENTO_FC = 54, // Future Composer CMD_TONEPORTA_DURATION = 55, // Parameter = how many rows the slide should last CMD_VOLUMEDOWN_DURATION = 56, // Parameter = how many rows the slide should last CMD_VOLUMEDOWN_ETX = 57, // EasyTrax fade-out (parameter = speed, independent of song tempo) MAX_EFFECTS }; enum class EffectType : uint8 { Normal = 0, Global = 1, Volume = 2, Panning = 3, Pitch = 4, NumTypes = 5 }; class ModCommand { public: using NOTE = uint8; using INSTR = uint8; using VOL = uint8; using VOLCMD = VolumeCommand; using COMMAND = EffectCommand; using PARAM = uint8; // Defines the maximum value for column data when interpreted as 2-byte value // (for example volcmd and vol). The valid value range is [0, maxColumnValue]. static constexpr int maxColumnValue = 999; bool operator==(const ModCommand &mc) const { return (note == mc.note) && (instr == mc.instr) && (volcmd == mc.volcmd) && (command == mc.command) && ((volcmd == VOLCMD_NONE && !IsPcNote()) || vol == mc.vol) && ((command == CMD_NONE && !IsPcNote()) || param == mc.param); } bool operator!=(const ModCommand& mc) const { return !(*this == mc); } MPT_FORCEINLINE void SetVolumeCommand(const VolumeCommand c, const VOL v) { volcmd = c; vol = v; } MPT_FORCEINLINE void SetVolumeCommand(const std::pair cmd) { volcmd = cmd.first; vol = cmd.second; } MPT_FORCEINLINE void SetVolumeCommand(const ModCommand &other) { volcmd = other.volcmd; vol = other. vol; } MPT_FORCEINLINE void SetEffectCommand(const EffectCommand c, const PARAM p) { command = c; param = p; } MPT_FORCEINLINE void SetEffectCommand(const std::pair cmd) { command = cmd.first; param = cmd.second; } MPT_FORCEINLINE void SetEffectCommand(const ModCommand &other) { command = other.command; param = other.param; } void Set(NOTE n, INSTR ins, uint16 volcol, uint16 effectcol) { note = n; instr = ins; SetValueVolCol(volcol); SetValueEffectCol(effectcol); } uint16 GetValueVolCol() const { return GetValueVolCol(volcmd, vol); } static uint16 GetValueVolCol(uint8 volcmd, uint8 vol) { return static_cast(volcmd << 8) + vol; } void SetValueVolCol(const uint16 val) { volcmd = static_cast(val >> 8); vol = static_cast(val & 0xFF); } uint16 GetValueEffectCol() const { return GetValueEffectCol(command, param); } static uint16 GetValueEffectCol(uint8 command, uint8 param) { return static_cast(command << 8) + param; } void SetValueEffectCol(const uint16 val) { command = static_cast(val >> 8); param = static_cast(val & 0xFF); } // Clears modcommand. void Clear() { memset(this, 0, sizeof(ModCommand)); } // Returns true if modcommand is empty, false otherwise. bool IsEmpty() const { return (note == NOTE_NONE && instr == 0 && volcmd == VOLCMD_NONE && command == CMD_NONE); } // Returns true if instrument column represents plugin index. bool IsInstrPlug() const { return IsPcNote(); } // Returns true if and only if note is NOTE_PC or NOTE_PCS. bool IsPcNote() const { return IsPcNote(note); } static bool IsPcNote(NOTE note) { return note == NOTE_PC || note == NOTE_PCS; } // Returns true if and only if note is a valid musical note. bool IsNote() const { return mpt::is_in_range(note, NOTE_MIN, NOTE_MAX); } static bool IsNote(NOTE note) { return mpt::is_in_range(note, NOTE_MIN, NOTE_MAX); } // Returns true if and only if note is a valid special note. bool IsSpecialNote() const { return mpt::is_in_range(note, NOTE_MIN_SPECIAL, NOTE_MAX_SPECIAL); } static bool IsSpecialNote(NOTE note) { return mpt::is_in_range(note, NOTE_MIN_SPECIAL, NOTE_MAX_SPECIAL); } // Returns true if and only if note is a valid musical note or the note entry is empty. bool IsNoteOrEmpty() const { return note == NOTE_NONE || IsNote(); } static bool IsNoteOrEmpty(NOTE note) { return note == NOTE_NONE || IsNote(note); } // Returns true if any of the commands in this cell trigger a tone portamento. bool IsTonePortamento() const { return command == CMD_TONEPORTAMENTO || command == CMD_TONEPORTAVOL || command == CMD_TONEPORTA_DURATION || volcmd == VOLCMD_TONEPORTAMENTO; } // Returns true if any commands in this cell trigger any sort of pitch slide / portamento. bool IsAnyPitchSlide() const; // Returns true if the cell contains a sliding or otherwise continuous effect command. bool IsContinousCommand(const CSoundFile &sndFile) const; bool IsContinousVolColCommand() const; // Returns true if the cell contains a sliding command with separate up/down nibbles. bool IsSlideUpDownCommand() const; // Returns true if the cell contains an effect command that may affect the global state of the module. bool IsGlobalCommand() const { return IsGlobalCommand(command, param); } static bool IsGlobalCommand(COMMAND command, PARAM param); // Returns true if the cell contains an effect command whose parameter is divided into two nibbles bool CommandHasTwoNibbles() const { return CommandHasTwoNibbles(command); } static bool CommandHasTwoNibbles(COMMAND command); // Returns true if the command is a regular volume slide bool IsNormalVolumeSlide() const { return command == CMD_VOLUMESLIDE || command == CMD_VIBRATOVOL || command == CMD_TONEPORTAVOL; } // Returns true if the note is inside the Amiga frequency range bool IsAmigaNote() const { return IsAmigaNote(note); } static bool IsAmigaNote(NOTE note) { return !IsNote(note) || (note >= NOTE_MIDDLEC - 12 && note < NOTE_MIDDLEC + 24); } static EffectType GetEffectType(COMMAND cmd); EffectType GetEffectType() const { return GetEffectType(command); } static EffectType GetVolumeEffectType(VOLCMD volcmd); EffectType GetVolumeEffectType() const { return GetVolumeEffectType(volcmd); } // Convert a complete ModCommand item from one format to another void Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &sndFile); // Convert MOD/XM Exx to S3M/IT Sxx void ExtendedMODtoS3MEffect(); // Convert S3M/IT Sxx to MOD/XM Exx void ExtendedS3MtoMODEffect(); // "Importance" of every FX command. Table is used for importing from formats with multiple effect columns // and is approximately the same as in SchismTracker. static size_t GetEffectWeight(COMMAND cmd); // Try to convert a an effect into a volume column effect. Returns converted effect on success. [[nodiscard]] static std::pair ConvertToVolCommand(const EffectCommand effect, PARAM param, bool force); // Takes two "normal" effect commands and converts them to volume column + effect column commands. Returns the dropped command + param (CMD_NONE if nothing had to be dropped). std::pair FillInTwoCommands(EffectCommand effect1, uint8 param1, EffectCommand effect2, uint8 param2, bool allowLowResOffset = false); // Try to combine two commands into one. Returns true on success and the combined command is placed in eff1 / param1. static bool CombineEffects(EffectCommand &eff1, uint8 ¶m1, EffectCommand &eff2, uint8 ¶m2); public: uint8 note = NOTE_NONE; uint8 instr = 0; VolumeCommand volcmd = VOLCMD_NONE; EffectCommand command = CMD_NONE; uint8 vol = 0; uint8 param = 0; }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/opal.h0000644000175000017500000013641014613274223017212 00000000000000// This is the Opal OPL3 emulator from Reality Adlib Tracker v2.0a (http://www.3eality.com/productions/reality-adlib-tracker). // It was released by Shayde/Reality into the public domain. // Minor modifications to silence some warnings and fix a bug in the envelope generator have been applied. // Additional fixes by JP Cimalando. /* The Opal OPL3 emulator. Note: this is not a complete emulator, just enough for Reality Adlib Tracker tunes. Missing features compared to a real OPL3: - Timers/interrupts - OPL3 enable bit (it defaults to always on) - CSW mode - Test register - Percussion mode */ #include #include "../common/mptBaseUtils.h" OPENMPT_NAMESPACE_BEGIN //================================================================================================== // Opal class. //================================================================================================== class Opal { class Channel; // Various constants enum { OPL3SampleRate = 49716, NumChannels = 18, NumOperators = 36, EnvOff = -1, EnvAtt, EnvDec, EnvSus, EnvRel, }; // A single FM operator class Operator { public: Operator(); void SetMaster(Opal *opal) { Master = opal; } void SetChannel(Channel *chan) { Chan = chan; } int16_t Output(uint16_t keyscalenum, uint32_t phase_step, int16_t vibrato, int16_t mod = 0, int16_t fbshift = 0); void SetKeyOn(bool on); void SetTremoloEnable(bool on); void SetVibratoEnable(bool on); void SetSustainMode(bool on); void SetEnvelopeScaling(bool on); void SetFrequencyMultiplier(uint16_t scale); void SetKeyScale(uint16_t scale); void SetOutputLevel(uint16_t level); void SetAttackRate(uint16_t rate); void SetDecayRate(uint16_t rate); void SetSustainLevel(uint16_t level); void SetReleaseRate(uint16_t rate); void SetWaveform(uint16_t wave); void ComputeRates(); void ComputeKeyScaleLevel(); protected: Opal * Master; // Master object Channel * Chan; // Owning channel uint32_t Phase; // The current offset in the selected waveform uint16_t Waveform; // The waveform id this operator is using uint16_t FreqMultTimes2; // Frequency multiplier * 2 int EnvelopeStage; // Which stage the envelope is at (see Env* enums above) int16_t EnvelopeLevel; // 0 - $1FF, 0 being the loudest uint16_t OutputLevel; // 0 - $FF uint16_t AttackRate; uint16_t DecayRate; uint16_t SustainLevel; uint16_t ReleaseRate; uint16_t AttackShift; uint16_t AttackMask; uint16_t AttackAdd; const uint16_t *AttackTab; uint16_t DecayShift; uint16_t DecayMask; uint16_t DecayAdd; const uint16_t *DecayTab; uint16_t ReleaseShift; uint16_t ReleaseMask; uint16_t ReleaseAdd; const uint16_t *ReleaseTab; uint16_t KeyScaleShift; uint16_t KeyScaleLevel; int16_t Out[2]; bool KeyOn; bool KeyScaleRate; // Affects envelope rate scaling bool SustainMode; // Whether to sustain during the sustain phase, or release instead bool TremoloEnable; bool VibratoEnable; }; // A single channel, which can contain two or more operators class Channel { public: Channel(); void SetMaster(Opal *opal) { Master = opal; } void SetOperators(Operator *a, Operator *b, Operator *c, Operator *d) { Op[0] = a; Op[1] = b; Op[2] = c; Op[3] = d; if (a) a->SetChannel(this); if (b) b->SetChannel(this); if (c) c->SetChannel(this); if (d) d->SetChannel(this); } void Output(int16_t &left, int16_t &right); void SetEnable(bool on) { Enable = on; } void SetChannelPair(Channel *pair) { ChannelPair = pair; } void SetFrequencyLow(uint16_t freq); void SetFrequencyHigh(uint16_t freq); void SetKeyOn(bool on); void SetOctave(uint16_t oct); void SetLeftEnable(bool on); void SetRightEnable(bool on); void SetFeedback(uint16_t val); void SetModulationType(uint16_t type); uint16_t GetFreq() const { return Freq; } uint16_t GetOctave() const { return Octave; } uint16_t GetKeyScaleNumber() const { return KeyScaleNumber; } uint16_t GetModulationType() const { return ModulationType; } Channel * GetChannelPair() const { return ChannelPair; } void ComputeKeyScaleNumber(); protected: void ComputePhaseStep(); Operator * Op[4]; Opal * Master; // Master object uint16_t Freq; // Frequency; actually it's a phase stepping value uint16_t Octave; // Also known as "block" in Yamaha parlance uint32_t PhaseStep; uint16_t KeyScaleNumber; uint16_t FeedbackShift; uint16_t ModulationType; Channel * ChannelPair; bool Enable; bool LeftEnable, RightEnable; }; public: Opal(int sample_rate); Opal(const Opal &) = delete; Opal(Opal &&) = delete; ~Opal(); void SetSampleRate(int sample_rate); void Port(uint16_t reg_num, uint8_t val); void Sample(int16_t *left, int16_t *right); protected: void Init(int sample_rate); void Output(int16_t &left, int16_t &right); int32_t SampleRate; int32_t SampleAccum; int16_t LastOutput[2], CurrOutput[2]; Channel Chan[NumChannels]; Operator Op[NumOperators]; // uint16_t ExpTable[256]; // uint16_t LogSinTable[256]; uint16_t Clock; uint16_t TremoloClock; uint16_t TremoloLevel; uint16_t VibratoTick; uint16_t VibratoClock; bool NoteSel; bool TremoloDepth; bool VibratoDepth; static const uint16_t RateTables[4][8]; static const uint16_t ExpTable[256]; static const uint16_t LogSinTable[256]; }; //-------------------------------------------------------------------------------------------------- const uint16_t Opal::RateTables[4][8] = { { 1, 0, 1, 0, 1, 0, 1, 0 }, { 1, 0, 1, 0, 0, 0, 1, 0 }, { 1, 0, 0, 0, 1, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0 }, }; //-------------------------------------------------------------------------------------------------- const uint16_t Opal::ExpTable[0x100] = { 1018, 1013, 1007, 1002, 996, 991, 986, 980, 975, 969, 964, 959, 953, 948, 942, 937, 932, 927, 921, 916, 911, 906, 900, 895, 890, 885, 880, 874, 869, 864, 859, 854, 849, 844, 839, 834, 829, 824, 819, 814, 809, 804, 799, 794, 789, 784, 779, 774, 770, 765, 760, 755, 750, 745, 741, 736, 731, 726, 722, 717, 712, 708, 703, 698, 693, 689, 684, 680, 675, 670, 666, 661, 657, 652, 648, 643, 639, 634, 630, 625, 621, 616, 612, 607, 603, 599, 594, 590, 585, 581, 577, 572, 568, 564, 560, 555, 551, 547, 542, 538, 534, 530, 526, 521, 517, 513, 509, 505, 501, 496, 492, 488, 484, 480, 476, 472, 468, 464, 460, 456, 452, 448, 444, 440, 436, 432, 428, 424, 420, 416, 412, 409, 405, 401, 397, 393, 389, 385, 382, 378, 374, 370, 367, 363, 359, 355, 352, 348, 344, 340, 337, 333, 329, 326, 322, 318, 315, 311, 308, 304, 300, 297, 293, 290, 286, 283, 279, 276, 272, 268, 265, 262, 258, 255, 251, 248, 244, 241, 237, 234, 231, 227, 224, 220, 217, 214, 210, 207, 204, 200, 197, 194, 190, 187, 184, 181, 177, 174, 171, 168, 164, 161, 158, 155, 152, 148, 145, 142, 139, 136, 133, 130, 126, 123, 120, 117, 114, 111, 108, 105, 102, 99, 96, 93, 90, 87, 84, 81, 78, 75, 72, 69, 66, 63, 60, 57, 54, 51, 48, 45, 42, 40, 37, 34, 31, 28, 25, 22, 20, 17, 14, 11, 8, 6, 3, 0, }; //-------------------------------------------------------------------------------------------------- const uint16_t Opal::LogSinTable[0x100] = { 2137, 1731, 1543, 1419, 1326, 1252, 1190, 1137, 1091, 1050, 1013, 979, 949, 920, 894, 869, 846, 825, 804, 785, 767, 749, 732, 717, 701, 687, 672, 659, 646, 633, 621, 609, 598, 587, 576, 566, 556, 546, 536, 527, 518, 509, 501, 492, 484, 476, 468, 461, 453, 446, 439, 432, 425, 418, 411, 405, 399, 392, 386, 380, 375, 369, 363, 358, 352, 347, 341, 336, 331, 326, 321, 316, 311, 307, 302, 297, 293, 289, 284, 280, 276, 271, 267, 263, 259, 255, 251, 248, 244, 240, 236, 233, 229, 226, 222, 219, 215, 212, 209, 205, 202, 199, 196, 193, 190, 187, 184, 181, 178, 175, 172, 169, 167, 164, 161, 159, 156, 153, 151, 148, 146, 143, 141, 138, 136, 134, 131, 129, 127, 125, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96, 94, 92, 91, 89, 87, 85, 83, 82, 80, 78, 77, 75, 74, 72, 70, 69, 67, 66, 64, 63, 62, 60, 59, 57, 56, 55, 53, 52, 51, 49, 48, 47, 46, 45, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 23, 22, 21, 20, 20, 19, 18, 17, 17, 16, 15, 15, 14, 13, 13, 12, 12, 11, 10, 10, 9, 9, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, }; //================================================================================================== // This is the temporary code for generating the above tables. Maths and data from this nice // reverse-engineering effort: // // https://docs.google.com/document/d/18IGx18NQY_Q1PJVZ-bHywao9bhsDoAqoIn1rIm42nwo/edit //================================================================================================== #if 0 #include void GenerateTables() { // Build the exponentiation table (reversed from the official OPL3 ROM) FILE *fd = fopen("exptab.txt", "wb"); if (fd) { for (int i = 0; i < 0x100; i++) { int v = (pow(2, (0xFF - i) / 256.0) - 1) * 1024 + 0.5; if (i & 15) fprintf(fd, " %4d,", v); else fprintf(fd, "\n\t%4d,", v); } fclose(fd); } // Build the log-sin table fd = fopen("sintab.txt", "wb"); if (fd) { for (int i = 0; i < 0x100; i++) { int v = -log(sin((i + 0.5) * 3.1415926535897933 / 256 / 2)) / log(2) * 256 + 0.5; if (i & 15) fprintf(fd, " %4d,", v); else fprintf(fd, "\n\t%4d,", v); } fclose(fd); } } #endif //================================================================================================== // Constructor/destructor. //================================================================================================== Opal::Opal(int sample_rate) { Init(sample_rate); } //-------------------------------------------------------------------------------------------------- Opal::~Opal() { } //================================================================================================== // Initialise the emulation. //================================================================================================== void Opal::Init(int sample_rate) { Clock = 0; TremoloClock = 0; TremoloLevel = 0; VibratoTick = 0; VibratoClock = 0; NoteSel = false; TremoloDepth = false; VibratoDepth = false; // // Build the exponentiation table (reversed from the official OPL3 ROM) // for (int i = 0; i < 0x100; i++) // ExpTable[i] = (pow(2, (0xFF - i) / 256.0) - 1) * 1024 + 0.5; // // // Build the log-sin table // for (int i = 0; i < 0x100; i++) // LogSinTable[i] = -log(sin((i + 0.5) * 3.1415926535897933 / 256 / 2)) / log(2) * 256 + 0.5; // Let sub-objects know where to find us for (int i = 0; i < NumOperators; i++) Op[i].SetMaster(this); for (int i = 0; i < NumChannels; i++) Chan[i].SetMaster(this); // Add the operators to the channels. Note, some channels can't use all the operators // FIXME: put this into a separate routine const int chan_ops[] = { 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32, }; for (int i = 0; i < NumChannels; i++) { Channel *chan = &Chan[i]; int op = chan_ops[i]; if (i < 3 || (i >= 9 && i < 12)) chan->SetOperators(&Op[op], &Op[op + 3], &Op[op + 6], &Op[op + 9]); else chan->SetOperators(&Op[op], &Op[op + 3], 0, 0); } // Initialise the operator rate data. We can't do this in the Operator constructor as it // relies on referencing the master and channel objects for (int i = 0; i < NumOperators; i++) Op[i].ComputeRates(); SetSampleRate(sample_rate); } //================================================================================================== // Change the sample rate. //================================================================================================== void Opal::SetSampleRate(int sample_rate) { // Sanity if (sample_rate == 0) sample_rate = OPL3SampleRate; SampleRate = sample_rate; SampleAccum = 0; LastOutput[0] = LastOutput[1] = 0; CurrOutput[0] = CurrOutput[1] = 0; } //================================================================================================== // Write a value to an OPL3 register. //================================================================================================== void Opal::Port(uint16_t reg_num, uint8_t val) { static constexpr int8_t op_lookup[] = { // 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, // 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; uint16_t type = reg_num & 0xE0; // Is it BD, the one-off register stuck in the middle of the register array? if (reg_num == 0xBD) { TremoloDepth = (val & 0x80) != 0; VibratoDepth = (val & 0x40) != 0; return; } // Global registers if (type == 0x00) { // 4-OP enables if (reg_num == 0x104) { // Enable/disable channels based on which 4-op enables uint8_t mask = 1; for (int i = 0; i < 6; i++, mask <<= 1) { // The 4-op channels are 0, 1, 2, 9, 10, 11 uint16_t chan = static_cast(i < 3 ? i : i + 6); // cppcheck false-positive // cppcheck-suppress arrayIndexOutOfBounds Channel *primary = &Chan[chan]; // cppcheck false-positive // cppcheck-suppress arrayIndexOutOfBounds Channel *secondary = &Chan[chan + 3]; if (val & mask) { // Let primary channel know it's controlling the secondary channel primary->SetChannelPair(secondary); // Turn off the second channel in the pair secondary->SetEnable(false); } else { // Let primary channel know it's no longer controlling the secondary channel primary->SetChannelPair(0); // Turn on the second channel in the pair secondary->SetEnable(true); } } // CSW / Note-sel } else if (reg_num == 0x08) { NoteSel = (val & 0x40) != 0; // Get the channels to recompute the Key Scale No. as this varies based on NoteSel for (int i = 0; i < NumChannels; i++) Chan[i].ComputeKeyScaleNumber(); } // Channel registers } else if (type >= 0xA0 && type <= 0xC0) { // Convert to channel number int chan_num = reg_num & 15; // Valid channel? if (chan_num >= 9) return; // Is it the other bank of channels? if (reg_num & 0x100) chan_num += 9; Channel &chan = Chan[chan_num]; // Registers Ax and Bx affect both channels Channel *chans[2] = {&chan, chan.GetChannelPair()}; int numchans = chans[1] ? 2 : 1; // Do specific registers switch (reg_num & 0xF0) { // Frequency low case 0xA0: { for (int i = 0; i < numchans; i++) { chans[i]->SetFrequencyLow(val); } break; } // Key-on / Octave / Frequency High case 0xB0: { for (int i = 0; i < numchans; i++) { chans[i]->SetKeyOn((val & 0x20) != 0); chans[i]->SetOctave(val >> 2 & 7); chans[i]->SetFrequencyHigh(val & 3); } break; } // Right Stereo Channel Enable / Left Stereo Channel Enable / Feedback Factor / Modulation Type case 0xC0: { chan.SetRightEnable((val & 0x20) != 0); chan.SetLeftEnable((val & 0x10) != 0); chan.SetFeedback(val >> 1 & 7); chan.SetModulationType(val & 1); break; } } // Operator registers } else if ((type >= 0x20 && type <= 0x80) || type == 0xE0) { // Convert to operator number int op_num = op_lookup[reg_num & 0x1F]; // Valid register? if (op_num < 0) return; // Is it the other bank of operators? if (reg_num & 0x100) op_num += 18; Operator &op = Op[op_num]; // Do specific registers switch (type) { // Tremolo Enable / Vibrato Enable / Sustain Mode / Envelope Scaling / Frequency Multiplier case 0x20: { op.SetTremoloEnable((val & 0x80) != 0); op.SetVibratoEnable((val & 0x40) != 0); op.SetSustainMode((val & 0x20) != 0); op.SetEnvelopeScaling((val & 0x10) != 0); op.SetFrequencyMultiplier(val & 15); break; } // Key Scale / Output Level case 0x40: { op.SetKeyScale(val >> 6); op.SetOutputLevel(val & 0x3F); break; } // Attack Rate / Decay Rate case 0x60: { op.SetAttackRate(val >> 4); op.SetDecayRate(val & 15); break; } // Sustain Level / Release Rate case 0x80: { op.SetSustainLevel(val >> 4); op.SetReleaseRate(val & 15); break; } // Waveform case 0xE0: { op.SetWaveform(val & 7); break; } } } } //================================================================================================== // Generate sample. Every time you call this you will get two signed 16-bit samples (one for each // stereo channel) which will sound correct when played back at the sample rate given when the // class was constructed. //================================================================================================== void Opal::Sample(int16_t *left, int16_t *right) { // If the destination sample rate is higher than the OPL3 sample rate, we need to skip ahead while (SampleAccum >= SampleRate) { LastOutput[0] = CurrOutput[0]; LastOutput[1] = CurrOutput[1]; Output(CurrOutput[0], CurrOutput[1]); SampleAccum -= SampleRate; } // Mix with the partial accumulation const int32_t fract = Util::muldivr(SampleAccum, 65536, SampleRate); *left = static_cast(LastOutput[0] + ((fract * (CurrOutput[0] - LastOutput[0])) / 65536)); *right = static_cast(LastOutput[1] + ((fract * (CurrOutput[1] - LastOutput[1])) / 65536)); SampleAccum += OPL3SampleRate; } //================================================================================================== // Produce final output from the chip. This is at the OPL3 sample-rate. //================================================================================================== void Opal::Output(int16_t &left, int16_t &right) { int32_t leftmix = 0, rightmix = 0; // Sum the output of each channel for (int i = 0; i < NumChannels; i++) { int16_t chanleft, chanright; Chan[i].Output(chanleft, chanright); leftmix += chanleft; rightmix += chanright; } // Clamp if (leftmix < -0x8000) left = -0x8000; else if (leftmix > 0x7FFF) left = 0x7FFF; else left = static_cast(leftmix); if (rightmix < -0x8000) right = -0x8000; else if (rightmix > 0x7FFF) right = 0x7FFF; else right = static_cast(rightmix); Clock++; // Tremolo. According to this post, the OPL3 tremolo is a 13,440 sample length triangle wave // with a peak at 26 and a trough at 0 and is simply added to the logarithmic level accumulator // http://forums.submarine.org.uk/phpBB/viewtopic.php?f=9&t=1171 TremoloClock = (TremoloClock + 1) % 13440; TremoloLevel = ((TremoloClock < 13440 / 2) ? TremoloClock : 13440 - TremoloClock) / 256; if (!TremoloDepth) TremoloLevel >>= 2; // Vibrato. This appears to be a 8 sample long triangle wave with a magnitude of the three // high bits of the channel frequency, positive and negative, divided by two if the vibrato // depth is zero. It is only cycled every 1,024 samples. VibratoTick++; if (VibratoTick >= 1024) { VibratoTick = 0; VibratoClock = (VibratoClock + 1) & 7; } } //================================================================================================== // Channel constructor. //================================================================================================== Opal::Channel::Channel() { Master = 0; Freq = 0; Octave = 0; PhaseStep = 0; KeyScaleNumber = 0; FeedbackShift = 0; ModulationType = 0; ChannelPair = 0; Enable = true; LeftEnable = true; RightEnable = true; } //================================================================================================== // Produce output from channel. //================================================================================================== void Opal::Channel::Output(int16_t &left, int16_t &right) { // Has the channel been disabled? This is usually a result of the 4-op enables being used to // disable the secondary channel in each 4-op pair if (!Enable) { left = right = 0; return; } int16_t vibrato = (Freq >> 7) & 7; if (!Master->VibratoDepth) vibrato >>= 1; // 0 3 7 3 0 -3 -7 -3 uint16_t clk = Master->VibratoClock; if (!(clk & 3)) vibrato = 0; // Position 0 and 4 is zero else { if (clk & 1) vibrato >>= 1; // Odd positions are half the magnitude vibrato <<= Octave; if (clk & 4) vibrato = -vibrato; // The second half positions are negative } // Combine individual operator outputs int16_t out, acc; // Running in 4-op mode? if (ChannelPair) { // Get the secondary channel's modulation type. This is the only thing from the secondary // channel that is used if (ChannelPair->GetModulationType() == 0) { if (ModulationType == 0) { // feedback -> modulator -> modulator -> modulator -> carrier out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift); out = Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato, out, 0); out = Op[2]->Output(KeyScaleNumber, PhaseStep, vibrato, out, 0); out = Op[3]->Output(KeyScaleNumber, PhaseStep, vibrato, out, 0); } else { // (feedback -> carrier) + (modulator -> modulator -> carrier) out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift); acc = Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, 0); acc = Op[2]->Output(KeyScaleNumber, PhaseStep, vibrato, acc, 0); out += Op[3]->Output(KeyScaleNumber, PhaseStep, vibrato, acc, 0); } } else { if (ModulationType == 0) { // (feedback -> modulator -> carrier) + (modulator -> carrier) out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift); out = Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato, out, 0); acc = Op[2]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, 0); out += Op[3]->Output(KeyScaleNumber, PhaseStep, vibrato, acc, 0); } else { // (feedback -> carrier) + (modulator -> carrier) + carrier out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift); acc = Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, 0); out += Op[2]->Output(KeyScaleNumber, PhaseStep, vibrato, acc, 0); out += Op[3]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, 0); } } } else { // Standard 2-op mode if (ModulationType == 0) { // Frequency modulation (well, phase modulation technically) out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift); out = Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato, out, 0); } else { // Additive out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift); out += Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato); } } left = LeftEnable ? out : 0; right = RightEnable ? out : 0; } //================================================================================================== // Set phase step for operators using this channel. //================================================================================================== void Opal::Channel::SetFrequencyLow(uint16_t freq) { Freq = (Freq & 0x300) | (freq & 0xFF); ComputePhaseStep(); } //-------------------------------------------------------------------------------------------------- void Opal::Channel::SetFrequencyHigh(uint16_t freq) { Freq = (Freq & 0xFF) | ((freq & 3) << 8); ComputePhaseStep(); // Only the high bits of Freq affect the Key Scale No. ComputeKeyScaleNumber(); } //================================================================================================== // Set the octave of the channel (0 to 7). //================================================================================================== void Opal::Channel::SetOctave(uint16_t oct) { Octave = oct & 7; ComputePhaseStep(); ComputeKeyScaleNumber(); } //================================================================================================== // Keys the channel on/off. //================================================================================================== void Opal::Channel::SetKeyOn(bool on) { Op[0]->SetKeyOn(on); Op[1]->SetKeyOn(on); } //================================================================================================== // Enable left stereo channel. //================================================================================================== void Opal::Channel::SetLeftEnable(bool on) { LeftEnable = on; } //================================================================================================== // Enable right stereo channel. //================================================================================================== void Opal::Channel::SetRightEnable(bool on) { RightEnable = on; } //================================================================================================== // Set the channel feedback amount. //================================================================================================== void Opal::Channel::SetFeedback(uint16_t val) { FeedbackShift = val ? 9 - val : 0; } //================================================================================================== // Set frequency modulation/additive modulation //================================================================================================== void Opal::Channel::SetModulationType(uint16_t type) { ModulationType = type; } //================================================================================================== // Compute the stepping factor for the operator waveform phase based on the frequency and octave // values of the channel. //================================================================================================== void Opal::Channel::ComputePhaseStep() { PhaseStep = uint32_t(Freq) << Octave; } //================================================================================================== // Compute the key scale number and key scale levels. // // From the Yamaha data sheet this is the block/octave number as bits 3-1, with bit 0 coming from // the MSB of the frequency if NoteSel is 1, and the 2nd MSB if NoteSel is 0. //================================================================================================== void Opal::Channel::ComputeKeyScaleNumber() { uint16_t lsb = Master->NoteSel ? Freq >> 9 : (Freq >> 8) & 1; KeyScaleNumber = Octave << 1 | lsb; // Get the channel operators to recompute their rates as they're dependent on this number. They // also need to recompute their key scale level for (int i = 0; i < 4; i++) { if (!Op[i]) continue; Op[i]->ComputeRates(); Op[i]->ComputeKeyScaleLevel(); } } //================================================================================================== // Operator constructor. //================================================================================================== Opal::Operator::Operator() { Master = 0; Chan = 0; Phase = 0; Waveform = 0; FreqMultTimes2 = 1; EnvelopeStage = EnvOff; EnvelopeLevel = 0x1FF; AttackRate = 0; DecayRate = 0; SustainLevel = 0; ReleaseRate = 0; KeyScaleShift = 0; KeyScaleLevel = 0; Out[0] = Out[1] = 0; KeyOn = false; KeyScaleRate = false; SustainMode = false; TremoloEnable = false; VibratoEnable = false; } //================================================================================================== // Produce output from operator. //================================================================================================== int16_t Opal::Operator::Output(uint16_t /*keyscalenum*/, uint32_t phase_step, int16_t vibrato, int16_t mod, int16_t fbshift) { // Advance wave phase if (VibratoEnable) phase_step += vibrato; Phase += (phase_step * FreqMultTimes2) / 2; uint16_t level = (EnvelopeLevel + OutputLevel + KeyScaleLevel + (TremoloEnable ? Master->TremoloLevel : 0)) << 3; switch (EnvelopeStage) { // Attack stage case EnvAtt: { uint16_t add = ((AttackAdd >> AttackTab[Master->Clock >> AttackShift & 7]) * ~EnvelopeLevel) >> 3; if (AttackRate == 0) add = 0; if (AttackMask && (Master->Clock & AttackMask)) add = 0; EnvelopeLevel += add; if (EnvelopeLevel <= 0) { EnvelopeLevel = 0; EnvelopeStage = EnvDec; } break; } // Decay stage case EnvDec: { uint16_t add = DecayAdd >> DecayTab[Master->Clock >> DecayShift & 7]; if (DecayRate == 0) add = 0; if (DecayMask && (Master->Clock & DecayMask)) add = 0; EnvelopeLevel += add; if (EnvelopeLevel >= SustainLevel) { EnvelopeLevel = SustainLevel; EnvelopeStage = EnvSus; } break; } // Sustain stage case EnvSus: { if (SustainMode) break; // Note: fall-through! [[fallthrough]]; } // Release stage case EnvRel: { uint16_t add = ReleaseAdd >> ReleaseTab[Master->Clock >> ReleaseShift & 7]; if (ReleaseRate == 0) add = 0; if (ReleaseMask && (Master->Clock & ReleaseMask)) add = 0; EnvelopeLevel += add; if (EnvelopeLevel >= 0x1FF) { EnvelopeLevel = 0x1FF; EnvelopeStage = EnvOff; Out[0] = Out[1] = 0; return 0; } break; } // Envelope, and therefore the operator, is not running default: Out[0] = Out[1] = 0; return 0; } // Feedback? In that case we modulate by a blend of the last two samples if (fbshift) mod += (Out[0] + Out[1]) >> fbshift; uint16_t phase = static_cast(Phase >> 10) + mod; uint16_t offset = phase & 0xFF; uint16_t logsin; bool negate = false; switch (Waveform) { //------------------------------------ // Standard sine wave //------------------------------------ case 0: if (phase & 0x100) offset ^= 0xFF; logsin = Master->LogSinTable[offset]; negate = (phase & 0x200) != 0; break; //------------------------------------ // Half sine wave //------------------------------------ case 1: if (phase & 0x200) offset = 0; else if (phase & 0x100) offset ^= 0xFF; logsin = Master->LogSinTable[offset]; break; //------------------------------------ // Positive sine wave //------------------------------------ case 2: if (phase & 0x100) offset ^= 0xFF; logsin = Master->LogSinTable[offset]; break; //------------------------------------ // Quarter positive sine wave //------------------------------------ case 3: if (phase & 0x100) offset = 0; logsin = Master->LogSinTable[offset]; break; //------------------------------------ // Double-speed sine wave //------------------------------------ case 4: if (phase & 0x200) offset = 0; else { if (phase & 0x80) offset ^= 0xFF; offset = (offset + offset) & 0xFF; negate = (phase & 0x100) != 0; } logsin = Master->LogSinTable[offset]; break; //------------------------------------ // Double-speed positive sine wave //------------------------------------ case 5: if (phase & 0x200) offset = 0; else { offset = (offset + offset) & 0xFF; if (phase & 0x80) offset ^= 0xFF; } logsin = Master->LogSinTable[offset]; break; //------------------------------------ // Square wave //------------------------------------ case 6: logsin = 0; negate = (phase & 0x200) != 0; break; //------------------------------------ // Exponentiation wave //------------------------------------ default: logsin = phase & 0x1FF; if (phase & 0x200) { logsin ^= 0x1FF; negate = true; } logsin <<= 3; break; } uint16_t mix = logsin + level; if (mix > 0x1FFF) mix = 0x1FFF; // From the OPLx decapsulated docs: // "When such a table is used for calculation of the exponential, the table is read at the // position given by the 8 LSB's of the input. The value + 1024 (the hidden bit) is then the // significand of the floating point output and the yet unused MSB's of the input are the // exponent of the floating point output." int16_t v = (Master->ExpTable[mix & 0xFF] + 1024u) >> (mix >> 8u); v += v; if (negate) v = ~v; // Keep last two results for feedback calculation Out[1] = Out[0]; Out[0] = v; return v; } //================================================================================================== // Trigger operator. //================================================================================================== void Opal::Operator::SetKeyOn(bool on) { // Already on/off? if (KeyOn == on) return; KeyOn = on; if (on) { // The highest attack rate is instant; it bypasses the attack phase if (AttackRate == 15) { EnvelopeStage = EnvDec; EnvelopeLevel = 0; } else EnvelopeStage = EnvAtt; Phase = 0; } else { // Stopping current sound? if (EnvelopeStage != EnvOff && EnvelopeStage != EnvRel) EnvelopeStage = EnvRel; } } //================================================================================================== // Enable amplitude vibrato. //================================================================================================== void Opal::Operator::SetTremoloEnable(bool on) { TremoloEnable = on; } //================================================================================================== // Enable frequency vibrato. //================================================================================================== void Opal::Operator::SetVibratoEnable(bool on) { VibratoEnable = on; } //================================================================================================== // Sets whether we release or sustain during the sustain phase of the envelope. 'true' is to // sustain, otherwise release. //================================================================================================== void Opal::Operator::SetSustainMode(bool on) { SustainMode = on; } //================================================================================================== // Key scale rate. Sets how much the Key Scaling Number affects the envelope rates. //================================================================================================== void Opal::Operator::SetEnvelopeScaling(bool on) { KeyScaleRate = on; ComputeRates(); } //================================================================================================== // Multiplies the phase frequency. //================================================================================================== void Opal::Operator::SetFrequencyMultiplier(uint16_t scale) { // Needs to be multiplied by two (and divided by two later when we use it) because the first // entry is actually .5 const uint16_t mul_times_2[] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30, }; FreqMultTimes2 = mul_times_2[scale & 15]; } //================================================================================================== // Attenuates output level towards higher pitch. //================================================================================================== void Opal::Operator::SetKeyScale(uint16_t scale) { static constexpr uint8_t kslShift[4] = { 8, 1, 2, 0 }; KeyScaleShift = kslShift[scale]; ComputeKeyScaleLevel(); } //================================================================================================== // Sets the output level (volume) of the operator. //================================================================================================== void Opal::Operator::SetOutputLevel(uint16_t level) { OutputLevel = level * 4; } //================================================================================================== // Operator attack rate. //================================================================================================== void Opal::Operator::SetAttackRate(uint16_t rate) { AttackRate = rate; ComputeRates(); } //================================================================================================== // Operator decay rate. //================================================================================================== void Opal::Operator::SetDecayRate(uint16_t rate) { DecayRate = rate; ComputeRates(); } //================================================================================================== // Operator sustain level. //================================================================================================== void Opal::Operator::SetSustainLevel(uint16_t level) { SustainLevel = level < 15 ? level : 31; SustainLevel *= 16; } //================================================================================================== // Operator release rate. //================================================================================================== void Opal::Operator::SetReleaseRate(uint16_t rate) { ReleaseRate = rate; ComputeRates(); } //================================================================================================== // Assign the waveform this operator will use. //================================================================================================== void Opal::Operator::SetWaveform(uint16_t wave) { Waveform = wave & 7; } //================================================================================================== // Compute actual rate from register rate. From the Yamaha data sheet: // // Actual rate = Rate value * 4 + Rof, if Rate value = 0, actual rate = 0 // // Rof is set as follows depending on the KSR setting: // // Key scale 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // KSR = 0 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 // KSR = 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // // Note: zero rates are infinite, and are treated separately elsewhere //================================================================================================== void Opal::Operator::ComputeRates() { int combined_rate = AttackRate * 4 + (Chan->GetKeyScaleNumber() >> (KeyScaleRate ? 0 : 2)); int rate_high = combined_rate >> 2; int rate_low = combined_rate & 3; AttackShift = static_cast(rate_high < 12 ? 12 - rate_high : 0); AttackMask = (1 << AttackShift) - 1; AttackAdd = (rate_high < 12) ? 1 : 1 << (rate_high - 12); AttackTab = Master->RateTables[rate_low]; // Attack rate of 15 is always instant if (AttackRate == 15) AttackAdd = 0xFFF; combined_rate = DecayRate * 4 + (Chan->GetKeyScaleNumber() >> (KeyScaleRate ? 0 : 2)); rate_high = combined_rate >> 2; rate_low = combined_rate & 3; DecayShift = static_cast(rate_high < 12 ? 12 - rate_high : 0); DecayMask = (1 << DecayShift) - 1; DecayAdd = (rate_high < 12) ? 1 : 1 << (rate_high - 12); DecayTab = Master->RateTables[rate_low]; combined_rate = ReleaseRate * 4 + (Chan->GetKeyScaleNumber() >> (KeyScaleRate ? 0 : 2)); rate_high = combined_rate >> 2; rate_low = combined_rate & 3; ReleaseShift = static_cast(rate_high < 12 ? 12 - rate_high : 0); ReleaseMask = (1 << ReleaseShift) - 1; ReleaseAdd = (rate_high < 12) ? 1 : 1 << (rate_high - 12); ReleaseTab = Master->RateTables[rate_low]; } //================================================================================================== // Compute the operator's key scale level. This changes based on the channel frequency/octave and // operator key scale value. //================================================================================================== void Opal::Operator::ComputeKeyScaleLevel() { static constexpr uint8_t levtab[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 12, 16, 20, 24, 28, 32, 0, 0, 0, 0, 0, 12, 20, 28, 32, 40, 44, 48, 52, 56, 60, 64, 0, 0, 0, 20, 32, 44, 52, 60, 64, 72, 76, 80, 84, 88, 92, 96, 0, 0, 32, 52, 64, 76, 84, 92, 96, 104, 108, 112, 116, 120, 124, 128, 0, 32, 64, 84, 96, 108, 116, 124, 128, 136, 140, 144, 148, 152, 156, 160, 0, 64, 96, 116, 128, 140, 148, 156, 160, 168, 172, 176, 180, 184, 188, 192, 0, 96, 128, 148, 160, 172, 180, 188, 192, 200, 204, 208, 212, 216, 220, 224, }; // This uses a combined value of the top four bits of frequency with the octave/block uint16_t i = (Chan->GetOctave() << 4) | (Chan->GetFreq() >> 6); KeyScaleLevel = levtab[i] >> KeyScaleShift; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/PlaybackTest.h0000644000175000017500000000267114754163262020654 00000000000000/* * PlaybackTest.h * -------------- * Purpose: Tools for verifying correct playback of modules * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #if defined(MPT_ENABLE_PLAYBACK_TRACE) #include "../common/FileReaderFwd.h" #include #endif // MPT_ENABLE_PLAYBACK_TRACE OPENMPT_NAMESPACE_BEGIN #if defined(MPT_ENABLE_PLAYBACK_TRACE) struct PlaybackTestData; struct PlaybackTestSettings; class CSoundFile; class PlaybackTest { public: explicit PlaybackTest(FileReader file) noexcept(false); explicit PlaybackTest(PlaybackTestData &&testData); PlaybackTest(PlaybackTest &&other) noexcept; PlaybackTest(const PlaybackTest &) = delete; ~PlaybackTest(); PlaybackTest& operator=(PlaybackTest &&other) noexcept; PlaybackTest& operator=(const PlaybackTest &) = delete; void Deserialize(FileReader file) noexcept(false); void Serialize(std::ostream &output) const noexcept(false); void ToTSV(std::ostream &output) const noexcept(false); PlaybackTestSettings GetSettings() const noexcept; static std::vector Compare(const PlaybackTest &lhs, const PlaybackTest &rhs); private: std::vector Compare(const PlaybackTest &otherTest) const; private: std::unique_ptr m_testData; }; #endif // MPT_ENABLE_PLAYBACK_TRACE OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleFormatMediaFoundation.cpp0000644000175000017500000003142514430470740024172 00000000000000/* * SampleFormatMediaSoundation.cpp * ------------------------------- * Purpose: MediaFoundation sample import. * Notes : * Authors: Joern Heusipp * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Sndfile.h" #ifndef MODPLUG_NO_FILESAVE #include "../common/mptFileIO.h" #endif #include "../common/misc_util.h" #include "Tagging.h" #include "Loaders.h" #include "../common/FileReader.h" #include "modsmp_ctrl.h" #include "openmpt/soundbase/Copy.hpp" #include "../soundlib/ModSampleCopy.h" #include "../common/ComponentManager.h" #if defined(MPT_WITH_MEDIAFOUNDATION) #include "mpt/io_file_adapter/fileadapter.hpp" #include "../common/FileReader.h" #include "../common/mptFileTemporary.h" #include #include #include #include #include #include #include #endif // MPT_WITH_MEDIAFOUNDATION #include "mpt/string/utility.hpp" OPENMPT_NAMESPACE_BEGIN #if defined(MPT_WITH_MEDIAFOUNDATION) struct PropVariant : PROPVARIANT { PropVariant() { PropVariantInit(this); } ~PropVariant() { PropVariantClear(this); } }; // Implementing IMFByteStream is apparently not enough to stream raw bytes // data to MediaFoundation. // Additionally, one has to also implement a custom IMFAsyncResult for the // BeginRead/EndRead interface which allows transferring the number of read // bytes around. // To make things even worse, MediaFoundation fails to detect some AAC and MPEG // files if a non-file-based or read-only stream is used for opening. // The only sane option which remains if we do not have an on-disk filename // available: // 1 - write a temporary file // 2 - close it // 3 - open it using MediaFoundation. // We use FILE_ATTRIBUTE_TEMPORARY which will try to keep the file data in // memory just like regular allocated memory and reduce the overhead basically // to memcpy. static FileTags ReadMFMetadata(IMFMediaSource *mediaSource) { FileTags tags; CComPtr presentationDescriptor; if(!SUCCEEDED(mediaSource->CreatePresentationDescriptor(&presentationDescriptor))) { return tags; } DWORD streams = 0; if(!SUCCEEDED(presentationDescriptor->GetStreamDescriptorCount(&streams))) { return tags; } CComPtr metadataProvider; if(!SUCCEEDED(MFGetService(mediaSource, MF_METADATA_PROVIDER_SERVICE, IID_IMFMetadataProvider, (void**)&metadataProvider))) { return tags; } CComPtr metadata; if(!SUCCEEDED(metadataProvider->GetMFMetadata(presentationDescriptor, 0, 0, &metadata))) { return tags; } PropVariant varPropNames; if(!SUCCEEDED(metadata->GetAllPropertyNames(&varPropNames))) { return tags; } for(DWORD propIndex = 0; propIndex < varPropNames.calpwstr.cElems; ++propIndex) { PropVariant propVal; LPWSTR propName = varPropNames.calpwstr.pElems[propIndex]; if(S_OK != metadata->GetProperty(propName, &propVal)) { break; } std::wstring stringVal; #if !MPT_OS_WINDOWS_WINRT // WTF, no PropVariantToString() in WinRT std::vector wcharVal(256); for(;;) { HRESULT hrToString = PropVariantToString(propVal, wcharVal.data(), mpt::saturate_cast(wcharVal.size())); if(hrToString == S_OK) { stringVal = wcharVal.data(); break; } else if(hrToString == ERROR_INSUFFICIENT_BUFFER) { wcharVal.resize(mpt::exponential_grow(wcharVal.size())); } else { break; } } #endif // !MPT_OS_WINDOWS_WINRT if(stringVal.length() > 0) { if(propName == std::wstring(L"Author")) tags.artist = mpt::ToUnicode(stringVal); if(propName == std::wstring(L"Title")) tags.title = mpt::ToUnicode(stringVal); if(propName == std::wstring(L"WM/AlbumTitle")) tags.album = mpt::ToUnicode(stringVal); if(propName == std::wstring(L"WM/Track")) tags.trackno = mpt::ToUnicode(stringVal); if(propName == std::wstring(L"WM/Year")) tags.year = mpt::ToUnicode(stringVal); if(propName == std::wstring(L"WM/Genre")) tags.genre = mpt::ToUnicode(stringVal); } } return tags; } class ComponentMediaFoundation : public ComponentLibrary { MPT_DECLARE_COMPONENT_MEMBERS(ComponentMediaFoundation, "MediaFoundation") public: ComponentMediaFoundation() : ComponentLibrary(ComponentTypeSystem) { return; } bool DoInitialize() override { #if !MPT_OS_WINDOWS_WINRT if(!(true && AddLibrary("mf", mpt::LibraryPath::System(P_("mf"))) && AddLibrary("mfplat", mpt::LibraryPath::System(P_("mfplat"))) && AddLibrary("mfreadwrite", mpt::LibraryPath::System(P_("mfreadwrite"))) && AddLibrary("propsys", mpt::LibraryPath::System(P_("propsys"))) )) { return false; } #endif // !MPT_OS_WINDOWS_WINRT if(!SUCCEEDED(MFStartup(MF_VERSION))) { return false; } return true; } virtual ~ComponentMediaFoundation() { if(IsAvailable()) { MFShutdown(); } } }; #endif // MPT_WITH_MEDIAFOUNDATION #ifdef MODPLUG_TRACKER std::vector CSoundFile::GetMediaFoundationFileTypes() { std::vector result; #if defined(MPT_WITH_MEDIAFOUNDATION) ComponentHandle mf; if(!IsComponentAvailable(mf)) { return result; } std::map guidMap; HKEY hkHandlers = NULL; LSTATUS regResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows Media Foundation\\ByteStreamHandlers", 0, KEY_READ, &hkHandlers); if(regResult != ERROR_SUCCESS) { return result; } for(DWORD handlerIndex = 0; ; ++handlerIndex) { WCHAR handlerTypeBuf[256]; MemsetZero(handlerTypeBuf); regResult = RegEnumKeyW(hkHandlers, handlerIndex, handlerTypeBuf, 256); if(regResult != ERROR_SUCCESS) { break; } std::wstring handlerType = handlerTypeBuf; if(handlerType.length() < 1) { continue; } HKEY hkHandler = NULL; regResult = RegOpenKeyExW(hkHandlers, handlerTypeBuf, 0, KEY_READ, &hkHandler); if(regResult != ERROR_SUCCESS) { continue; } std::vector valueNameBuf(16384); std::vector valueData(16384); for(DWORD valueIndex = 0; ; ++valueIndex) { std::fill(valueNameBuf.begin(), valueNameBuf.end(), WCHAR{0}); DWORD valueNameBufLen = 16384; DWORD valueType = 0; std::fill(valueData.begin(), valueData.end(), BYTE{0}); DWORD valueDataLen = 16384; regResult = RegEnumValueW(hkHandler, valueIndex, valueNameBuf.data(), &valueNameBufLen, NULL, &valueType, valueData.data(), &valueDataLen); if(regResult != ERROR_SUCCESS) { break; } if(valueNameBufLen <= 0 || valueType != REG_SZ || valueDataLen <= 0) { continue; } std::wstring guid = std::wstring(valueNameBuf.data()); mpt::ustring description = mpt::ToUnicode(ParseMaybeNullTerminatedStringFromBufferWithSizeInBytes(valueData.data(), valueDataLen)); description = mpt::replace(description, U_("Byte Stream Handler"), U_("Files")); description = mpt::replace(description, U_("ByteStreamHandler"), U_("Files")); guidMap[guid] .ShortName(U_("mf")) .Description(description) ; if(handlerType[0] == L'.') { guidMap[guid].AddExtension(mpt::PathString::FromWide(handlerType.substr(1))); } else { guidMap[guid].AddMimeType(mpt::ToCharset(mpt::Charset::ASCII, handlerType)); } } RegCloseKey(hkHandler); hkHandler = NULL; } RegCloseKey(hkHandlers); hkHandlers = NULL; for(const auto &it : guidMap) { result.push_back(it.second); } #endif // MPT_WITH_MEDIAFOUNDATION return result; } #endif // MODPLUG_TRACKER bool CSoundFile::ReadMediaFoundationSample(SAMPLEINDEX sample, FileReader &file, bool mo3Decode) { #if !defined(MPT_WITH_MEDIAFOUNDATION) MPT_UNREFERENCED_PARAMETER(sample); MPT_UNREFERENCED_PARAMETER(file); MPT_UNREFERENCED_PARAMETER(mo3Decode); return false; #else ComponentHandle mf; if(!IsComponentAvailable(mf)) { return false; } file.Rewind(); // When using MF to decode MP3 samples in MO3 files, we need the mp3 file extension // for some of them or otherwise MF refuses to recognize them. mpt::PathString tmpfileExtension = (mo3Decode ? P_("mp3") : P_("tmp")); mpt::IO::FileAdapter diskfile(file, mpt::TemporaryPathname{tmpfileExtension}.GetPathname()); if(!diskfile.IsValid()) { return false; } #define MPT_MF_CHECKED(x) do { \ HRESULT hr = (x); \ if(!SUCCEEDED(hr)) \ { \ return false; \ } \ } while(0) CComPtr sourceResolver; MPT_MF_CHECKED(MFCreateSourceResolver(&sourceResolver)); MF_OBJECT_TYPE objectType = MF_OBJECT_INVALID; CComPtr unknownMediaSource; MPT_MF_CHECKED(sourceResolver->CreateObjectFromURL(mpt::ToWide(diskfile.GetFilename()).c_str(), MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | MF_RESOLUTION_READ, NULL, &objectType, &unknownMediaSource)); if(objectType != MF_OBJECT_MEDIASOURCE) { return false; } CComPtr mediaSource; MPT_MF_CHECKED(unknownMediaSource->QueryInterface(&mediaSource)); FileTags tags = ReadMFMetadata(mediaSource); CComPtr sourceReader; MPT_MF_CHECKED(MFCreateSourceReaderFromMediaSource(mediaSource, NULL, &sourceReader)); CComPtr partialType; MPT_MF_CHECKED(MFCreateMediaType(&partialType)); MPT_MF_CHECKED(partialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)); MPT_MF_CHECKED(partialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM)); MPT_MF_CHECKED(sourceReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, NULL, partialType)); CComPtr uncompressedAudioType; MPT_MF_CHECKED(sourceReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, &uncompressedAudioType)); MPT_MF_CHECKED(sourceReader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, TRUE)); UINT32 numChannels = 0; MPT_MF_CHECKED(uncompressedAudioType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &numChannels)); UINT32 samplesPerSecond = 0; MPT_MF_CHECKED(uncompressedAudioType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &samplesPerSecond)); UINT32 bitsPerSample = 0; MPT_MF_CHECKED(uncompressedAudioType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bitsPerSample)); if(numChannels <= 0 || numChannels > 2) { return false; } if(samplesPerSecond <= 0) { return false; } if(bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 && bitsPerSample != 32) { return false; } std::vector rawData; for(;;) { CComPtr mfSample; DWORD mfSampleFlags = 0; CComPtr buffer; MPT_MF_CHECKED(sourceReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &mfSampleFlags, NULL, &mfSample)); if(mfSampleFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) { break; } if(mfSampleFlags & MF_SOURCE_READERF_ENDOFSTREAM) { break; } MPT_MF_CHECKED(mfSample->ConvertToContiguousBuffer(&buffer)); { BYTE *data = NULL; DWORD dataSize = 0; MPT_MF_CHECKED(buffer->Lock(&data, NULL, &dataSize)); mpt::append(rawData, mpt::byte_cast(data), mpt::byte_cast(data + dataSize)); MPT_MF_CHECKED(buffer->Unlock()); if(rawData.size() / numChannels / (bitsPerSample / 8) > MAX_SAMPLE_LENGTH) { break; } } } std::string sampleName = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(tags)); const size_t length = rawData.size() / numChannels / (bitsPerSample / 8); if(length < 1 || length > MAX_SAMPLE_LENGTH) { return false; } DestroySampleThreadsafe(sample); if(!mo3Decode) { Samples[sample].Initialize(); Samples[sample].nC5Speed = samplesPerSecond; m_szNames[sample] = sampleName; } Samples[sample].nLength = static_cast(length); Samples[sample].uFlags.set(CHN_16BIT, bitsPerSample >= 16); Samples[sample].uFlags.set(CHN_STEREO, numChannels == 2); Samples[sample].AllocateSample(); if(!Samples[sample].HasSampleData()) { return false; } if(bitsPerSample == 24) { if(numChannels == 2) { CopyStereoInterleavedSample, SC::DecodeInt24<0, littleEndian24>>>(Samples[sample], rawData.data(), rawData.size()); } else { CopyMonoSample, SC::DecodeInt24<0, littleEndian24>>>(Samples[sample], rawData.data(), rawData.size()); } } else if(bitsPerSample == 32) { if(numChannels == 2) { CopyStereoInterleavedSample, SC::DecodeInt32<0, littleEndian32>>>(Samples[sample], rawData.data(), rawData.size()); } else { CopyMonoSample, SC::DecodeInt32<0, littleEndian32>>>(Samples[sample], rawData.data(), rawData.size()); } } else { // just copy std::copy(rawData.begin(), rawData.end(), mpt::byte_cast(Samples[sample].sampleb())); } #undef MPT_MF_CHECKED if(!mo3Decode) { Samples[sample].Convert(MOD_TYPE_IT, GetType()); Samples[sample].PrecomputeLoops(*this, false); } return true; #endif } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleCopy.h0000644000175000017500000000342414053010430020313 00000000000000/* * SampleCopy.h * ------------ * Purpose: Functions for copying sample data. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/soundbase/SampleConvert.hpp" #include "openmpt/soundbase/SampleDecode.hpp" OPENMPT_NAMESPACE_BEGIN // Copy a sample data buffer. // targetBuffer: Buffer in which the sample should be copied into. // numSamples: Number of samples of size T that should be copied. targetBuffer is expected to be able to hold "numSamples * incTarget" samples. // incTarget: Number of samples by which the target data pointer is increased each time. // sourceBuffer: Buffer from which the samples should be read. // sourceSize: Size of source buffer, in bytes. // incSource: Number of samples by which the source data pointer is increased each time. // // Template arguments: // SampleConversion: Functor of type SampleConversionFunctor to apply sample conversion (see above for existing functors). template size_t CopySample(typename SampleConversion::output_t *MPT_RESTRICT outBuf, size_t numSamples, size_t incTarget, const typename SampleConversion::input_t *MPT_RESTRICT inBuf, size_t sourceSize, size_t incSource, SampleConversion conv = SampleConversion()) { const size_t sampleSize = incSource * SampleConversion::input_inc * sizeof(typename SampleConversion::input_t); LimitMax(numSamples, sourceSize / sampleSize); const size_t copySize = numSamples * sampleSize; SampleConversion sampleConv(conv); while(numSamples--) { *outBuf = sampleConv(inBuf); outBuf += incTarget; inBuf += incSource * SampleConversion::input_inc; } return copySize; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_667.cpp0000644000175000017500000001147114630721373020074 00000000000000/* * Load_667.cpp * ------------ * Purpose: Composer 667 module loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct _667FileHeader { using InstrName = std::array; char magic[2]; // 'gf' (0x6667, ha ha) InstrName names[64]; uint8 speed; uint8 numOrders; uint16le patOffsets[128]; // Relative to end of instrument definitions bool IsValid() const { if(memcmp(magic, "gf", 2) || speed < 1 || speed > 15 || numOrders > 128) return false; for(const auto &name : names) { for(const char c : name) { if(static_cast(c) <= 31) return false; } } int32 prevOffset = -1; for(const int32 offset : patOffsets) { if(offset <= prevOffset) return false; prevOffset = offset; } return true; } uint32 GetHeaderMinimumAdditionalSize() const { return numOrders + 64 * 11; } }; MPT_BINARY_STRUCT(_667FileHeader, 772) CSoundFile::ProbeResult CSoundFile::ProbeFileHeader667(MemoryFileReader file, const uint64 *pfilesize) { _667FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::Read667(FileReader &file, ModLoadingFlags loadFlags) { _667FileHeader fileHeader; file.Rewind(); if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) return false; if(!file.CanRead(fileHeader.GetHeaderMinimumAdditionalSize())) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_S3M, 18); m_SongFlags.set(SONG_IMPORTED); Order().SetDefaultTempoInt(150); Order().SetDefaultSpeed(fileHeader.speed); m_nSamples = 64; ReadOrderFromFile(Order(), file, fileHeader.numOrders); for(PATTERNINDEX pat : Order()) { if(pat >= 128) return false; } for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { // Reorder OPL patch bytes (interleave modulator and carrier) const auto fm = file.ReadArray(); OPLPatch patch{{}}; patch[0] = fm[1]; patch[1] = fm[6]; patch[2] = fm[2]; patch[3] = fm[7]; patch[4] = fm[3]; patch[5] = fm[8]; patch[6] = fm[4]; patch[7] = fm[9]; patch[8] = fm[5]; patch[9] = fm[10]; patch[10] = fm[0]; ModSample &mptSmp = Samples[smp]; mptSmp.Initialize(MOD_TYPE_S3M); mptSmp.SetAdlib(true, patch); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.names[smp - 1]); } if(loadFlags & loadPatternData) { const auto patternOffset = file.GetPosition(); bool leftChn = false, rightChn = false; Patterns.ResizeArray(128); for(PATTERNINDEX pat = 0; pat < 128; pat++) { // 4674 bytes is the largest sensible pattern size (every cell is written to exactly once + jump at end of pattern) FileReader patData = file.GetChunkAt(patternOffset + fileHeader.patOffsets[pat], 4674); if(!patData.IsValid() || !Patterns.Insert(pat, 32)) break; ROWINDEX row = 0; auto rowData = Patterns[pat].GetRow(row); while(patData.CanRead(1)) { uint8 b = patData.ReadUint8(); if(b == 0xFF) { // End of row uint8 skip = patData.ReadUint8(); row += skip; if(row >= 32 || skip == 0) break; rowData = Patterns[pat].GetRow(row); } else if(b == 0xFE) { // Instrument auto instr = patData.ReadArray(); if(instr[0] >= GetNumChannels() || instr[1] > 63) return false; rowData[instr[0]].instr = instr[1] + 1; } else if(b == 0xFD) { // Volume auto vol = patData.ReadArray(); if(vol[0] >= GetNumChannels() || vol[1] > 63) return false; rowData[vol[0]].SetVolumeCommand(VOLCMD_VOLUME, 63u - vol[1]); } else if(b == 0xFC) { // Jump to pattern uint8 target = patData.ReadUint8(); rowData[0].SetEffectCommand(CMD_POSITIONJUMP, target); } else if(b == 0xFB) { // Pattern break rowData[0].SetEffectCommand(CMD_PATTERNBREAK, 0); } else if(b < GetNumChannels()) { // Note data uint8 note = patData.ReadUint8(); if(note >= 0x7C) return false; rowData[b].note = static_cast(NOTE_MIN + 12 + (note & 0x0F) + (note >> 4) * 12); if(b % 2u) rightChn = true; else leftChn = true; } else { return false; } } } if(leftChn && rightChn) { for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = (chn % 2u) ? 256 : 0; } } } m_modFormat.formatName = UL_("Composer 667"); m_modFormat.type = UL_("667"); m_modFormat.madeWithTracker = UL_("Composer 667"); m_modFormat.charset = mpt::Charset::CP437; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ModInstrument.h0000644000175000017500000002044514734547233021077 00000000000000/* * ModInstrument.h * --------------- * Purpose: Module Instrument header class and helpers * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "InstrumentSynth.h" #include "modcommand.h" #include "tuningbase.h" #include "Snd_defs.h" #include "openmpt/base/FlagSet.hpp" #include "../common/misc_util.h" #include #include OPENMPT_NAMESPACE_BEGIN struct ModChannel; // Instrument Nodes struct EnvelopeNode { using tick_t = uint16; using value_t = uint8; tick_t tick = 0; // Envelope node position (x axis) value_t value = 0; // Envelope node value (y axis) constexpr EnvelopeNode() = default; constexpr EnvelopeNode(tick_t tick, value_t value) : tick{tick}, value{value} { } bool operator== (const EnvelopeNode &other) const { return tick == other.tick && value == other.value; } }; // Instrument Envelopes struct InstrumentEnvelope : public std::vector { FlagSet dwFlags; // Envelope flags uint8 nLoopStart = 0; // Loop start node uint8 nLoopEnd = 0; // Loop end node uint8 nSustainStart = 0; // Sustain start node uint8 nSustainEnd = 0; // Sustain end node uint8 nReleaseNode = ENV_RELEASE_NODE_UNSET; // Release node // Convert envelope data between various formats. void Convert(MODTYPE fromType, MODTYPE toType); // Get envelope value at a given tick. Assumes that the envelope data is in rage [0, rangeIn], // returns value in range [0, rangeOut]. int32 GetValueFromPosition(int position, int32 rangeOut, int32 rangeIn = ENVELOPE_MAX) const; // Ensure that ticks are ordered in increasing order and values are within the allowed range. void Sanitize(uint8 maxValue = ENVELOPE_MAX); uint32 size() const { return static_cast(std::vector::size()); } uint8 LastPoint() const { return static_cast(std::max(size(), uint32(1)) - 1); } using std::vector::push_back; void push_back(EnvelopeNode::tick_t tick, EnvelopeNode::value_t value) { emplace_back(tick, value); } }; // Instrument Struct struct ModInstrument { uint32 nFadeOut = 256; // Instrument fadeout speed uint32 nGlobalVol = 64; // Global volume (0...64, all sample volumes are multiplied with this - TODO: This is 0...128 in Impulse Tracker) uint32 nPan = 32 * 4; // Default pan (0...256), if the appropriate flag is set. Sample panning overrides instrument panning. uint16 nVolRampUp = 0; // Default sample ramping up, 0 = use global default ResamplingMode resampling = SRCMODE_DEFAULT; // Resampling mode FlagSet dwFlags; // Instrument flags NewNoteAction nNNA = NewNoteAction::NoteCut; // New note action DuplicateCheckType nDCT = DuplicateCheckType::None; // Duplicate check type (i.e. which condition will trigger the duplicate note action) DuplicateNoteAction nDNA = DuplicateNoteAction::NoteCut; // Duplicate note action uint8 nPanSwing = 0; // Random panning factor (0...64) uint8 nVolSwing = 0; // Random volume factor (0...100) uint8 nIFC = 0; // Default filter cutoff (0...127). Used if the high bit is set uint8 nIFR = 0; // Default filter resonance (0...127). Used if the high bit is set uint8 nCutSwing = 0; // Random cutoff factor (0...64) uint8 nResSwing = 0; // Random resonance factor (0...64) FilterMode filterMode = FilterMode::Unchanged; // Default filter mode int8 nPPS = 0; // Pitch/Pan separation (i.e. how wide the panning spreads, -32...32) uint8 nPPC = NOTE_MIDDLEC - NOTE_MIN; // Pitch/Pan centre (zero-based) uint16 wMidiBank = 0; // MIDI Bank (1...16384). 0 = Don't send. uint8 nMidiProgram = 0; // MIDI Program (1...128). 0 = Don't send. uint8 nMidiChannel = 0; // MIDI Channel (1...16). 0 = Don't send. 17 = Mapped (Send to tracker channel modulo 16). uint8 nMidiDrumKey = 0; // Drum set note mapping (currently only used by the .MID loader) int8 midiPWD = 2; // MIDI Pitch Wheel Depth and CMD_FINETUNE depth in semitones PLUGINDEX nMixPlug = 0; // Plugin assigned to this instrument (0 = no plugin, 1 = first plugin) PlugVelocityHandling pluginVelocityHandling = PLUGIN_VELOCITYHANDLING_CHANNEL; // How to deal with plugin velocity PlugVolumeHandling pluginVolumeHandling = PLUGIN_VOLUMEHANDLING_IGNORE; // How to deal with plugin volume TEMPO pitchToTempoLock; // BPM at which the samples assigned to this instrument loop correctly (0 = unset) CTuning *pTuning = nullptr; // sample tuning assigned to this instrument InstrumentSynth synth; // Synth scripts for this instrument InstrumentEnvelope VolEnv; // Volume envelope data InstrumentEnvelope PanEnv; // Panning envelope data InstrumentEnvelope PitchEnv; // Pitch / filter envelope data std::array NoteMap; // Note mapping, e.g. C-5 => D-5 std::array Keyboard; // Sample mapping, e.g. C-5 => Sample 1 mpt::charbuf name; mpt::charbuf filename; std::string GetName() const { return name; } std::string GetFilename() const { return filename; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // WHEN adding new members here, ALSO update InstrumentExtensions.cpp // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MPT_CONSTEXPR20_CONTAINER_FUN explicit ModInstrument(SAMPLEINDEX sample = 0) : NoteMap{mpt::generate_array([](std::size_t i){ return static_cast(NOTE_MIN + i); })} , Keyboard{mpt::init_array(sample)} { return; } // Assign all notes to a given sample. MPT_CONSTEXPR20_ALGORITHM_FUN void AssignSample(SAMPLEINDEX sample) { Keyboard.fill(sample); } // Reset note mapping (i.e. every note is mapped to itself) MPT_CONSTEXPR20_ALGORITHM_FUN void ResetNoteMap() { std::iota(NoteMap.begin(), NoteMap.end(), static_cast(NOTE_MIN)); } // If the instrument has a non-default note mapping and can be simplified to use the default note mapping by transposing samples, // the list of samples that would need to be transposed and the corresponding transpose values are returned - otherwise an empty map. std::map CanConvertToDefaultNoteMap() const; // Transpose entire note mapping by given number of semitones void Transpose(int8 amount); MPT_CONSTEXPRINLINE bool IsCutoffEnabled() const { return (nIFC & 0x80) != 0; } MPT_CONSTEXPRINLINE bool IsResonanceEnabled() const { return (nIFR & 0x80) != 0; } MPT_CONSTEXPRINLINE uint8 GetCutoff() const { return (nIFC & 0x7F); } MPT_CONSTEXPRINLINE uint8 GetResonance() const { return (nIFR & 0x7F); } MPT_CONSTEXPRINLINE void SetCutoff(uint8 cutoff, bool enable) { nIFC = std::min(cutoff, uint8(0x7F)) | (enable ? 0x80 : 0x00); } MPT_CONSTEXPRINLINE void SetResonance(uint8 resonance, bool enable) { nIFR = std::min(resonance, uint8(0x7F)) | (enable ? 0x80 : 0x00); } MPT_CONSTEXPRINLINE bool HasValidMIDIChannel() const { return (nMidiChannel >= 1 && nMidiChannel <= 17); } uint8 GetMIDIChannel(const ModChannel &channel, CHANNELINDEX chn) const; MPT_CONSTEXPRINLINE void SetTuning(CTuning *pT) { pTuning = pT; } // Get a reference to a specific envelope of this instrument MPT_CONSTEXPRINLINE const InstrumentEnvelope &GetEnvelope(EnvelopeType envType) const { switch(envType) { case ENV_VOLUME: default: return VolEnv; case ENV_PANNING: return PanEnv; case ENV_PITCH: return PitchEnv; } } InstrumentEnvelope &GetEnvelope(EnvelopeType envType) { return const_cast(static_cast(*this).GetEnvelope(envType)); } // Get a set of all samples referenced by this instrument std::set GetSamples() const; // Write sample references into a bool vector. If a sample is referenced by this instrument, true is written. // The caller has to initialize the vector. void GetSamples(std::vector &referencedSamples) const; // Translate instrument properties between two given formats. void Convert(MODTYPE fromType, MODTYPE toType); // Sanitize all instrument data. void Sanitize(MODTYPE modType); }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_pt36.cpp0000644000175000017500000001166714644610543020356 00000000000000/* * Load_pt36.cpp * ------------- * Purpose: ProTracker 3.6 wrapper format loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct PT36IffChunk { // IFF chunk names enum ChunkIdentifiers { idVERS = MagicBE("VERS"), idINFO = MagicBE("INFO"), idCMNT = MagicBE("CMNT"), idPTDT = MagicBE("PTDT"), }; uint32be signature; // IFF chunk name uint32be chunksize; // chunk size without header }; MPT_BINARY_STRUCT(PT36IffChunk, 8) struct PT36InfoChunk { char name[32]; uint16be numSamples; uint16be numOrders; uint16be numPatterns; uint16be volume; uint16be tempo; uint16be flags; uint16be dateDay; uint16be dateMonth; uint16be dateYear; uint16be dateHour; uint16be dateMinute; uint16be dateSecond; uint16be playtimeHour; uint16be playtimeMinute; uint16be playtimeSecond; uint16be playtimeMsecond; }; MPT_BINARY_STRUCT(PT36InfoChunk, 64) struct PT36Header { char magicFORM[4]; // "FORM" uint32be size; char magicMODL[4]; // "MODL" bool IsValid() const { if(std::memcmp(magicFORM, "FORM", 4)) return false; if(std::memcmp(magicMODL, "MODL", 4)) return false; return true; } }; MPT_BINARY_STRUCT(PT36Header, 12) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize) { PT36Header fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } // ProTracker 3.6 version of the MOD format // Basically just a normal ProTracker mod with different magic, wrapped in an IFF file. // The "PTDT" chunk is passed to the normal MOD loader. bool CSoundFile::ReadPT36(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); PT36Header fileHeader; if(!file.ReadStruct(fileHeader)) return false; if(!fileHeader.IsValid()) return false; bool ok = false, infoOk = false; FileReader commentChunk; mpt::ustring version; PT36InfoChunk info; MemsetZero(info); // Go through IFF chunks... PT36IffChunk iffHead; if(!file.ReadStruct(iffHead)) { return false; } // First chunk includes "MODL" magic in size iffHead.chunksize -= 4; do { // All chunk sizes include chunk header iffHead.chunksize -= 8; if(loadFlags == onlyVerifyHeader && iffHead.signature == PT36IffChunk::idPTDT) { return true; } FileReader chunk = file.ReadChunk(iffHead.chunksize); if(!chunk.IsValid()) { break; } switch(iffHead.signature) { case PT36IffChunk::idVERS: chunk.Skip(4); if(chunk.ReadMagic("PT") && iffHead.chunksize > 6) { chunk.ReadString(version, mpt::Charset::Amiga_no_C1, iffHead.chunksize - 6); } break; case PT36IffChunk::idINFO: infoOk = chunk.ReadStruct(info); break; case PT36IffChunk::idCMNT: commentChunk = chunk; break; case PT36IffChunk::idPTDT: ok = ReadMOD(chunk, loadFlags); break; } } while(file.ReadStruct(iffHead)); if(version.empty()) { version = UL_("3.6"); } // both an info chunk and a module are required if(ok && infoOk) { bool vblank = (info.flags & 0x100) == 0; m_playBehaviour.set(kMODVBlankTiming, vblank); if(info.volume != 0) m_nSamplePreAmp = std::min(uint16(64), static_cast(info.volume)); if(info.tempo != 0 && !vblank) Order().SetDefaultTempoInt(info.tempo); if(info.name[0]) m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, info.name); if(mpt::is_in_range(info.dateMonth, 1, 12) && mpt::is_in_range(info.dateDay, 1, 31) && mpt::is_in_range(info.dateHour, 0, 23) && mpt::is_in_range(info.dateMinute, 0, 59) && mpt::is_in_range(info.dateSecond, 0, 59)) { #ifdef MODPLUG_TRACKER m_modFormat.timezone = mpt::Date::LogicalTimezone::Local; #else m_modFormat.timezone = mpt::Date::LogicalTimezone::Unspecified; #endif FileHistory mptHistory; mptHistory.loadDate.year = info.dateYear + 1900; mptHistory.loadDate.month = info.dateMonth; mptHistory.loadDate.day = info.dateDay; mptHistory.loadDate.hours = info.dateHour; mptHistory.loadDate.minutes = info.dateMinute; mptHistory.loadDate.seconds = info.dateSecond; m_FileHistory.push_back(mptHistory); } } if(ok) { if(commentChunk.IsValid()) { std::string author; commentChunk.ReadString(author, 32); if(author != "UNNAMED AUTHOR") m_songArtist = mpt::ToUnicode(mpt::Charset::Amiga_no_C1, author); if(!commentChunk.NoBytesLeft()) { m_songMessage.ReadFixedLineLength(commentChunk, commentChunk.BytesLeft(), 40, 0); } } m_modFormat.madeWithTracker = UL_("ProTracker ") + version; } m_SongFlags.set(SONG_PT_MODE); m_playBehaviour.set(kMODIgnorePanning); m_playBehaviour.set(kMODOneShotLoops); m_playBehaviour.reset(kMODSampleSwap); return ok; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Dlsbank.cpp0000644000175000017500000021242114733325141020164 00000000000000/* * DLSBank.cpp * ----------- * Purpose: Sound bank loading. * Notes : Supported sound bank types: DLS (including embedded DLS in MSS & RMI), SF2, SF3 / SF4 (modified SF2 with compressed samples) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Dlsbank.h" #include "Sndfile.h" #ifdef MODPLUG_TRACKER #include "../common/mptFileIO.h" #include "../mptrack/Mptrack.h" #include "mpt/io_file/inputfile.hpp" #include "mpt/io_file_read/inputfile_filecursor.hpp" #endif #include "Loaders.h" #include "SampleCopy.h" #include "SampleIO.h" #include "../common/FileReader.h" #include "../common/mptStringBuffer.h" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "openmpt/base/Endian.hpp" OPENMPT_NAMESPACE_BEGIN #ifdef MODPLUG_TRACKER #ifdef MPT_ALL_LOGGING #define DLSBANK_LOG #define DLSINSTR_LOG #endif #define F_RGN_OPTION_SELFNONEXCLUSIVE 0x0001 // Region Flags enum RegionFlags { DLSREGION_KEYGROUPMASK = 0x0F, DLSREGION_OVERRIDEWSMP = 0x10, DLSREGION_PINGPONGLOOP = 0x20, DLSREGION_SAMPLELOOP = 0x40, DLSREGION_SELFNONEXCLUSIVE = 0x80, DLSREGION_SUSTAINLOOP = 0x100, }; /////////////////////////////////////////////////////////////////////////// // Articulation connection graph definitions enum ConnectionSource : uint16 { // Generic Sources CONN_SRC_NONE = 0x0000, CONN_SRC_LFO = 0x0001, CONN_SRC_KEYONVELOCITY = 0x0002, CONN_SRC_KEYNUMBER = 0x0003, CONN_SRC_EG1 = 0x0004, CONN_SRC_EG2 = 0x0005, CONN_SRC_PITCHWHEEL = 0x0006, CONN_SRC_POLYPRESSURE = 0x0007, CONN_SRC_CHANNELPRESSURE = 0x0008, CONN_SRC_VIBRATO = 0x0009, // Midi Controllers 0-127 CONN_SRC_CC1 = 0x0081, CONN_SRC_CC7 = 0x0087, CONN_SRC_CC10 = 0x008a, CONN_SRC_CC11 = 0x008b, CONN_SRC_CC91 = 0x00db, CONN_SRC_CC93 = 0x00dd, CONN_SRC_RPN0 = 0x0100, CONN_SRC_RPN1 = 0x0101, CONN_SRC_RPN2 = 0x0102, }; enum ConnectionDestination : uint16 { // Generic Destinations CONN_DST_NONE = 0x0000, CONN_DST_ATTENUATION = 0x0001, CONN_DST_RESERVED = 0x0002, CONN_DST_PITCH = 0x0003, CONN_DST_PAN = 0x0004, // LFO Destinations CONN_DST_LFO_FREQUENCY = 0x0104, CONN_DST_LFO_STARTDELAY = 0x0105, CONN_DST_KEYNUMBER = 0x0005, // EG1 Destinations CONN_DST_EG1_ATTACKTIME = 0x0206, CONN_DST_EG1_DECAYTIME = 0x0207, CONN_DST_EG1_RESERVED = 0x0208, CONN_DST_EG1_RELEASETIME = 0x0209, CONN_DST_EG1_SUSTAINLEVEL = 0x020a, CONN_DST_EG1_DELAYTIME = 0x020b, CONN_DST_EG1_HOLDTIME = 0x020c, CONN_DST_EG1_SHUTDOWNTIME = 0x020d, // EG2 Destinations CONN_DST_EG2_ATTACKTIME = 0x030a, CONN_DST_EG2_DECAYTIME = 0x030b, CONN_DST_EG2_RESERVED = 0x030c, CONN_DST_EG2_RELEASETIME = 0x030d, CONN_DST_EG2_SUSTAINLEVEL = 0x030e, CONN_DST_EG2_DELAYTIME = 0x030f, CONN_DST_EG2_HOLDTIME = 0x0310, CONN_TRN_NONE = 0x0000, CONN_TRN_CONCAVE = 0x0001, }; ////////////////////////////////////////////////////////// // Supported DLS1 Articulations // [4-bit transform][12-bit dest][8-bit control][8-bit source] = 32-bit ID constexpr uint32 DLSArt(uint8 src, uint8 ctl, uint16 dst) { return (dst << 16u) | (ctl << 8u) | src; } enum DLSArt : uint32 { // Vibrato / Tremolo ART_LFO_FREQUENCY = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_LFO_FREQUENCY), ART_LFO_STARTDELAY = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_LFO_STARTDELAY), ART_LFO_ATTENUATION = DLSArt(CONN_SRC_LFO, CONN_SRC_NONE, CONN_DST_ATTENUATION), ART_LFO_PITCH = DLSArt(CONN_SRC_LFO, CONN_SRC_NONE, CONN_DST_PITCH), ART_LFO_MODWTOATTN = DLSArt(CONN_SRC_LFO, CONN_SRC_CC1, CONN_DST_ATTENUATION), ART_LFO_MODWTOPITCH = DLSArt(CONN_SRC_LFO, CONN_SRC_CC1, CONN_DST_PITCH), // Volume Envelope ART_VOL_EG_ATTACKTIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_ATTACKTIME), ART_VOL_EG_DECAYTIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_DECAYTIME), ART_VOL_EG_SUSTAINLEVEL = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_SUSTAINLEVEL), ART_VOL_EG_RELEASETIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_RELEASETIME), ART_VOL_EG_DELAYTIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_DELAYTIME), ART_VOL_EG_HOLDTIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_HOLDTIME), ART_VOL_EG_SHUTDOWNTIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG1_SHUTDOWNTIME), ART_VOL_EG_VELTOATTACK = DLSArt(CONN_SRC_KEYONVELOCITY, CONN_SRC_NONE, CONN_DST_EG1_ATTACKTIME), ART_VOL_EG_KEYTODECAY = DLSArt(CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_EG1_DECAYTIME), // Pitch Envelope ART_PITCH_EG_ATTACKTIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_ATTACKTIME), ART_PITCH_EG_DECAYTIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_DECAYTIME), ART_PITCH_EG_SUSTAINLEVEL = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_SUSTAINLEVEL), ART_PITCH_EG_RELEASETIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_RELEASETIME), ART_PITCH_EG_VELTOATTACK = DLSArt(CONN_SRC_KEYONVELOCITY, CONN_SRC_NONE, CONN_DST_EG2_ATTACKTIME), ART_PITCH_EG_KEYTODECAY = DLSArt(CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_EG2_DECAYTIME), ART_PITCH_EG_DELAYTIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_DELAYTIME), ART_PITCH_EG_HOLDTIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_HOLDTIME), ART_PITCH_EG_DEPTH = DLSArt(CONN_SRC_EG2, CONN_SRC_NONE, CONN_DST_PITCH), // Default Pan ART_DEFAULTPAN = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_PAN), }; ////////////////////////////////////////////////////////// // DLS IFF Chunk IDs enum IFFChunkID : uint32 { // Standard IFF chunks IDs IFFID_FORM = MagicLE("FORM"), IFFID_RIFF = MagicLE("RIFF"), IFFID_LIST = MagicLE("LIST"), IFFID_INFO = MagicLE("INFO"), // IFF Info fields IFFID_ICOP = MagicLE("ICOP"), IFFID_INAM = MagicLE("INAM"), IFFID_ICMT = MagicLE("ICMT"), IFFID_IENG = MagicLE("IENG"), IFFID_ISFT = MagicLE("ISFT"), IFFID_ISBJ = MagicLE("ISBJ"), // Wave IFF chunks IDs IFFID_wave = MagicLE("wave"), IFFID_wsmp = MagicLE("wsmp"), IFFID_XDLS = MagicLE("XDLS"), IFFID_DLS = MagicLE("DLS "), IFFID_MLS = MagicLE("MLS "), IFFID_RMID = MagicLE("RMID"), IFFID_colh = MagicLE("colh"), IFFID_ins = MagicLE("ins "), IFFID_insh = MagicLE("insh"), IFFID_ptbl = MagicLE("ptbl"), IFFID_wvpl = MagicLE("wvpl"), IFFID_rgn = MagicLE("rgn "), IFFID_rgn2 = MagicLE("rgn2"), IFFID_rgnh = MagicLE("rgnh"), IFFID_wlnk = MagicLE("wlnk"), IFFID_art1 = MagicLE("art1"), IFFID_art2 = MagicLE("art2"), }; ////////////////////////////////////////////////////////// // DLS Structures definitions struct IFFCHUNK { uint32le id; uint32le len; }; MPT_BINARY_STRUCT(IFFCHUNK, 8) struct RIFFChunkID { uint32le id_RIFF; uint32le riff_len; uint32le id_DLS; }; MPT_BINARY_STRUCT(RIFFChunkID, 12) struct LISTChunk { uint32le id; uint32le len; uint32le listid; }; MPT_BINARY_STRUCT(LISTChunk, 12) struct DLSRgnRange { uint16le usLow; uint16le usHigh; }; MPT_BINARY_STRUCT(DLSRgnRange, 4) struct VERSChunk { uint32le id; uint32le len; uint16le version[4]; }; MPT_BINARY_STRUCT(VERSChunk, 16) struct PTBLChunk { uint32le cbSize; uint32le cCues; }; MPT_BINARY_STRUCT(PTBLChunk, 8) struct INSHChunk { uint32le cRegions; uint32le ulBank; uint32le ulInstrument; }; MPT_BINARY_STRUCT(INSHChunk, 12) struct RGNHChunk { DLSRgnRange RangeKey; DLSRgnRange RangeVelocity; uint16le fusOptions; uint16le usKeyGroup; }; MPT_BINARY_STRUCT(RGNHChunk, 12) struct WLNKChunk { uint16le fusOptions; uint16le usPhaseGroup; uint32le ulChannel; uint32le ulTableIndex; }; MPT_BINARY_STRUCT(WLNKChunk, 12) struct ART1Chunk { uint32le cbSize; uint32le cConnectionBlocks; }; MPT_BINARY_STRUCT(ART1Chunk, 8) struct ConnectionBlock { uint16le usSource; uint16le usControl; uint16le usDestination; uint16le usTransform; int32le lScale; }; MPT_BINARY_STRUCT(ConnectionBlock, 12) struct WSMPChunk { uint32le cbSize; uint16le usUnityNote; int16le sFineTune; int32le lAttenuation; uint32le fulOptions; uint32le cSampleLoops; }; MPT_BINARY_STRUCT(WSMPChunk, 20) struct WSMPSampleLoop { uint32le cbSize; uint32le ulLoopType; uint32le ulLoopStart; uint32le ulLoopLength; }; MPT_BINARY_STRUCT(WSMPSampleLoop, 16) ///////////////////////////////////////////////////////////////////// // SF2 IFF Chunk IDs enum SF2ChunkID : uint32 { IFFID_ifil = MagicLE("ifil"), IFFID_sfbk = MagicLE("sfbk"), IFFID_sfpk = MagicLE("sfpk"), // SF2Pack compressed soundfont IFFID_sdta = MagicLE("sdta"), IFFID_pdta = MagicLE("pdta"), IFFID_phdr = MagicLE("phdr"), IFFID_pbag = MagicLE("pbag"), IFFID_pgen = MagicLE("pgen"), IFFID_inst = MagicLE("inst"), IFFID_ibag = MagicLE("ibag"), IFFID_igen = MagicLE("igen"), IFFID_shdr = MagicLE("shdr"), }; /////////////////////////////////////////// // SF2 Generators IDs enum SF2Generators : uint16 { SF2_GEN_START_LOOP_FINE = 2, SF2_GEN_END_LOOP_FINE = 3, SF2_GEN_MODENVTOPITCH = 7, SF2_GEN_MODENVTOFILTERFC = 11, SF2_GEN_PAN = 17, SF2_GEN_DELAYMODENV = 25, SF2_GEN_ATTACKMODENV = 26, SF2_GEN_HOLDMODENV = 27, SF2_GEN_DECAYMODENV = 28, SF2_GEN_SUSTAINMODENV = 29, SF2_GEN_RELEASEMODENV = 30, SF2_GEN_DELAYVOLENV = 33, SF2_GEN_ATTACKVOLENV = 34, SF2_GEN_HOLDVOLENV = 35, SF2_GEN_DECAYVOLENV = 36, SF2_GEN_SUSTAINVOLENV = 37, SF2_GEN_RELEASEVOLENV = 38, SF2_GEN_INSTRUMENT = 41, SF2_GEN_KEYRANGE = 43, SF2_GEN_START_LOOP_COARSE = 45, SF2_GEN_ATTENUATION = 48, SF2_GEN_END_LOOP_COARSE = 50, SF2_GEN_COARSETUNE = 51, SF2_GEN_FINETUNE = 52, SF2_GEN_SAMPLEID = 53, SF2_GEN_SAMPLEMODES = 54, SF2_GEN_SCALE_TUNING = 56, SF2_GEN_KEYGROUP = 57, SF2_GEN_UNITYNOTE = 58, }; ///////////////////////////////////////////////////////////////////// // SF2 Structures Definitions struct SFPresetHeader { char achPresetName[20]; uint16le wPreset; uint16le wBank; uint16le wPresetBagNdx; uint32le dwLibrary; uint32le dwGenre; uint32le dwMorphology; }; MPT_BINARY_STRUCT(SFPresetHeader, 38) struct SFPresetBag { uint16le wGenNdx; uint16le wModNdx; }; MPT_BINARY_STRUCT(SFPresetBag, 4) struct SFGenList { uint16le sfGenOper; uint16le genAmount; bool ApplyToEnvelope(DLSENVELOPE &env) const; }; MPT_BINARY_STRUCT(SFGenList, 4) struct SFInst { char achInstName[20]; uint16le wInstBagNdx; }; MPT_BINARY_STRUCT(SFInst, 22) struct SFInstBag { uint16le wGenNdx; uint16le wModNdx; }; MPT_BINARY_STRUCT(SFInstBag, 4) using SFInstGenList = SFGenList; struct SFSample { char achSampleName[20]; uint32le dwStart; uint32le dwEnd; uint32le dwStartloop; uint32le dwEndloop; uint32le dwSampleRate; uint8le byOriginalPitch; int8le chPitchCorrection; uint16le wSampleLink; uint16le sfSampleType; }; MPT_BINARY_STRUCT(SFSample, 46) // End of structures definitions ///////////////////////////////////////////////////////////////////// struct SF2LoaderInfo { FileReader presetBags; FileReader presetGens; FileReader insts; FileReader instBags; FileReader instGens; }; ///////////////////////////////////////////////////////////////////// // Unit conversion static uint8 DLSSustainLevelToLinear(int32 sustain) { // 0.1% units if(sustain >= 0) { int32 l = sustain / (1000 * 512); if(l >= 0 && l <= 128) return static_cast(l); } return 128; } static int16 SF2TimeToDLS(int16 amount) { int32 time = CDLSBank::DLS32BitTimeCentsToMilliseconds(static_cast(amount) << 16); return static_cast(Clamp(time, 20, 20000) / 20); } static uint8 SF2SustainLevelToLinear(int32 sustain) { // 0.1% units int32 l = 128 * (1000 - Clamp(sustain, 0, 1000)) / 1000; return static_cast(l); } bool SFGenList::ApplyToEnvelope(DLSENVELOPE &env) const { switch(sfGenOper) { case SF2_GEN_DELAYVOLENV: env.volumeEnv.delay = SF2TimeToDLS(genAmount); break; case SF2_GEN_ATTACKVOLENV: env.volumeEnv.attack = SF2TimeToDLS(genAmount); break; case SF2_GEN_HOLDVOLENV: env.volumeEnv.hold = SF2TimeToDLS(genAmount); break; case SF2_GEN_DECAYVOLENV: env.volumeEnv.decay = SF2TimeToDLS(genAmount); break; case SF2_GEN_SUSTAINVOLENV: // 0.1% units if(genAmount >= 0) { env.volumeEnv.sustainLevel = SF2SustainLevelToLinear(genAmount); } break; case SF2_GEN_RELEASEVOLENV: env.volumeEnv.release = SF2TimeToDLS(genAmount); break; case SF2_GEN_DELAYMODENV: env.pitchEnv.delay = SF2TimeToDLS(genAmount); break; case SF2_GEN_ATTACKMODENV: env.pitchEnv.attack = SF2TimeToDLS(genAmount); break; case SF2_GEN_HOLDMODENV: env.pitchEnv.hold = SF2TimeToDLS(genAmount); break; case SF2_GEN_DECAYMODENV: env.pitchEnv.decay = SF2TimeToDLS(genAmount); break; case SF2_GEN_SUSTAINMODENV: env.pitchEnv.sustainLevel = SF2SustainLevelToLinear(genAmount); break; case SF2_GEN_RELEASEMODENV: env.pitchEnv.release = SF2TimeToDLS(genAmount); break; case SF2_GEN_MODENVTOPITCH: env.pitchEnvDepth = static_cast(genAmount); break; default: return false; } return true; } int32 CDLSBank::DLS32BitTimeCentsToMilliseconds(int32 lTimeCents) { // tc = log2(time[secs]) * 1200*65536 // time[secs] = 2^(tc/(1200*65536)) if ((uint32)lTimeCents == 0x80000000) return 0; double fmsecs = 1000.0 * std::pow(2.0, ((double)lTimeCents)/(1200.0*65536.0)); if (fmsecs < -32767) return -32767; if (fmsecs > 32767) return 32767; return (int32)fmsecs; } uint16 CDLSBank::DLSEnvelopeTimeCentsToMilliseconds(int32 value) { if(value <= -0x40000000) return 0; int32 decaytime = DLS32BitTimeCentsToMilliseconds(value); if(decaytime > 20000) decaytime = 20000; if(decaytime >= 20) return static_cast(decaytime / 20); return 0; } // 0dB = 0x10000 int32 CDLSBank::DLS32BitRelativeGainToLinear(int32 lCentibels) { // v = 10^(cb/(200*65536)) * V return (int32)(65536.0 * std::pow(10.0, ((double)lCentibels)/(200*65536.0)) ); } int32 CDLSBank::DLS32BitRelativeLinearToGain(int32 lGain) { // cb = log10(v/V) * 200 * 65536 if (lGain <= 0) return -960 * 65536; return (int32)(200 * 65536.0 * std::log10(((double)lGain) / 65536.0)); } int32 CDLSBank::DLSMidiVolumeToLinear(uint32 nMidiVolume) { return (nMidiVolume * nMidiVolume << 16) / (127*127); } ///////////////////////////////////////////////////////////////////// // Implementation CDLSBank::CDLSBank() { m_nMaxWaveLink = 0; m_nType = SOUNDBANK_TYPE_INVALID; } bool CDLSBank::IsDLSBank(const mpt::PathString &filename) { if(filename.empty()) return false; mpt::IO::InputFile f(filename, false); if(!f.IsValid()) return false; return IsDLSBank(GetFileReader(f)); } bool CDLSBank::IsDLSBank(FileReader file) { file.Rewind(); RIFFChunkID riff; if(!file.ReadStruct(riff)) return false; // Check for embedded DLS sections if(riff.id_RIFF == IFFID_FORM) { // Miles Sound System do { uint32 len = mpt::bit_cast(riff.riff_len); if(len <= 4) break; if(riff.id_DLS == IFFID_XDLS) { if(!file.ReadStruct(riff)) return false; break; // found it } if((len % 2u) != 0) len++; if(!file.Skip(len - 4)) return false; } while(file.ReadStruct(riff)); } else if(riff.id_RIFF == IFFID_RIFF && riff.id_DLS == IFFID_RMID) { for (;;) { if(!file.ReadStruct(riff)) return false; if(riff.id_DLS == IFFID_DLS || riff.id_DLS == IFFID_sfbk) break; // found it int len = riff.riff_len; if((len % 2u) != 0) len++; if((len <= 4) || !file.Skip(len - 4)) return false; } } return ((riff.id_RIFF == IFFID_RIFF) && ((riff.id_DLS == IFFID_DLS) || (riff.id_DLS == IFFID_MLS) || (riff.id_DLS == IFFID_sfbk)) && (riff.riff_len >= 256)); } /////////////////////////////////////////////////////////////// // Find an instrument based on the given parameters const DLSINSTRUMENT *CDLSBank::FindInstrument(bool isDrum, uint32 bank, uint32 program, uint32 key, uint32 *pInsNo) const { uint32 minBank = ((bank << 1) & 0x7F00) | (bank & 0x7F); uint32 maxBank = minBank; if(bank >= 0x4000) { minBank = 0x0000; maxBank = 0x7F7F; } if(isDrum) { minBank |= F_INSTRUMENT_DRUMS; maxBank |= F_INSTRUMENT_DRUMS; } const bool singleInstr = (minBank == maxBank) && (program < 0x80); const auto CompareInstrFunc = [singleInstr](const DLSINSTRUMENT &l, const DLSINSTRUMENT &r) { if(singleInstr) return l < r; else return l.ulBank < r.ulBank; }; DLSINSTRUMENT findInstr{}; findInstr.ulInstrument = program; findInstr.ulBank = minBank; const auto minInstr = std::lower_bound(m_Instruments.begin(), m_Instruments.end(), findInstr, CompareInstrFunc); findInstr.ulBank = maxBank; const auto maxInstr = std::upper_bound(m_Instruments.begin(), m_Instruments.end(), findInstr, CompareInstrFunc); const auto instrRange = mpt::as_span(m_Instruments.data() + std::distance(m_Instruments.begin(), minInstr), std::distance(minInstr, maxInstr)); for(const DLSINSTRUMENT &dlsIns : instrRange) { if((program < 0x80) && program != (dlsIns.ulInstrument & 0x7F)) continue; if(isDrum) { const bool anyKey = !key || key >= 0x80; for(const auto ®ion : dlsIns.Regions) { if(region.IsDummy()) continue; if(anyKey || (key >= region.uKeyMin && key <= region.uKeyMax)) { if(pInsNo) *pInsNo = static_cast(std::distance(m_Instruments.data(), &dlsIns)); return &dlsIns; } else if(region.uKeyMin > key) { // Regions are sorted, if we arrived here we won't find anything in the remaining regions break; } } } else { if(pInsNo) *pInsNo = static_cast(std::distance(m_Instruments.data(), &dlsIns)); return &dlsIns; } } return nullptr; } bool CDLSBank::FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum, FileReader *file) const { ModInstrument *pIns = sndFile.Instruments[ins]; if(pIns == nullptr) return false; uint32 dlsIns = 0, drumRgn = 0; const uint32 program = (pIns->nMidiProgram != 0) ? pIns->nMidiProgram - 1 : 0; const uint32 key = isDrum ? (pIns->nMidiDrumKey & 0x7F) : 0xFF; if(FindInstrument(isDrum, (pIns->wMidiBank - 1) & 0x3FFF, program, key, &dlsIns) || FindInstrument(isDrum, (pIns->wMidiBank - 1) & 0x3F80, program, key, &dlsIns) || FindInstrument(isDrum, 0xFFFF, isDrum ? 0xFF : program, key, &dlsIns)) { if(key < 0x80) drumRgn = GetRegionFromKey(dlsIns, key); if(ExtractInstrument(sndFile, ins, dlsIns, drumRgn, file)) { pIns = sndFile.Instruments[ins]; // Reset pointer because ExtractInstrument may delete the previous value. if((key >= 24) && (key < 24 + std::size(szMidiPercussionNames))) { #if MPT_COMPILER_MSVC #pragma warning(push) // false-positive #pragma warning(disable:6385) // Reading invalid data from 'szMidiPercussionNames'. #endif pIns->name = szMidiPercussionNames[key - 24]; #if MPT_COMPILER_MSVC #pragma warning(pop) #endif } return true; } } return false; } /////////////////////////////////////////////////////////////// // Update DLS instrument definition from an IFF chunk bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, FileReader chunk) { IFFCHUNK header; chunk.ReadStruct(header); if(!header.len || !chunk.CanRead(header.len)) return false; if(header.id == IFFID_LIST) { uint32 listid = chunk.ReadUint32LE(); while(chunk.CanRead(sizeof(IFFCHUNK))) { IFFCHUNK subHeader; chunk.ReadStruct(subHeader); chunk.SkipBack(sizeof(IFFCHUNK)); FileReader subData = chunk.ReadChunk(subHeader.len + sizeof(IFFCHUNK)); if(subHeader.len & 1) { chunk.Skip(1); } UpdateInstrumentDefinition(pDlsIns, subData); } switch(listid) { case IFFID_rgn: // Level 1 region case IFFID_rgn2: // Level 2 region pDlsIns->Regions.push_back({}); break; } } else { switch(header.id) { case IFFID_insh: { INSHChunk insh; chunk.ReadStruct(insh); pDlsIns->ulBank = insh.ulBank; pDlsIns->ulInstrument = insh.ulInstrument; //Log("%3d regions, bank 0x%04X instrument %3d\n", insh.cRegions, pDlsIns->ulBank, pDlsIns->ulInstrument); break; } case IFFID_rgnh: if(!pDlsIns->Regions.empty()) { RGNHChunk rgnh; chunk.ReadStruct(rgnh); DLSREGION ®ion = pDlsIns->Regions.back(); region.uKeyMin = (uint8)rgnh.RangeKey.usLow; region.uKeyMax = (uint8)rgnh.RangeKey.usHigh; region.fuOptions = (uint8)(rgnh.usKeyGroup & DLSREGION_KEYGROUPMASK); if(rgnh.fusOptions & F_RGN_OPTION_SELFNONEXCLUSIVE) region.fuOptions |= DLSREGION_SELFNONEXCLUSIVE; //Log(" Region %d: fusOptions=0x%02X usKeyGroup=0x%04X ", pDlsIns->nRegions, rgnh.fusOptions, rgnh.usKeyGroup); //Log("KeyRange[%3d,%3d] ", rgnh.RangeKey.usLow, rgnh.RangeKey.usHigh); } break; case IFFID_wlnk: if (!pDlsIns->Regions.empty()) { WLNKChunk wlnk; chunk.ReadStruct(wlnk); DLSREGION ®ion = pDlsIns->Regions.back(); region.nWaveLink = (uint16)wlnk.ulTableIndex; if((region.nWaveLink < Util::MaxValueOfType(region.nWaveLink)) && (region.nWaveLink >= m_nMaxWaveLink)) m_nMaxWaveLink = region.nWaveLink + 1; //Log(" WaveLink %d: fusOptions=0x%02X usPhaseGroup=0x%04X ", pDlsIns->nRegions, wlnk.fusOptions, wlnk.usPhaseGroup); //Log("ulChannel=%d ulTableIndex=%4d\n", wlnk.ulChannel, wlnk.ulTableIndex); } break; case IFFID_wsmp: if(!pDlsIns->Regions.empty()) { DLSREGION ®ion = pDlsIns->Regions.back(); WSMPChunk wsmp; chunk.ReadStruct(wsmp); region.fuOptions |= DLSREGION_OVERRIDEWSMP; region.uUnityNote = (uint8)wsmp.usUnityNote; region.sFineTune = wsmp.sFineTune; int32 lVolume = DLS32BitRelativeGainToLinear(wsmp.lAttenuation) / 256; if (lVolume > 256) lVolume = 256; if (lVolume < 4) lVolume = 4; region.usVolume = (uint16)lVolume; //Log(" WaveSample %d: usUnityNote=%2d sFineTune=%3d ", pDlsEnv->nRegions, p->usUnityNote, p->sFineTune); //Log("fulOptions=0x%04X loops=%d\n", p->fulOptions, p->cSampleLoops); if((wsmp.cSampleLoops) && (wsmp.cbSize + sizeof(WSMPSampleLoop) <= header.len)) { WSMPSampleLoop loop; chunk.Seek(sizeof(IFFCHUNK) + wsmp.cbSize); chunk.ReadStruct(loop); //Log("looptype=%2d loopstart=%5d loopend=%5d\n", ploop->ulLoopType, ploop->ulLoopStart, ploop->ulLoopLength); if(loop.ulLoopLength > 3) { region.fuOptions |= DLSREGION_SAMPLELOOP; //if(loop.ulLoopType) region.fuOptions |= DLSREGION_PINGPONGLOOP; region.ulLoopStart = loop.ulLoopStart; region.ulLoopEnd = loop.ulLoopStart + loop.ulLoopLength; } } } break; case IFFID_art1: case IFFID_art2: { ART1Chunk art1; chunk.ReadStruct(art1); if(!(pDlsIns->ulBank & F_INSTRUMENT_DRUMS)) { pDlsIns->nMelodicEnv = static_cast(m_Envelopes.size() + 1); } else { if(!pDlsIns->Regions.empty()) pDlsIns->Regions.back().uPercEnv = static_cast(m_Envelopes.size() + 1); } if(art1.cbSize + art1.cConnectionBlocks * sizeof(ConnectionBlock) > header.len) break; DLSENVELOPE dlsEnv; //Log(" art1 (%3d bytes): cbSize=%d cConnectionBlocks=%d\n", p->len, p->cbSize, p->cConnectionBlocks); chunk.Seek(sizeof(IFFCHUNK) + art1.cbSize); for (uint32 iblk = 0; iblk < art1.cConnectionBlocks; iblk++) { ConnectionBlock blk; chunk.ReadStruct(blk); // [4-bit transform][12-bit dest][8-bit control][8-bit source] = 32-bit ID uint32 dwArticulation = blk.usTransform; dwArticulation = (dwArticulation << 12) | (blk.usDestination & 0x0FFF); dwArticulation = (dwArticulation << 8) | (blk.usControl & 0x00FF); dwArticulation = (dwArticulation << 8) | (blk.usSource & 0x00FF); switch(dwArticulation) { case ART_DEFAULTPAN: { int32 pan = 128 + blk.lScale / (65536000/128); dlsEnv.defaultPan = mpt::saturate_cast(pan); } break; case ART_VOL_EG_DELAYTIME: // 32-bit time cents units. range = [0s, 20s] dlsEnv.volumeEnv.delay = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); break; case ART_VOL_EG_ATTACKTIME: // 32-bit time cents units. range = [0s, 20s] if(blk.lScale > -0x40000000) { int32 l = std::min(0, blk.lScale - 78743200); // maximum velocity dlsEnv.volumeEnv.attack = DLSEnvelopeTimeCentsToMilliseconds(l); } break; case ART_VOL_EG_HOLDTIME: // 32-bit time cents units. range = [0s, 20s] dlsEnv.volumeEnv.hold = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); break; case ART_VOL_EG_DECAYTIME: // 32-bit time cents units. range = [0s, 20s] dlsEnv.volumeEnv.decay = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); break; case ART_VOL_EG_RELEASETIME: // 32-bit time cents units. range = [0s, 20s] dlsEnv.volumeEnv.release = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); break; case ART_VOL_EG_SUSTAINLEVEL: // 0.1% units if(blk.lScale >= 0) { dlsEnv.volumeEnv.sustainLevel = DLSSustainLevelToLinear(blk.lScale); } break; case ART_PITCH_EG_DELAYTIME: // 32-bit time cents units. range = [0s, 20s] dlsEnv.pitchEnv.delay = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); break; case ART_PITCH_EG_ATTACKTIME: // 32-bit time cents units. range = [0s, 20s] if(blk.lScale > -0x40000000) { int32 l = std::min(0, blk.lScale - 78743200); // maximum velocity dlsEnv.pitchEnv.attack = DLSEnvelopeTimeCentsToMilliseconds(l); } break; case ART_PITCH_EG_HOLDTIME: // 32-bit time cents units. range = [0s, 20s] dlsEnv.pitchEnv.hold = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); break; case ART_PITCH_EG_DECAYTIME: // 32-bit time cents units. range = [0s, 20s] dlsEnv.pitchEnv.decay = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); break; case ART_PITCH_EG_RELEASETIME: // 32-bit time cents units. range = [0s, 20s] dlsEnv.pitchEnv.release = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); break; case ART_PITCH_EG_SUSTAINLEVEL: // 0.1% units dlsEnv.pitchEnv.sustainLevel = DLSSustainLevelToLinear(blk.lScale); break; case ART_PITCH_EG_DEPTH: dlsEnv.pitchEnvDepth = mpt::saturate_cast(blk.lScale / 65536); break; //default: // Log(" Articulation = 0x%08X value=%d\n", dwArticulation, blk.lScale); } } m_Envelopes.push_back(dlsEnv); } break; case IFFID_INAM: chunk.ReadString(pDlsIns->szName, header.len); break; default: #ifdef DLSINSTR_LOG { char sid[5]{}; memcpy(sid, &header.id, 4); MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT("Unsupported DLS chunk: {} ({} bytes)")(mpt::ToUnicode(mpt::Charset::ASCII, mpt::String::ReadAutoBuf(sid)), header.len.get())); } #endif break; } } return true; } /////////////////////////////////////////////////////////////// // Converts SF2 chunks to DLS bool CDLSBank::UpdateSF2PresetData(SF2LoaderInfo &sf2info, const IFFCHUNK &header, FileReader &chunk) { if (!chunk.IsValid()) return false; switch(header.id) { case IFFID_phdr: if(m_Instruments.empty()) { uint32 numIns = static_cast(chunk.GetLength() / sizeof(SFPresetHeader)); if(numIns <= 1) break; // The terminal sfPresetHeader record should never be accessed, and exists only to provide a terminal wPresetBagNdx with which to determine the number of zones in the last preset. numIns--; m_Instruments.resize(numIns); #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBank", MPT_UFORMAT("phdr: {} instruments")(m_Instruments.size())); #endif SFPresetHeader psfh; chunk.ReadStruct(psfh); for(auto &dlsIns : m_Instruments) { mpt::String::WriteAutoBuf(dlsIns.szName) = mpt::String::ReadAutoBuf(psfh.achPresetName); dlsIns.ulInstrument = psfh.wPreset & 0x7F; dlsIns.ulBank = (psfh.wBank >= 128) ? F_INSTRUMENT_DRUMS : (psfh.wBank << 8); dlsIns.wPresetBagNdx = psfh.wPresetBagNdx; dlsIns.wPresetBagNum = 1; chunk.ReadStruct(psfh); if (psfh.wPresetBagNdx > dlsIns.wPresetBagNdx) dlsIns.wPresetBagNum = static_cast(psfh.wPresetBagNdx - dlsIns.wPresetBagNdx); } } break; case IFFID_pbag: if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFPresetBag))) { sf2info.presetBags = chunk.GetChunk(chunk.BytesLeft()); } #ifdef DLSINSTR_LOG else MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", U_("pbag: no instruments!")); #endif break; case IFFID_pgen: if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFGenList))) { sf2info.presetGens = chunk.GetChunk(chunk.BytesLeft()); } #ifdef DLSINSTR_LOG else MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", U_("pgen: no instruments!")); #endif break; case IFFID_inst: if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFInst))) { sf2info.insts = chunk.GetChunk(chunk.BytesLeft()); } break; case IFFID_ibag: if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFInstBag))) { sf2info.instBags = chunk.GetChunk(chunk.BytesLeft()); } break; case IFFID_igen: if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFInstGenList))) { sf2info.instGens = chunk.GetChunk(chunk.BytesLeft()); } break; case IFFID_shdr: if (m_SamplesEx.empty()) { uint32 numSmp = static_cast(chunk.GetLength() / sizeof(SFSample)); if (numSmp < 1) break; m_SamplesEx.resize(numSmp); m_WaveForms.resize(numSmp); #ifdef DLSINSTR_LOG MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT("shdr: {} samples")(m_SamplesEx.size())); #endif for (uint32 i = 0; i < numSmp; i++) { SFSample p; chunk.ReadStruct(p); DLSSAMPLEEX &dlsSmp = m_SamplesEx[i]; mpt::String::WriteAutoBuf(dlsSmp.szName) = mpt::String::ReadAutoBuf(p.achSampleName); dlsSmp.dwLen = 0; dlsSmp.dwSampleRate = p.dwSampleRate; dlsSmp.byOriginalPitch = p.byOriginalPitch; dlsSmp.chPitchCorrection = static_cast(Util::muldivr(p.chPitchCorrection, 128, 100)); // cognitone's sf2convert tool doesn't set the correct sample flags (0x01 / 0x02 instead of 0x10/ 0x20). // For SF3, we ignore this and go by https://github.com/FluidSynth/fluidsynth/wiki/SoundFont3Format instead // As cognitone's tool is the only tool writing SF4 files, we always assume compressed samples with SF4 files if bits 0/1 are set. uint16 sampleType = p.sfSampleType; if(m_sf2version >= 0x4'0000 && m_sf2version <= 0x4'FFFF && (sampleType & 0x03)) sampleType = (sampleType & 0xFFFC) | 0x10; dlsSmp.compressed = (sampleType & 0x10); if(((sampleType & 0x7FCF) <= 4) && (p.dwEnd >= p.dwStart + 4)) { m_WaveForms[i] = p.dwStart; dlsSmp.dwLen = (p.dwEnd - p.dwStart); if(!dlsSmp.compressed) { m_WaveForms[i] *= 2; dlsSmp.dwLen *= 2; if((p.dwEndloop > p.dwStartloop + 7) && (p.dwStartloop >= p.dwStart)) { dlsSmp.dwStartloop = p.dwStartloop - p.dwStart; dlsSmp.dwEndloop = p.dwEndloop - p.dwStart; } } else { if(p.dwEndloop > p.dwStartloop + 7) { dlsSmp.dwStartloop = p.dwStartloop; dlsSmp.dwEndloop = p.dwEndloop; } } } } } break; default: #ifdef DLSINSTR_LOG { char sdbg[5]{}; memcpy(sdbg, &header.id, 4); MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT("Unsupported SF2 chunk: {} ({} bytes)")(mpt::ToUnicode(mpt::Charset::ASCII, mpt::String::ReadAutoBuf(sdbg)), header.len.get())); } #endif break; } return true; } // Convert all instruments to the DLS format bool CDLSBank::ConvertSF2ToDLS(SF2LoaderInfo &sf2info) { if (m_Instruments.empty() || m_SamplesEx.empty()) return false; const uint32 numInsts = static_cast(sf2info.insts.GetLength() / sizeof(SFInst)); const uint32 numInstBags = static_cast(sf2info.instBags.GetLength() / sizeof(SFInstBag)); std::vector> instruments; // instrument, key range std::vector generators; std::vector instrGenerators; for(auto &dlsIns : m_Instruments) { instruments.clear(); DLSENVELOPE dlsEnv; int32 instrAttenuation = 0; int16 instrFinetune = 0; // Load Preset Bags sf2info.presetBags.Seek(dlsIns.wPresetBagNdx * sizeof(SFPresetBag)); for(uint32 ipbagcnt = 0; ipbagcnt < dlsIns.wPresetBagNum; ipbagcnt++) { // Load generators for each preset bag SFPresetBag bag[2]; if(!sf2info.presetBags.ReadArray(bag)) break; sf2info.presetBags.SkipBack(sizeof(SFPresetBag)); sf2info.presetGens.Seek(bag[0].wGenNdx * sizeof(SFGenList)); uint16 keyRange = 0xFFFF; if(!sf2info.presetGens.ReadVector(generators, bag[1].wGenNdx - bag[0].wGenNdx)) continue; for(const auto &gen : generators) { const int16 value = static_cast(gen.genAmount); switch(gen.sfGenOper) { case SF2_GEN_INSTRUMENT: if(const auto instr = std::make_pair(gen.genAmount.get(), keyRange); !mpt::contains(instruments, instr)) instruments.push_back(instr); keyRange = 0xFFFF; break; case SF2_GEN_KEYRANGE: keyRange = gen.genAmount; break; case SF2_GEN_ATTENUATION: instrAttenuation = -value; break; case SF2_GEN_COARSETUNE: instrFinetune += value * 128; break; case SF2_GEN_FINETUNE: instrFinetune += static_cast(Util::muldiv(static_cast(value), 128, 100)); break; default: if(!gen.ApplyToEnvelope(dlsEnv)) { #ifdef DLSINSTR_LOG MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT("Preset {} bag {} gen {}: genoper={} amount={}{}") (static_cast(&dlsIns - m_Instruments.data()), ipbagcnt, static_cast(&gen - generators.data()), gen.sfGenOper, gen.genAmount, (dlsIns.ulBank & F_INSTRUMENT_DRUMS) ? U_(" (drum)") : U_(""))); #endif } break; } } } // Envelope if (!(dlsIns.ulBank & F_INSTRUMENT_DRUMS)) { m_Envelopes.push_back(dlsEnv); dlsIns.nMelodicEnv = static_cast(m_Envelopes.size()); } // Load Instrument Bags dlsIns.Regions.clear(); for(const auto & [nInstrNdx, keyRange] : instruments) { if(nInstrNdx >= numInsts) continue; sf2info.insts.Seek(nInstrNdx * sizeof(SFInst)); SFInst insts[2]; sf2info.insts.ReadArray(insts); const uint32 numRegions = insts[1].wInstBagNdx - insts[0].wInstBagNdx; dlsIns.Regions.reserve(dlsIns.Regions.size() + numRegions); //Log("\nIns %3d, %2d regions:\n", nIns, pSmp->nRegions); DLSREGION globalZone{}; globalZone.uUnityNote = 0xFF; // 0xFF means undefined -> use sample root note globalZone.tuning = 100; globalZone.sFineTune = instrFinetune; globalZone.nWaveLink = Util::MaxValueOfType(globalZone.nWaveLink); if(keyRange != 0xFFFF) { globalZone.uKeyMin = static_cast(keyRange & 0xFF); globalZone.uKeyMax = static_cast(keyRange >> 8); if(globalZone.uKeyMin > globalZone.uKeyMax) std::swap(globalZone.uKeyMin, globalZone.uKeyMax); } else { globalZone.uKeyMin = 0; globalZone.uKeyMax = 127; } for(uint32 nRgn = 0; nRgn < numRegions; nRgn++) { uint32 ibagcnt = insts[0].wInstBagNdx + nRgn; if(ibagcnt >= numInstBags) break; // Create a new envelope for drums DLSENVELOPE *pDlsEnv = &dlsEnv; if(!(dlsIns.ulBank & F_INSTRUMENT_DRUMS) && dlsIns.nMelodicEnv > 0 && dlsIns.nMelodicEnv <= m_Envelopes.size()) { pDlsEnv = &m_Envelopes[dlsIns.nMelodicEnv - 1]; } DLSREGION rgn = globalZone; if(dlsIns.ulBank & F_INSTRUMENT_DRUMS) { m_Envelopes.push_back(dlsEnv); rgn.uPercEnv = static_cast(m_Envelopes.size()); pDlsEnv = &m_Envelopes[rgn.uPercEnv - 1]; if(globalZone.uPercEnv) *pDlsEnv = m_Envelopes[globalZone.uPercEnv - 1]; } // Region Default Values int32 regionAttn = 0; // Load Generators sf2info.instBags.Seek(ibagcnt * sizeof(SFInstBag)); SFInstBag bags[2]; sf2info.instBags.ReadArray(bags); sf2info.instGens.Seek(bags[0].wGenNdx * sizeof(SFInstGenList)); uint16 lastOp = SF2_GEN_SAMPLEID; int32 loopStart = 0, loopEnd = 0; if(!sf2info.instGens.ReadVector(instrGenerators, bags[1].wGenNdx - bags[0].wGenNdx)) break; for(const auto &gen : instrGenerators) { uint16 value = gen.genAmount; lastOp = gen.sfGenOper; switch(gen.sfGenOper) { case SF2_GEN_KEYRANGE: { uint8 keyMin = static_cast(value & 0xFF); uint8 keyMax = static_cast(value >> 8); if(keyMin > keyMax) std::swap(keyMin, keyMax); rgn.uKeyMin = std::max(rgn.uKeyMin, keyMin); rgn.uKeyMax = std::min(rgn.uKeyMax, keyMax); // There was no overlap between instrument region and preset region - skip it if(rgn.uKeyMin > rgn.uKeyMax) rgn.uKeyMin = rgn.uKeyMax = 0xFF; } break; case SF2_GEN_UNITYNOTE: if (value < 128) rgn.uUnityNote = static_cast(value); break; case SF2_GEN_PAN: { int32 pan = static_cast(value); pan = std::clamp(Util::muldivr(pan + 500, 256, 1000), 0, 256); rgn.panning = static_cast(pan); pDlsEnv->defaultPan = mpt::saturate_cast(pan); } break; case SF2_GEN_ATTENUATION: regionAttn = -static_cast(value); break; case SF2_GEN_SAMPLEID: if (value < m_SamplesEx.size()) { rgn.nWaveLink = value; rgn.ulLoopStart = mpt::saturate_cast(m_SamplesEx[value].dwStartloop + loopStart); rgn.ulLoopEnd = mpt::saturate_cast(m_SamplesEx[value].dwEndloop + loopEnd); } break; case SF2_GEN_SAMPLEMODES: value &= 3; rgn.fuOptions &= uint16(~(DLSREGION_SAMPLELOOP|DLSREGION_PINGPONGLOOP|DLSREGION_SUSTAINLOOP)); if(value == 1) rgn.fuOptions |= DLSREGION_SAMPLELOOP; else if(value == 2) rgn.fuOptions |= DLSREGION_SAMPLELOOP | DLSREGION_PINGPONGLOOP; else if(value == 3) rgn.fuOptions |= DLSREGION_SAMPLELOOP | DLSREGION_SUSTAINLOOP; rgn.fuOptions |= DLSREGION_OVERRIDEWSMP; break; case SF2_GEN_KEYGROUP: rgn.fuOptions |= (value & DLSREGION_KEYGROUPMASK); break; case SF2_GEN_COARSETUNE: rgn.sFineTune += static_cast(value) * 128; break; case SF2_GEN_FINETUNE: rgn.sFineTune += static_cast(Util::muldiv(static_cast(value), 128, 100)); break; case SF2_GEN_SCALE_TUNING: rgn.tuning = mpt::saturate_cast(value); break; case SF2_GEN_START_LOOP_FINE: loopStart += static_cast(value); break; case SF2_GEN_END_LOOP_FINE: loopEnd += static_cast(value); break; case SF2_GEN_START_LOOP_COARSE: loopStart += static_cast(value) * 32768; break; case SF2_GEN_END_LOOP_COARSE: loopEnd += static_cast(value) * 32768; break; default: if(!gen.ApplyToEnvelope(*pDlsEnv)) { #ifdef DLSINSTR_LOG MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT("Instr {} region {} gen {}: genoper={} amount={}{}") (nInstrNdx, nRgn, static_cast(&gen - instrGenerators.data()), gen.sfGenOper, gen.genAmount, (dlsIns.ulBank & F_INSTRUMENT_DRUMS) ? U_(" (drum)") : U_(""))); #endif } break; } } int32 linearVol = DLS32BitRelativeGainToLinear(((instrAttenuation + regionAttn) * 65536) / 10) / 256; Limit(linearVol, 16, 256); rgn.usVolume = static_cast(linearVol); if(lastOp != SF2_GEN_SAMPLEID && nRgn == 0) globalZone = rgn; else if(!rgn.IsDummy()) dlsIns.Regions.push_back(rgn); } } } return true; } /////////////////////////////////////////////////////////////// // Open: opens a DLS bank bool CDLSBank::Open(const mpt::PathString &filename) { if(filename.empty()) return false; m_szFileName = filename; mpt::IO::InputFile f(filename, false); if(!f.IsValid()) return false; return Open(GetFileReader(f)); } bool CDLSBank::Open(FileReader file) { uint32 nInsDef; if(file.GetOptionalFileName()) { #if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE) m_szFileName = *(file.GetOptionalFileName()); #else m_szFileName = file.GetOptionalFileName().value(); #endif } file.Rewind(); if(!file.CanRead(256)) return false; RIFFChunkID riff; file.ReadStruct(riff); // Check DLS sections embedded in RMI midi files if(riff.id_RIFF == IFFID_RIFF && riff.id_DLS == IFFID_RMID) { while(file.ReadStruct(riff)) { if(riff.id_RIFF == IFFID_RIFF && (riff.id_DLS == IFFID_DLS || riff.id_DLS == IFFID_sfbk)) break; uint32 len = riff.riff_len; if((len % 2u) != 0) len++; file.SkipBack(4); file.Skip(len); } } // Check XDLS sections embedded in big endian IFF files (Miles Sound System) if (riff.id_RIFF == IFFID_FORM) { do { if(riff.id_DLS == IFFID_XDLS) { file.ReadStruct(riff); break; } uint32 len = mpt::bit_cast(riff.riff_len); if((len % 2u) != 0) len++; file.SkipBack(4); file.Skip(len); } while(file.ReadStruct(riff)); } if (riff.id_RIFF != IFFID_RIFF || (riff.id_DLS != IFFID_DLS && riff.id_DLS != IFFID_MLS && riff.id_DLS != IFFID_sfbk) || !file.CanRead(riff.riff_len - 4)) { #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", U_("Invalid DLS bank!")); #endif return false; } SF2LoaderInfo sf2info; m_nType = (riff.id_DLS == IFFID_sfbk) ? SOUNDBANK_TYPE_SF2 : SOUNDBANK_TYPE_DLS; m_dwWavePoolOffset = 0; m_sf2version = 0; m_Instruments.clear(); m_WaveForms.clear(); m_Envelopes.clear(); nInsDef = 0; bool applyPaddingToSampleChunk = true; while(file.CanRead(sizeof(IFFCHUNK))) { IFFCHUNK chunkHeader; file.ReadStruct(chunkHeader); const auto chunkStartPos = file.GetPosition(); FileReader chunk = file.ReadChunk(chunkHeader.len); bool applyPadding = (chunkHeader.len % 2u) != 0; if(!chunk.LengthIsAtLeast(chunkHeader.len)) break; switch(chunkHeader.id) { // DLS 1.0: Instruments Collection Header case IFFID_colh: #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("colh ({} bytes)")(chunkHeader.len.get())); #endif if (m_Instruments.empty()) { m_Instruments.resize(chunk.ReadUint32LE()); #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT(" {} instruments")(m_Instruments.size())); #endif } break; // DLS 1.0: Instruments Pointers Table case IFFID_ptbl: #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("ptbl ({} bytes)")(chunkHeader.len.get())); #endif if (m_WaveForms.empty()) { PTBLChunk ptbl; chunk.ReadStruct(ptbl); chunk.Skip(ptbl.cbSize - 8); uint32 cues = std::min(ptbl.cCues.get(), mpt::saturate_cast(chunk.BytesLeft() / sizeof(uint32))); m_WaveForms.reserve(cues); for(uint32 i = 0; i < cues; i++) { m_WaveForms.push_back(chunk.ReadUint32LE()); } #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT(" {} waveforms")(m_WaveForms.size())); #endif } break; // DLS 1.0: LIST section case IFFID_LIST: #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", U_("LIST")); #endif { uint32 listid = chunk.ReadUint32LE(); if (((listid == IFFID_wvpl) && (m_nType & SOUNDBANK_TYPE_DLS)) || ((listid == IFFID_sdta) && (m_nType & SOUNDBANK_TYPE_SF2))) { m_dwWavePoolOffset = chunkStartPos + 4; #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("Wave Pool offset: {}")(m_dwWavePoolOffset)); #endif if(!applyPaddingToSampleChunk) applyPadding = false; break; } while (chunk.CanRead(12)) { IFFCHUNK listHeader; chunk.ReadStruct(listHeader); if(!chunk.CanRead(listHeader.len)) break; FileReader subData = chunk.GetChunkAt(chunk.GetPosition() - sizeof(IFFCHUNK), listHeader.len + 8); FileReader listChunk = chunk.ReadChunk(listHeader.len); if(listHeader.len % 2u) chunk.Skip(1); // DLS Instrument Headers if (listHeader.id == IFFID_LIST && (m_nType & SOUNDBANK_TYPE_DLS)) { uint32 subID = listChunk.ReadUint32LE(); if ((subID == IFFID_ins) && (nInsDef < m_Instruments.size())) { DLSINSTRUMENT &dlsIns = m_Instruments[nInsDef]; //Log("Instrument %d:\n", nInsDef); dlsIns.Regions.push_back({}); UpdateInstrumentDefinition(&dlsIns, subData); nInsDef++; } } else // DLS/SF2 Bank Information if (listid == IFFID_INFO && listHeader.len) { switch(listHeader.id) { case IFFID_ifil: m_sf2version = listChunk.ReadUint16LE() << 16; m_sf2version |= listChunk.ReadUint16LE(); if(m_sf2version >= 0x3'0000 && m_sf2version <= 0x4'FFFF) { // "SF3" / "SF4" with compressed samples. The padding of the sample chunk is now optional (probably because it was simply forgotten to be added) applyPaddingToSampleChunk = false; } listChunk.Skip(2); break; case IFFID_INAM: listChunk.ReadString(m_BankInfo.szBankName, listChunk.BytesLeft()); break; case IFFID_IENG: listChunk.ReadString(m_BankInfo.szEngineer, listChunk.BytesLeft()); break; case IFFID_ICOP: listChunk.ReadString(m_BankInfo.szCopyRight, listChunk.BytesLeft()); break; case IFFID_ICMT: listChunk.ReadString(m_BankInfo.szComments, listChunk.BytesLeft()); break; case IFFID_ISFT: listChunk.ReadString(m_BankInfo.szSoftware, listChunk.BytesLeft()); break; case IFFID_ISBJ: listChunk.ReadString(m_BankInfo.szDescription, listChunk.BytesLeft()); break; } } else if ((listid == IFFID_pdta) && (m_nType & SOUNDBANK_TYPE_SF2)) { UpdateSF2PresetData(sf2info, listHeader, listChunk); } } } break; #ifdef DLSBANK_LOG default: { char sdbg[5]; memcpy(sdbg, &chunkHeader.id, 4); sdbg[4] = 0; MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("Unsupported chunk: {} ({} bytes)")(mpt::ToUnicode(mpt::Charset::ASCII, mpt::String::ReadAutoBuf(sdbg)), chunkHeader.len.get())); } break; #endif } if(applyPadding) file.Skip(1); } // Build the ptbl is not present in file if ((m_WaveForms.empty()) && (m_dwWavePoolOffset) && (m_nType & SOUNDBANK_TYPE_DLS) && (m_nMaxWaveLink > 0)) { #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("ptbl not present: building table ({} wavelinks)...")(m_nMaxWaveLink)); #endif m_WaveForms.reserve(m_nMaxWaveLink); file.Seek(m_dwWavePoolOffset); while(m_WaveForms.size() < m_nMaxWaveLink && file.CanRead(sizeof(IFFCHUNK))) { IFFCHUNK chunk; file.ReadStruct(chunk); if (chunk.id == IFFID_LIST) m_WaveForms.push_back(file.GetPosition() - m_dwWavePoolOffset - sizeof(IFFCHUNK)); file.Skip(chunk.len); } #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("Found {} waveforms")(m_WaveForms.size())); #endif } // Convert the SF2 data to DLS if ((m_nType & SOUNDBANK_TYPE_SF2) && !m_SamplesEx.empty() && !m_Instruments.empty()) { ConvertSF2ToDLS(sf2info); } // FindInstrument requires the instrument to be sorted for picking the best instrument from the MIDI library when there are multiple banks. // And of course this is also helpful for creating the treeview UI std::sort(m_Instruments.begin(), m_Instruments.end()); // Sort regions (for drums) for(auto &instr : m_Instruments) { std::sort(instr.Regions.begin(), instr.Regions.end(), [](const DLSREGION &l, const DLSREGION &r) { return std::tie(l.uKeyMin, l.uKeyMax) < std::tie(r.uKeyMin, r.uKeyMax); }); } return true; } //////////////////////////////////////////////////////////////////////////////////////// // Extracts the Waveforms from a DLS/SF2 bank uint32 CDLSBank::GetRegionFromKey(uint32 nIns, uint32 nKey) const { if(nIns >= m_Instruments.size()) return 0; const DLSINSTRUMENT &dlsIns = m_Instruments[nIns]; for(uint32 rgn = 0; rgn < static_cast(dlsIns.Regions.size()); rgn++) { const auto ®ion = dlsIns.Regions[rgn]; // Regions are sorted, if we arrived here we won't find anything in the remaining regions if(region.uKeyMin > nKey) break; if(nKey > region.uKeyMax) continue; if(region.nWaveLink == Util::MaxValueOfType(region.nWaveLink)) continue; return rgn; } return 0; } std::vector CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, FileReader *file) const { std::vector waveData; if (nIns >= m_Instruments.size() || !m_dwWavePoolOffset) { #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("ExtractWaveForm({}) failed: m_Instruments.size()={} m_dwWavePoolOffset={} m_WaveForms.size()={}")(nIns, m_Instruments.size(), m_dwWavePoolOffset, m_WaveForms.size())); #endif return waveData; } const DLSINSTRUMENT &dlsIns = m_Instruments[nIns]; if(nRgn >= dlsIns.Regions.size()) { #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("invalid waveform region: nIns={} nRgn={} pSmp->nRegions={}")(nIns, nRgn, dlsIns.Regions.size())); #endif return waveData; } uint32 nWaveLink = dlsIns.Regions[nRgn].nWaveLink; if(nWaveLink >= m_WaveForms.size()) { #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("Invalid wavelink id: nWaveLink={} nWaveForms={}")(nWaveLink, m_WaveForms.size())); #endif return waveData; } std::unique_ptr inputFile; FileReader f; if(file) { f = *file; } else { inputFile = std::make_unique(m_szFileName, false); if(!inputFile->IsValid()) return waveData; f = GetFileReader(*inputFile); } auto sampleOffset = mpt::saturate_cast(m_WaveForms[nWaveLink] + m_dwWavePoolOffset); if(f.Seek(sampleOffset)) { if (m_nType & SOUNDBANK_TYPE_SF2) { if (m_SamplesEx[nWaveLink].dwLen) { if (f.Skip(8)) { try { f.ReadVector(waveData, m_SamplesEx[nWaveLink].dwLen); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); } } } } else { LISTChunk chunk; if(f.ReadStruct(chunk)) { if((chunk.id == IFFID_LIST) && (chunk.listid == IFFID_wave) && (chunk.len > 4)) { try { f.SkipBack(sizeof(chunk)); f.ReadVector(waveData, chunk.len + sizeof(IFFCHUNK)); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); } } } } } return waveData; } bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose, FileReader *file) const { bool ok, hasWaveform; if(nIns >= m_Instruments.size()) return false; const DLSINSTRUMENT &dlsIns = m_Instruments[nIns]; if(nRgn >= dlsIns.Regions.size()) return false; const std::vector waveData = ExtractWaveForm(nIns, nRgn, file); if(waveData.size() < 16) return false; ok = false; FileReader wsmpChunk; if (m_nType & SOUNDBANK_TYPE_SF2) { sndFile.DestroySample(nSample); uint32 nWaveLink = dlsIns.Regions[nRgn].nWaveLink; ModSample &sample = sndFile.GetSample(nSample); if (sndFile.m_nSamples < nSample) sndFile.m_nSamples = nSample; if (nWaveLink < m_SamplesEx.size()) { const DLSSAMPLEEX &p = m_SamplesEx[nWaveLink]; #ifdef DLSINSTR_LOG MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT(" SF2 WaveLink #{}: {}Hz")(nWaveLink, p.dwSampleRate)); #endif sample.Initialize(); FileReader chunk{mpt::as_span(waveData)}; if(!p.compressed || !sndFile.ReadSampleFromFile(nSample, chunk, false, false)) { sample.nLength = mpt::saturate_cast(waveData.size() / 2); SampleIO( SampleIO::_16bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(sample, chunk); } sample.nLoopStart = dlsIns.Regions[nRgn].ulLoopStart; sample.nLoopEnd = dlsIns.Regions[nRgn].ulLoopEnd; sample.nC5Speed = p.dwSampleRate; sample.RelativeTone = p.byOriginalPitch; sample.nFineTune = p.chPitchCorrection; if(p.szName[0]) sndFile.m_szNames[nSample] = mpt::String::ReadAutoBuf(p.szName); else if(dlsIns.szName[0]) sndFile.m_szNames[nSample] = mpt::String::ReadAutoBuf(dlsIns.szName); } hasWaveform = sample.HasSampleData(); } else { FileReader wavChunk(mpt::as_span(waveData)); hasWaveform = sndFile.ReadWAVSample(nSample, wavChunk, false, &wsmpChunk); if(dlsIns.szName[0]) sndFile.m_szNames[nSample] = mpt::String::ReadAutoBuf(dlsIns.szName); } if (hasWaveform) { ModSample &sample = sndFile.GetSample(nSample); const DLSREGION &rgn = dlsIns.Regions[nRgn]; sample.uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN); if (rgn.fuOptions & DLSREGION_SAMPLELOOP) sample.uFlags.set(CHN_LOOP); if (rgn.fuOptions & DLSREGION_SUSTAINLOOP) sample.uFlags.set(CHN_SUSTAINLOOP); if (rgn.fuOptions & DLSREGION_PINGPONGLOOP) sample.uFlags.set(CHN_PINGPONGLOOP); if (sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP]) { if (rgn.ulLoopEnd > rgn.ulLoopStart) { if (sample.uFlags[CHN_SUSTAINLOOP]) { sample.nSustainStart = rgn.ulLoopStart; sample.nSustainEnd = rgn.ulLoopEnd; } else { sample.nLoopStart = rgn.ulLoopStart; sample.nLoopEnd = rgn.ulLoopEnd; } } else { sample.uFlags.reset(CHN_LOOP|CHN_SUSTAINLOOP); } } // WSMP chunk { uint32 usUnityNote = rgn.uUnityNote; int sFineTune = rgn.sFineTune; int lVolume = rgn.usVolume; WSMPChunk wsmp; if(!(rgn.fuOptions & DLSREGION_OVERRIDEWSMP) && wsmpChunk.IsValid() && wsmpChunk.Skip(sizeof(IFFCHUNK)) && wsmpChunk.ReadStructPartial(wsmp)) { usUnityNote = wsmp.usUnityNote; sFineTune = wsmp.sFineTune; lVolume = DLS32BitRelativeGainToLinear(wsmp.lAttenuation) / 256; if(wsmp.cSampleLoops) { WSMPSampleLoop loop; wsmpChunk.Seek(sizeof(IFFCHUNK) + wsmp.cbSize); wsmpChunk.ReadStruct(loop); if(loop.ulLoopLength > 3) { sample.uFlags.set(CHN_LOOP); //if (loop.ulLoopType) sample.uFlags |= CHN_PINGPONGLOOP; sample.nLoopStart = loop.ulLoopStart; sample.nLoopEnd = loop.ulLoopStart + loop.ulLoopLength; } } } else if (m_nType & SOUNDBANK_TYPE_SF2) { usUnityNote = (usUnityNote < 0x80) ? usUnityNote : sample.RelativeTone; sFineTune += sample.nFineTune; } #ifdef DLSINSTR_LOG MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT("WSMP: usUnityNote={}.{}, {}Hz (transp={})")(usUnityNote, sFineTune, sample.nC5Speed, transpose)); #endif if (usUnityNote > 0x7F) usUnityNote = 60; int steps = (60 + transpose - usUnityNote) * 128 + sFineTune; sample.Transpose(steps * (1.0 / (12.0 * 128.0))); sample.RelativeTone = 0; Limit(lVolume, 16, 256); sample.nGlobalVol = (uint8)(lVolume / 4); // 0-64 } sample.nPan = GetPanning(nIns, nRgn); sample.Convert(MOD_TYPE_IT, sndFile.GetType()); sample.PrecomputeLoops(sndFile, false); ok = true; } return ok; } static uint16 ScaleEnvelope(uint32 time, float tempoScale) { return std::max(mpt::saturate_round(time * tempoScale), uint16(1)); } uint32 DLSENVELOPE::Envelope::ConvertToMPT(InstrumentEnvelope &mptEnv, const EnvelopeType envType, const float tempoScale, const int16 valueScale) const { if(!attack && decay >= 20 * 50 && (!sustainLevel && envType != ENV_PITCH) && release >= 20 * 50) return uint32_max; const EnvelopeNode::value_t neutralValue = (envType == ENV_VOLUME) ? 0 : ENVELOPE_MID; mptEnv.dwFlags.set(ENV_ENABLED); mptEnv.clear(); // Delay section uint16 attackStart = 0; if(delay) { mptEnv.push_back(0, neutralValue); attackStart = ScaleEnvelope(delay, tempoScale); } // Attack section const auto attackValue = mpt::saturate_cast(neutralValue + Util::muldivr(ENVELOPE_MAX, valueScale, 3200)); if(attack) { mptEnv.push_back(attackStart, static_cast(attackValue / (attack / 2 + 2) + 8)); // /----- mptEnv.push_back(attackStart + ScaleEnvelope(attack, tempoScale), attackValue); // | } else { mptEnv.push_back(attackStart, attackValue); } // Hold section if(EnvelopeNode::tick_t holdTick = attackStart + ScaleEnvelope(attack + hold, tempoScale); hold > 0 && holdTick > mptEnv.back().tick) mptEnv.push_back(holdTick, attackValue); // Sustain Level if(sustainLevel > 0 || envType == ENV_PITCH) { if(sustainLevel < 128) { uint16 lStartTime = mptEnv.back().tick; int32 lSusLevel = -CDLSBank::DLS32BitRelativeLinearToGain(sustainLevel << 9) / 65536; int32 lDecayTime = 1; if(lSusLevel > 0) { lDecayTime = (lSusLevel * (int32)decay) / 960; for(uint32 i = 0; i < 7; i++) { int32 lFactor = 128 - (1 << i); if(lFactor <= sustainLevel) break; int32 lev = -CDLSBank::DLS32BitRelativeLinearToGain(lFactor << 9) / 65536; if(lev > 0) { int32 ltime = (lev * (int32)decay) / 960; if((ltime > 1) && (ltime < lDecayTime)) { uint16 tick = lStartTime + ScaleEnvelope(ltime, tempoScale); if(tick > mptEnv.back().tick) { mptEnv.push_back(tick, mpt::saturate_cast(neutralValue + Util::muldivr(lFactor, valueScale, 6400))); } } } } } uint16 decayEnd = lStartTime + ScaleEnvelope(lDecayTime, tempoScale); if(decayEnd > mptEnv.back().tick) { mptEnv.push_back(decayEnd, mpt::saturate_cast(neutralValue + Util::muldivr(sustainLevel + 1, valueScale, 6400))); } } mptEnv.dwFlags.set(ENV_SUSTAIN); } else { mptEnv.dwFlags.set(ENV_SUSTAIN); mptEnv.push_back(mptEnv.back().tick + 1u, mptEnv.back().value); } mptEnv.nSustainStart = mptEnv.nSustainEnd = (uint8)(mptEnv.size() - 1); if(mptEnv.nSustainEnd > 0 && envType == ENV_VOLUME) mptEnv.nReleaseNode = mptEnv.nSustainEnd; // Release section const bool lastIsNeutral = mptEnv.back().value > 1 && mptEnv.back().value == neutralValue; if(release && mptEnv.back().value > 1 && !lastIsNeutral) { int32 lReleaseTime = release; uint16 lStartTime = mptEnv.back().tick; int32 lStartFactor = mptEnv.back().value; int32 lSusLevel = -CDLSBank::DLS32BitRelativeLinearToGain(lStartFactor << 10) / 65536; int32 lDecayEndTime = (lReleaseTime * lSusLevel) / 960; lReleaseTime -= lDecayEndTime; int32 prevFactor = lStartFactor; for(uint32 i = 0; i < 7; i++) { int32 lFactor = 1 + ((lStartFactor * 3) >> (i + 2)); if((lFactor < 1) ||(lFactor == 1 && prevFactor == 1) || (lFactor >= lStartFactor)) continue; prevFactor = lFactor; int32 lev = -CDLSBank::DLS32BitRelativeLinearToGain(lFactor << 10) / 65536; if(lev > 0) { int32 ltime = (((int32)release * lev) / 960) - lDecayEndTime; if((ltime > 1) && (ltime < lReleaseTime)) { uint16 tick = lStartTime + ScaleEnvelope(ltime, tempoScale); if(tick > mptEnv.back().tick) { mptEnv.push_back(tick, mpt::saturate_cast(neutralValue + Util::muldivr(lFactor, valueScale, 3200))); if(mptEnv.back().value == neutralValue) break; } } } } if(lReleaseTime < 1) lReleaseTime = 1; auto releaseTicks = ScaleEnvelope(lReleaseTime, tempoScale); mptEnv.push_back(lStartTime + releaseTicks, neutralValue); if(releaseTicks > 0) { return 32768 / releaseTicks; } } else if(!lastIsNeutral) { mptEnv.push_back(mptEnv.back().tick + 1u, neutralValue); } return uint32_max; } bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn, FileReader *file) const { uint32 minRegion, maxRegion, nEnv; if (nIns >= m_Instruments.size()) return false; const DLSINSTRUMENT &dlsIns = m_Instruments[nIns]; const bool isDrum = (dlsIns.ulBank & F_INSTRUMENT_DRUMS) && nDrumRgn != uint32_max; if(isDrum) { if(nDrumRgn >= dlsIns.Regions.size()) return false; minRegion = nDrumRgn; maxRegion = nDrumRgn + 1; nEnv = dlsIns.Regions[nDrumRgn].uPercEnv; } else { if(dlsIns.Regions.empty()) return false; minRegion = 0; maxRegion = static_cast(dlsIns.Regions.size()); nEnv = dlsIns.nMelodicEnv; } #ifdef DLSINSTR_LOG MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT("DLS Instrument #{}: {}")(nIns, mpt::ToUnicode(mpt::Charset::ASCII, mpt::String::ReadAutoBuf(dlsIns.szName)))); MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT(" Bank=0x{} Instrument=0x{}")(mpt::ufmt::HEX0<4>(dlsIns.ulBank), mpt::ufmt::HEX0<4>(dlsIns.ulInstrument))); MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT(" {} regions, nMelodicEnv={}")(dlsIns.Regions.size(), dlsIns.nMelodicEnv)); for (uint32 iDbg=0; iDbgnWaveLink, prgn->ulLoopStart, prgn->ulLoopEnd)); MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT(" Key Range: [{}, {}]")(prgn->uKeyMin, prgn->uKeyMax)); MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT(" fuOptions = 0x{}")(mpt::ufmt::HEX0<4>(prgn->fuOptions))); MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT(" usVolume = {}, Unity Note = {}")(prgn->usVolume, prgn->uUnityNote)); } #endif ModInstrument *pIns = new (std::nothrow) ModInstrument(); if(pIns == nullptr) { return false; } if(sndFile.Instruments[nInstr]) { sndFile.DestroyInstrument(nInstr, deleteAssociatedSamples); } // Initializes Instrument if(isDrum) { uint32 key = dlsIns.Regions[nDrumRgn].uKeyMin; if((key >= 24) && (key <= 84)) { std::string s = szMidiPercussionNames[key-24]; if(!mpt::String::ReadAutoBuf(dlsIns.szName).empty()) { s += MPT_AFORMAT(" ({})")(mpt::trim_right(mpt::String::ReadAutoBuf(dlsIns.szName))); } pIns->name = s; } else { pIns->name = mpt::String::ReadAutoBuf(dlsIns.szName); } } else { pIns->name = mpt::String::ReadAutoBuf(dlsIns.szName); } int transpose = 0; if(isDrum) { for(uint32 iNoteMap = 0; iNoteMap < NOTE_MAX; iNoteMap++) { if(sndFile.GetType() & (MOD_TYPE_IT | MOD_TYPE_MID | MOD_TYPE_MPT)) { // Format has instrument note mapping if(dlsIns.Regions[nDrumRgn].tuning == 0) pIns->NoteMap[iNoteMap] = NOTE_MIDDLEC; else if (iNoteMap < dlsIns.Regions[nDrumRgn].uKeyMin) pIns->NoteMap[iNoteMap] = (uint8)(dlsIns.Regions[nDrumRgn].uKeyMin + NOTE_MIN); else if(iNoteMap > dlsIns.Regions[nDrumRgn].uKeyMax) pIns->NoteMap[iNoteMap] = (uint8)(dlsIns.Regions[nDrumRgn].uKeyMax + NOTE_MIN); } else { if(iNoteMap == dlsIns.Regions[nDrumRgn].uKeyMin) { transpose = (dlsIns.Regions[nDrumRgn].uKeyMin + (dlsIns.Regions[nDrumRgn].uKeyMax - dlsIns.Regions[nDrumRgn].uKeyMin) / 2) - 60; } } } } pIns->nFadeOut = 1024; pIns->nMidiProgram = static_cast(1 + (dlsIns.ulInstrument & 0x7F)); pIns->nMidiChannel = static_cast(isDrum ? 10 : 0); pIns->wMidiBank = static_cast(1 + (((dlsIns.ulBank & 0x7F00) >> 1) | (dlsIns.ulBank & 0x7F))); pIns->nNNA = NewNoteAction::NoteOff; pIns->nDCT = DuplicateCheckType::Note; pIns->nDNA = DuplicateNoteAction::NoteFade; sndFile.Instruments[nInstr] = pIns; uint32 nLoadedSmp = 0; SAMPLEINDEX nextSample = 0; // Extract Samples std::vector RgnToSmp(dlsIns.Regions.size()); std::set extractedSamples; for(uint32 nRgn = minRegion; nRgn < maxRegion; nRgn++) { bool duplicateRegion = false; SAMPLEINDEX nSmp = 0; const DLSREGION &rgn = dlsIns.Regions[nRgn]; if(rgn.IsDummy()) continue; // Eliminate Duplicate Regions uint32 dupRegion; for(dupRegion = minRegion; dupRegion < nRgn; dupRegion++) { const DLSREGION &rgn2 = dlsIns.Regions[dupRegion]; if(RgnToSmp[dupRegion] == 0 || rgn2.IsDummy()) continue; // No need to extract the same sample data twice const bool sameSample = (rgn2.nWaveLink == rgn.nWaveLink) && (rgn2.ulLoopEnd == rgn.ulLoopEnd) && (rgn2.ulLoopStart == rgn.ulLoopStart) && extractedSamples.count(rgn.nWaveLink); // Candidate for stereo sample creation const bool sameKeyRange = (rgn2.uKeyMin == rgn.uKeyMin) && (rgn2.uKeyMax == rgn.uKeyMax); if(sameSample || sameKeyRange) { duplicateRegion = true; if(!sameKeyRange) nSmp = RgnToSmp[dupRegion]; break; } } // Create a new sample if (!duplicateRegion) { uint32 nmaxsmp = (m_nType & MOD_TYPE_XM) ? 16 : (NOTE_MAX - NOTE_MIN + 1); if (nLoadedSmp >= nmaxsmp) { nSmp = RgnToSmp[nRgn - 1]; } else { nextSample = sndFile.GetNextFreeSample(nInstr, nextSample + 1); if (nextSample == SAMPLEINDEX_INVALID) break; if (nextSample > sndFile.GetNumSamples()) sndFile.m_nSamples = nextSample; nSmp = nextSample; nLoadedSmp++; } } RgnToSmp[nRgn] = nSmp; // Map all notes to the right sample if(nSmp) { for(uint8 key = 0; key < NOTE_MAX; key++) { if(isDrum || (key >= rgn.uKeyMin && key <= rgn.uKeyMax)) { pIns->Keyboard[key] = nSmp; } } // Load the sample if(!duplicateRegion || !sndFile.GetSample(nSmp).HasSampleData()) { ExtractSample(sndFile, nSmp, nIns, nRgn, transpose, file); extractedSamples.insert(rgn.nWaveLink); } } else if(duplicateRegion && sndFile.GetSample(RgnToSmp[dupRegion]).GetNumChannels() == 1) { // Try to combine stereo samples const uint16 pan1 = GetPanning(nIns, nRgn), pan2 = GetPanning(nIns, dupRegion); if((pan1 < 16 && pan2 >= 240) || (pan2 < 16 && pan1 >= 240)) { ModSample &sample = sndFile.GetSample(RgnToSmp[dupRegion]); ModSample sampleCopy = sample; sampleCopy.pData.pSample = nullptr; sampleCopy.uFlags.set(CHN_16BIT | CHN_STEREO); if(!sampleCopy.AllocateSample()) continue; const uint8 offsetOrig = (pan1 < pan2) ? 1 : 0; const uint8 offsetNew = (pan1 < pan2) ? 0 : 1; const std::vector waveData = ExtractWaveForm(nIns, nRgn, file); if(waveData.empty()) continue; extractedSamples.insert(rgn.nWaveLink); // First copy over original channel auto pDest = sampleCopy.sample16() + offsetOrig; if(sample.uFlags[CHN_16BIT]) CopySample, SC::DecodeIdentity>>(pDest, sample.nLength, 2, sample.sample16(), sample.GetSampleSizeInBytes(), 1); else CopySample, SC::DecodeIdentity>>(pDest, sample.nLength, 2, sample.sample8(), sample.GetSampleSizeInBytes(), 1); sample.FreeSample(); // Now read the other channel if(m_SamplesEx[m_Instruments[nIns].Regions[nRgn].nWaveLink].compressed) { FileReader smpChunk{mpt::as_span(waveData)}; if(sndFile.ReadSampleFromFile(nSmp, smpChunk, false, false)) { pDest = sampleCopy.sample16() + offsetNew; const SmpLength copyLength = std::min(sample.nLength, sampleCopy.nLength); if(sample.uFlags[CHN_16BIT]) CopySample, SC::DecodeIdentity>>(pDest, copyLength, 2, sample.sample16(), sample.GetSampleSizeInBytes(), sample.GetNumChannels()); else CopySample, SC::DecodeIdentity>>(pDest, copyLength, 2, sample.sample8(), sample.GetSampleSizeInBytes(), sample.GetNumChannels()); } } else { SmpLength len = std::min(mpt::saturate_cast(waveData.size() / 2u), sampleCopy.nLength); const std::byte *src = mpt::byte_cast(waveData.data()); int16 *dst = sampleCopy.sample16() + offsetNew; CopySample, SC::DecodeInt16<0, littleEndian16>>>(dst, len, 2, src, waveData.size(), 1); } sample.FreeSample(); sample = sampleCopy; } } } float tempoScale = 1.0f; if(sndFile.m_nTempoMode == TempoMode::Modern) { uint32 ticksPerBeat = sndFile.m_nDefaultRowsPerBeat * sndFile.Order().GetDefaultSpeed(); if(ticksPerBeat != 0) tempoScale = ticksPerBeat / 24.0f; } // Initializes Envelope if ((nEnv) && (nEnv <= m_Envelopes.size())) { const DLSENVELOPE &part = m_Envelopes[nEnv - 1]; if(const auto fadeout = part.volumeEnv.ConvertToMPT(pIns->VolEnv, ENV_VOLUME, tempoScale, 3200); fadeout != uint32_max) pIns->nFadeOut = fadeout; if(std::abs(part.pitchEnvDepth) >= 50) part.pitchEnv.ConvertToMPT(pIns->PitchEnv, ENV_PITCH, tempoScale, part.pitchEnvDepth); } if(isDrum) { // Create a default envelope for drums if(!pIns->VolEnv.dwFlags[ENV_ENABLED]) { pIns->VolEnv.dwFlags.set(ENV_ENABLED); pIns->VolEnv.dwFlags.reset(ENV_SUSTAIN); pIns->VolEnv.resize(4); pIns->VolEnv[0] = EnvelopeNode(0, ENVELOPE_MAX); pIns->VolEnv[1] = EnvelopeNode(ScaleEnvelope(5, tempoScale), ENVELOPE_MAX); pIns->VolEnv[2] = EnvelopeNode(pIns->VolEnv[1].tick * 2u, ENVELOPE_MID); pIns->VolEnv[3] = EnvelopeNode(pIns->VolEnv[2].tick * 2u, ENVELOPE_MIN); // 1 second max. for drums } } pIns->Sanitize(MOD_TYPE_MPT); pIns->Convert(MOD_TYPE_MPT, sndFile.GetType()); return true; } const char *CDLSBank::GetRegionName(uint32 nIns, uint32 nRgn) const { if(nIns >= m_Instruments.size()) return nullptr; const DLSINSTRUMENT &dlsIns = m_Instruments[nIns]; if(nRgn >= dlsIns.Regions.size()) return nullptr; if (m_nType & SOUNDBANK_TYPE_SF2) { uint32 nWaveLink = dlsIns.Regions[nRgn].nWaveLink; if (nWaveLink < m_SamplesEx.size()) { return m_SamplesEx[nWaveLink].szName; } } return nullptr; } uint16 CDLSBank::GetPanning(uint32 ins, uint32 region) const { const DLSINSTRUMENT &dlsIns = m_Instruments[ins]; if(region >= std::size(dlsIns.Regions)) return 128; const DLSREGION &rgn = dlsIns.Regions[region]; if(rgn.panning >= 0) return static_cast(rgn.panning); if(dlsIns.ulBank & F_INSTRUMENT_DRUMS) { if(rgn.uPercEnv > 0 && rgn.uPercEnv <= m_Envelopes.size()) { return m_Envelopes[rgn.uPercEnv - 1].defaultPan; } } else { if(dlsIns.nMelodicEnv > 0 && dlsIns.nMelodicEnv <= m_Envelopes.size()) { return m_Envelopes[dlsIns.nMelodicEnv - 1].defaultPan; } } return 128; } #else // !MODPLUG_TRACKER MPT_MSVC_WORKAROUND_LNK4221(Dlsbank) #endif // MODPLUG_TRACKER OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ModSequence.h0000644000175000017500000002403314704715777020503 00000000000000/* * ModSequence.h * ------------- * Purpose: Order and sequence handling. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" #include #include OPENMPT_NAMESPACE_BEGIN class CPattern; class CSoundFile; class ModSequenceSet; class ModSequence: public std::vector { friend class ModSequenceSet; protected: mpt::ustring m_name; // Sequence name CSoundFile &m_sndFile; // Associated CSoundFile ORDERINDEX m_restartPos = 0; // Restart position when playback of this order ended TEMPO m_defaultTempo{125, 0}; // Default tempo at start of sequence uint32 m_defaultSpeed = 6; // Default ticks per row at start of sequence public: ModSequence(CSoundFile &sndFile); ModSequence(ModSequence &&) noexcept = default; ModSequence(const ModSequence &) = default; ModSequence& operator=(const ModSequence &other); bool operator==(const ModSequence &other) const noexcept; bool operator!=(const ModSequence &other) const noexcept { return !(*this == other); } ORDERINDEX GetLength() const noexcept { return mpt::saturate_cast(size()); } // Returns last accessible index, i.e. GetLength() - 1, or 0 if the order list is empty. ORDERINDEX GetLastIndex() const noexcept { return static_cast(std::max(ORDERINDEX(1), GetLength()) - 1u); } // Returns length of sequence without counting trailing '---' items. ORDERINDEX GetLengthTailTrimmed() const noexcept; // Returns length of sequence stopping counting on first '---' (or at the end of sequence). ORDERINDEX GetLengthFirstEmpty() const noexcept; // Returns amount of patterns that can be added at the end of the order list before reaching the current format's limits. ORDERINDEX GetRemainingCapacity(ORDERINDEX startingFrom = ORDERINDEX_INVALID, bool enforceFormatLimits = true) const noexcept; // Replaces order list with 'newSize' copies of 'pat'. void assign(ORDERINDEX newSize, PATTERNINDEX pat); // Inserts 'count' orders starting from 'pos' using 'fill' as the pattern index for all inserted orders. // Sequence will automatically grow if needed and if it can't grow enough, some tail orders will be discarded. // Return: Number of orders inserted (up to 'count' many). ORDERINDEX insert(ORDERINDEX pos, ORDERINDEX count) { return insert(pos, count, PATTERNINDEX_INVALID, true); } ORDERINDEX insert(ORDERINDEX pos, ORDERINDEX count, PATTERNINDEX fill, bool enforceFormatLimits = true); ORDERINDEX insert(ORDERINDEX pos, const mpt::span orders, bool enforceFormatLimits = true); void push_back() { push_back(PATTERNINDEX_INVALID); } void push_back(PATTERNINDEX pat) { if(GetLength() < MAX_ORDERS) std::vector::push_back(pat); } void resize(ORDERINDEX newSize) { resize(newSize, PATTERNINDEX_INVALID); } void resize(ORDERINDEX newSize, PATTERNINDEX pat) { std::vector::resize(std::min(MAX_ORDERS, newSize), pat); } // Removes orders from range [posBegin, posEnd]. void Remove(ORDERINDEX posBegin, ORDERINDEX posEnd) noexcept; // Remove all references to a given pattern index from the order list. Jump commands are updated accordingly. void RemovePattern(PATTERNINDEX pat); // Replaces all occurences of oldPat with newPat. void Replace(PATTERNINDEX oldPat, PATTERNINDEX newPat) noexcept { if(oldPat != newPat) std::replace(begin(), end(), oldPat, newPat); } // Removes any "---" patterns at the end of the list. void Shrink() { resize(GetLengthTailTrimmed()); } // Check if pattern at sequence position ord is valid. bool IsValidPat(ORDERINDEX ord) const noexcept; CPattern *PatternAt(ORDERINDEX ord) const noexcept; void AdjustToNewModType(const MODTYPE oldtype); // Returns the previous/next order ignoring skip indices (+++). // If no previous/next order exists, return first/last order, and zero // when orderlist is empty. ORDERINDEX GetPreviousOrderIgnoringSkips(const ORDERINDEX start) const noexcept; ORDERINDEX GetNextOrderIgnoringSkips(const ORDERINDEX start) const noexcept; // Returns the first item that contains a pattern that actually exists, ORDERINDEX_INVALID if no such item exists. ORDERINDEX GetFirstValidIndex() const noexcept; // Find an order item that contains a given pattern number. ORDERINDEX FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt = 0, bool searchForward = true) const noexcept; // Ensures that the pattern at the specified order position is used only once (across all sequences). // If another usage is found, the pattern is replaced by a copy and the new index is returned. PATTERNINDEX EnsureUnique(ORDERINDEX ord); #ifndef MODPLUG_NO_FILESAVE // Write order items as bytes. '---' is written as stopIndex, '+++' is written as ignoreIndex size_t WriteAsByte(std::ostream &f, const ORDERINDEX count, uint8 stopIndex = 0xFF, uint8 ignoreIndex = 0xFE) const; #endif // MODPLUG_NO_FILESAVE // Returns true if the IT orderlist datafield is not sufficient to store orderlist information. bool NeedsExtraDatafield() const noexcept; #ifdef MODPLUG_TRACKER // Check if a playback position is currently locked (inaccessible) bool IsPositionLocked(ORDERINDEX position) const noexcept; // Check if this sequence has subsongs separated by invalid ("---" or non-existing) patterns bool HasSubsongs() const noexcept; #endif // MODPLUG_TRACKER inline void SetName(mpt::ustring newName) noexcept { m_name = std::move(newName); } inline mpt::ustring GetName() const { return m_name; } inline void SetRestartPos(ORDERINDEX restartPos) noexcept { m_restartPos = restartPos; } inline ORDERINDEX GetRestartPos() const noexcept { return m_restartPos; } void SetDefaultTempo(TEMPO tempo) noexcept; inline void SetDefaultTempoInt(uint32 tempo) noexcept { SetDefaultTempo(TEMPO{mpt::saturate_cast(tempo), 0}); } inline TEMPO GetDefaultTempo() const noexcept { return m_defaultTempo; } inline void SetDefaultSpeed(uint32 speed) noexcept { m_defaultSpeed = speed ? speed : 6; } inline uint32 GetDefaultSpeed() const noexcept { return m_defaultSpeed; } }; class ModSequenceSet { friend void ReadModSequenceOld(std::istream& iStrm, ModSequenceSet& seq, const size_t); friend void ReadModSequences(std::istream& iStrm, ModSequenceSet& seq, const size_t, mpt::Charset defaultCharset); protected: std::vector m_Sequences; // Array of sequences CSoundFile &m_sndFile; SEQUENCEINDEX m_currentSeq = 0; // Index of current sequence. public: ModSequenceSet(CSoundFile &sndFile); ModSequenceSet(ModSequenceSet &&) noexcept = default; ModSequenceSet& operator=(const ModSequenceSet & other); // Remove all sequences and initialize default sequence void Initialize(); // Get the working sequence ModSequence& operator() () { return m_Sequences[m_currentSeq]; } const ModSequence& operator() () const { return m_Sequences[m_currentSeq]; } // Get an arbitrary sequence ModSequence& operator() (SEQUENCEINDEX seq) { return m_Sequences[seq]; } const ModSequence& operator() (SEQUENCEINDEX seq) const { return m_Sequences[seq]; } SEQUENCEINDEX GetNumSequences() const noexcept { return static_cast(m_Sequences.size()); } SEQUENCEINDEX GetCurrentSequenceIndex() const noexcept { return m_currentSeq; } // Sets working sequence. void SetSequence(SEQUENCEINDEX) noexcept; // Add new empty sequence. // Returns the ID of the new sequence, or SEQUENCEINDEX_INVALID on failure. SEQUENCEINDEX AddSequence(); // Removes given sequence. void RemoveSequence(SEQUENCEINDEX); #ifdef MODPLUG_TRACKER // Assigns a new set of sequences. The vector contents indicate which existing sequences to keep / duplicate or if a new sequences should be inserted (SEQUENCEINDEX_INVALID) // The function fails if the vector is empty or contains too many sequences. bool Rearrange(const std::vector &newOrder); // Adjust sequence when converting between module formats void OnModTypeChanged(MODTYPE oldType); // Check if there is a single sequences that qualifies for subsong splitting bool CanSplitSubsongs() const noexcept; // If there are subsongs (separated by "---" patterns) in the module, // asks user whether to convert these into multiple sequences (given that the // modformat supports multiple sequences). // Returns true if sequences were modified, false otherwise. bool SplitSubsongsToMultipleSequences(); // Convert the sequence's restart position and tempo information to a pattern command. bool WriteGlobalsToPattern(SEQUENCEINDEX seq, bool writeRestartPos, bool writeTempo); // Merges multiple sequences into one and destroys all other sequences. // Returns false if there were no sequences to merge, true otherwise. bool MergeSequences(); #endif // MODPLUG_TRACKER std::vector::iterator begin() noexcept { return m_Sequences.begin(); } std::vector::const_iterator begin() const noexcept { return m_Sequences.begin(); } std::vector::const_iterator cbegin() const noexcept { return m_Sequences.cbegin(); } std::vector::iterator end() noexcept { return m_Sequences.end(); } std::vector::const_iterator end() const noexcept { return m_Sequences.end(); } std::vector::const_iterator cend() const noexcept { return m_Sequences.cend(); } }; const char FileIdSequences[] = "mptSeqC"; const char FileIdSequence[] = "mptSeq"; #ifndef MODPLUG_NO_FILESAVE void WriteModSequences(std::ostream& oStrm, const ModSequenceSet& seq); #endif // MODPLUG_NO_FILESAVE void ReadModSequences(std::istream& iStrm, ModSequenceSet& seq, const size_t nSize, mpt::Charset defaultCharset); #ifndef MODPLUG_NO_FILESAVE void WriteModSequence(std::ostream& oStrm, const ModSequence& seq); #endif // MODPLUG_NO_FILESAVE void ReadModSequence(std::istream& iStrm, ModSequence& seq, const size_t, mpt::Charset defaultCharset); #ifndef MODPLUG_NO_FILESAVE void WriteModSequenceOld(std::ostream& oStrm, const ModSequenceSet& seq); #endif // MODPLUG_NO_FILESAVE void ReadModSequenceOld(std::istream& iStrm, ModSequenceSet& seq, const size_t); OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/WindowedFIR.cpp0000644000175000017500000000556614313611740020736 00000000000000/* * WindowedFIR.cpp * --------------- * Purpose: FIR resampling code * Notes : Original code from modplug-xmms * Authors: OpenMPT Devs * ModPlug-XMMS Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "WindowedFIR.h" #include "mpt/base/numbers.hpp" #include OPENMPT_NAMESPACE_BEGIN double CWindowedFIR::coef(int cnr, double ofs, double cut, int width, int type) { const double epsilon = 1e-8; const double widthM1 = width - 1; const double widthM1Half = 0.5 * widthM1; const double posU = (cnr - ofs); const double idl = (2.0 * mpt::numbers::pi) / widthM1; double pos = posU - widthM1Half; double wc, si; if(std::abs(pos) < epsilon) { wc = 1.0; si = cut; } else { switch(type) { case WFIR_HANN: wc = 0.50 - 0.50 * std::cos(idl * posU); break; case WFIR_HAMMING: wc = 0.54 - 0.46 * std::cos(idl * posU); break; case WFIR_BLACKMANEXACT: wc = 0.42 - 0.50 * std::cos(idl * posU) + 0.08 * std::cos(2.0 * idl * posU); break; case WFIR_BLACKMAN3T61: wc = 0.44959 - 0.49364 * std::cos(idl * posU) + 0.05677 * std::cos(2.0 * idl * posU); break; case WFIR_BLACKMAN3T67: wc = 0.42323 - 0.49755 * std::cos(idl * posU) + 0.07922 * std::cos(2.0 * idl * posU); break; case WFIR_BLACKMAN4T92: // blackman harris wc = 0.35875 - 0.48829 * std::cos(idl * posU) + 0.14128 * std::cos(2.0 * idl * posU) - 0.01168 * std::cos(3.0 * idl * posU); break; case WFIR_BLACKMAN4T74: wc = 0.40217 - 0.49703 * std::cos(idl * posU) + 0.09392 * std::cos(2.0 * idl * posU) - 0.00183 * std::cos(3.0 * idl * posU); break; case WFIR_KAISER4T: // kaiser-bessel, alpha~7.5 wc = 0.40243 - 0.49804 * std::cos(idl * posU) + 0.09831 * std::cos(2.0 * idl * posU) - 0.00122 * std::cos(3.0 * idl * posU); break; default: wc = 1.0; break; } pos *= mpt::numbers::pi; si = std::sin(cut * pos) / pos; } return (wc * si); } void CWindowedFIR::InitTable(double WFIRCutoff, uint8 WFIRType) { const double pcllen = (double)(1 << WFIR_FRACBITS); // number of precalculated lines for 0..1 (-1..0) const double norm = 1.0 / (2.0 * pcllen); const double cut = WFIRCutoff; for(int pcl = 0; pcl < WFIR_LUTLEN; pcl++) { double gain = 0.0, coefs[WFIR_WIDTH]; const double ofs = (pcl - pcllen) * norm; const int idx = pcl << WFIR_LOG2WIDTH; for(int cc = 0; cc < WFIR_WIDTH; cc++) { gain += (coefs[cc] = coef(cc, ofs, cut, WFIR_WIDTH, WFIRType)); } gain = 1.0 / gain; for(int cc = 0; cc < WFIR_WIDTH; cc++) { #ifdef MPT_INTMIXER double coef = std::floor(0.5 + WFIR_QUANTSCALE * coefs[cc] * gain); lut[idx + cc] = (signed short)((coef < -WFIR_QUANTSCALE) ? -WFIR_QUANTSCALE : ((coef > WFIR_QUANTSCALE) ? WFIR_QUANTSCALE : coef)); #else double coef = coefs[cc] * gain; lut[idx + cc] = (float)coef; #endif // MPT_INTMIXER } } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_okt.cpp0000644000175000017500000003207714726404561020357 00000000000000/* * Load_okt.cpp * ------------ * Purpose: OKT (Oktalyzer) module loader * Notes : (currently none) * Authors: Storlek (Original author - http://schismtracker.org/ - code ported with permission) * Johannes Schultz (OpenMPT Port, tweaks) * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct OktIffChunk { // IFF chunk names enum ChunkIdentifiers { idCMOD = MagicBE("CMOD"), idSAMP = MagicBE("SAMP"), idSPEE = MagicBE("SPEE"), idSLEN = MagicBE("SLEN"), idPLEN = MagicBE("PLEN"), idPATT = MagicBE("PATT"), idPBOD = MagicBE("PBOD"), idSBOD = MagicBE("SBOD"), }; uint32be signature; // IFF chunk name uint32be chunkSize; // Chunk size without header }; MPT_BINARY_STRUCT(OktIffChunk, 8) struct OktSample { char name[20]; uint32be length; // Length in bytes uint16be loopStart; // *2 for real value uint16be loopLength; // ditto uint16be volume; // Default volume uint16be type; // 7-/8-bit sample (0: 7-bit, only usable on paired channels ["8" in GUI], 1: 8-bit, only usable on unpaired channels ["4" in GUI], 2: 7-bit, usable on all channels ["B" in GUI]) }; MPT_BINARY_STRUCT(OktSample, 32) // Parse the sample header block static void ReadOKTSamples(FileReader &chunk, CSoundFile &sndFile) { static_assert(MAX_SAMPLES >= 72); // For copies of type "B" samples sndFile.m_nSamples = std::min(static_cast(chunk.BytesLeft() / sizeof(OktSample)), SAMPLEINDEX(36)); for(SAMPLEINDEX smp = 1; smp <= sndFile.GetNumSamples(); smp++) { ModSample &mptSmp = sndFile.GetSample(smp); OktSample oktSmp; chunk.ReadStruct(oktSmp); mptSmp.Initialize(); sndFile.m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, oktSmp.name); mptSmp.nC5Speed = 8287; mptSmp.nVolume = std::min(oktSmp.volume.get(), uint16(64)) * 4u; mptSmp.nLength = oktSmp.length & ~1; mptSmp.cues[0] = oktSmp.type; // Temporary storage for pattern reader, will be reset later mptSmp.cues[1] = 0; // Parse loops const SmpLength loopStart = oktSmp.loopStart * 2; const SmpLength loopLength = oktSmp.loopLength * 2; if(loopLength > 2 && loopStart + loopLength <= mptSmp.nLength) { mptSmp.uFlags.set(CHN_SUSTAINLOOP); mptSmp.nSustainStart = loopStart; mptSmp.nSustainEnd = loopStart + loopLength; } } } // Turn negative arpeggio offset into equivalent positive arpeggio offset static uint8 InvertArpeggioParam(uint8 param) { param &= 0x0F; if(!param) return param; else if(param <= 0x0C) return (0x0C - param); else return (0x18 - param); } // Parse a pattern block static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX pat, CSoundFile &sndFile, const std::array pairedChn) { if(!chunk.CanRead(2)) { // Invent empty pattern sndFile.Patterns.Insert(pat, 64); return; } ROWINDEX rows = Clamp(static_cast(chunk.ReadUint16BE()), ROWINDEX(1), MAX_PATTERN_ROWS); if(!sndFile.Patterns.Insert(pat, rows)) { return; } const CHANNELINDEX chns = sndFile.GetNumChannels(); for(ROWINDEX row = 0; row < rows; row++) { auto rowCmd = sndFile.Patterns[pat].GetRow(row); for(CHANNELINDEX chn = 0; chn < chns; chn++) { ModCommand &m = rowCmd[chn]; const auto oldCmd = m.command; const auto oldParam = m.param; const auto [note, instr, effect, param] = chunk.ReadArray(); if(note > 0 && note <= 36) { m.note = note + (NOTE_MIDDLEC - 13); if(pairedChn[chn] && m.note >= NOTE_MIDDLEC + 22) m.note = NOTE_MIDDLEC + 21; m.instr = instr + 1; if(m.instr > 0 && m.instr <= sndFile.GetNumSamples()) { auto &sample = sndFile.GetSample(m.instr); // Default volume only works on raw Paula channels if(pairedChn[chn] && sample.nVolume < 256) m.SetVolumeCommand(VOLCMD_VOLUME, 64); // If channel and sample type don't match, stop this channel (add 100 to the instrument number to make it understandable what happened during import) if((sample.cues[0] == 1 && pairedChn[chn] != 0) || (sample.cues[0] == 0 && pairedChn[chn] == 0)) { m.instr += 100; } else if(sample.cues[0] == 2 && pairedChn[chn] && sample.uFlags[CHN_SUSTAINLOOP]) { // Type "B" sample: Loops only work on raw Paula channels sample.cues[1] = 1; m.instr += 36; } } } switch(effect) { case 0: // Nothing break; case 1: // 1 Portamento Down (Period) if(param) { m.SetEffectCommand(CMD_PORTAMENTOUP, param); } break; case 2: // 2 Portamento Up (Period) if(param) m.SetEffectCommand(CMD_PORTAMENTODOWN, param); break; case 10: // A Arpeggio 1 (down, orig, up) if(param) m.SetEffectCommand(CMD_ARPEGGIO, (param & 0x0F) | (InvertArpeggioParam(param >> 4) << 4)); break; case 11: // B Arpeggio 2 (orig, up, orig, down) if(param) m.SetEffectCommand(CMD_ARPEGGIO, (param & 0xF0) | InvertArpeggioParam(param & 0x0F)); break; // This one is close enough to "standard" arpeggio -- I think! case 12: // C Arpeggio 3 (up, up, orig) if(param) m.SetEffectCommand(CMD_ARPEGGIO, param); break; case 13: // D Slide Down (Notes) if(param) m.SetEffectCommand(CMD_NOTESLIDEDOWN, 0x10 | std::min(uint8(0x0F), param)); break; case 30: // U Slide Up (Notes) if(param) m.SetEffectCommand(CMD_NOTESLIDEUP, 0x10 | std::min(uint8(0x0F), param)); break; // Fine Slides are only implemented for libopenmpt. For OpenMPT, // sliding every 5 (non-note) ticks kind of works (at least at // speed 6), but implementing separate (format-agnostic) fine slide commands would of course be better. case 21: // L Slide Down Once (Notes) if(param) m.SetEffectCommand(CMD_NOTESLIDEDOWN, 0x50 | std::min(uint8(0x0F), param)); break; case 17: // H Slide Up Once (Notes) if(param) m.SetEffectCommand(CMD_NOTESLIDEUP, 0x50 | std::min(uint8(0x0F), param)); break; case 15: // F Set Filter <>00:ON m.SetEffectCommand(CMD_MODCMDEX, !!param); break; case 25: // P Pos Jump m.SetEffectCommand(CMD_POSITIONJUMP, param); break; case 27: // R Release sample (apparently not listed in the help!) m.note = NOTE_KEYOFF; m.instr = 0; break; case 28: // S Speed if(param < 0x20) m.SetEffectCommand(CMD_SPEED, param); break; case 31: // V Volume // Volume on mixed channels is permanent, on hardware channels it behaves like in regular MODs if(param & 0x0F) m.SetEffectCommand(pairedChn[chn] ? CMD_CHANNELVOLSLIDE : CMD_VOLUMESLIDE, param & 0x0F); switch(param >> 4) { case 4: // Normal slide down if(param != 0x40) break; // 0x40 is set volume -- fall through [[fallthrough]]; case 0: case 1: case 2: case 3: if(pairedChn[chn]) { m.SetEffectCommand(CMD_CHANNELVOLUME, param); } else { m.SetVolumeCommand(VOLCMD_VOLUME, param); m.SetEffectCommand(oldCmd, oldParam); } break; case 5: // Normal slide up m.param <<= 4; break; case 6: // Fine slide down m.param = 0xF0 | std::min(static_cast(m.param), uint8(0x0E)); break; case 7: // Fine slide up m.param = (std::min(static_cast(m.param), uint8(0x0E)) << 4) | 0x0F; break; default: // Junk. m.SetEffectCommand(oldCmd, oldParam); break; } // Volume is shared between two mixed channels, second channel has priority if(m.command == CMD_CHANNELVOLUME || m.command == CMD_CHANNELVOLSLIDE) { ModCommand &other = rowCmd[chn + pairedChn[chn]]; // Try to preserve effect if there already was one if(auto volCmd = other.ConvertToVolCommand(other.command, other.param, true); volCmd.first != VOLCMD_NONE) { other.SetVolumeCommand(volCmd); } if(ModCommand::GetEffectWeight(other.command) < ModCommand::GetEffectWeight(m.command)) { other.SetEffectCommand(m); } else if(row < rows - 1) { // Retry on next row sndFile.Patterns[pat].GetpModCommand(row + 1, static_cast(chn + pairedChn[chn]))->SetEffectCommand(m); } } break; #if 0 case 24: // O Old Volume (???) m.command = CMD_VOLUMESLIDE; m.param = 0; break; #endif default: break; } // In case we overwrote the volume command from a mixed channel if(oldCmd != CMD_NONE && m.command != oldCmd) { m.FillInTwoCommands(m.command, m.param, oldCmd, oldParam); } } } } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize) { if(!file.CanRead(8)) { return ProbeWantMoreData; } if(!file.ReadMagic("OKTASONG")) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); if(!file.ReadMagic("OKTASONG")) { return false; } std::vector patternChunks; std::vector sampleChunks; std::array pairedChn{{}}; ORDERINDEX numOrders = 0; InitializeGlobals(MOD_TYPE_OKT, 0); m_modFormat.formatName = UL_("Oktalyzer"); m_modFormat.type = UL_("okt"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; // Go through IFF chunks... while(file.CanRead(sizeof(OktIffChunk))) { OktIffChunk iffHead; if(!file.ReadStruct(iffHead)) break; FileReader chunk = file.ReadChunk(iffHead.chunkSize); if(!chunk.IsValid()) continue; switch(iffHead.signature) { case OktIffChunk::idCMOD: // Channel setup table if(GetNumChannels() == 0 && chunk.CanRead(8)) { const auto chnTable = chunk.ReadArray(); ChnSettings.reserve(8); CHANNELINDEX realChn = 0; for(CHANNELINDEX chn = 0; chn < 4; chn++) { if(chnTable[chn]) { pairedChn[realChn++] = 1; pairedChn[realChn] = -1; ChnSettings.emplace_back().nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 0xC0 : 0x40; } realChn++; ChnSettings.emplace_back().nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 0xC0 : 0x40; } if(loadFlags == onlyVerifyHeader) { return true; } } break; case OktIffChunk::idSAMP: // Convert sample headers if(m_nSamples > 0) { break; } ReadOKTSamples(chunk, *this); break; case OktIffChunk::idSPEE: // Read default speed if(chunk.GetLength() >= 2) { Order().SetDefaultSpeed(Clamp(chunk.ReadUint16BE(), uint16(1), uint16(255))); } break; case OktIffChunk::idSLEN: // Number of patterns, we don't need this. break; case OktIffChunk::idPLEN: // Read number of valid orders if(chunk.GetLength() >= 2) { numOrders = chunk.ReadUint16BE(); } break; case OktIffChunk::idPATT: // Read the orderlist ReadOrderFromFile(Order(), chunk, chunk.GetLength(), 0xFF, 0xFE); break; case OktIffChunk::idPBOD: // Don't read patterns for now, as the number of channels might be unknown at this point. if(patternChunks.size() < 256) { patternChunks.push_back(chunk); } break; case OktIffChunk::idSBOD: // Sample data - same as with patterns, as we need to know the sample format / length if(sampleChunks.size() < MAX_SAMPLES - 1 && chunk.GetLength() > 0) { sampleChunks.push_back(chunk); } break; } } // If there wasn't even a CMOD chunk, we can't really load this. if(GetNumChannels() == 0) return false; Order().SetDefaultTempoInt(125); m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; m_nSamplePreAmp = m_nVSTiVolume = 48; m_nMinPeriod = 113 * 4; m_nMaxPeriod = 856 * 4; m_SongFlags.set(SONG_FASTPORTAS); // Fix orderlist Order().resize(numOrders); // Read patterns if(loadFlags & loadPatternData) { Patterns.ResizeArray(static_cast(patternChunks.size())); for(PATTERNINDEX pat = 0; pat < patternChunks.size(); pat++) { ReadOKTPattern(patternChunks[pat], pat, *this, pairedChn); } } // Read samples size_t fileSmp = 0; const SAMPLEINDEX origSamples = m_nSamples; for(SAMPLEINDEX smp = 1; smp <= origSamples; smp++) { if(fileSmp >= sampleChunks.size() || !(loadFlags & loadSampleData)) break; ModSample &mptSample = Samples[smp]; const bool needCopy = mptSample.cues[1] != 0; if(mptSample.nLength == 0) continue; // Weird stuff? LimitMax(mptSample.nLength, mpt::saturate_cast(sampleChunks[fileSmp].GetLength())); SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM) .ReadSample(mptSample, sampleChunks[fileSmp]); if(needCopy) { // Type "B" samples (can play on both paired and unpaired channels) can have loop information, // which can only be used on unpaired channels. So we need a looped and unlooped copy of the sample. m_nSamples = std::max(m_nSamples, static_cast(smp + 36)); ModSample ©Sample = Samples[smp + 36]; copySample.Initialize(); copySample.nC5Speed = mptSample.nC5Speed; copySample.nVolume = mptSample.nVolume; copySample.nLength = mptSample.nLength; copySample.CopyWaveform(mptSample); m_szNames[smp + 36] = m_szNames[smp]; } fileSmp++; } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MIDIEvents.h0000644000175000017500000001231014705226003020151 00000000000000/* * MIDIEvents.h * ------------ * Purpose: MIDI event handling, event lists, ... * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" OPENMPT_NAMESPACE_BEGIN // MIDI related enums and helper functions namespace MIDIEvents { // MIDI Event Types enum EventType { evNoteOff = 0x8, // Note Off event evNoteOn = 0x9, // Note On event evPolyAftertouch = 0xA, // Poly Aftertouch / Poly Pressure event evControllerChange = 0xB, // Controller Change (see MidiCC enum) evProgramChange = 0xC, // Program Change evChannelAftertouch = 0xD, // Channel Aftertouch evPitchBend = 0xE, // Pitchbend event (see PitchBend enum) evSystem = 0xF, // System event (see SystemEvent enum) }; // System Events (Fx ...) enum SystemEvent { sysExStart = 0x0, // Begin of System Exclusive message sysQuarterFrame = 0x1, // Quarter Frame Message sysPositionPointer = 0x2, // Song Position Pointer sysSongSelect = 0x3, // Song Select sysTuneRequest = 0x6, // Tune Request sysExEnd = 0x7, // End of System Exclusive message sysMIDIClock = 0x8, // MIDI Clock event sysMIDITick = 0x9, // MIDI Tick event sysStart = 0xA, // Start Song sysContinue = 0xB, // Continue Song sysStop = 0xC, // Stop Song sysActiveSense = 0xE, // Active Sense Message sysReset = 0xF, // Reset Device }; // MIDI Pitchbend Constants enum PitchBend { pitchBendMin = 0x00, pitchBendCentre = 0x2000, pitchBendMax = 0x3FFF }; // MIDI Continuous Controller Codes // http://home.roadrunner.com/~jgglatt/tech/midispec/ctllist.htm enum MidiCC { MIDICC_start = 0, MIDICC_BankSelect_Coarse = MIDICC_start, MIDICC_ModulationWheel_Coarse = 1, MIDICC_Breathcontroller_Coarse = 2, MIDICC_FootPedal_Coarse = 4, MIDICC_PortamentoTime_Coarse = 5, MIDICC_DataEntry_Coarse = 6, MIDICC_Volume_Coarse = 7, MIDICC_Balance_Coarse = 8, MIDICC_Panposition_Coarse = 10, MIDICC_Expression_Coarse = 11, MIDICC_EffectControl1_Coarse = 12, MIDICC_EffectControl2_Coarse = 13, MIDICC_GeneralPurposeSlider1 = 16, MIDICC_GeneralPurposeSlider2 = 17, MIDICC_GeneralPurposeSlider3 = 18, MIDICC_GeneralPurposeSlider4 = 19, MIDICC_BankSelect_Fine = 32, MIDICC_ModulationWheel_Fine = 33, MIDICC_Breathcontroller_Fine = 34, MIDICC_FootPedal_Fine = 36, MIDICC_PortamentoTime_Fine = 37, MIDICC_DataEntry_Fine = 38, MIDICC_Volume_Fine = 39, MIDICC_Balance_Fine = 40, MIDICC_Panposition_Fine = 42, MIDICC_Expression_Fine = 43, MIDICC_EffectControl1_Fine = 44, MIDICC_EffectControl2_Fine = 45, MIDICC_HoldPedal_OnOff = 64, MIDICC_Portamento_OnOff = 65, MIDICC_SustenutoPedal_OnOff = 66, MIDICC_SoftPedal_OnOff = 67, MIDICC_LegatoPedal_OnOff = 68, MIDICC_Hold2Pedal_OnOff = 69, MIDICC_SoundVariation = 70, MIDICC_SoundTimbre = 71, MIDICC_SoundReleaseTime = 72, MIDICC_SoundAttackTime = 73, MIDICC_SoundBrightness = 74, MIDICC_SoundControl6 = 75, MIDICC_SoundControl7 = 76, MIDICC_SoundControl8 = 77, MIDICC_SoundControl9 = 78, MIDICC_SoundControl10 = 79, MIDICC_GeneralPurposeButton1_OnOff = 80, MIDICC_GeneralPurposeButton2_OnOff = 81, MIDICC_GeneralPurposeButton3_OnOff = 82, MIDICC_GeneralPurposeButton4_OnOff = 83, MIDICC_EffectsLevel = 91, MIDICC_TremoloLevel = 92, MIDICC_ChorusLevel = 93, MIDICC_CelesteLevel = 94, MIDICC_PhaserLevel = 95, MIDICC_DataButtonincrement = 96, MIDICC_DataButtondecrement = 97, MIDICC_NonRegisteredParameter_Fine = 98, MIDICC_NonRegisteredParameter_Coarse = 99, MIDICC_RegisteredParameter_Fine = 100, MIDICC_RegisteredParameter_Coarse = 101, MIDICC_AllSoundOff = 120, MIDICC_AllControllersOff = 121, MIDICC_LocalKeyboard_OnOff = 122, MIDICC_AllNotesOff = 123, MIDICC_OmniModeOff = 124, MIDICC_OmniModeOn = 125, MIDICC_MonoOperation = 126, MIDICC_PolyOperation = 127, MIDICC_end = MIDICC_PolyOperation, }; // MIDI CC Names extern const char* const MidiCCNames[MIDICC_end + 1]; // Charset::UTF8 // Build a generic MIDI event uint32 Event(EventType eventType, uint8 midiChannel, uint8 dataByte1, uint8 dataByte2); // Build a MIDI CC event uint32 CC(MidiCC midiCC, uint8 midiChannel, uint8 param); // Build a MIDI Pitchbend event uint32 PitchBend(uint8 midiChannel, uint16 bendAmount); // Build a MIDI Program Change event uint32 ProgramChange(uint8 midiChannel, uint8 program); // Build a MIDI Note Off event uint32 NoteOff(uint8 midiChannel, uint8 note, uint8 velocity); // Build a MIDI Note On event uint32 NoteOn(uint8 midiChannel, uint8 note, uint8 velocity); // Build a MIDI System Event uint8 System(SystemEvent eventType); // Build a MIDI Song Position Event uint32 SongPosition(uint16 quarterNotes); // Get MIDI channel from a MIDI event uint8 GetChannelFromEvent(uint32 midiMsg); // Get MIDI Event type from a MIDI event EventType GetTypeFromEvent(uint32 midiMsg); // Get first data byte from a MIDI event uint8 GetDataByte1FromEvent(uint32 midiMsg); // Get second data byte from a MIDI event uint8 GetDataByte2FromEvent(uint32 midiMsg); // Get the length of a MIDI event in bytes uint8 GetEventLength(uint8 firstByte); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/UMXTools.cpp0000644000175000017500000002111614502511125020270 00000000000000/* * UMXTools.h * ------------ * Purpose: UMX/UAX (Unreal package) helper functions * Notes : (currently none) * Authors: OpenMPT Devs (inspired by code from https://wiki.beyondunreal.com/Legacy:Package_File_Format) * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "UMXTools.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN namespace UMX { bool FileHeader::IsValid() const { return !std::memcmp(magic, "\xC1\x83\x2A\x9E", 4) && nameOffset >= sizeof(FileHeader) && exportOffset >= sizeof(FileHeader) && importOffset >= sizeof(FileHeader) && nameCount > 0 && nameCount <= uint32_max / 5u && exportCount > 0 && exportCount <= uint32_max / 8u && importCount > 0 && importCount <= uint32_max / 4u && uint32_max - nameCount * 5u >= nameOffset && uint32_max - exportCount * 8u >= exportOffset && uint32_max - importCount * 4u >= importOffset; } uint32 FileHeader::GetMinimumAdditionalFileSize() const { return std::max({nameOffset + nameCount * 5u, exportOffset + exportCount * 8u, importOffset + importCount * 4u}) - static_cast(sizeof(FileHeader)); } CSoundFile::ProbeResult ProbeFileHeader(MemoryFileReader file, const uint64 *pfilesize, const char *requiredType) { FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return CSoundFile::ProbeWantMoreData; } if(!fileHeader.IsValid()) { return CSoundFile::ProbeFailure; } if(requiredType != nullptr && !FindNameTableEntryMemory(file, fileHeader, requiredType)) { return CSoundFile::ProbeFailure; } return CSoundFile::ProbeAdditionalSize(file, pfilesize, fileHeader.GetMinimumAdditionalFileSize()); } // Read compressed unreal integers - similar to MIDI integers, but signed values are possible. template static int32 ReadIndexImpl(Tfile &chunk) { enum { signMask = 0x80, // Highest bit of first byte indicates if value is signed valueMask1 = 0x3F, // Low 6 bits of first byte are actual value continueMask1 = 0x40, // Second-highest bit of first byte indicates if further bytes follow valueMask = 0x7F, // Low 7 bits of following bytes are actual value continueMask = 0x80, // Highest bit of following bytes indicates if further bytes follow }; // Read first byte uint8 b = chunk.ReadUint8(); bool isSigned = (b & signMask) != 0; uint32 result = (b & valueMask1); int shift = 6; if(b & continueMask1) { // Read remaining bytes do { b = chunk.ReadUint8(); uint32 data = static_cast(b) & valueMask; data <<= shift; result |= data; shift += 7; } while((b & continueMask) != 0 && (shift < 32)); } if(isSigned && result <= int32_max) return -static_cast(result); else if(isSigned) return int32_min; else return result; } int32 ReadIndex(FileReader &chunk) { return ReadIndexImpl(chunk); } // Returns true if the given nme exists in the name table. template static bool FindNameTableEntryImpl(TFile &file, const FileHeader &fileHeader, const char *name) { if(!name) { return false; } const std::size_t nameLen = std::strlen(name); if(nameLen == 0) { return false; } bool result = false; const FileReader::pos_type oldpos = file.GetPosition(); if(file.Seek(fileHeader.nameOffset)) { for(uint32 i = 0; i < fileHeader.nameCount && file.CanRead(5); i++) { if(fileHeader.packageVersion >= 64) { int32 length = ReadIndexImpl(file); if(length <= 0) { continue; } } bool match = true; std::size_t pos = 0; char c = 0; while((c = file.ReadUint8()) != 0) { c = mpt::ToLowerCaseAscii(c); if(pos < nameLen) { match = match && (c == name[pos]); } pos++; } if(pos != nameLen) { match = false; } if(match) { result = true; } file.Skip(4); // Object flags } } file.Seek(oldpos); return result; } bool FindNameTableEntry(FileReader &file, const FileHeader &fileHeader, const char *name) { return FindNameTableEntryImpl(file, fileHeader, name); } bool FindNameTableEntryMemory(MemoryFileReader &file, const FileHeader &fileHeader, const char *name) { return FindNameTableEntryImpl(file, fileHeader, name); } // Read an entry from the name table. std::string ReadNameTableEntry(FileReader &chunk, uint16 packageVersion) { std::string name; if(packageVersion >= 64) { // String length int32 length = ReadIndex(chunk); if(length <= 0) { return ""; } name.reserve(std::min(length, mpt::saturate_cast(chunk.BytesLeft()))); } // Simple zero-terminated string uint8 chr; while((chr = chunk.ReadUint8()) != 0) { // Convert string to lower case if(chr >= 'A' && chr <= 'Z') { chr = chr - 'A' + 'a'; } name.append(1, static_cast(chr)); } chunk.Skip(4); // Object flags return name; } // Read complete name table. std::vector ReadNameTable(FileReader &file, const FileHeader &fileHeader) { file.Seek(fileHeader.nameOffset); // nameOffset and nameCount were validated when parsing header std::vector names; names.reserve(fileHeader.nameCount); for(uint32 i = 0; i < fileHeader.nameCount && file.CanRead(5); i++) { names.push_back(ReadNameTableEntry(file, fileHeader.packageVersion)); } return names; } // Read an entry from the import table. int32 ReadImportTableEntry(FileReader &chunk, uint16 packageVersion) { ReadIndex(chunk); // Class package ReadIndex(chunk); // Class name if(packageVersion >= 60) { chunk.Skip(4); // Package } else { ReadIndex(chunk); // ?? } return ReadIndex(chunk); // Object name (offset into the name table) } // Read import table. std::vector ReadImportTable(FileReader &file, const FileHeader &fileHeader, const std::vector &names) { file.Seek(fileHeader.importOffset); // importOffset and importCount were validated when parsing header std::vector classes; classes.reserve(fileHeader.importCount); for(uint32 i = 0; i < fileHeader.importCount && file.CanRead(4); i++) { int32 objName = ReadImportTableEntry(file, fileHeader.packageVersion); if(static_cast(objName) < names.size()) { classes.push_back(objName); } } return classes; } // Read an entry from the export table. std::pair ReadExportTableEntry(FileReader &file, const FileHeader &fileHeader, const std::vector &classes, const std::vector &names, const char *filterType) { const uint32 objClass = ~static_cast(ReadIndex(file)); // Object class if(objClass >= classes.size()) return {}; ReadIndex(file); // Object parent if(fileHeader.packageVersion >= 60) { file.Skip(4); // Internal package / group of the object } int32 objName = ReadIndex(file); // Object name (offset into the name table) file.Skip(4); // Object flags int32 objSize = ReadIndex(file); int32 objOffset = ReadIndex(file); if(objSize <= 0 || objOffset <= static_cast(sizeof(FileHeader))) return {}; // If filterType is set, reject any objects not of that type if(filterType != nullptr && names[classes[objClass]] != filterType) return {}; FileReader chunk = file.GetChunkAt(objOffset, objSize); if(!chunk.IsValid()) return {}; if(fileHeader.packageVersion < 40) { chunk.Skip(8); // 00 00 00 00 00 00 00 00 } if(fileHeader.packageVersion < 60) { chunk.Skip(16); // 81 00 00 00 00 00 FF FF FF FF FF FF FF FF 00 00 } // Read object properties #if 0 size_t propertyName = static_cast(ReadIndex(chunk)); if(propertyName >= names.size() || names[propertyName] != "none") { // Can't bother to implement property reading, as no UMX files I've seen so far use properties for the relevant objects, // and only the UAX files in the Unreal 1997/98 beta seem to use this and still load just fine when ignoring it. // If it should be necessary to implement this, check CUnProperty.cpp in http://ut-files.com/index.php?dir=Utilities/&file=utcms_source.zip MPT_ASSERT_NOTREACHED(); continue; } #else ReadIndex(chunk); #endif if(fileHeader.packageVersion >= 120) { // UT2003 Packages ReadIndex(chunk); chunk.Skip(8); } else if(fileHeader.packageVersion >= 100) { // AAO Packages chunk.Skip(4); ReadIndex(chunk); chunk.Skip(4); } else if(fileHeader.packageVersion >= 62) { // UT Packages // Mech8.umx and a few other UT tunes have packageVersion = 62. // In CUnSound.cpp, the condition above reads "packageVersion >= 63" but if that is used, those tunes won't load properly. ReadIndex(chunk); chunk.Skip(4); } else { // Old Unreal Packagaes ReadIndex(chunk); } int32 size = ReadIndex(chunk); return {chunk.ReadChunk(size), objName}; } } // namespace UMX OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_uax.cpp0000644000175000017500000000461314644610543020350 00000000000000/* * Load_uax.cpp * ------------ * Purpose: UAX (Unreal Sounds) module ripper * Notes : The sounds are read into module sample slots. * Authors: Johannes Schultz (inspired by code from http://wiki.beyondunreal.com/Legacy:Package_File_Format) * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "UMXTools.h" OPENMPT_NAMESPACE_BEGIN CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderUAX(MemoryFileReader file, const uint64 *pfilesize) { return UMX::ProbeFileHeader(file, pfilesize, "sound"); } bool CSoundFile::ReadUAX(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); UMX::FileHeader fileHeader; if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) return false; // Note that this can be a false positive, e.g. Unreal maps will have music and sound // in their name table because they usually import such files. However, it spares us // from wildly seeking through the file, as the name table is usually right at the // start of the file, so it is hopefully a good enough heuristic for our purposes. if(!UMX::FindNameTableEntry(file, fileHeader, "sound")) return false; else if(!file.CanRead(fileHeader.GetMinimumAdditionalFileSize())) return false; else if(loadFlags == onlyVerifyHeader) return true; const std::vector names = UMX::ReadNameTable(file, fileHeader); const std::vector classes = UMX::ReadImportTable(file, fileHeader, names); InitializeGlobals(MOD_TYPE_MPT, 4); m_modFormat.formatName = MPT_UFORMAT("Unreal Package v{}")(fileHeader.packageVersion); m_modFormat.type = UL_("uax"); m_modFormat.charset = mpt::Charset::Windows1252; // Read export table file.Seek(fileHeader.exportOffset); for(uint32 i = 0; i < fileHeader.exportCount && file.CanRead(8); i++) { auto [fileChunk, objName] = UMX::ReadExportTableEntry(file, fileHeader, classes, names, "sound"); if(!fileChunk.IsValid()) continue; if(CanAddMoreSamples()) { // Read as sample if(ReadSampleFromFile(GetNumSamples() + 1, fileChunk, true)) { if(objName > 0 && static_cast(objName) < names.size()) { m_szNames[GetNumSamples()] = names[objName]; } } } } if(m_nSamples != 0) { m_ContainerType = ModContainerType::UAX; Patterns.Insert(0, 64); Order().assign(1, 0); return true; } else { return false; } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ModChannel.h0000644000175000017500000002376114731624663020303 00000000000000/* * ModChannel.h * ------------ * Purpose: The ModChannel struct represents the state of one mixer channel. * ModChannelSettings represents the default settings of one pattern channel. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "InstrumentSynth.h" #include "modcommand.h" #include "Paula.h" #include "tuningbase.h" #include OPENMPT_NAMESPACE_BEGIN class CSoundFile; struct ModSample; struct ModInstrument; // Mix Channel Struct struct ModChannel { // Envelope playback info struct EnvInfo { uint32 nEnvPosition = 0; int16 nEnvValueAtReleaseJump = NOT_YET_RELEASED; FlagSet flags; void Reset() { nEnvPosition = 0; nEnvValueAtReleaseJump = NOT_YET_RELEASED; } }; struct AutoSlideStatus { bool AnyActive() const noexcept { return m_set.any(); } bool IsActive(AutoSlideCommand cmd) const noexcept { return m_set[static_cast(cmd)]; } void SetActive(AutoSlideCommand cmd, bool active = true) noexcept { m_set[static_cast(cmd)] = active; } void Reset() noexcept { m_set.reset(); } bool AnyPitchSlideActive() const noexcept { return IsActive(AutoSlideCommand::TonePortamento) || IsActive(AutoSlideCommand::PortamentoUp) || IsActive(AutoSlideCommand::PortamentoDown) || IsActive(AutoSlideCommand::FinePortamentoUp) || IsActive(AutoSlideCommand::FinePortamentoDown) || IsActive(AutoSlideCommand::PortamentoFC); } private: std::bitset(AutoSlideCommand::NumCommands)> m_set; }; // Information used in the mixer (should be kept tight for better caching) SamplePosition position; // Current play position (fixed point) SamplePosition increment; // Sample speed relative to mixing frequency (fixed point) const void *pCurrentSample; // Currently playing sample (nullptr if no sample is playing) int32 leftVol; // 0...4096 (12 bits, since 16 bits + 12 bits = 28 bits = 0dB in integer mixer, see MIXING_ATTENUATION) int32 rightVol; // Ditto int32 leftRamp; // Ramping delta, 20.12 fixed point (see VOLUMERAMPPRECISION) int32 rightRamp; // Ditto int32 rampLeftVol; // Current ramping volume, 20.12 fixed point (see VOLUMERAMPPRECISION) int32 rampRightVol; // Ditto mixsample_t nFilter_Y[2][2]; // Filter memory - two history items per sample channel mixsample_t nFilter_A0, nFilter_B0, nFilter_B1; // Filter coeffs mixsample_t nFilter_HP; SmpLength nLength; SmpLength nLoopStart; SmpLength nLoopEnd; FlagSet dwFlags; mixsample_t nROfs, nLOfs; uint32 nRampLength; const ModSample *pModSample; // Currently assigned sample slot (may already be stopped) Paula::State paulaState; InstrumentSynth::States synthState; // Information not used in the mixer const ModInstrument *pModInstrument; // Currently assigned instrument slot SmpLength prevNoteOffset; // Offset for instrument-less notes for ProTracker/ScreamTracker SmpLength oldOffset; // Offset command memory FlagSet dwOldFlags; // Flags from previous tick int32 newLeftVol, newRightVol; int32 nRealVolume, nRealPan; int32 nVolume, nPan, nFadeOutVol; int32 nPeriod; // Frequency in Hz if CSoundFile::PeriodsAreFrequencies() or using custom tuning, 4x Amiga periods otherwise int32 nC5Speed, nPortamentoDest; int32 cachedPeriod, glissandoPeriod; int32 nCalcVolume; // Calculated channel volume, 14-Bit (without global volume, pre-amp etc applied) - for MIDI macros EnvInfo VolEnv, PanEnv, PitchEnv; // Envelope playback info int32 nAutoVibDepth; uint32 nEFxOffset; // Offset memory for Invert Loop (EFx, .MOD only) ROWINDEX nPatternLoop; AutoSlideStatus autoSlide; uint16 portamentoSlide; int16 nFineTune; int16 microTuning; // Micro-tuning / MIDI pitch wheel command int16 nVolSwing, nPanSwing; int16 nCutSwing, nResSwing; uint16 volSlideDownRemain, volSlideDownTotal; union { uint16 nRestorePanOnNewNote; // If > 0, nPan should be set to nRestorePanOnNewNote - 1 on new note. Used to recover from pan swing and IT sample / instrument panning. High bit set = surround uint16 nnaChannelAge; // If channel is moved to background (NNA), this counts up how old it is }; uint16 nnaGeneration; // For PlaybackTest implementation CHANNELINDEX nMasterChn; SAMPLEINDEX swapSampleIndex; // Sample to swap to when current sample (loop) has finished playing ModCommand rowCommand; // 8-bit members uint8 nGlobalVol; // Channel volume (CV in ITTECH.TXT) 0...64 uint8 nInsVol; // Sample / Instrument volume (SV * IV in ITTECH.TXT) 0...64 int8 nTranspose; ResamplingMode resamplingMode; uint8 nRestoreResonanceOnNewNote; // See nRestorePanOnNewNote uint8 nRestoreCutoffOnNewNote; // ditto uint8 nNote; NewNoteAction nNNA; uint8 nLastNote; // Last note, ignoring note offs and cuts - for MIDI macros uint8 nArpeggioLastNote, lastMidiNoteWithoutArp; // For plugin arpeggio and NNA handling uint8 nNewNote, nNewIns, nOldIns, nCommand, nArpeggio; uint8 nRetrigParam, nRetrigCount; uint8 nOldVolumeSlide, nOldFineVolUpDown; uint8 nOldPortaUp, nOldPortaDown, nOldFinePortaUpDown, nOldExtraFinePortaUpDown; uint8 nOldPanSlide, nOldChnVolSlide; uint8 nOldGlobalVolSlide; uint8 nAutoVibPos, nVibratoPos, nTremoloPos, nPanbrelloPos; uint8 nVibratoType, nVibratoSpeed, nVibratoDepth; uint8 nTremoloType, nTremoloSpeed, nTremoloDepth; uint8 nPanbrelloType, nPanbrelloSpeed, nPanbrelloDepth; int8 nPanbrelloOffset, nPanbrelloRandomMemory; uint8 nOldCmdEx, nOldVolParam, nOldTempo; uint8 nOldHiOffset; uint8 nCutOff, nResonance; uint8 nTremorCount, nTremorParam; uint8 nPatternLoopCount; uint8 nLeftVU, nRightVU; uint8 nActiveMacro; uint8 volSlideDownStart; FilterMode nFilterMode; uint8 nEFxSpeed, nEFxDelay; // memory for Invert Loop (EFx, .MOD only) uint8 noteSlideParam, noteSlideCounter; // IMF / PTM Note Slide uint8 lastZxxParam; // Memory for \xx slides bool isFirstTick : 1; // Execute tick-0 effects on this channel? (condition differs between formats due to Pattern Delay commands) bool triggerNote : 1; // Trigger note on this tick on this channel if there is one? bool isPreviewNote : 1; // Notes preview in editor bool isPaused : 1; // Don't mix or increment channel position, but keep the note alive bool portaTargetReached : 1; // Tone portamento is finished bool fcPortaTick : 1; // Future Composer portamento state //-->Variables used to make user-definable tuning modes work with pattern effects. //If true, freq should be recalculated in ReadNote() on first tick. //Currently used only for vibrato things - using in other context might be //problematic. bool m_ReCalculateFreqOnFirstTick : 1; //To tell whether to calculate frequency. bool m_CalculateFreq : 1; int32 m_PortamentoFineSteps, m_PortamentoTickSlide; //NOTE_PCs memory. float m_plugParamValueStep, m_plugParamTargetValue; uint16 m_RowPlugParam; PLUGINDEX m_RowPlug; // Get a reference to a specific envelope of this channel const EnvInfo &GetEnvelope(EnvelopeType envType) const { switch(envType) { case ENV_VOLUME: default: return VolEnv; case ENV_PANNING: return PanEnv; case ENV_PITCH: return PitchEnv; } } EnvInfo &GetEnvelope(EnvelopeType envType) { return const_cast(static_cast(this)->GetEnvelope(envType)); } void ResetEnvelopes() { VolEnv.Reset(); PanEnv.Reset(); PitchEnv.Reset(); } enum ResetFlags { resetChannelSettings = 1, // Reload initial channel settings resetSetPosBasic = 2, // Reset basic runtime channel attributes resetSetPosAdvanced = 4, // Reset more runtime channel attributes resetSetPosFull = resetSetPosBasic | resetSetPosAdvanced | resetChannelSettings, // Reset all runtime channel attributes resetTotal = resetSetPosFull, }; void Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel, ChannelFlags muteFlag); void Stop(); bool IsSamplePlaying() const noexcept { return !increment.IsZero(); } uint32 GetVSTVolume() const noexcept; ModCommand::NOTE GetPluginNote(bool ignoreArpeggio = false) const noexcept; // Check if the channel has a valid MIDI output. A return value of true implies that pModInstrument != nullptr. bool HasMIDIOutput() const noexcept; // Check if the channel uses custom tuning. A return value of true implies that pModInstrument != nullptr. bool HasCustomTuning() const noexcept; // Check if currently processed loop is a sustain loop. pModSample is not checked for validity! bool InSustainLoop() const noexcept; void UpdateInstrumentVolume(const ModSample *smp, const ModInstrument *ins); void SetInstrumentPan(int32 pan, const CSoundFile &sndFile); void RestorePanAndFilter(); void RecalcTuningFreq(Tuning::RATIOTYPE vibratoFactor, Tuning::NOTEINDEXTYPE arpeggioSteps, const CSoundFile &sndFile); // IT command S73-S7E void InstrumentControl(uint8 param, const CSoundFile &sndFile); // Volume command :xx void PlayControl(uint8 param); int32 GetMIDIPitchBend() const noexcept { return (static_cast(microTuning) + 0x8000) / 4; } void SetMIDIPitchBend(const uint8 high, const uint8 low) noexcept { microTuning = static_cast(((high << 9) | (low << 2)) - 0x8000); } }; // Default pattern channel settings struct ModChannelSettings { #ifdef MODPLUG_TRACKER static constexpr uint32 INVALID_COLOR = 0xFFFFFFFF; uint32 color = INVALID_COLOR; // For pattern editor #endif // MODPLUG_TRACKER FlagSet dwFlags; // Channel flags uint16 nPan = 128; // Initial pan (0...256) uint8 nVolume = 64; // Initial channel volume (0...64) PLUGINDEX nMixPlugin = 0; // Assigned plugin mpt::charbuf szName; // Channel name }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MIDIMacroParser.cpp0000644000175000017500000002276614723070552021504 00000000000000/* * MIDIMacroParser.cpp * ------------------- * Purpose: Class for parsing IT MIDI macro strings and splitting them into individual raw MIDI messages. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "MIDIMacroParser.h" #include "MIDIEvents.h" #include "Sndfile.h" #include "plugins/PlugInterface.h" OPENMPT_NAMESPACE_BEGIN bool MIDIMacroParser::NextMessage(mpt::span &message, bool outputRunningStatus) { if(m_runningStatusPos < m_data.size()) { m_data[m_runningStatusPos] = m_runningstatusOldData; m_runningStatusPos = uint32_max; } const uint32 outSize = static_cast(m_data.size()); while(m_sendPos < outSize) { uint32 sendLen = 0; if(m_data[m_sendPos] == 0xF0) { // SysEx start if((outSize - m_sendPos >= 4) && (m_data[m_sendPos + 1] == 0xF0 || m_data[m_sendPos + 1] == 0xF1)) { // Internal macro (normal (F0F0) or extended (F0F1)), 4 bytes long sendLen = 4; } else { // SysEx message, find end of message sendLen = outSize - m_sendPos; for(uint32 i = m_sendPos + 1; i < outSize; i++) { if(m_data[i] == 0xF7) { // Found end of SysEx message sendLen = i - m_sendPos + 1; break; } } } } else if(!(m_data[m_sendPos] & 0x80)) { // Missing status byte? Try inserting running status if(m_runningStatus != 0) { if(outputRunningStatus) { m_sendPos--; m_runningstatusOldData = m_data[m_sendPos]; m_data[m_sendPos] = m_runningStatus; m_runningStatusPos = m_sendPos; continue; } else { sendLen = std::min(static_cast(MIDIEvents::GetEventLength(m_runningStatus) - 1), outSize - m_sendPos); } } else { // No running status to re-use; skip this byte m_sendPos++; continue; } } else { // Other MIDI messages sendLen = std::min(static_cast(MIDIEvents::GetEventLength(m_data[m_sendPos])), outSize - m_sendPos); } if(sendLen == 0) break; if(m_data[m_sendPos] < 0xF0) m_runningStatus = m_data[m_sendPos]; message = m_data.subspan(m_sendPos, sendLen); m_sendPos += sendLen; return true; } message = {}; return false; } MIDIMacroParser::MIDIMacroParser(const CSoundFile &sndFile, PlayState *playState, CHANNELINDEX nChn, bool isSmooth, const mpt::span macro, mpt::span out, uint8 param, PLUGINDEX plugin) : m_data{out} { // Need to be able to add potentially missing F7 (End Of SysEx) MPT_ASSERT(out.size() > macro.size()); ModChannel *chn = (playState && nChn < playState->Chn.size()) ? &playState->Chn[nChn] : nullptr; const ModInstrument *pIns = chn ? chn->pModInstrument : nullptr; MPT_ASSERT(!isSmooth || chn); // If we want to interpolate, we need access to the channel. const uint8 lastZxxParam = chn ? chn->lastZxxParam : 0xFF; // always interpolate based on original value in case z appears multiple times in macro string uint8 updateZxxParam = 0xFF; // avoid updating lastZxxParam immediately if macro contains both internal and external MIDI message bool firstNibble = true; size_t outPos = 0; // output buffer position, which also equals the number of complete bytes for(size_t pos = 0; pos < macro.size() && outPos < out.size(); pos++) { bool isNibble = false; // did we parse a nibble or a byte value? uint8 data = 0; // data that has just been parsed // Parse next macro byte... See Impulse Tracker's MIDI.TXT for detailed information on each possible character. if(macro[pos] >= '0' && macro[pos] <= '9') { isNibble = true; data = static_cast(macro[pos] - '0'); } else if(macro[pos] >= 'A' && macro[pos] <= 'F') { isNibble = true; data = static_cast(macro[pos] - 'A' + 0x0A); } else if(macro[pos] == 'c') { // MIDI channel isNibble = true; data = 0xFF; #ifndef NO_PLUGINS const PLUGINDEX plug = (plugin != 0 || !chn) ? plugin : sndFile.GetBestPlugin(*chn, nChn, PrioritiseChannel, EvenIfMuted); if(plug > 0 && plug <= MAX_MIXPLUGINS) { auto midiPlug = dynamic_cast(sndFile.m_MixPlugins[plug - 1u].pMixPlugin); if(midiPlug && chn) data = midiPlug->GetMidiChannel(*chn, nChn); } #endif // NO_PLUGINS if(data == 0xFF) { // Fallback if no plugin was found if(pIns && chn) data = pIns->GetMIDIChannel(*chn, nChn); else data = 0; } } else if(macro[pos] == 'n') { // Last triggered note if(chn && ModCommand::IsNote(chn->nLastNote)) data = chn->nLastNote - NOTE_MIN; } else if(macro[pos] == 'v') { // Velocity // This is "almost" how IT does it - apparently, IT seems to lag one row behind on global volume or channel volume changes. if(chn && playState) { const int swing = (sndFile.m_playBehaviour[kITSwingBehaviour] || sndFile.m_playBehaviour[kMPTOldSwingBehaviour]) ? chn->nVolSwing : 0; const int vol = Util::muldiv((chn->nVolume + swing) * playState->m_nGlobalVolume, chn->nGlobalVol * chn->nInsVol, 1 << 20); data = static_cast(Clamp(vol / 2, 1, 127)); //data = static_cast(std::min((chn->nVolume * chn->nGlobalVol * playState->m_nGlobalVolume) >> (1 + 6 + 8), 127)); } } else if(macro[pos] == 'u') { // Calculated volume // Same note as with velocity applies here, but apparently also for instrument / sample volumes? if(chn && playState) { const int vol = Util::muldiv(chn->nCalcVolume * playState->m_nGlobalVolume, chn->nGlobalVol * chn->nInsVol, 1 << 26); data = static_cast(Clamp(vol / 2, 1, 127)); //data = static_cast(std::min((chn->nCalcVolume * chn->nGlobalVol * playState->m_nGlobalVolume) >> (7 + 6 + 8), 127)); } } else if(macro[pos] == 'x') { // Pan set if(chn) data = static_cast(std::min(static_cast(chn->nPan / 2), 127)); } else if(macro[pos] == 'y') { // Calculated pan if(chn) data = static_cast(std::min(static_cast(chn->nRealPan / 2), 127)); } else if(macro[pos] == 'a') { // High byte of bank select if(pIns && pIns->wMidiBank) { data = static_cast(((pIns->wMidiBank - 1) >> 7) & 0x7F); } } else if(macro[pos] == 'b') { // Low byte of bank select if(pIns && pIns->wMidiBank) { data = static_cast((pIns->wMidiBank - 1) & 0x7F); } } else if(macro[pos] == 'o') { // Offset (ignoring high offset) if(chn) data = static_cast((chn->oldOffset >> 8) & 0xFF); } else if(macro[pos] == 'h') { // Host channel number if(chn) data = static_cast((nChn >= sndFile.GetNumChannels() ? (chn->nMasterChn - 1) : nChn) & 0x7F); } else if(macro[pos] == 'm') { // Loop direction (on sample channels - MIDI note on MIDI channels) if(chn) data = chn->dwFlags[CHN_PINGPONGFLAG] ? 1 : 0; } else if(macro[pos] == 'p') { // Program select if(pIns && pIns->nMidiProgram) { data = static_cast((pIns->nMidiProgram - 1) & 0x7F); } } else if(macro[pos] == 'z') { // Zxx parameter data = param; if(isSmooth && playState && chn && chn->lastZxxParam < 0x80 && (outPos < 3 || out[outPos - 3] != 0xF0 || out[outPos - 2] < 0xF0)) { // Interpolation for external MIDI messages - interpolation for internal messages // is handled separately to allow for more than 7-bit granularity where it's possible data = static_cast(CSoundFile::CalculateSmoothParamChange(*playState, lastZxxParam, data)); chn->lastZxxParam = data; updateZxxParam = 0x80; } else if(updateZxxParam == 0xFF) { updateZxxParam = data; } } else if(macro[pos] == 's') { // SysEx Checksum (not an original Impulse Tracker macro variable, but added for convenience) if(!firstNibble) // From MIDI.TXT: '9n' is exactly the same as '09 n' or '9 n' -- so finish current byte first { outPos++; firstNibble = true; } auto startPos = outPos; while(startPos > 0 && out[--startPos] != 0xF0) ; if(outPos - startPos < 3 || out[startPos] != 0xF0) continue; // If first byte of model number is 0, read one more uint8 checksumStart = out[startPos + 3] ? 5 : 6; if(outPos - startPos < checksumStart) continue; for(auto p = startPos + checksumStart; p != outPos; p++) { data += out[p]; } data = (~data + 1) & 0x7F; } else { // Unrecognized byte (e.g. space char) continue; } // Append parsed data if(isNibble) // parsed a nibble (constant or 'c' variable) { if(firstNibble) { out[outPos] = data; } else { out[outPos] = (out[outPos] << 4) | data; outPos++; } firstNibble = !firstNibble; } else // parsed a byte (variable) { if(!firstNibble) // From MIDI.TXT: '9n' is exactly the same as '09 n' or '9 n' -- so finish current byte first { outPos++; } out[outPos++] = data; firstNibble = true; } } // Finish current byte if(!firstNibble) outPos++; if(chn && updateZxxParam < 0x80) chn->lastZxxParam = updateZxxParam; // Add end of SysEx byte if necessary for(size_t i = 0; i < outPos; i++) { if(out[i] != 0xF0) continue; if(outPos - i >= 4 && (out[i + 1] == 0xF0 || out[i + 1] == 0xF1)) { // Internal message i += 3; } else { // Real SysEx while(i < outPos && out[i] != 0xF7) i++; if(i == outPos && outPos < out.size()) out[outPos++] = 0xF7; } } m_data = out.first(outPos); } MIDIMacroParser::~MIDIMacroParser() { if(m_runningStatusPos < m_data.size()) m_data[m_runningStatusPos] = m_runningstatusOldData; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/mod_specifications.h0000644000175000017500000001221715015401723022111 00000000000000/* * mod_specifications.h * -------------------- * Purpose: Mod specifications characterise the features of every editable module format in OpenMPT, such as the number of supported channels, samples, effects, etc... * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" #include "modcommand.h" // ModCommand:: #include "../soundlib/SoundFilePlayConfig.h" // mixlevel constants. OPENMPT_NAMESPACE_BEGIN struct CModSpecifications { /// Returns modtype corresponding to given file extension. The extension string /// may begin with or without dot, e.g. both ".it" and "it" will be handled correctly. static MODTYPE ExtensionToType(std::string ext); // (encoded in ASCII) static MODTYPE ExtensionToType(mpt::ustring ext); // Return true if format supports given note. bool HasNote(ModCommand::NOTE note) const; bool HasVolCommand(ModCommand::VOLCMD volcmd) const; bool HasCommand(ModCommand::COMMAND cmd) const; // Return corresponding effect letter for this format char GetEffectLetter(ModCommand::COMMAND cmd) const; char GetVolEffectLetter(ModCommand::VOLCMD volcmd) const; static char GetGenericVolEffectLetter(ModCommand::VOLCMD volcmd); // NOTE: If changing order, update all initializations in .cpp file. MODTYPE internalType; // Internal MODTYPE value const char *fileExtension; // File extension without dot (encoded in ASCII). mpt::ustring GetFileExtension() const { return mpt::ToUnicode(mpt::Charset::ASCII, fileExtension); } mpt::ustring GetFileExtensionLower() const { return mpt::ToUnicode(mpt::Charset::ASCII, mpt::ToLowerCaseAscii(fileExtension)); } mpt::ustring GetFileExtensionUpper() const { return mpt::ToUnicode(mpt::Charset::ASCII, mpt::ToUpperCaseAscii(fileExtension)); } ModCommand::NOTE noteMin; // Minimum note index (index starts from 1) ModCommand::NOTE noteMax; // Maximum note index (index starts from 1) PATTERNINDEX patternsMax; ORDERINDEX ordersMax; SEQUENCEINDEX sequencesMax; CHANNELINDEX channelsMin; // Minimum number of editable channels in pattern. CHANNELINDEX channelsMax; // Maximum number of editable channels in pattern. uint32 tempoMinInt; uint32 tempoMaxInt; uint32 speedMin; // Minimum ticks per frame uint32 speedMax; // Maximum ticks per frame ROWINDEX patternRowsMin; ROWINDEX patternRowsMax; uint16 modNameLengthMax; // Meaning 'usable letters', possible null character is not included. uint16 sampleNameLengthMax; // Ditto uint16 sampleFilenameLengthMax; // Ditto uint16 instrNameLengthMax; // Ditto uint16 instrFilenameLengthMax; // Ditto uint16 commentLineLengthMax; // not including line break, 0 for unlimited SAMPLEINDEX samplesMax; // Max number of samples == Highest possible sample index INSTRUMENTINDEX instrumentsMax; // Max number of instruments == Highest possible instrument index MixLevels defaultMixLevels; // Default mix levels that are used when creating a new file in this format FlagSet songFlags; // Supported song flags uint8 MIDIMappingDirectivesMax; // Number of MIDI Mapping directives that the format can store (0 = none) uint8 envelopePointsMax; // Maximum number of points of each envelope bool hasNoteCut; // True if format has note cut (^^). bool hasNoteOff; // True if format has note off (==). bool hasNoteFade; // True if format has note fade (~~). bool hasReleaseNode; // Envelope release node bool hasComments; // True if format has a comments field bool hasIgnoreIndex; // Does "+++" pattern exist? bool hasStopIndex; // Does "---" pattern exist? bool hasRestartPos; // Format has an automatic restart order position bool supportsPlugins; // Format can store plugins bool hasPatternSignatures; // Can patterns have a custom time signature? bool hasPatternNames; // Can patterns have a name? bool hasArtistName; // Can artist name be stored in file? bool hasDefaultResampling; // Can default resampling be saved? (if not, it can still be modified in the GUI but won't set the module as modified) bool hasFractionalTempo; // Are fractional tempos allowed? const char *commands; // An array holding all commands this format supports; commands that are not supported are marked with "?" const char *volcommands; // Ditto, but for volume column MPT_CONSTEXPRINLINE TEMPO GetTempoMin() const { return TEMPO(tempoMinInt, 0); } MPT_CONSTEXPRINLINE TEMPO GetTempoMax() const { return TEMPO(tempoMaxInt, 0); } }; namespace ModSpecs { extern const CModSpecifications & mptm; extern const CModSpecifications & mod; extern const CModSpecifications & s3m; extern const CModSpecifications & s3mEx; extern const CModSpecifications & xm; extern const CModSpecifications & xmEx; extern const CModSpecifications & it; extern const CModSpecifications & itEx; extern const std::array Collection; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Tables.h0000644000175000017500000000270314616246231017467 00000000000000/* * Tables.h * -------- * Purpose: Effect, interpolation, data and other pre-calculated tables. * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" OPENMPT_NAMESPACE_BEGIN // Compute Bessel function Izero(y) using a series approximation double Izero(double y); extern const mpt::uchar NoteNamesSharp[12][4]; extern const mpt::uchar NoteNamesFlat[12][4]; extern const uint8 ImpulseTrackerPortaVolCmd[16]; extern const uint16 ProTrackerPeriodTable[7*12]; extern const uint16 ProTrackerTunedPeriods[16*12]; extern const uint8 ModEFxTable[16]; extern const uint16 FreqS3MTable[12]; extern const uint16 S3MFineTuneTable[16]; extern const int8 ModSinusTable[64]; extern const int8 ModRandomTable[64]; extern const int8 ITSinusTable[256]; extern const int8 retrigTable1[16]; extern const int8 retrigTable2[16]; extern const uint16 XMPeriodTable[104]; extern const uint32 XMLinearTable[768]; extern const uint32 FineLinearSlideUpTable[16]; extern const uint32 FineLinearSlideDownTable[16]; extern const uint32 LinearSlideUpTable[256]; extern const uint32 LinearSlideDownTable[256]; extern const uint16 XMPanningTable[256]; extern const std::array HisMastersNoiseMegaArp[16]; extern const uint8 AutoVibratoIT2XM[8]; extern const uint8 AutoVibratoXM2IT[8]; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_c67.cpp0000644000175000017500000001634414644610543020156 00000000000000/* * Load_c67.cpp * ------------ * Purpose: C67 (CDFM Composer) module loader * Notes : C67 is the composer format; 670 files can be converted back to C67 using the converter that comes with CDFM. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct C67SampleHeader { uint32le unknown; // Probably placeholder for in-memory address, 0 on disk uint32le length; uint32le loopStart; uint32le loopEnd; }; MPT_BINARY_STRUCT(C67SampleHeader, 16) struct C67FileHeader { using InstrName = std::array; using OPLInstr = std::array; uint8 speed; uint8 restartPos; InstrName sampleNames[32]; C67SampleHeader samples[32]; InstrName fmInstrNames[32]; OPLInstr fmInstr[32]; uint8 orders[256]; }; MPT_BINARY_STRUCT(C67FileHeader, 1954) static bool ValidateHeader(const C67FileHeader &fileHeader) { if(fileHeader.speed < 1 || fileHeader.speed > 15) return false; for(auto ord : fileHeader.orders) { if(ord >= 128 && ord != 0xFF) return false; } bool anyNonSilent = false; for(SAMPLEINDEX smp = 0; smp < 32; smp++) { if(fileHeader.sampleNames[smp][12] != 0 || fileHeader.samples[smp].unknown != 0 || fileHeader.samples[smp].length > 0xFFFFF || fileHeader.fmInstrNames[smp][12] != 0 || (fileHeader.fmInstr[smp][0] & 0xF0) // No OPL3 || (fileHeader.fmInstr[smp][5] & 0xFC) // No OPL3 || (fileHeader.fmInstr[smp][10] & 0xFC)) // No OPL3 { return false; } if(fileHeader.samples[smp].length != 0 && fileHeader.samples[smp].loopEnd < 0xFFFFF) { if(fileHeader.samples[smp].loopEnd > fileHeader.samples[smp].length || fileHeader.samples[smp].loopStart > fileHeader.samples[smp].loopEnd) { return false; } } if(!anyNonSilent && (fileHeader.samples[smp].length != 0 || fileHeader.fmInstr[smp] != C67FileHeader::OPLInstr{{}})) { anyNonSilent = true; } } return anyNonSilent; } static uint64 GetHeaderMinimumAdditionalSize(const C67FileHeader &) { return 1024; // Pattern offsets and lengths } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderC67(MemoryFileReader file, const uint64 *pfilesize) { C67FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } static void TranslateVolume(ModCommand &m, uint8 volume, bool isFM) { // CDFM uses a linear volume scale for FM instruments. // ScreamTracker, on the other hand, directly uses the OPL chip's logarithmic volume scale. // Neither FM nor PCM instruments can be fully muted in CDFM. static constexpr uint8 fmVolume[16] = { 0x08, 0x10, 0x18, 0x20, 0x28, 0x2C, 0x30, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, }; volume &= 0x0F; m.volcmd = VOLCMD_VOLUME; m.vol = isFM ? fmVolume[volume] : static_cast((4u + volume * 4u)); } bool CSoundFile::ReadC67(FileReader &file, ModLoadingFlags loadFlags) { C67FileHeader fileHeader; file.Rewind(); if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } // Validate pattern offsets and lengths uint32le patOffsets[128], patLengths[128]; file.ReadArray(patOffsets); file.ReadArray(patLengths); for(PATTERNINDEX pat = 0; pat < 128; pat++) { if(patOffsets[pat] > 0xFFFFFF || patLengths[pat] < 3 // Smallest well-formed pattern consists of command 0x40 followed by command 0x60 || patLengths[pat] > 0x1000 // Any well-formed pattern is smaller than this || !file.LengthIsAtLeast(2978 + patOffsets[pat] + patLengths[pat])) { return false; } } InitializeGlobals(MOD_TYPE_S3M, 4 + 9); m_modFormat.formatName = UL_("CDFM"); m_modFormat.type = UL_("c67"); m_modFormat.madeWithTracker = UL_("Composer 670"); m_modFormat.charset = mpt::Charset::CP437; Order().SetDefaultSpeed(fileHeader.speed); Order().SetDefaultTempoInt(143); Order().SetRestartPos(fileHeader.restartPos); m_nSamples = 64; m_playBehaviour.set(kOPLBeatingOscillators); m_SongFlags.set(SONG_IMPORTED); // Pan PCM channels only for(CHANNELINDEX chn = 0; chn < 4; chn++) { ChnSettings[chn].nPan = (chn & 1) ? 192 : 64; } // PCM instruments for(SAMPLEINDEX smp = 0; smp < 32; smp++) { ModSample &mptSmp = Samples[smp + 1]; mptSmp.Initialize(MOD_TYPE_S3M); m_szNames[smp + 1] = mpt::String::ReadBuf(mpt::String::nullTerminated, fileHeader.sampleNames[smp]); mptSmp.nLength = fileHeader.samples[smp].length; if(fileHeader.samples[smp].loopEnd <= fileHeader.samples[smp].length) { mptSmp.nLoopStart = fileHeader.samples[smp].loopStart; mptSmp.nLoopEnd = fileHeader.samples[smp].loopEnd; mptSmp.uFlags = CHN_LOOP; } mptSmp.nC5Speed = 8287; } // OPL instruments for(SAMPLEINDEX smp = 0; smp < 32; smp++) { ModSample &mptSmp = Samples[smp + 33]; mptSmp.Initialize(MOD_TYPE_S3M); m_szNames[smp + 33] = mpt::String::ReadBuf(mpt::String::nullTerminated, fileHeader.fmInstrNames[smp]); // Reorder OPL patch bytes (interleave modulator and carrier) const auto &fm = fileHeader.fmInstr[smp]; OPLPatch patch{{}}; patch[0] = fm[1]; patch[1] = fm[6]; patch[2] = fm[2]; patch[3] = fm[7]; patch[4] = fm[3]; patch[5] = fm[8]; patch[6] = fm[4]; patch[7] = fm[9]; patch[8] = fm[5]; patch[9] = fm[10]; patch[10] = fm[0]; mptSmp.SetAdlib(true, patch); } ReadOrderFromArray(Order(), fileHeader.orders, 256, 0xFF); Patterns.ResizeArray(128); for(PATTERNINDEX pat = 0; pat < 128; pat++) { file.Seek(2978 + patOffsets[pat]); FileReader patChunk = file.ReadChunk(patLengths[pat]); if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) { continue; } CPattern &pattern = Patterns[pat]; ROWINDEX row = 0; while(row < 64 && patChunk.CanRead(1)) { uint8 cmd = patChunk.ReadUint8(); if(cmd <= 0x0C) { // Note, instrument, volume ModCommand &m = *pattern.GetpModCommand(row, cmd); const auto [note, instrVol] = patChunk.ReadArray(); bool fmChn = (cmd >= 4); m.note = static_cast(NOTE_MIN + (fmChn ? 12 : 36) + (note & 0x0F) + ((note >> 4) & 0x07) * 12); m.instr = static_cast((fmChn ? 33 : 1) + (instrVol >> 4) + ((note & 0x80) >> 3)); TranslateVolume(m, instrVol, fmChn); } else if(cmd >= 0x20 && cmd <= 0x2C) { // Volume TranslateVolume(*pattern.GetpModCommand(row, cmd - 0x20), patChunk.ReadUint8(), cmd >= 0x24); } else if(cmd == 0x40) { // Delay (row done) row += patChunk.ReadUint8(); } else if(cmd == 0x60) { // End of pattern if(row > 0) { pattern.GetpModCommand(row - 1, 0)->command = CMD_PATTERNBREAK; } break; } else { return false; } } } if(loadFlags & loadSampleData) { for(SAMPLEINDEX smp = 1; smp <= 32; smp++) { SampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::unsignedPCM).ReadSample(Samples[smp], file); } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/WindowedFIR.h0000644000175000017500000000500214052666041020370 00000000000000/* * WindowedFIR.h * ------------- * Purpose: FIR resampling code * Notes : (currently none) * Authors: OpenMPT Devs * ModPlug-XMMS Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Mixer.h" OPENMPT_NAMESPACE_BEGIN /* ------------------------------------------------------------------------------------------------ fir interpolation doc, (derived from "an engineer's guide to fir digital filters", n.j. loy) calculate coefficients for ideal lowpass filter (with cutoff = fc in 0..1 (mapped to 0..nyquist)) c[-N..N] = (i==0) ? fc : sin(fc*pi*i)/(pi*i) then apply selected window to coefficients c[-N..N] *= w(0..N) with n in 2*N and w(n) being a window function (see loy) then calculate gain and scale filter coefs to have unity gain. ------------------------------------------------------------------------------------------------ */ #ifdef MPT_INTMIXER // quantizer scale of window coefs - only required for integer mixing inline constexpr int WFIR_QUANTBITS = 15; inline constexpr double WFIR_QUANTSCALE = 1 << WFIR_QUANTBITS; inline constexpr int WFIR_8SHIFT = (WFIR_QUANTBITS - 8); inline constexpr int WFIR_16BITSHIFT = (WFIR_QUANTBITS); using WFIR_TYPE = int16; #else using WFIR_TYPE = mixsample_t; #endif // INTMIXER // log2(number)-1 of precalculated taps range is [4..12] inline constexpr int WFIR_FRACBITS = 12; //10 inline constexpr int WFIR_LUTLEN = ((1 << (WFIR_FRACBITS + 1)) + 1); // number of samples in window inline constexpr int WFIR_LOG2WIDTH = 3; inline constexpr int WFIR_WIDTH = (1 << WFIR_LOG2WIDTH); // cutoff (1.0 == pi/2) // wfir type enum WFIRType { WFIR_HANN = 0, // Hann WFIR_HAMMING = 1, // Hamming WFIR_BLACKMANEXACT = 2, // Blackman Exact WFIR_BLACKMAN3T61 = 3, // Blackman 3-Tap 61 WFIR_BLACKMAN3T67 = 4, // Blackman 3-Tap 67 WFIR_BLACKMAN4T92 = 5, // Blackman-Harris WFIR_BLACKMAN4T74 = 6, // Blackman 4-Tap 74 WFIR_KAISER4T = 7, // Kaiser a=7.5 }; // fir interpolation inline constexpr int WFIR_FRACSHIFT = (16 - (WFIR_FRACBITS + 1 + WFIR_LOG2WIDTH)); inline constexpr int WFIR_FRACMASK = ((((1 << (17 - WFIR_FRACSHIFT)) - 1) & ~(WFIR_WIDTH - 1))); inline constexpr int WFIR_FRACHALVE = (1 << (16 - (WFIR_FRACBITS + 2))); class CWindowedFIR { private: double coef(int,double,double,int,int); public: void InitTable(double WFIRCutoff, uint8 WFIRType); WFIR_TYPE lut[WFIR_LUTLEN * WFIR_WIDTH]; }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/UMXTools.h0000644000175000017500000000420414500065511017735 00000000000000/* * UMXTools.h * ------------ * Purpose: UMX/UAX (Unreal) helper functions * Notes : (currently none) * Authors: OpenMPT Devs (inspired by code from http://wiki.beyondunreal.com/Legacy:Package_File_Format) * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Sndfile.h" OPENMPT_NAMESPACE_BEGIN namespace UMX { // UMX File Header struct FileHeader { char magic[4]; // C1 83 2A 9E uint16le packageVersion; uint16le licenseMode; uint32le flags; uint32le nameCount; uint32le nameOffset; uint32le exportCount; uint32le exportOffset; uint32le importCount; uint32le importOffset; bool IsValid() const; uint32 GetMinimumAdditionalFileSize() const; }; MPT_BINARY_STRUCT(FileHeader, 36) // Check validity of file header CSoundFile::ProbeResult ProbeFileHeader(MemoryFileReader file, const uint64* pfilesize, const char *requiredType); // Read compressed unreal integers - similar to MIDI integers, but signed values are possible. int32 ReadIndex(FileReader &chunk); // Returns true if the given nme exists in the name table. bool FindNameTableEntry(FileReader &file, const FileHeader &fileHeader, const char *name); // Returns true if the given nme exists in the name table. bool FindNameTableEntryMemory(MemoryFileReader &file, const FileHeader &fileHeader, const char *name); // Read an entry from the name table. std::string ReadNameTableEntry(FileReader &chunk, uint16 packageVersion); // Read complete name table. std::vector ReadNameTable(FileReader &file, const FileHeader &fileHeader); // Read import table. std::vector ReadImportTable(FileReader &file, const FileHeader &fileHeader, const std::vector &names); // Read an entry from the import table. int32 ReadImportTableEntry(FileReader &chunk, uint16 packageVersion); // Read an entry from the export table. std::pair ReadExportTableEntry(FileReader &file, const FileHeader &fileHeader, const std::vector &classes, const std::vector &names, const char *filterType); } // namespace UMX OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/FloatMixer.h0000644000175000017500000002373314376464777020361 00000000000000/* * FloatMixer.h * ------------ * Purpose: Floating point mixer classes * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "MixerInterface.h" #include "Resampler.h" OPENMPT_NAMESPACE_BEGIN template struct IntToFloatTraits : public MixerTraits { static_assert(std::numeric_limits::is_integer, "Input must be integer"); static_assert(!std::numeric_limits::is_integer, "Output must be floating point"); static MPT_CONSTEXPRINLINE output_t Convert(const input_t x) { return static_cast(x) * (static_cast(1) / static_cast(int2float)); } }; using Int8MToFloatS = IntToFloatTraits<2, 1, mixsample_t, int8, -int8_min>; using Int16MToFloatS = IntToFloatTraits<2, 1, mixsample_t, int16, -int16_min>; using Int8SToFloatS = IntToFloatTraits<2, 2, mixsample_t, int8, -int8_min>; using Int16SToFloatS = IntToFloatTraits<2, 2, mixsample_t, int16, -int16_min>; ////////////////////////////////////////////////////////////////////////// // Interpolation templates template struct LinearInterpolation { MPT_FORCEINLINE LinearInterpolation(const ModChannel &, const CResampler &, unsigned int) { } MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo) { static_assert(static_cast(Traits::numChannelsIn) <= static_cast(Traits::numChannelsOut), "Too many input channels"); const typename Traits::output_t fract = posLo / static_cast(0x100000000); //CResampler::LinearTablef[posLo >> 24]; for(int i = 0; i < Traits::numChannelsIn; i++) { typename Traits::output_t srcVol = Traits::Convert(inBuffer[i]); typename Traits::output_t destVol = Traits::Convert(inBuffer[i + Traits::numChannelsIn]); outSample[i] = srcVol + fract * (destVol - srcVol); } } }; template struct FastSincInterpolation { MPT_FORCEINLINE FastSincInterpolation(const ModChannel &, const CResampler &, unsigned int) { } MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo) { static_assert(static_cast(Traits::numChannelsIn) <= static_cast(Traits::numChannelsOut), "Too many input channels"); const typename Traits::output_t *lut = CResampler::FastSincTablef + ((posLo >> 22) & 0x3FC); for(int i = 0; i < Traits::numChannelsIn; i++) { outSample[i] = lut[0] * Traits::Convert(inBuffer[i - Traits::numChannelsIn]) + lut[1] * Traits::Convert(inBuffer[i]) + lut[2] * Traits::Convert(inBuffer[i + Traits::numChannelsIn]) + lut[3] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn]); } } }; template struct PolyphaseInterpolation { const typename Traits::output_t *sinc; MPT_FORCEINLINE PolyphaseInterpolation(const ModChannel &chn, const CResampler &resampler, unsigned int) { sinc = (((chn.increment > SamplePosition(0x130000000ll)) || (chn.increment < -SamplePosition(-0x130000000ll))) ? (((chn.increment > SamplePosition(0x180000000ll)) || (chn.increment < SamplePosition(-0x180000000ll))) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc); } MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo) { static_assert(static_cast(Traits::numChannelsIn) <= static_cast(Traits::numChannelsOut), "Too many input channels"); const typename Traits::output_t *lut = sinc + ((posLo >> (32 - SINC_PHASES_BITS)) & SINC_MASK) * SINC_WIDTH; for(int i = 0; i < Traits::numChannelsIn; i++) { outSample[i] = lut[0] * Traits::Convert(inBuffer[i - 3 * Traits::numChannelsIn]) + lut[1] * Traits::Convert(inBuffer[i - 2 * Traits::numChannelsIn]) + lut[2] * Traits::Convert(inBuffer[i - Traits::numChannelsIn]) + lut[3] * Traits::Convert(inBuffer[i]) + lut[4] * Traits::Convert(inBuffer[i + Traits::numChannelsIn]) + lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn]) + lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn]) + lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn]); } } }; template struct FIRFilterInterpolation { const typename Traits::output_t *WFIRlut; MPT_FORCEINLINE FIRFilterInterpolation(const ModChannel &, const CResampler &resampler, unsigned int) { WFIRlut = resampler.m_WindowedFIR.lut; } MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo) { static_assert(static_cast(Traits::numChannelsIn) <= static_cast(Traits::numChannelsOut), "Too many input channels"); const typename Traits::output_t * const lut = WFIRlut + ((((posLo >> 16) + WFIR_FRACHALVE) >> WFIR_FRACSHIFT) & WFIR_FRACMASK); for(int i = 0; i < Traits::numChannelsIn; i++) { outSample[i] = lut[0] * Traits::Convert(inBuffer[i - 3 * Traits::numChannelsIn]) + lut[1] * Traits::Convert(inBuffer[i - 2 * Traits::numChannelsIn]) + lut[2] * Traits::Convert(inBuffer[i - Traits::numChannelsIn]) + lut[3] * Traits::Convert(inBuffer[i]) + lut[4] * Traits::Convert(inBuffer[i + Traits::numChannelsIn]) + lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn]) + lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn]) + lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn]); } } }; ////////////////////////////////////////////////////////////////////////// // Mixing templates (add sample to stereo mix) template struct NoRamp { typename Traits::output_t lVol, rVol; MPT_FORCEINLINE NoRamp(const ModChannel &chn) { lVol = static_cast(chn.leftVol) * (1.0f / 4096.0f); rVol = static_cast(chn.rightVol) * (1.0f / 4096.0f); } }; struct Ramp { ModChannel &channel; int32 lRamp, rRamp; MPT_FORCEINLINE Ramp(ModChannel &chn) : channel{chn} { lRamp = chn.rampLeftVol; rRamp = chn.rampRightVol; } MPT_FORCEINLINE ~Ramp() { channel.rampLeftVol = lRamp; channel.leftVol = lRamp >> VOLUMERAMPPRECISION; channel.rampRightVol = rRamp; channel.rightVol = rRamp >> VOLUMERAMPPRECISION; } }; // Legacy optimization: If chn.nLeftVol == chn.nRightVol, save one multiplication instruction template struct MixMonoFastNoRamp : public NoRamp { MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer) { typename Traits::output_t vol = outSample[0] * lVol; for(int i = 0; i < Traits::numChannelsOut; i++) { outBuffer[i] += vol; } } }; template struct MixMonoNoRamp : public NoRamp { MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const outBuffer) { outBuffer[0] += outSample[0] * lVol; outBuffer[1] += outSample[0] * rVol; } }; template struct MixMonoRamp : public Ramp { MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer) { // TODO volume is not float, can we optimize this? lRamp += chn.leftRamp; rRamp += chn.rightRamp; outBuffer[0] += outSample[0] * (lRamp >> VOLUMERAMPPRECISION) * (1.0f / 4096.0f); outBuffer[1] += outSample[0] * (rRamp >> VOLUMERAMPPRECISION) * (1.0f / 4096.0f); } }; template struct MixStereoNoRamp : public NoRamp { MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const outBuffer) { outBuffer[0] += outSample[0] * lVol; outBuffer[1] += outSample[1] * rVol; } }; template struct MixStereoRamp : public Ramp { MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer) { // TODO volume is not float, can we optimize this? lRamp += chn.leftRamp; rRamp += chn.rightRamp; outBuffer[0] += outSample[0] * (lRamp >> VOLUMERAMPPRECISION) * (1.0f / 4096.0f); outBuffer[1] += outSample[1] * (rRamp >> VOLUMERAMPPRECISION) * (1.0f / 4096.0f); } }; ////////////////////////////////////////////////////////////////////////// // Filter templates template struct NoFilter { MPT_FORCEINLINE NoFilter(const ModChannel &) { } MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &, const ModChannel &) { } }; // Resonant filter template struct ResonantFilter { ModChannel &channel; // Filter history typename Traits::output_t fy[Traits::numChannelsIn][2]; MPT_FORCEINLINE ResonantFilter(ModChannel &chn) : channel{chn} { for(int i = 0; i < Traits::numChannelsIn; i++) { fy[i][0] = chn.nFilter_Y[i][0]; fy[i][1] = chn.nFilter_Y[i][1]; } } MPT_FORCEINLINE ~ResonantFilter(ModChannel &chn) { for(int i = 0; i < Traits::numChannelsIn; i++) { channel.nFilter_Y[i][0] = fy[i][0]; channel.nFilter_Y[i][1] = fy[i][1]; } } // Filter values are clipped to double the input range #define ClipFilter(x) Clamp(x, static_cast(-2.0f), static_cast(2.0f)) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const ModChannel &chn) { static_assert(static_cast(Traits::numChannelsIn) <= static_cast(Traits::numChannelsOut), "Too many input channels"); for(int i = 0; i < Traits::numChannelsIn; i++) { typename Traits::output_t val = outSample[i] * chn.nFilter_A0 + ClipFilter(fy[i][0]) * chn.nFilter_B0 + ClipFilter(fy[i][1]) * chn.nFilter_B1; fy[i][1] = fy[i][0]; fy[i][0] = val - (outSample[i] * chn.nFilter_HP); outSample[i] = val; } } #undef ClipFilter }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_symmod.cpp0000644000175000017500000020013014730244445021053 00000000000000/* * Load_symmod.cpp * --------------- * Purpose: SymMOD (Symphonie / Symphonie Pro) module loader * Notes : Based in part on Patrick Meng's Java-based Symphonie player and its source. * Some effect behaviour and other things are based on the original Amiga assembly source. * Symphonie is an interesting beast, with a surprising combination of features and lack thereof. * It offers advanced DSPs (for its time) but has a fixed track tempo. It can handle stereo samples * but free panning support was only added in one of the very last versions. Still, a good number * of high-quality modules were made with it despite (or because of) its lack of features. * Authors: Devin Acker * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "Mixer.h" #include "MixFuncTable.h" #include "modsmp_ctrl.h" #include "openmpt/soundbase/SampleConvert.hpp" #include "openmpt/soundbase/SampleConvertFixedPoint.hpp" #include "openmpt/soundbase/SampleDecode.hpp" #include "SampleCopy.h" #ifdef MPT_EXTERNAL_SAMPLES #include "../common/mptPathString.h" #endif // MPT_EXTERNAL_SAMPLES #include "mpt/base/numbers.hpp" #include OPENMPT_NAMESPACE_BEGIN struct SymFileHeader { char magic[4]; // "SymM" uint32be version; // Technically this is already the first chunk; for simplicity we always assume that the channel count comes first (which in practice it does) int32be firstChunkID; uint32be numChannels; bool Validate() const { return !std::memcmp(magic, "SymM", 4) && version == 1 && firstChunkID == -1 && numChannels > 0 && numChannels <= 256; } }; MPT_BINARY_STRUCT(SymFileHeader, 16) struct SymEvent { enum Command : uint8 { KeyOn = 0, VolSlideUp, VolSlideDown, PitchSlideUp, PitchSlideDown, ReplayFrom, FromAndPitch, SetFromAdd, FromAdd, SetSpeed, AddPitch, AddVolume, Tremolo, Vibrato, SampleVib, PitchSlideTo, Retrig, Emphasis, AddHalfTone, CV, CVAdd, Filter = 23, DSPEcho, DSPDelay, }; enum Volume : uint8 { VolCommand = 200, StopSample = 254, ContSample = 253, StartSample = 252, // unused KeyOff = 251, SpeedDown = 250, SpeedUp = 249, SetPitch = 248, PitchUp = 247, PitchDown = 246, PitchUp2 = 245, PitchDown2 = 244, PitchUp3 = 243, PitchDown3 = 242 }; uint8be command; // See Command enum int8be note; uint8be param; // Volume if <= 100, see Volume enum otherwise uint8be inst; bool IsGlobal() const { if(command == SymEvent::SetSpeed || command == SymEvent::DSPEcho || command == SymEvent::DSPDelay) return true; if(command == SymEvent::KeyOn && (param == SymEvent::SpeedUp || param == SymEvent::SpeedDown)) return true; return false; } // used to compare DSP events for mapping them to MIDI macro numbers bool operator<(const SymEvent &other) const { return std::tie(command, note, param, inst) < std::tie(other.command, other.note, other.param, other.inst); } }; MPT_BINARY_STRUCT(SymEvent, 4) struct SymVirtualHeader { char id[4]; // "ViRT" uint8be zero; uint8be filler1; uint16be version; // 0 = regular, 1 = transwave uint16be mixInfo; // unused, but not 0 in all modules uint16be filler2; uint16be eos; // 0 uint16be numEvents; uint16be maxEvents; // always 20 uint16be eventSize; // 4 for virtual instruments, 10 for transwave instruments (number of cycles, not used) bool IsValid() const { return !memcmp(id, "ViRT", 4) && zero == 0 && version <= 1 && eos == 0 && maxEvents == 20; } bool IsVirtual() const { return IsValid() && version == 0 && numEvents <= 20 && eventSize == sizeof(SymEvent); } bool IsTranswave() const { return IsValid() && version == 1 && numEvents == 2 && eventSize == 10; } }; MPT_BINARY_STRUCT(SymVirtualHeader, 20) // Virtual instrument info // This allows instruments to be created based on a mix of other instruments. // The sample mixing is done at load time. struct SymVirtualInst { SymVirtualHeader header; SymEvent noteEvents[20]; char padding[28]; bool Render(CSoundFile &sndFile, const bool asQueue, ModSample &target, uint16 sampleBoost) const { if(header.numEvents < 1 || header.numEvents > std::size(noteEvents) || noteEvents[0].inst >= sndFile.GetNumSamples()) return false; target.Initialize(MOD_TYPE_IT); target.uFlags = CHN_16BIT; const auto events = mpt::as_span(noteEvents).subspan(0, header.numEvents); const double rateFactor = 1.0 / std::max(sndFile.GetSample(events[0].inst + 1).nC5Speed, uint32(1)); for(const auto &event : events.subspan(0, asQueue ? events.size() : 1u)) { if(event.inst >= sndFile.GetNumSamples() || event.note < 0) continue; const ModSample &sourceSmp = sndFile.GetSample(event.inst + 1); const double length = sourceSmp.nLength * std::pow(2.0, (event.note - events[0].note) / -12.0) * sourceSmp.nC5Speed * rateFactor; target.nLength += mpt::saturate_round(length); } if(!target.AllocateSample()) return false; std::vector channels(events.size()); SmpLength lastSampleOffset = 0; for(size_t ev = 0; ev < events.size(); ev++) { const SymEvent &event = events[ev]; ModChannel &chn = channels[ev]; if(event.inst >= sndFile.GetNumSamples() || event.note < 0) continue; int8 finetune = 0; if(event.param >= SymEvent::PitchDown3 && event.param <= SymEvent::PitchUp) { static constexpr int8 PitchTable[] = {-4, 4, -2, 2, -1, 1}; static_assert(mpt::array_size::size == SymEvent::PitchUp - SymEvent::PitchDown3 + 1); finetune = PitchTable[event.param - SymEvent::PitchDown3]; } const ModSample &sourceSmp = sndFile.GetSample(event.inst + 1); const double increment = std::pow(2.0, (event.note - events[0].note) / 12.0 + finetune / 96.0) * sourceSmp.nC5Speed * rateFactor; if(increment <= 0) continue; chn.increment = SamplePosition::FromDouble(increment); chn.pCurrentSample = sourceSmp.samplev(); chn.nLength = sourceSmp.nLength; chn.dwFlags = sourceSmp.uFlags & CHN_SAMPLEFLAGS; if(asQueue) { // This determines when the queued sample will be played chn.oldOffset = lastSampleOffset; lastSampleOffset += mpt::saturate_round(chn.nLength / chn.increment.ToDouble()); } int32 volume = 4096 * sampleBoost / 10000; // avoid clipping the filters if the virtual sample is later also filtered (see e.g. 303 emulator.symmod) if(!asQueue) volume /= header.numEvents; chn.leftVol = chn.rightVol = volume; } SmpLength writeOffset = 0; while(writeOffset < target.nLength) { std::array buffer{}; const SmpLength writeCount = std::min(static_cast(MIXBUFFERSIZE), target.nLength - writeOffset); for(auto &chn : channels) { if(!chn.pCurrentSample) continue; // Should queued sample be played yet? if(chn.oldOffset >= writeCount) { chn.oldOffset -= writeCount; continue; } uint32 functionNdx = MixFuncTable::ndxLinear; if(chn.dwFlags[CHN_16BIT]) functionNdx |= MixFuncTable::ndx16Bit; if(chn.dwFlags[CHN_STEREO]) functionNdx |= MixFuncTable::ndxStereo; const SmpLength procCount = std::min(writeCount - chn.oldOffset, mpt::saturate_round((chn.nLength - chn.position.ToDouble()) / chn.increment.ToDouble())); MixFuncTable::Functions[functionNdx](chn, sndFile.m_Resampler, buffer.data() + chn.oldOffset * 2, procCount); chn.oldOffset = 0; if(chn.position.GetUInt() >= chn.nLength) chn.pCurrentSample = nullptr; } CopySample, SC::DecodeIdentity>>(target.sample16() + writeOffset, writeCount, 1, buffer.data(), sizeof(buffer), 2); writeOffset += writeCount; } return true; } }; MPT_BINARY_STRUCT(SymVirtualInst, 128) // Transwave instrument info // Similar to virtual instruments, allows blending between two sample loops struct SymTranswaveInst { struct Transwave { uint16be sourceIns; uint16be volume; // According to source label - but appears to be unused uint32be loopStart; uint32be loopLen; uint32be padding; std::pair ConvertLoop(const ModSample &mptSmp) const { const double loopScale = static_cast(mptSmp.nLength) / (100 << 16); const SmpLength start = mpt::saturate_trunc(loopScale * std::min(uint32(100 << 16), loopStart.get())); const SmpLength length = mpt::saturate_trunc(loopScale * std::min(uint32(100 << 16), loopLen.get())); return {start, std::min(mptSmp.nLength - start, length)}; } }; SymVirtualHeader header; Transwave points[2]; char padding[76]; // Morph between two sample loops bool Render(const ModSample &smp1, const ModSample &smp2, ModSample &target) const { target.Initialize(MOD_TYPE_IT); const auto [loop1Start, loop1Len] = points[0].ConvertLoop(smp1); const auto [loop2Start, loop2Len] = points[1].ConvertLoop(smp2); if(loop1Len < 1 || loop1Len > MAX_SAMPLE_LENGTH / (4u * 80u)) return false; const SmpLength cycleLength = loop1Len * 4u; const double cycleFactor1 = loop1Len / static_cast(cycleLength); const double cycleFactor2 = loop2Len / static_cast(cycleLength); target.uFlags = CHN_16BIT; target.nLength = cycleLength * 80u; if(!target.AllocateSample()) return false; const double ampFactor = 1.0 / target.nLength; for(SmpLength i = 0; i < cycleLength; i++) { const double v1 = TranswaveInterpolate(smp1, loop1Start + i * cycleFactor1); const double v2 = TranswaveInterpolate(smp2, loop2Start + i * cycleFactor2); SmpLength writeOffset = i; for(int cycle = 0; cycle < 80; cycle++, writeOffset += cycleLength) { const double amp = writeOffset * ampFactor; target.sample16()[writeOffset] = mpt::saturate_round(v1 * (1.0 - amp) + v2 * amp); } } return true; } static MPT_FORCEINLINE double TranswaveInterpolate(const ModSample &smp, double offset) { if(!smp.HasSampleData()) return 0.0; SmpLength intOffset = static_cast(offset); const double fractOffset = offset - intOffset; const uint8 numChannels = smp.GetNumChannels(); intOffset *= numChannels; int16 v1, v2; if(smp.uFlags[CHN_16BIT]) { v1 = smp.sample16()[intOffset]; v2 = smp.sample16()[intOffset + numChannels]; } else { v1 = smp.sample8()[intOffset] * 256; v2 = smp.sample8()[intOffset + numChannels] * 256; } return (v1 * (1.0 - fractOffset) + v2 * fractOffset); } }; MPT_BINARY_STRUCT(SymTranswaveInst, 128) // Instrument definition struct SymInstrument { using SymInstrumentName = std::array; SymVirtualInst virt; // or SymInstrumentName, or SymTranswaveInst enum Type : int8 { Silent = -8, Kill = -4, Normal = 0, Loop = 4, Sustain = 8 }; enum Channel : uint8 { Mono, StereoL, StereoR, LineSrc // virtual mix instrument }; enum SampleFlags : uint8 { PlayReverse = 1, // reverse sample AsQueue = 2, // "queue" virtual instrument (rendereds samples one after another rather than simultaneously) MirrorX = 4, // invert sample phase Is16Bit = 8, // not used, we already know the bit depth of the samples NewLoopSystem = 16, // use fine loop start/len values MakeNewSample = (PlayReverse | MirrorX) }; enum InstFlags : uint8 { NoTranspose = 1, // don't apply sequence/position transpose NoDSP = 2, // don't apply DSP effects SyncPlay = 4 // play a stereo instrument pair (or two copies of the same mono instrument) on consecutive channels }; int8be type; // see Type enum uint8be loopStartHigh; uint8be loopLenHigh; uint8be numRepetitions; // for "sustain" instruments uint8be channel; // see Channel enum uint8be dummy1; // called "automaximize" (normalize?) in Amiga source, but unused uint8be volume; // 0-199 uint8be dummy2[3]; // info about "parent/child" and sample format int8be finetune; // -128..127 ~= 2 semitones int8be transpose; uint8be sampleFlags; // see SampleFlags enum int8be filter; // negative: highpass, positive: lowpass uint8be instFlags; // see InstFlags enum uint8be downsample; // downsample factor; affects sample tuning uint8be dummy3[2]; // resonance, "loadflags" (both unused) uint8be info; // bit 0 should indicate that rangeStart/rangeLen are valid, but they appear to be unused uint8be rangeStart; // ditto uint8be rangeLen; // ditto uint8be dummy4; uint16be loopStartFine; uint16be loopLenFine; uint8be dummy5[6]; uint8be filterFlags; // bit 0 = enable, bit 1 = highpass uint8be numFilterPoints; // # of filter envelope points (up to 4, possibly only 1-2 ever actually used) struct SymFilterSetting { uint8be cutoff; uint8be resonance; } filterPoint[4]; uint8be volFadeFlag; uint8be volFadeFrom; uint8be volFadeTo; uint8be padding[83]; bool IsVirtual() const { return virt.header.IsValid(); } // Valid instrument either is virtual or has a name bool IsEmpty() const { return virt.header.id[0] == 0 || type < 0; } std::string GetName() const { return mpt::String::ReadBuf(mpt::String::maybeNullTerminated, mpt::bit_cast(virt)); } SymTranswaveInst GetTranswave() const { return mpt::bit_cast(virt); } void ConvertToMPT(ModInstrument &mptIns, ModSample &mptSmp, CSoundFile &sndFile) const { if(!IsVirtual()) mptIns.name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, mpt::bit_cast(virt)); mptSmp.uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP | CHN_SUSTAINLOOP | CHN_PANNING); // Avoid these coming in from sample files const auto [loopStart, loopLen] = GetSampleLoop(mptSmp); if(type == Loop && loopLen > 0) { mptSmp.uFlags.set(CHN_LOOP); mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = loopStart + loopLen; } // volume (0-199, default 100) // Symphonie actually compresses the sample data if the volume is above 100 (see end of function) // We spread the volume between sample and instrument global volume if it's below 100 for the best possible resolution. // This can be simplified if instrument volume ever gets adjusted to 0...128 range like in IT. uint8 effectiveVolume = (volume > 0 && volume < 200) ? static_cast(std::min(volume.get(), uint8(100)) * 128u / 100) : 128; mptSmp.nGlobalVol = std::max(effectiveVolume, uint8(64)) / 2u; mptIns.nGlobalVol = std::min(effectiveVolume, uint8(64)); // Tuning info (we'll let our own mixer take care of the downsampling instead of doing it at load time) mptSmp.nC5Speed = 40460; mptSmp.Transpose(-downsample + (transpose / 12.0) + (finetune / (128.0 * 12.0))); // DSP settings mptIns.nMixPlug = (instFlags & NoDSP) ? 2 : 1; if(instFlags & NoDSP) { // This is not 100% correct: An instrument playing after this one should pick up previous filter settings. mptIns.SetCutoff(127, true); mptIns.SetResonance(0, true); } // Various sample processing follows if(!mptSmp.HasSampleData()) return; if(sampleFlags & PlayReverse) ctrlSmp::ReverseSample(mptSmp, 0, 0, sndFile); if(sampleFlags & MirrorX) ctrlSmp::InvertSample(mptSmp, 0, 0, sndFile); // Always use 16-bit data to help with heavily filtered 8-bit samples (like in Future_Dream.SymMOD) const bool doVolFade = (volFadeFlag == 2) && (volFadeFrom <= 100) && (volFadeTo <= 100); if(!mptSmp.uFlags[CHN_16BIT] && (filterFlags || doVolFade || filter)) { int16 *newSample = static_cast(ModSample::AllocateSample(mptSmp.nLength, 2 * mptSmp.GetNumChannels())); if(!newSample) return; CopySample, SC::DecodeIdentity>>(newSample, mptSmp.nLength * mptSmp.GetNumChannels(), 1, mptSmp.sample8(), mptSmp.GetSampleSizeInBytes(), 1); mptSmp.uFlags.set(CHN_16BIT); mptSmp.ReplaceWaveform(newSample, mptSmp.nLength, sndFile); } // Highpass if(filter < 0) { auto sampleData = mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels()); for(int i = 0; i < -filter; i++) { int32 mix = sampleData[0]; for(auto &sample : sampleData) { mix = mpt::rshift_signed(sample - mpt::rshift_signed(mix, 1), 1); sample = static_cast(mix); } } } // Volume Fade if(doVolFade) { auto sampleData = mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels()); int32 amp = volFadeFrom << 24, inc = Util::muldivr(volFadeTo - volFadeFrom, 1 << 24, static_cast(sampleData.size())); for(auto &sample : sampleData) { sample = static_cast(Util::muldivr(sample, amp, 100 << 24)); amp += inc; } } // Resonant Filter Sweep if(filterFlags != 0) { auto sampleData = mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels()); int32 cutoff = filterPoint[0].cutoff << 23, resonance = filterPoint[0].resonance << 23; const int32 cutoffStep = numFilterPoints > 1 ? Util::muldivr(filterPoint[1].cutoff - filterPoint[0].cutoff, 1 << 23, static_cast(sampleData.size())) : 0; const int32 resoStep = numFilterPoints > 1 ? Util::muldivr(filterPoint[1].resonance - filterPoint[0].resonance, 1 << 23, static_cast(sampleData.size())) : 0; const uint8 highpass = filterFlags & 2; int32 filterState[3]{}; for(auto &sample : sampleData) { const int32 currentCutoff = cutoff / (1 << 23), currentReso = resonance / (1 << 23); cutoff += cutoffStep; resonance += resoStep; filterState[2] = mpt::rshift_signed(sample, 1) - filterState[0]; filterState[1] += mpt::rshift_signed(currentCutoff * filterState[2], 8); filterState[0] += mpt::rshift_signed(currentCutoff * filterState[1], 6); filterState[0] += mpt::rshift_signed(currentReso * filterState[0], 6); filterState[0] = mpt::rshift_signed(filterState[0], 2); sample = mpt::saturate_cast(filterState[highpass]); } } // Lowpass if(filter > 0) { auto sampleData = mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels()); for(int i = 0; i < filter; i++) { int32 mix = sampleData[0]; for(auto &sample : sampleData) { mix = (sample + sample + mix) / 3; sample = static_cast(mix); } } } // Symphonie normalizes samples at load time (it normalizes them to the sample boost value - but we will use the full 16-bit range) // Indeed, the left and right channel instruments are normalized separately. const auto Normalize = [](auto sampleData) { const auto scale = Util::MaxValueOfType(sampleData[0]); const auto [minElem, maxElem] = std::minmax_element(sampleData.begin(), sampleData.end()); const int max = std::max(-*minElem, +*maxElem); if(max >= scale || max == 0) return; for(auto &v : sampleData) { v = static_cast::type>(static_cast(v) * scale / max); } }; if(mptSmp.uFlags[CHN_16BIT]) Normalize(mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels())); else Normalize(mpt::as_span(mptSmp.sample8(), mptSmp.nLength * mptSmp.GetNumChannels())); // "Non-destructive" over-amplification with hard knee compression if(volume > 100 && volume < 200) { const auto Amplify = [](auto sampleData, const uint8 gain) { const int32 knee = 16384 * (200 - gain) / 100, kneeInv = 32768 - knee; constexpr int32 scale = 1 << (16 - (sizeof(sampleData[0]) * 8)); for(auto &sample : sampleData) { int32 v = sample * scale; if(v > knee) v = (v - knee) * knee / kneeInv + kneeInv; else if(v < -knee) v = (v + knee) * knee / kneeInv - kneeInv; else v = v * kneeInv / knee; sample = mpt::saturate_cast::type>(v / scale); } }; const auto length = mptSmp.nLength * mptSmp.GetNumChannels(); if(mptSmp.uFlags[CHN_16BIT]) Amplify(mpt::span(mptSmp.sample16(), mptSmp.sample16() + length), volume); else Amplify(mpt::span(mptSmp.sample8(), mptSmp.sample8() + length), volume); } // This must be applied last because some sample processors are time-dependent and Symphonie would be doing this during playback instead mptSmp.RemoveAllCuePoints(); if(type == Sustain && numRepetitions > 0 && loopLen > 0) { mptSmp.cues[0] = loopStart + loopLen * (numRepetitions + 1u); mptSmp.nSustainStart = loopStart; // This is of purely informative value and not used for playback mptSmp.nSustainEnd = loopStart + loopLen; if(MAX_SAMPLE_LENGTH / numRepetitions < loopLen) return; if(MAX_SAMPLE_LENGTH - numRepetitions * loopLen < mptSmp.nLength) return; const uint8 bps = mptSmp.GetBytesPerSample(); SmpLength loopEnd = loopStart + loopLen * (numRepetitions + 1); SmpLength newLength = mptSmp.nLength + loopLen * numRepetitions; std::byte *newSample = static_cast(ModSample::AllocateSample(newLength, bps)); if(!newSample) return; std::memcpy(newSample, mptSmp.sampleb(), (loopStart + loopLen) * bps); for(uint8 i = 0; i < numRepetitions; i++) { std::memcpy(newSample + (loopStart + loopLen * (i + 1)) * bps, mptSmp.sampleb() + loopStart * bps, loopLen * bps); } std::memcpy(newSample + loopEnd * bps, mptSmp.sampleb() + (loopStart + loopLen) * bps, (newLength - loopEnd) * bps); mptSmp.ReplaceWaveform(newSample, newLength, sndFile); } } std::pair GetSampleLoop(const ModSample &mptSmp) const { if(type != Loop && type != Sustain) return {0, 0}; SmpLength loopStart = std::min(loopStartHigh.get(), uint8(100)); SmpLength loopLen = std::min(loopLenHigh.get(), uint8(100)); if(sampleFlags & NewLoopSystem) { loopStart = (loopStart << 16) + loopStartFine; loopLen = (loopLen << 16) + loopLenFine; const double loopScale = static_cast(mptSmp.nLength) / (100 << 16); loopStart = std::min(mptSmp.nLength, mpt::saturate_trunc(loopStart * loopScale)); loopLen = std::min(mptSmp.nLength - loopStart, mpt::saturate_trunc(loopLen * loopScale)); } else if(mptSmp.HasSampleData()) { // The order of operations here may seem weird as it reduces precision, but it's taken directly from the original assembly source (UpdateRecalcLoop) loopStart = ((loopStart << 7) / 100u) * (mptSmp.nLength >> 7); loopLen = std::min(mptSmp.nLength - loopStart, ((loopLen << 7) / 100u) * (mptSmp.nLength >> 7)); const auto FindLoopEnd = [](auto sampleData, const uint8 numChannels, SmpLength loopStart, SmpLength loopLen, const int threshold) { const auto valAtStart = sampleData.data()[loopStart * numChannels]; auto *endPtr = sampleData.data() + (loopStart + loopLen) * numChannels; while(loopLen) { if(std::abs(*endPtr - valAtStart) < threshold) return loopLen; endPtr -= numChannels; loopLen--; } return loopLen; }; if(mptSmp.uFlags[CHN_16BIT]) loopLen = FindLoopEnd(mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels()), mptSmp.GetNumChannels(), loopStart, loopLen, 6 * 256); else loopLen = FindLoopEnd(mpt::as_span(mptSmp.sample8(), mptSmp.nLength * mptSmp.GetNumChannels()), mptSmp.GetNumChannels(), loopStart, loopLen, 6); } return {loopStart, loopLen}; } }; MPT_BINARY_STRUCT(SymInstrument, 256) struct SymSequence { uint16be start; uint16be length; uint16be loop; int16be info; int16be transpose; uint8be padding[6]; }; MPT_BINARY_STRUCT(SymSequence, 16) struct SymPosition { uint8be dummy[4]; uint16be loopNum; uint16be loopCount; // Only used during playback uint16be pattern; uint16be start; uint16be length; uint16be speed; int16be transpose; uint16be eventsPerLine; // Unused uint8be padding[12]; // Used to compare position entries for mapping them to OpenMPT patterns bool operator<(const SymPosition &other) const { return std::tie(pattern, start, length, transpose, speed) < std::tie(other.pattern, other.start, other.length, other.transpose, other.speed); } }; MPT_BINARY_STRUCT(SymPosition, 32) static std::vector DecodeSymChunk(FileReader &file) { std::vector data; const uint32 packedLength = file.ReadUint32BE(); if(!file.CanRead(packedLength)) { file.Skip(file.BytesLeft()); return data; } FileReader chunk = file.ReadChunk(packedLength); if(packedLength >= 10 && chunk.ReadMagic("PACK\xFF\xFF")) { // RLE-compressed chunk uint32 unpackedLength = chunk.ReadUint32BE(); // The best compression ratio can be achieved with type 1, where six bytes turn into up to 255*4 bytes, a ratio of 1:170. uint32 maxLength = packedLength - 10; if(Util::MaxValueOfType(maxLength) / 170 >= maxLength) maxLength *= 170; else maxLength = Util::MaxValueOfType(maxLength); LimitMax(unpackedLength, maxLength); data.resize(unpackedLength); bool done = false; uint32 offset = 0, remain = unpackedLength; while(!done && !chunk.EndOfFile()) { uint8 len; std::array dword; const int8 type = chunk.ReadInt8(); switch(type) { case 0: // Copy raw bytes len = chunk.ReadUint8(); if(remain >= len && chunk.CanRead(len)) { chunk.ReadRaw(mpt::as_span(data).subspan(offset, len)); offset += len; remain -= len; } else { done = true; } break; case 1: // Copy a dword multiple times len = chunk.ReadUint8(); if(remain >= (len * 4u) && chunk.ReadArray(dword)) { remain -= len * 4u; while(len--) { std::copy(dword.begin(), dword.end(), data.begin() + offset); offset += 4; } } else { done = true; } break; case 2: // Copy a dword twice if(remain >= 8 && chunk.ReadArray(dword)) { std::copy(dword.begin(), dword.end(), data.begin() + offset); std::copy(dword.begin(), dword.end(), data.begin() + offset + 4); offset += 8; remain -= 8; } else { done = true; } break; case 3: // Zero bytes len = chunk.ReadUint8(); if(remain >= len) { // vector is already initialized to zero offset += len; remain -= len; } else { done = true; } break; case -1: done = true; break; default: // error done = true; break; } } #ifndef MPT_BUILD_FUZZER // When using a fuzzer, we should not care if the decompressed buffer has the correct size. // This makes finding new interesting test cases much easier. if(remain) mpt::reconstruct(data); #endif } else { // Uncompressed chunk chunk.ReadVector(data, packedLength); } return data; } template static std::vector DecodeSymArray(FileReader &file) { const auto data = DecodeSymChunk(file); FileReader chunk(mpt::as_span(data)); std::vector retVal; chunk.ReadVector(retVal, data.size() / sizeof(T)); return retVal; } static bool ReadRawSymSample(ModSample &sample, FileReader &file) { SampleIO sampleIO(SampleIO::_16bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM); SmpLength nullBytes = 0; sample.Initialize(); file.Rewind(); if(file.ReadMagic("MAESTRO")) { file.Seek(12); if(file.ReadUint32BE() == 0) sampleIO |= SampleIO::stereoInterleaved; file.Seek(24); } else if(file.ReadMagic("16BT")) { file.Rewind(); nullBytes = 4; // In Symphonie, the anti-click would take care of those... } else { sampleIO |= SampleIO::_8bit; } sample.nLength = mpt::saturate_cast(file.BytesLeft() / (sampleIO.GetNumChannels() * sampleIO.GetBitDepth() / 8u)); const bool ok = sampleIO.ReadSample(sample, file) > 0; if(ok && nullBytes) std::memset(sample.samplev(), 0, std::min(nullBytes, sample.GetSampleSizeInBytes())); return ok; } static std::vector DecodeSample8(FileReader &file) { auto data = DecodeSymChunk(file); uint8 lastVal = 0; for(auto &val : data) { lastVal += mpt::byte_cast(val); val = mpt::byte_cast(lastVal); } return data; } static std::vector DecodeSample16(FileReader &file) { auto data = DecodeSymChunk(file); std::array buf; constexpr size_t blockSize = buf.size() / 2; // Size of block in 16-bit samples for(size_t block = 0; block < data.size() / buf.size(); block++) { const size_t offset = block * sizeof(buf); uint8 lastVal = 0; // Decode LSBs for(size_t i = 0; i < blockSize; i++) { lastVal += mpt::byte_cast(data[offset + i]); buf[i * 2 + 1] = mpt::byte_cast(lastVal); } // Decode MSBs for(size_t i = 0; i < blockSize; i++) { lastVal += mpt::byte_cast(data[offset + i + blockSize]); buf[i * 2] = mpt::byte_cast(lastVal); } std::copy(buf.begin(), buf.end(), data.begin() + offset); } return data; } static bool ConvertDSP(const SymEvent event, MIDIMacroConfigData::Macro ¯o, const CSoundFile &sndFile) { if(event.command == SymEvent::Filter) { // Symphonie practically uses the same filter for this as for the sample processing. // The cutoff and resonance are an approximation. const uint8 type = static_cast(event.note % 5u); const uint8 cutoff = sndFile.FrequencyToCutOff(event.param * 10000.0 / 240.0); const uint8 reso = static_cast(std::min(127, event.inst * 127 / 185)); if(type == 1) // lowpass filter macro = MPT_AFORMAT("F0F000{} F0F001{} F0F00200")(mpt::afmt::HEX0<2>(cutoff), mpt::afmt::HEX0<2>(reso)); else if(type == 2) // highpass filter macro = MPT_AFORMAT("F0F000{} F0F001{} F0F00210")(mpt::afmt::HEX0<2>(cutoff), mpt::afmt::HEX0<2>(reso)); else // no filter or unsupported filter type macro = "F0F0007F F0F00100"; return true; } else if(event.command == SymEvent::DSPEcho) { const uint8 type = (event.note < 5) ? event.note : 0; const uint8 length = (event.param < 128) ? event.param : 127; const uint8 feedback = (event.inst < 128) ? event.inst : 127; macro = MPT_AFORMAT("F0F080{} F0F081{} F0F082{}")(mpt::afmt::HEX0<2>(type), mpt::afmt::HEX0<2>(length), mpt::afmt::HEX0<2>(feedback)); return true; } else if(event.command == SymEvent::DSPDelay) { // DSP first has to be turned on from the Symphonie GUI before it can be used in a track (unlike Echo), // so it's not implemented for now. return false; } return false; } static uint8 MapToClosestMidiMacro(const SymEvent event, std::map ¯oMap) { if(event.command == SymEvent::DSPDelay) return 0; uint8 bestMatch = 0; uint32 bestDistance = uint32_max; for(const auto &m : macroMap) { const auto &mapEvent = m.first; if(event.command != mapEvent.command || event.note != mapEvent.note) continue; const uint32 diff1 = static_cast(event.param) - mapEvent.param, diff2 = static_cast(event.inst) - mapEvent.inst; const uint32 distance = diff1 * diff1 + diff2 * diff2; if(distance >= bestDistance) continue; bestMatch = m.second; bestDistance = distance; } macroMap[event] = bestMatch; return bestMatch; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSymMOD(MemoryFileReader file, const uint64 *pfilesize) { MPT_UNREFERENCED_PARAMETER(pfilesize); SymFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.Validate()) return ProbeFailure; return ProbeSuccess; } bool CSoundFile::ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); SymFileHeader fileHeader; if(!file.ReadStruct(fileHeader) || !fileHeader.Validate()) return false; else if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_MPT, std::min(MAX_BASECHANNELS, static_cast(fileHeader.numChannels))); m_SongFlags.set(SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_AUTO_VIBRATO | SONG_AUTO_TREMOLO | SONG_IMPORTED); m_playBehaviour = GetDefaultPlaybackBehaviour(MOD_TYPE_IT); m_playBehaviour.reset(kITShortSampleRetrig); m_nSamplePreAmp = Clamp(512 / GetNumChannels(), 16, 128); enum class ChunkType : int32 { NumChannels = -1, TrackLength = -2, PatternSize = -3, NumInstruments = -4, EventSize = -5, Tempo = -6, ExternalSamples = -7, PositionList = -10, SampleFile = -11, EmptySample = -12, PatternEvents = -13, InstrumentList = -14, Sequences = -15, InfoText = -16, SamplePacked = -17, SamplePacked16 = -18, InfoType = -19, InfoBinary = -20, InfoString = -21, SampleBoost = 10, // All samples will be normalized to this value StereoDetune = 11, // Note: Not affected by no-DSP flag in instrument! So this would need to have its own plugin... StereoPhase = 12, }; uint32 trackLen = 0; uint16 sampleBoost = 2500; bool isSymphoniePro = false; bool externalSamples = false; bool unknownHunks = false; std::vector positions; std::vector sequences; std::vector patternData; std::vector instruments; while(file.CanRead(sizeof(int32))) { const ChunkType chunkType = static_cast(file.ReadInt32BE()); switch(chunkType) { // Simple values case ChunkType::NumChannels: file.Skip(sizeof(uint32be)); // Already handled break; case ChunkType::TrackLength: trackLen = file.ReadUint32BE(); if(trackLen > 1024) return false; break; case ChunkType::EventSize: if(auto eventSize = (file.ReadUint32BE() & 0xFFFF); eventSize != sizeof(SymEvent)) return false; break; case ChunkType::Tempo: Order().SetDefaultTempo(TEMPO(1.24 * std::min(file.ReadUint32BE(), uint32(800)))); break; // Unused values case ChunkType::NumInstruments: // determined from # of instrument headers instead case ChunkType::PatternSize: file.Skip(4); break; case ChunkType::SampleBoost: sampleBoost = static_cast(Clamp(file.ReadUint32BE(), 0u, 10000u)); isSymphoniePro = true; break; case ChunkType::StereoDetune: case ChunkType::StereoPhase: isSymphoniePro = true; if(uint32 val = file.ReadUint32BE(); val != 0) AddToLog(LogWarning, U_("Stereo Detune / Stereo Phase is not supported")); break; case ChunkType::ExternalSamples: file.Skip(4); if(!m_nSamples) externalSamples = true; break; // Binary chunk types case ChunkType::PositionList: if((loadFlags & loadPatternData) && positions.empty()) positions = DecodeSymArray(file); else file.Skip(file.ReadUint32BE()); break; case ChunkType::SampleFile: case ChunkType::SamplePacked: case ChunkType::SamplePacked16: if(m_nSamples >= instruments.size()) break; if(!externalSamples && (loadFlags & loadSampleData) && CanAddMoreSamples()) { const SAMPLEINDEX sample = ++m_nSamples; std::vector unpackedSample; FileReader chunk; if(chunkType == ChunkType::SampleFile) { chunk = file.ReadChunk(file.ReadUint32BE()); } else if(chunkType == ChunkType::SamplePacked) { unpackedSample = DecodeSample8(file); chunk = FileReader(mpt::as_span(unpackedSample)); } else // SamplePacked16 { unpackedSample = DecodeSample16(file); chunk = FileReader(mpt::as_span(unpackedSample)); } if(!ReadIFFSample(sample, chunk, false) && !ReadWAVSample(sample, chunk) && !ReadAIFFSample(sample, chunk) && !ReadRawSymSample(Samples[sample], chunk)) { AddToLog(LogWarning, U_("Unknown sample format.")); } // Symphonie represents stereo instruments as two consecutive mono instruments which are // automatically played at the same time. If this one uses a stereo sample, split it // and map two OpenMPT instruments to the stereo halves to ensure correct playback if(Samples[sample].uFlags[CHN_STEREO] && CanAddMoreSamples()) { const SAMPLEINDEX sampleL = ++m_nSamples; ctrlSmp::SplitStereo(Samples[sample], Samples[sampleL], Samples[sample], *this); Samples[sampleL].filename = "Left"; Samples[sample].filename = "Right"; } else if(sample < instruments.size() && instruments[sample].channel == SymInstrument::StereoR && CanAddMoreSamples()) { // Prevent misalignment of samples in exit.symmod (see condition in MoveNextMonoInstrument in Symphonie source) m_nSamples++; } } else { // Skip sample file.Skip(file.ReadUint32BE()); } break; case ChunkType::EmptySample: if(CanAddMoreSamples()) m_nSamples++; break; case ChunkType::PatternEvents: if((loadFlags & loadPatternData) && patternData.empty()) patternData = DecodeSymArray(file); else file.Skip(file.ReadUint32BE()); break; case ChunkType::InstrumentList: if(instruments.empty()) instruments = DecodeSymArray(file); else file.Skip(file.ReadUint32BE()); break; case ChunkType::Sequences: if((loadFlags & loadPatternData) && sequences.empty()) sequences = DecodeSymArray(file); else file.Skip(file.ReadUint32BE()); break; case ChunkType::InfoText: if(const auto text = DecodeSymChunk(file); !text.empty()) m_songMessage.Read(text.data(), text.size(), SongMessage::leLF); break; // Unused binary chunks case ChunkType::InfoType: case ChunkType::InfoBinary: case ChunkType::InfoString: file.Skip(file.ReadUint32BE()); break; // Unrecognized chunk/value type (e.g. garbage at the end of Natsh1.SymMOD) default: unknownHunks = true; break; } } if(!trackLen || instruments.empty()) return false; if((loadFlags & loadPatternData) && (positions.empty() || patternData.empty() || sequences.empty())) return false; if(unknownHunks) AddToLog(LogWarning, U_("Unknown hunks were found and ignored.")); // Let's hope noone is going to use the 256th instrument ;) if(instruments.size() >= MAX_INSTRUMENTS) instruments.resize(MAX_INSTRUMENTS - 1u); m_nInstruments = static_cast(instruments.size()); static_assert(MAX_SAMPLES >= MAX_INSTRUMENTS); m_nSamples = std::max(m_nSamples, m_nInstruments); // Supporting this is probably rather useless, as the paths will always be full Amiga paths. We just take the filename without path for now. if(externalSamples) { #ifdef MPT_EXTERNAL_SAMPLES m_nSamples = m_nInstruments; for(SAMPLEINDEX sample = 1; sample <= m_nSamples; sample++) { const SymInstrument &symInst = instruments[sample - 1]; if(symInst.IsEmpty() || symInst.IsVirtual()) continue; auto filename = mpt::PathString::FromUnicode(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, symInst.GetName())); if(file.GetOptionalFileName()) filename = file.GetOptionalFileName()->GetDirectoryWithDrive() + filename.GetFilename(); if(!LoadExternalSample(sample, filename)) AddToLog(LogError, MPT_UFORMAT("Unable to load sample {}: {}")(sample, filename)); else ResetSamplePath(sample); if(Samples[sample].uFlags[CHN_STEREO] && sample < m_nSamples) { const SAMPLEINDEX sampleL = sample + 1; ctrlSmp::SplitStereo(Samples[sample], Samples[sampleL], Samples[sample], *this); Samples[sampleL].filename = "Left"; Samples[sample].filename = "Right"; sample++; } } #else AddToLog(LogWarning, U_("External samples are not supported.")); #endif // MPT_EXTERNAL_SAMPLES } // Convert instruments for(int pass = 0; pass < 2; pass++) { for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++) { SymInstrument &symInst = instruments[ins - 1]; if(symInst.IsEmpty()) continue; // First load all regular instruments, and when we have the required information, render the virtual ones if(symInst.IsVirtual() != (pass == 1)) continue; SAMPLEINDEX sample = ins; if(symInst.virt.header.IsVirtual()) { const uint8 firstSource = symInst.virt.noteEvents[0].inst; ModSample &target = Samples[sample]; if(symInst.virt.Render(*this, symInst.sampleFlags & SymInstrument::AsQueue, target, sampleBoost)) { m_szNames[sample] = "Virtual"; if(firstSource < instruments.size()) symInst.downsample += instruments[firstSource].downsample; } else { sample = firstSource + 1; } } else if(symInst.virt.header.IsTranswave()) { const SymTranswaveInst transwaveInst = symInst.GetTranswave(); const auto &trans1 = transwaveInst.points[0], &trans2 = transwaveInst.points[1]; if(trans1.sourceIns < m_nSamples) { const ModSample emptySample; const ModSample &smp1 = Samples[trans1.sourceIns + 1]; const ModSample &smp2 = trans2.sourceIns < m_nSamples ? Samples[trans2.sourceIns + 1] : emptySample; ModSample &target = Samples[sample]; if(transwaveInst.Render(smp1, smp2, target)) { m_szNames[sample] = "Transwave"; // Transwave instruments play an octave lower than the original source sample, but are 4x oversampled, // so effectively they play an octave higher symInst.transpose += 12; } } } if(ModInstrument *instr = AllocateInstrument(ins, sample); instr != nullptr && sample <= m_nSamples) symInst.ConvertToMPT(*instr, Samples[sample], *this); } } // Convert patterns // map Symphonie positions to converted patterns std::map patternMap; // map DSP commands to MIDI macro numbers std::map macroMap; bool useDSP = false; const uint32 patternSize = fileHeader.numChannels * trackLen; const PATTERNINDEX numPatterns = mpt::saturate_cast(patternData.size() / patternSize); Patterns.ResizeArray(numPatterns); Order().clear(); struct ChnState { float curVolSlide = 0; // Current volume slide factor of a channel float curVolSlideAmt = 0; // Cumulative volume slide amount float curPitchSlide = 0; // Current pitch slide factor of a channel float curPitchSlideAmt = 0; // Cumulative pitch slide amount bool stopped = false; // Sample paused or not (affects volume and pitch slides) uint8 lastNote = 0; // Last note played on a channel uint8 lastInst = 0; // Last instrument played on a channel uint8 lastVol = 64; // Last specified volume of a channel (to avoid excessive Mxx commands) uint8 channelVol = 100; // Volume multiplier, 0...100 uint8 calculatedVol = 64; // Final channel volume uint8 fromAdd = 0; // Base sample offset for FROM and FR&P effects bool retrigVibrato = false; uint8 curVibrato = 0; bool retrigTremolo = false; uint8 curTremolo = 0; uint8 sampleVibSpeed = 0; uint8 sampleVibDepth = 0; uint8 tonePortaAmt = 0; uint16 sampleVibPhase = 0; uint16 retriggerRemain = 0; uint16 tonePortaRemain = 0; }; std::vector chnStates(GetNumChannels()); // In Symphonie, sequences represent the structure of a song, and not separate songs like in OpenMPT. Hence they will all be loaded into the same ModSequence. for(SymSequence &seq : sequences) { if(seq.info == 1) continue; if(seq.info == -1) break; if(seq.start >= positions.size() || seq.length > positions.size() || seq.length == 0 || positions.size() - seq.length < seq.start) continue; auto seqPositions = mpt::as_span(positions).subspan(seq.start, seq.length); // Sequences are all part of the same song, just add a skip index as a divider ModSequence &order = Order(); if(!order.empty()) order.push_back(PATTERNINDEX_SKIP); for(auto &pos : seqPositions) { // before checking the map, apply the sequence transpose value pos.transpose += seq.transpose; // pattern already converted? PATTERNINDEX patternIndex = 0; if(patternMap.count(pos)) { patternIndex = patternMap[pos]; } else if(loadFlags & loadPatternData) { // Convert pattern now patternIndex = Patterns.InsertAny(pos.length); if(patternIndex == PATTERNINDEX_INVALID) break; patternMap[pos] = patternIndex; if(pos.pattern >= numPatterns || pos.start >= trackLen) continue; uint8 patternSpeed = static_cast(pos.speed); // This may intentionally read into the next pattern auto srcEvent = patternData.cbegin() + (pos.pattern * patternSize) + (pos.start * fileHeader.numChannels); const SymEvent emptyEvent{}; ModCommand syncPlayCommand; for(ROWINDEX row = 0; row < pos.length; row++) { ModCommand *rowBase = Patterns[patternIndex].GetpModCommand(row, 0); bool applySyncPlay = false; for(CHANNELINDEX chn = 0; chn < fileHeader.numChannels; chn++) { const SymEvent &event = (srcEvent != patternData.cend()) ? *srcEvent : emptyEvent; if(srcEvent != patternData.cend()) srcEvent++; if(chn >= GetNumChannels()) continue; ModCommand &m = rowBase[chn]; int8 note = (event.note >= 0 && event.note <= 84) ? event.note + 25 : -1; uint8 origInst = event.inst; uint8 mappedInst = 0; if(origInst < instruments.size()) { mappedInst = static_cast(origInst + 1); if(!(instruments[origInst].instFlags & SymInstrument::NoTranspose) && note >= 0) note = Clamp(static_cast(note + pos.transpose), NOTE_MIN, NOTE_MAX); } // If we duplicated a stereo channel to this cell but the event is non-empty, remove it again. if(m.note != NOTE_NONE && (event.command != SymEvent::KeyOn || event.note != -1 || event.inst != 0 || event.param != 0) && m.instr > 0 && m.instr <= instruments.size() && instruments[m.instr - 1].channel == SymInstrument::StereoR) { m.Clear(); } auto &chnState = chnStates[chn]; if(applySyncPlay) { applySyncPlay = false; m = syncPlayCommand; if(m.command == CMD_NONE && chnState.calculatedVol != chnStates[chn - 1].calculatedVol) { chnState.calculatedVol = chnStates[chn - 1].calculatedVol; m.SetEffectCommand(CMD_CHANNELVOLUME, chnState.calculatedVol); } if(!event.IsGlobal()) continue; } bool applyVolume = false; switch(static_cast(event.command.get())) { case SymEvent::KeyOn: if(event.param > SymEvent::VolCommand) { switch(event.param) { case SymEvent::StopSample: m.SetVolumeCommand(VOLCMD_PLAYCONTROL, 0); chnState.stopped = true; break; case SymEvent::ContSample: m.SetVolumeCommand(VOLCMD_PLAYCONTROL, 1); chnState.stopped = false; break; case SymEvent::KeyOff: if(m.note == NOTE_NONE) m.note = chnState.lastNote; m.SetVolumeCommand(VOLCMD_OFFSET, 1); break; case SymEvent::SpeedDown: if(patternSpeed > 1) { m.SetEffectCommand(CMD_SPEED, --patternSpeed); } break; case SymEvent::SpeedUp: if(patternSpeed < 0xFF) { m.SetEffectCommand(CMD_SPEED, ++patternSpeed); } break; case SymEvent::SetPitch: chnState.lastNote = note; if(mappedInst != chnState.lastInst) break; m.note = note; m.SetEffectCommand(CMD_TONEPORTA_DURATION, 0); chnState.curPitchSlide = 0; chnState.tonePortaRemain = 0; chnState.retrigVibrato = chnState.retrigTremolo = true; break; // fine portamentos with range up to half a semitone case SymEvent::PitchUp: m.SetEffectCommand(CMD_PORTAMENTOUP, 0xF2); break; case SymEvent::PitchDown: m.SetEffectCommand(CMD_PORTAMENTODOWN, 0xF2); break; case SymEvent::PitchUp2: m.SetEffectCommand(CMD_PORTAMENTOUP, 0xF4); break; case SymEvent::PitchDown2: m.SetEffectCommand(CMD_PORTAMENTODOWN, 0xF4); break; case SymEvent::PitchUp3: m.SetEffectCommand(CMD_PORTAMENTOUP, 0xF8); break; case SymEvent::PitchDown3: m.SetEffectCommand(CMD_PORTAMENTODOWN, 0xF8); break; } } else { if(event.note >= 0 || event.param < 100) { if(event.note >= 0) { m.note = chnState.lastNote = note; m.instr = chnState.lastInst = mappedInst; chnState.curPitchSlide = 0; chnState.tonePortaRemain = 0; chnState.retrigVibrato = chnState.retrigTremolo = true; } if(event.param > 0) { chnState.lastVol = mpt::saturate_round(event.param * 0.64); if(chnState.curVolSlide != 0) applyVolume = true; chnState.curVolSlide = 0; } } } if(const uint8 newVol = static_cast(Util::muldivr_unsigned(chnState.lastVol, chnState.channelVol, 100)); applyVolume || chnState.calculatedVol != newVol) { chnState.calculatedVol = newVol; m.SetEffectCommand(CMD_CHANNELVOLUME, newVol); } // Key-On commands with stereo instruments are played on both channels - unless there's already some sort of event if(event.note > 0 && (chn < GetNumChannels() - 1) && !(chn % 2u) && origInst < instruments.size() && instruments[origInst].channel == SymInstrument::StereoL) { ModCommand &next = rowBase[chn + 1]; next = m; next.instr++; chnStates[chn + 1].lastVol = chnState.lastVol; chnStates[chn + 1].curVolSlide = chnState.curVolSlide; chnStates[chn + 1].curVolSlideAmt = chnState.curVolSlideAmt; chnStates[chn + 1].curPitchSlide = chnState.curPitchSlide; chnStates[chn + 1].curPitchSlideAmt = chnState.curPitchSlideAmt; chnStates[chn + 1].retriggerRemain = chnState.retriggerRemain; } break; // volume effects // Symphonie has very fine fractional volume slides which are applied at the output sample rate, // rather than per tick or per row, so instead let's simulate it based on the pattern speed // by keeping track of the volume and using normal volume commands // the math here is an approximation which works fine for most songs case SymEvent::VolSlideUp: chnState.curVolSlideAmt = 0; chnState.curVolSlide = event.param * 0.0333f; break; case SymEvent::VolSlideDown: chnState.curVolSlideAmt = 0; chnState.curVolSlide = event.param * -0.0333f; break; case SymEvent::AddVolume: m.command = CMD_NONE; break; case SymEvent::Tremolo: { // both tremolo speed and depth can go much higher than OpenMPT supports, // but modules will probably use pretty sane, supportable values anyway // TODO: handle very small nonzero params uint8 speed = std::min(15, event.inst >> 3); uint8 depth = std::min(15, event.param >> 3); chnState.curTremolo = (speed << 4) | depth; if(chnState.curTremolo) chnState.retrigTremolo = true; else m.SetEffectCommand(CMD_TREMOLO, 0); } break; // pitch effects // Pitch slides have a similar granularity to volume slides, and are approximated // the same way here based on a rough comparison against Exx/Fxx slides case SymEvent::PitchSlideUp: chnState.curPitchSlideAmt = 0; chnState.curPitchSlide = event.param * 0.0333f; chnState.tonePortaRemain = 0; break; case SymEvent::PitchSlideDown: chnState.curPitchSlideAmt = 0; chnState.curPitchSlide = event.param * -0.0333f; chnState.tonePortaRemain = 0; break; case SymEvent::PitchSlideTo: if(note >= 0 && event.param > 0) { const int distance = std::abs((note - chnState.lastNote) * 32); chnState.curPitchSlide = 0; m.note = chnState.lastNote = note; chnState.tonePortaAmt = mpt::saturate_cast(distance / (2 * event.param)); m.SetEffectCommand(CMD_TONEPORTAMENTO, chnState.tonePortaAmt); chnState.tonePortaRemain = static_cast(distance - std::min(distance, chnState.tonePortaAmt * (patternSpeed - 1))); } break; case SymEvent::AddPitch: // "The range (-128...127) is about 4 half notes." m.command = CMD_NONE; break; case SymEvent::Vibrato: { // both vibrato speed and depth can go much higher than OpenMPT supports, // but modules will probably use pretty sane, supportable values anyway // TODO: handle very small nonzero params uint8 speed = std::min(15, event.inst >> 3); uint8 depth = std::min(15, event.param); chnState.curVibrato = (speed << 4) | depth; if(chnState.curVibrato) chnState.retrigVibrato = true; else m.SetEffectCommand(CMD_VIBRATO, 0); } break; case SymEvent::AddHalfTone: m.note = chnState.lastNote = Clamp(static_cast(chnState.lastNote + event.param), NOTE_MIN, NOTE_MAX); m.SetEffectCommand(CMD_TONEPORTA_DURATION, 0); chnState.tonePortaRemain = 0; break; // DSP effects case SymEvent::Filter: #ifndef NO_PLUGINS case SymEvent::DSPEcho: case SymEvent::DSPDelay: #endif if(auto it = macroMap.find(event); it != macroMap.end() && it->second != 0) { m.SetEffectCommand(CMD_MIDI, it->second); } else if(macroMap.size() < m_MidiCfg.Zxx.size()) { uint8 param = static_cast(macroMap.size()); if(ConvertDSP(event, m_MidiCfg.Zxx[param], *this)) { m.SetEffectCommand(CMD_MIDI, macroMap[event] = 0x80 | param); if(event.command == SymEvent::DSPEcho || event.command == SymEvent::DSPDelay) useDSP = true; } } else if(uint8 param = MapToClosestMidiMacro(event, macroMap)) { m.SetEffectCommand(CMD_MIDI, param); } break; // other effects case SymEvent::Retrig: // This plays the note times every +1 ticks. // The effect continues on the following rows until the correct amount is reached. if(event.param < 1) break; m.SetEffectCommand(CMD_RETRIG, static_cast(std::min(15, event.inst + 1))); chnState.retriggerRemain = static_cast(event.param * (event.inst + 1u)); break; case SymEvent::SetSpeed: patternSpeed = event.param ? event.param : 4u; m.SetEffectCommand(CMD_SPEED, patternSpeed); break; // TODO this applies a fade on the sample level case SymEvent::Emphasis: m.command = CMD_NONE; break; case SymEvent::CV: if(event.note == 0 || event.note == 4) { uint8 pan = (event.note == 4) ? event.inst : 128; uint8 vol = std::min(event.param, 100); uint8 volL = static_cast(vol * std::min(128, 256 - pan) / 128); uint8 volR = static_cast(vol * std::min(uint8(128), pan) / 128); if(volL != chnState.channelVol) { chnState.channelVol = volL; chnState.calculatedVol = static_cast(Util::muldivr_unsigned(chnState.lastVol, chnState.channelVol, 100)); m.SetEffectCommand(CMD_CHANNELVOLUME, chnState.calculatedVol); } if(event.note == 4 && chn < (GetNumChannels() - 1) && chnStates[chn + 1].channelVol != volR) { chnStates[chn + 1].channelVol = volR; chnState.calculatedVol = static_cast(Util::muldivr_unsigned(chnState.lastVol, chnState.channelVol, 100)); rowBase[chn + 1].SetEffectCommand(CMD_CHANNELVOLUME, chnState.calculatedVol); } } break; case SymEvent::CVAdd: // Effect doesn't seem to exist in UI and code looks like a no-op m.command = CMD_NONE; break; case SymEvent::SetFromAdd: chnState.fromAdd = event.param; chnState.sampleVibSpeed = 0; chnState.sampleVibDepth = 0; break; case SymEvent::FromAdd: // TODO need to verify how signedness of this value is treated // C = -128...+127 //FORMEL: Neuer FADD := alter FADD + C* Samplelaenge/16384 chnState.fromAdd += event.param; break; case SymEvent::SampleVib: chnState.sampleVibSpeed = event.inst; chnState.sampleVibDepth = event.param; break; // sample effects case SymEvent::FromAndPitch: chnState.lastNote = note; m.instr = chnState.lastInst = mappedInst; [[fallthrough]]; case SymEvent::ReplayFrom: m.note = chnState.lastNote; if(note >= 0) m.instr = chnState.lastInst = mappedInst; if(event.command == SymEvent::ReplayFrom) { m.SetVolumeCommand(VOLCMD_TONEPORTAMENTO, 1); } // don't always add the command, because often FromAndPitch is used with offset 0 // to act as a key-on which doesn't cancel volume slides, etc if(event.param || chnState.fromAdd || chnState.sampleVibDepth) { double sampleVib = 0.0; if(chnState.sampleVibDepth) sampleVib = chnState.sampleVibDepth * (std::sin(chnState.sampleVibPhase * (mpt::numbers::pi * 2.0 / 1024.0) + 1.5 * mpt::numbers::pi) - 1.0) / 4.0; m.SetEffectCommand(CMD_OFFSETPERCENTAGE, mpt::saturate_round(event.param + chnState.fromAdd + sampleVib)); } chnState.tonePortaRemain = 0; break; } // Any event which plays a note should re-enable continuous effects if(m.note != NOTE_NONE) chnState.stopped = false; else if(chnState.stopped) continue; if(chnState.retriggerRemain) { chnState.retriggerRemain = std::max(chnState.retriggerRemain, static_cast(patternSpeed)) - patternSpeed; if(m.command == CMD_NONE) m.SetEffectCommand(CMD_RETRIG, 0); } // Handle fractional volume slides if(chnState.curVolSlide != 0) { chnState.curVolSlideAmt += chnState.curVolSlide * patternSpeed; if(m.command == CMD_NONE) { if(patternSpeed > 1 && chnState.curVolSlideAmt >= (patternSpeed - 1)) { uint8 slideAmt = std::min(15, mpt::saturate_round(chnState.curVolSlideAmt / (patternSpeed - 1))); chnState.curVolSlideAmt -= static_cast(slideAmt * (patternSpeed - 1)); // normal slide up m.SetEffectCommand(CMD_CHANNELVOLSLIDE, slideAmt << 4); } else if(chnState.curVolSlideAmt >= 1.0f) { uint8 slideAmt = std::min(15, mpt::saturate_round(chnState.curVolSlideAmt)); chnState.curVolSlideAmt -= static_cast(slideAmt); // fine slide up m.SetEffectCommand(CMD_CHANNELVOLSLIDE, (slideAmt << 4) | 0x0F); } else if(patternSpeed > 1 && chnState.curVolSlideAmt <= -(patternSpeed - 1)) { uint8 slideAmt = std::min(15, mpt::saturate_round(-chnState.curVolSlideAmt / (patternSpeed - 1))); chnState.curVolSlideAmt += static_cast(slideAmt * (patternSpeed - 1)); // normal slide down m.SetEffectCommand(CMD_CHANNELVOLSLIDE, slideAmt); } else if(chnState.curVolSlideAmt <= -1.0f) { uint8 slideAmt = std::min(14, mpt::saturate_round(-chnState.curVolSlideAmt)); chnState.curVolSlideAmt += static_cast(slideAmt); // fine slide down m.SetEffectCommand(CMD_CHANNELVOLSLIDE, slideAmt | 0xF0); } } } // Handle fractional pitch slides if(chnState.curPitchSlide != 0) { chnState.curPitchSlideAmt += chnState.curPitchSlide * patternSpeed; if(m.command == CMD_NONE) { if(patternSpeed > 1 && chnState.curPitchSlideAmt >= (patternSpeed - 1)) { uint8 slideAmt = std::min(0xDF, mpt::saturate_round(chnState.curPitchSlideAmt / (patternSpeed - 1))); chnState.curPitchSlideAmt -= static_cast(slideAmt * (patternSpeed - 1)); // normal slide up m.SetEffectCommand(CMD_PORTAMENTOUP, slideAmt); } else if(chnState.curPitchSlideAmt >= 1.0f) { uint8 slideAmt = std::min(15, mpt::saturate_round(chnState.curPitchSlideAmt)); chnState.curPitchSlideAmt -= static_cast(slideAmt); // fine slide up m.SetEffectCommand(CMD_PORTAMENTOUP, slideAmt | 0xF0); } else if(patternSpeed > 1 && chnState.curPitchSlideAmt <= -(patternSpeed - 1)) { uint8 slideAmt = std::min(0xDF, mpt::saturate_round(-chnState.curPitchSlideAmt / (patternSpeed - 1))); chnState.curPitchSlideAmt += static_cast(slideAmt * (patternSpeed - 1)); // normal slide down m.SetEffectCommand(CMD_PORTAMENTODOWN, slideAmt); } else if(chnState.curPitchSlideAmt <= -1.0f) { uint8 slideAmt = std::min(14, mpt::saturate_round(-chnState.curPitchSlideAmt)); chnState.curPitchSlideAmt += static_cast(slideAmt); // fine slide down m.SetEffectCommand(CMD_PORTAMENTODOWN, slideAmt | 0xF0); } } // TODO: use volume column if effect column is occupied else if(m.volcmd == VOLCMD_NONE) { if(patternSpeed > 1 && chnState.curPitchSlideAmt / 4 >= (patternSpeed - 1)) { uint8 slideAmt = std::min(9, mpt::saturate_round(chnState.curPitchSlideAmt / (patternSpeed - 1)) / 4); chnState.curPitchSlideAmt -= static_cast(slideAmt * (patternSpeed - 1) * 4); m.SetVolumeCommand(VOLCMD_PORTAUP, slideAmt); } else if(patternSpeed > 1 && chnState.curPitchSlideAmt / 4 <= -(patternSpeed - 1)) { uint8 slideAmt = std::min(9, mpt::saturate_round(-chnState.curPitchSlideAmt / (patternSpeed - 1)) / 4); chnState.curPitchSlideAmt += static_cast(slideAmt * (patternSpeed - 1) * 4); m.SetVolumeCommand(VOLCMD_PORTADOWN, slideAmt); } } } // Vibrato and Tremolo if(m.command == CMD_NONE && chnState.curVibrato && chnState.retrigVibrato) { m.SetEffectCommand(CMD_VIBRATO, chnState.curVibrato); chnState.retrigVibrato = false; } if(m.command == CMD_NONE && chnState.curTremolo && chnState.retrigTremolo) { m.SetEffectCommand(CMD_TREMOLO, chnState.curTremolo); chnState.retrigTremolo = false; } // Tone Portamento if(m.command != CMD_TONEPORTAMENTO && chnState.tonePortaRemain) { if(m.command == CMD_NONE) m.command = CMD_TONEPORTAMENTO; else m.volcmd = VOLCMD_TONEPORTAMENTO; chnState.tonePortaRemain -= std::min(chnState.tonePortaRemain, static_cast(chnState.tonePortaAmt * (patternSpeed - 1))); } chnState.sampleVibPhase = (chnState.sampleVibPhase + chnState.sampleVibSpeed * patternSpeed) & 1023; if(!(chn % 2u) && chnState.lastInst && chnState.lastInst <= instruments.size() && (instruments[chnState.lastInst - 1].instFlags & SymInstrument::SyncPlay)) { syncPlayCommand = m; applySyncPlay = true; if(syncPlayCommand.instr && instruments[chnState.lastInst - 1].channel == SymInstrument::StereoL) syncPlayCommand.instr++; } } } Patterns[patternIndex].WriteEffect(EffectWriter(CMD_SPEED, static_cast(pos.speed)).Row(0).RetryNextRow()); } order.insert(order.GetLength(), std::max(pos.loopNum.get(), uint16(1)), patternIndex); // Undo transpose tweak pos.transpose -= seq.transpose; } } #ifndef NO_PLUGINS if(useDSP) { SNDMIXPLUGIN &plugin = m_MixPlugins[0]; mpt::reconstruct(plugin); memcpy(&plugin.Info.dwPluginId1, "SymM", 4); memcpy(&plugin.Info.dwPluginId2, "Echo", 4); plugin.Info.routingFlags = SNDMIXPLUGININFO::irAutoSuspend; plugin.Info.mixMode = 0; plugin.Info.gain = 10; plugin.Info.reserved = 0; plugin.Info.dwOutputRouting = 0; std::fill(plugin.Info.dwReserved, plugin.Info.dwReserved + std::size(plugin.Info.dwReserved), 0); plugin.Info.szName = "Echo"; plugin.Info.szLibraryName = "SymMOD Echo"; m_MixPlugins[1].Info.szName = "No Echo"; } #endif // NO_PLUGINS // Channel panning for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) { ChnSettings[chn].nPan = (chn & 1) ? 256 : 0; ChnSettings[chn].nMixPlugin = useDSP ? 1 : 0; // For MIDI macros controlling the echo DSP } m_modFormat.formatName = UL_("Symphonie"); m_modFormat.type = UL_("symmod"); if(!isSymphoniePro) m_modFormat.madeWithTracker = UL_("Symphonie"); // or Symphonie Jr else if(instruments.size() <= 128) m_modFormat.madeWithTracker = UL_("Symphonie Pro"); else m_modFormat.madeWithTracker = UL_("Symphonie Pro 256"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/AudioReadTarget.h0000644000175000017500000001236014765261244021267 00000000000000/* * AudioReadTarget.h * ----------------- * Purpose: Callback class implementations for audio data read via CSoundFile::Read. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/audio/span.hpp" #include "mpt/base/macros.hpp" #include "mpt/string/types.hpp" #include "openmpt/soundbase/SampleFormat.hpp" #include "openmpt/soundbase/CopyMix.hpp" #include "openmpt/soundbase/Dither.hpp" #include "openmpt/soundbase/DitherModPlug.hpp" #include "openmpt/soundbase/DitherNone.hpp" #include "openmpt/soundbase/DitherSimple.hpp" #include "MixerLoops.h" #include "Mixer.h" #include "Sndfile.h" #include #include #include OPENMPT_NAMESPACE_BEGIN using Dither_Default = Dither_Simple; class DitherNamesOpenMPT { public: static mpt::ustring GetModeName(std::size_t mode) { mpt::ustring result; switch(mode) { case 0: // no dither result = MPT_USTRING("no"); break; case 1: // chosen by OpenMPT code, might change result = MPT_USTRING("default"); break; case 2: // rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker) result = MPT_USTRING("0.5 bit"); break; case 3: // rectangular, 1 bit depth, simple 1st order noise shaping result = MPT_USTRING("1 bit"); break; default: result = MPT_USTRING(""); break; } return result; } }; using DithersOpenMPT = Dithers, MultiChannelDither, MultiChannelDither, MultiChannelDither>, DitherNamesOpenMPT, 4, 1, 0, mpt::good_prng>; struct DithersWrapperOpenMPT : DithersOpenMPT { template DithersWrapperOpenMPT(Trd &rd, std::size_t mode = DithersOpenMPT::DefaultDither, std::size_t channels = DithersOpenMPT::DefaultChannels) : DithersOpenMPT(rd, mode, channels) { return; } }; template class AudioTargetBuffer : public IAudioTarget { private: std::size_t countRendered; TDithers &dithers; protected: Taudio_span outputBuffer; public: AudioTargetBuffer(Taudio_span buf, TDithers &dithers_) : countRendered(0) , dithers(dithers_) , outputBuffer(buf) { return; } std::size_t GetRenderedCount() const { return countRendered; } public: void Process(mpt::audio_span_interleaved buffer) override { std::visit( [&](auto &ditherInstance) { ConvertBufferMixInternalFixedToBuffer(mpt::make_audio_span_with_offset(outputBuffer, countRendered), buffer, ditherInstance, buffer.size_channels(), buffer.size_frames()); }, dithers.Variant() ); countRendered += buffer.size_frames(); } void Process(mpt::audio_span_interleaved buffer) override { std::visit( [&](auto &ditherInstance) { ConvertBufferMixInternalToBuffer(mpt::make_audio_span_with_offset(outputBuffer, countRendered), buffer, ditherInstance, buffer.size_channels(), buffer.size_frames()); }, dithers.Variant() ); countRendered += buffer.size_frames(); } }; template class AudioTargetBufferWithGain : public AudioTargetBuffer { private: using Tbase = AudioTargetBuffer; private: const MixSampleFloat gainFactor; public: AudioTargetBufferWithGain(Taudio_span buf, TDithers &dithers, float gainFactor_) : Tbase(buf, dithers) , gainFactor(static_cast(gainFactor_)) { return; } public: void Process(mpt::audio_span_interleaved buffer) override { const std::size_t countRendered_ = Tbase::GetRenderedCount(); if constexpr(!std::is_floating_point::value) { int32 gainFactor16_16 = mpt::saturate_round(gainFactor * (1 << 16)); if(gainFactor16_16 != (1<<16)) { // only apply gain when != +/- 0dB // no clipping prevention is done here for(std::size_t frame = 0; frame < buffer.size_frames(); ++frame) { for(std::size_t channel = 0; channel < buffer.size_channels(); ++channel) { buffer(channel, frame) = Util::muldiv(buffer(channel, frame), gainFactor16_16, 1 << 16); } } } } Tbase::Process(buffer); if constexpr(std::is_floating_point::value) { if(gainFactor != MixSampleFloat(1.0)) { // only apply gain when != +/- 0dB for(std::size_t frame = 0; frame < buffer.size_frames(); ++frame) { for(std::size_t channel = 0; channel < buffer.size_channels(); ++channel) { Tbase::outputBuffer(channel, countRendered_ + frame) *= static_cast(gainFactor); } } } } } void Process(mpt::audio_span_interleaved buffer) override { if(gainFactor != MixSampleFloat(1.0)) { // only apply gain when != +/- 0dB for(std::size_t frame = 0; frame < buffer.size_frames(); ++frame) { for(std::size_t channel = 0; channel < buffer.size_channels(); ++channel) { buffer(channel, frame) *= gainFactor; } } } Tbase::Process(buffer); } }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ModInstrument.cpp0000644000175000017500000002237214731076012021420 00000000000000/* * ModInstrument.cpp * ----------------- * Purpose: Helper functions for Module Instrument handling * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "ModInstrument.h" #include "Sndfile.h" OPENMPT_NAMESPACE_BEGIN // Convert envelope data between various formats. void InstrumentEnvelope::Convert(MODTYPE fromType, MODTYPE toType) { if(!(fromType & MOD_TYPE_XM) && (toType & MOD_TYPE_XM)) { // IT / MPTM -> XM: Expand loop by one tick, convert sustain loops to sustain points, remove carry flag. nSustainStart = nSustainEnd; dwFlags.reset(ENV_CARRY); if(nLoopEnd > nLoopStart && dwFlags[ENV_LOOP]) { for(uint32 node = nLoopEnd; node < size(); node++) { at(node).tick++; } } } else if((fromType & MOD_TYPE_XM) && !(toType & MOD_TYPE_XM)) { if(nSustainStart > nLoopEnd && dwFlags[ENV_LOOP]) { // In the IT format, the sustain loop is always considered before the envelope loop. // In the XM format, whichever of the two is encountered first is considered. // So we have to disable the sustain loop if it was behind the normal loop. dwFlags.reset(ENV_SUSTAIN); } if(!dwFlags[ENV_LOOP | ENV_SUSTAIN]) { // XM has no automatic fade-out behaviour at the end of the envelope. dwFlags.set(ENV_SUSTAIN); nSustainStart = nSustainEnd = LastPoint(); } // XM -> IT / MPTM: Shorten loop by one tick by inserting bogus point if(nLoopEnd > nLoopStart && dwFlags[ENV_LOOP] && nLoopEnd < size()) { if(at(nLoopEnd).tick - 1 > at(nLoopEnd - 1).tick) { // Insert an interpolated point just before the loop point. EnvelopeNode::tick_t tick = static_cast(at(nLoopEnd).tick - 1u); auto interpolatedValue = static_cast(GetValueFromPosition(tick, 64)); insert(begin() + nLoopEnd, EnvelopeNode(tick, interpolatedValue)); } else { // There is already a point before the loop point: Use it as new loop end. nLoopEnd--; } } } if(toType != MOD_TYPE_MPT) { nReleaseNode = ENV_RELEASE_NODE_UNSET; } } // Get envelope value at a given tick. Assumes that the envelope data is in rage [0, rangeIn], // returns value in range [0, rangeOut]. int32 InstrumentEnvelope::GetValueFromPosition(int position, int32 rangeOut, int32 rangeIn) const { if(empty()) return 0; uint32 pt = LastPoint(); const int32 ENV_PRECISION = 1 << 16; // Checking where current 'tick' is relative to the envelope points. for(uint32 i = 0; i < LastPoint(); i++) { if (position <= at(i).tick) { pt = i; break; } } int x2 = at(pt).tick; int32 value = 0; if(position >= x2) { // Case: current 'tick' is on a envelope point. value = at(pt).value * ENV_PRECISION / rangeIn; } else { // Case: current 'tick' is between two envelope points. int x1 = 0; if(pt) { // Get previous node's value and tick. value = at(pt - 1).value * ENV_PRECISION / rangeIn; x1 = at(pt - 1).tick; } if(x2 > x1 && position > x1) { // Linear approximation between the points; // f(x + d) ~ f(x) + f'(x) * d, where f'(x) = (y2 - y1) / (x2 - x1) value += Util::muldiv(position - x1, (at(pt).value * ENV_PRECISION / rangeIn - value), x2 - x1); } } Limit(value, int32(0), ENV_PRECISION); return (value * rangeOut + ENV_PRECISION / 2) / ENV_PRECISION; } void InstrumentEnvelope::Sanitize(uint8 maxValue) { if(!empty()) { front().tick = 0; LimitMax(front().value, maxValue); for(iterator it = begin() + 1; it != end(); it++) { it->tick = std::max(it->tick, (it - 1)->tick); LimitMax(it->value, maxValue); } LimitMax(nLoopEnd, LastPoint()); LimitMax(nLoopStart, nLoopEnd); LimitMax(nSustainEnd, LastPoint()); LimitMax(nSustainStart, nSustainEnd); if(nReleaseNode != ENV_RELEASE_NODE_UNSET) LimitMax(nReleaseNode, LastPoint()); } else { nLoopStart = 0; nLoopEnd = 0; nSustainStart = 0; nSustainEnd = 0; nReleaseNode = ENV_RELEASE_NODE_UNSET; } } // Translate instrument properties between two given formats. void ModInstrument::Convert(MODTYPE fromType, MODTYPE toType) { MPT_UNREFERENCED_PARAMETER(fromType); synth.Clear(); if(toType & MOD_TYPE_XM) { ResetNoteMap(); PitchEnv.dwFlags.reset(ENV_ENABLED | ENV_FILTER); dwFlags.reset(INS_SETPANNING); SetCutoff(GetCutoff(), false); SetResonance(GetResonance(), false); filterMode = FilterMode::Unchanged; nCutSwing = nPanSwing = nResSwing = nVolSwing = 0; nPPC = NOTE_MIDDLEC - 1; nPPS = 0; nNNA = NewNoteAction::NoteCut; nDCT = DuplicateCheckType::None; nDNA = DuplicateNoteAction::NoteCut; if(nMidiChannel == MidiMappedChannel) { nMidiChannel = MidiFirstChannel; } // FT2 only has unsigned Pitch Wheel Depth, and it's limited to 0...36 (in the GUI, at least. As you would expect it from FT2, this value is actually not sanitized on load). midiPWD = static_cast(std::abs(midiPWD)); Limit(midiPWD, int8(0), int8(36)); nGlobalVol = 64; nPan = 128; LimitMax(nFadeOut, 32767u); } VolEnv.Convert(fromType, toType); PanEnv.Convert(fromType, toType); PitchEnv.Convert(fromType, toType); if(fromType == MOD_TYPE_XM && (toType & (MOD_TYPE_IT | MOD_TYPE_MPT))) { if(!VolEnv.dwFlags[ENV_ENABLED]) { // Note-Off with no envelope cuts the note immediately in XM VolEnv.resize(2); VolEnv[0].tick = 0; VolEnv[0].value = ENVELOPE_MAX; VolEnv[1].tick = 1; VolEnv[1].value = ENVELOPE_MIN; VolEnv.dwFlags.set(ENV_ENABLED | ENV_SUSTAIN); VolEnv.dwFlags.reset(ENV_LOOP); VolEnv.nSustainStart = VolEnv.nSustainEnd = 0; } } // Limit fadeout length and precision for IT if(toType & MOD_TYPE_IT) { LimitMax(nFadeOut, 8192u); nFadeOut = ((nFadeOut + 16) / 32) * 32; } // MPT-specific features - remove instrument tunings, Pitch/Tempo Lock, cutoff / resonance swing and filter mode for other formats if(!(toType & MOD_TYPE_MPT)) { SetTuning(nullptr); pitchToTempoLock.Set(0); nCutSwing = nResSwing = 0; filterMode = FilterMode::Unchanged; nVolRampUp = 0; } } // Get a set of all samples referenced by this instrument std::set ModInstrument::GetSamples() const { std::set referencedSamples; for(const auto sample : Keyboard) { if(sample) { referencedSamples.insert(sample); } } return referencedSamples; } // Write sample references into a bool vector. If a sample is referenced by this instrument, true is written. // The caller has to initialize the vector. void ModInstrument::GetSamples(std::vector &referencedSamples) const { for(const auto sample : Keyboard) { if(sample != 0 && sample < referencedSamples.size()) { referencedSamples[sample] = true; } } } void ModInstrument::Sanitize(MODTYPE modType) { LimitMax(nFadeOut, 65536u); LimitMax(nGlobalVol, 64u); LimitMax(nPan, 256u); LimitMax(wMidiBank, uint16(16384)); LimitMax(nMidiProgram, uint8(128)); LimitMax(nMidiChannel, uint8(17)); if(nNNA > NewNoteAction::NoteFade) nNNA = NewNoteAction::NoteCut; if(nDCT > DuplicateCheckType::Plugin) nDCT = DuplicateCheckType::None; if(nDNA > DuplicateNoteAction::NoteFade) nDNA = DuplicateNoteAction::NoteCut; LimitMax(nPanSwing, uint8(64)); LimitMax(nVolSwing, uint8(100)); Limit(nPPS, int8(-32), int8(32)); LimitMax(nCutSwing, uint8(64)); LimitMax(nResSwing, uint8(64)); #ifdef MODPLUG_TRACKER MPT_UNREFERENCED_PARAMETER(modType); const uint8 range = ENVELOPE_MAX; #else const uint8 range = modType == MOD_TYPE_AMS ? uint8_max : uint8(ENVELOPE_MAX); #endif VolEnv.Sanitize(); PanEnv.Sanitize(); PitchEnv.Sanitize(range); synth.Sanitize(); for(size_t i = 0; i < std::size(NoteMap); i++) { if(NoteMap[i] < NOTE_MIN || NoteMap[i] > NOTE_MAX) NoteMap[i] = static_cast(i + NOTE_MIN); } if(!Resampling::IsKnownMode(resampling)) resampling = SRCMODE_DEFAULT; if(nMixPlug > MAX_MIXPLUGINS) nMixPlug = 0; } std::map ModInstrument::CanConvertToDefaultNoteMap() const { std::map transposeMap; for(size_t i = 0; i < std::size(NoteMap); i++) { if(Keyboard[i] == 0) continue; if(NoteMap[i] == NOTE_NONE) continue; const int8 relativeNote = static_cast(NoteMap[i] - (i + NOTE_MIN)); if(transposeMap.count(Keyboard[i]) && transposeMap[Keyboard[i]] != relativeNote) return {}; transposeMap[Keyboard[i]] = relativeNote; } // Remove all samples that wouldn't be transposed. // They were previously inserted into the map to catch the case where a specific sample's // map would start with a transpose value of 0 but end with a different value. for(auto it = transposeMap.begin(); it != transposeMap.end();) { if(it->second == 0) it = transposeMap.erase(it); else it++; } return transposeMap; } void ModInstrument::Transpose(int8 amount) { for(auto ¬e : NoteMap) { note = static_cast(Clamp(note + amount, NOTE_MIN, NOTE_MAX)); } } uint8 ModInstrument::GetMIDIChannel(const ModChannel &channel, CHANNELINDEX chn) const { // For mapped channels, return their pattern channel, modulo 16 (because there are only 16 MIDI channels) if(nMidiChannel == MidiMappedChannel) return static_cast((channel.nMasterChn ? (channel.nMasterChn - 1u) : chn) % 16u); else if(HasValidMIDIChannel()) return (nMidiChannel - MidiFirstChannel) % 16u; else return 0; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_mus_km.cpp0000644000175000017500000002440114721715306021042 00000000000000/* * Load_mus_km.cpp * --------------- * Purpose: Karl Morton Music Format module loader * Notes : This is probably not the official name of this format. * Karl Morton's engine has been used in Psycho Pinball and Micro Machines 2 and also Back To Baghdad * but the latter game only uses its sound effect format, not the music format. * So there are only two known games using this music format, and no official tools or documentation are available. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct KMChunkHeader { // 32-Bit chunk identifiers enum ChunkIdentifiers { idSONG = MagicLE("SONG"), idSMPL = MagicLE("SMPL"), }; uint32le id; // See ChunkIdentifiers uint32le length; // Chunk size including header size_t GetLength() const { return length <= 8 ? 0 : (length - 8); } ChunkIdentifiers GetID() const { return static_cast(id.get()); } }; MPT_BINARY_STRUCT(KMChunkHeader, 8) struct KMSampleHeader { char name[32]; uint32le loopStart; uint32le size; }; MPT_BINARY_STRUCT(KMSampleHeader, 40) struct KMSampleReference { char name[32]; uint8 finetune; uint8 volume; }; MPT_BINARY_STRUCT(KMSampleReference, 34) struct KMSongHeader { char name[32]; KMSampleReference samples[31]; uint16le unknown; // always 0 uint32le numChannels; uint32le restartPos; uint32le musicSize; }; MPT_BINARY_STRUCT(KMSongHeader, 32 + 31 * 34 + 14) struct KMFileHeader { KMChunkHeader chunkHeader; KMSongHeader songHeader; }; MPT_BINARY_STRUCT(KMFileHeader, sizeof(KMChunkHeader) + sizeof(KMSongHeader)) static uint64 GetHeaderMinimumAdditionalSize(const KMFileHeader &fileHeader) { // Require room for at least one more sample chunk header return static_cast(fileHeader.songHeader.musicSize) + sizeof(KMChunkHeader); } // Check if string only contains printable characters and doesn't contain any garbage after the required terminating null static bool IsValidKMString(const char (&str)[32]) { bool nullFound = false; for(char c : str) { if(c > 0x00 && c < 0x20) return false; else if(c == 0x00) nullFound = true; else if(nullFound) return false; } return nullFound; } static bool ValidateHeader(const KMFileHeader &fileHeader) { if(fileHeader.chunkHeader.id != KMChunkHeader::idSONG || fileHeader.chunkHeader.length < sizeof(fileHeader) || fileHeader.chunkHeader.length - sizeof(fileHeader) != fileHeader.songHeader.musicSize || fileHeader.chunkHeader.length > 0x40000 // That's enough space for 256 crammed 64-row patterns ;) || fileHeader.songHeader.unknown != 0 || fileHeader.songHeader.numChannels < 1 || fileHeader.songHeader.numChannels > 4 // Engine rejects anything above 32, channels 5 to 32 are simply ignored || !IsValidKMString(fileHeader.songHeader.name)) { return false; } for(const auto &sample : fileHeader.songHeader.samples) { if(sample.finetune > 15 || sample.volume > 64 || !IsValidKMString(sample.name)) return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMUS_KM(MemoryFileReader file, const uint64 *pfilesize) { KMFileHeader fileHeader; if(!file.Read(fileHeader)) return ProbeWantMoreData; if(!ValidateHeader(fileHeader)) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadMUS_KM(FileReader &file, ModLoadingFlags loadFlags) { { file.Rewind(); KMFileHeader fileHeader; if(!file.Read(fileHeader)) return false; if(!ValidateHeader(fileHeader)) return false; if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) return false; if(loadFlags == onlyVerifyHeader) return true; } file.Rewind(); const auto chunks = ChunkReader(file).ReadChunks(1); auto songChunks = chunks.GetAllChunks(KMChunkHeader::idSONG); auto sampleChunks = chunks.GetAllChunks(KMChunkHeader::idSMPL); if(songChunks.empty() || sampleChunks.empty()) return false; InitializeGlobals(MOD_TYPE_MOD, 4); m_SongFlags = SONG_AMIGALIMITS | SONG_IMPORTED | SONG_FORMAT_NO_VOLCOL | SONG_ISAMIGA; // Yes, those were not Amiga games but the format fully conforms to Amiga limits, so allow the Amiga Resampler to be used. m_nSamples = 0; static constexpr uint16 MUS_SAMPLE_UNUSED = 255; // Sentinel value to check if a sample needs to be duplicated for(auto &chunk : sampleChunks) { if(!CanAddMoreSamples()) break; m_nSamples++; ModSample &mptSample = Samples[m_nSamples]; mptSample.Initialize(MOD_TYPE_MOD); KMSampleHeader sampleHeader; if(!chunk.Read(sampleHeader) || !IsValidKMString(sampleHeader.name)) return false; m_szNames[m_nSamples] = sampleHeader.name; mptSample.nLoopEnd = mptSample.nLength = sampleHeader.size; mptSample.nLoopStart = sampleHeader.loopStart; mptSample.uFlags.set(CHN_LOOP); mptSample.nVolume = MUS_SAMPLE_UNUSED; if(!(loadFlags & loadSampleData)) continue; SampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(mptSample, chunk); } bool firstSong = true; for(auto &chunk : songChunks) { if(!firstSong && !Order.AddSequence()) break; firstSong = false; Order().clear(); KMSongHeader songHeader; if(!chunk.Read(songHeader) || songHeader.unknown != 0 || songHeader.numChannels < 1 || songHeader.numChannels > 4) return false; Order().SetName(mpt::ToUnicode(mpt::Charset::CP437, songHeader.name)); FileReader musicData = (loadFlags & loadPatternData) ? chunk.ReadChunk(songHeader.musicSize) : FileReader{}; // Map the samples for this subsong std::array sampleMap{}; for(uint8 smp = 1; smp <= 31; smp++) { const auto &srcSample = songHeader.samples[smp - 1]; const auto srcName = mpt::String::ReadAutoBuf(srcSample.name); if(srcName.empty()) continue; if(srcSample.finetune > 15 || srcSample.volume > 64 || !IsValidKMString(srcSample.name)) return false; const auto finetune = MOD2XMFineTune(srcSample.finetune); const uint16 volume = srcSample.volume * 4u; SAMPLEINDEX copyFrom = 0; for(SAMPLEINDEX srcSmp = 1; srcSmp <= m_nSamples; srcSmp++) { if(srcName != m_szNames[srcSmp]) continue; auto &mptSample = Samples[srcSmp]; sampleMap[smp] = srcSmp; if(mptSample.nVolume == MUS_SAMPLE_UNUSED || (mptSample.nFineTune == finetune && mptSample.nVolume == volume)) { // Sample was not used yet, or it uses the same finetune and volume mptSample.nFineTune = finetune; mptSample.nVolume = volume; copyFrom = 0; break; } else { copyFrom = srcSmp; } } if(copyFrom && CanAddMoreSamples()) { m_nSamples++; sampleMap[smp] = m_nSamples; const auto &smpFrom = Samples[copyFrom]; auto &newSample = Samples[m_nSamples]; newSample.FreeSample(); newSample = smpFrom; newSample.nFineTune = finetune; newSample.nVolume = volume; newSample.CopyWaveform(smpFrom); m_szNames[m_nSamples] = m_szNames[copyFrom]; } } struct ChannelState { ModCommand prevCommand; uint8 repeat = 0; }; std::array chnStates{}; static constexpr ROWINDEX MUS_PATTERN_LENGTH = 64; const CHANNELINDEX numChannels = static_cast(songHeader.numChannels); PATTERNINDEX pat = PATTERNINDEX_INVALID; ROWINDEX row = MUS_PATTERN_LENGTH; ROWINDEX restartRow = 0; uint32 repeatsLeft = 0; while(repeatsLeft || musicData.CanRead(1)) { row++; if(row >= MUS_PATTERN_LENGTH) { pat = Patterns.InsertAny(MUS_PATTERN_LENGTH); if(pat == PATTERNINDEX_INVALID) break; Order().push_back(pat); row = 0; } ModCommand *m = Patterns[pat].GetpModCommand(row, 0); for(CHANNELINDEX chn = 0; chn < numChannels; chn++, m++) { auto &chnState = chnStates[chn]; if(chnState.repeat) { chnState.repeat--; repeatsLeft--; *m = chnState.prevCommand; continue; } if(!musicData.CanRead(1)) continue; if(musicData.GetPosition() == songHeader.restartPos) { Order().SetRestartPos(Order().GetLastIndex()); restartRow = row; } const uint8 note = musicData.ReadUint8(); if(note & 0x80) { chnState.repeat = note & 0x7F; repeatsLeft += chnState.repeat; *m = chnState.prevCommand; continue; } if(note > 0 && note <= 3 * 12) m->note = note + NOTE_MIDDLEC - 13; const auto instr = musicData.ReadUint8(); m->instr = static_cast(sampleMap[instr & 0x1F]); if(instr & 0x80) { m->command = chnState.prevCommand.command; m->param = chnState.prevCommand.param; } else { static constexpr struct { ModCommand::COMMAND command; uint8 mask; } effTrans[] = { {CMD_VOLUME, 0x00}, {CMD_MODCMDEX, 0xA0}, {CMD_MODCMDEX, 0xB0}, {CMD_MODCMDEX, 0x10}, {CMD_MODCMDEX, 0x20}, {CMD_MODCMDEX, 0x50}, {CMD_OFFSET, 0x00}, {CMD_TONEPORTAMENTO, 0x00}, {CMD_TONEPORTAVOL, 0x00}, {CMD_VIBRATO, 0x00}, {CMD_VIBRATOVOL, 0x00}, {CMD_ARPEGGIO, 0x00}, {CMD_PORTAMENTOUP, 0x00}, {CMD_PORTAMENTODOWN, 0x00}, {CMD_VOLUMESLIDE, 0x00}, {CMD_MODCMDEX, 0x90}, {CMD_TONEPORTAMENTO, 0xFF}, {CMD_MODCMDEX, 0xC0}, {CMD_SPEED, 0x00}, {CMD_TREMOLO, 0x00}, }; const auto [command, param] = musicData.ReadArray(); if(command < std::size(effTrans)) { m->command = effTrans[command].command; m->param = param; if(m->command == CMD_SPEED && m->param >= 0x20) m->command = CMD_TEMPO; else if(effTrans[command].mask) m->param = effTrans[command].mask | (m->param & 0x0F); } } chnState.prevCommand = *m; } } if((restartRow != 0 || row < (MUS_PATTERN_LENGTH - 1u)) && pat != PATTERNINDEX_INVALID) { Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, static_cast(restartRow)).Row(row).RetryNextRow()); } } Order.SetSequence(0); m_modFormat.formatName = UL_("Karl Morton Music Format"); m_modFormat.type = UL_("mus"); m_modFormat.charset = mpt::Charset::CP437; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleFormatVorbis.cpp0000644000175000017500000002331414502511125022357 00000000000000/* * SampleFormatVorbis.cpp * ---------------------- * Purpose: Vorbis sample import * Notes : * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Sndfile.h" #ifndef MODPLUG_NO_FILESAVE #include "../common/mptFileIO.h" #endif #include "../common/misc_util.h" #include "Tagging.h" #include "Loaders.h" #include "../common/FileReader.h" #include "modsmp_ctrl.h" #include "openmpt/soundbase/Copy.hpp" #include "mpt/audio/span.hpp" #include "../soundlib/ModSampleCopy.h" //#include "mpt/crc/crc.hpp" #include "OggStream.h" #ifdef MPT_WITH_OGG #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif // MPT_COMPILER_CLANG #include #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #endif // MPT_WITH_OGG #if defined(MPT_WITH_VORBIS) #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif // MPT_COMPILER_CLANG #include #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #endif // MPT_WITH_VORBIS #if defined(MPT_WITH_VORBISFILE) #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif // MPT_COMPILER_CLANG #include #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #endif // MPT_WITH_VORBISFILE #ifdef MPT_WITH_STBVORBIS #include #endif // MPT_WITH_STBVORBIS OPENMPT_NAMESPACE_BEGIN //////////////////////////////////////////////////////////////////////////////// // Vorbis #if defined(MPT_WITH_VORBISFILE) static size_t VorbisfileFilereaderRead(void *ptr, size_t size, size_t nmemb, void *datasource) { FileReader &file = *mpt::void_ptr(datasource); return file.ReadRaw(mpt::span(mpt::void_cast(ptr), size * nmemb)).size() / size; } static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int whence) { FileReader &file = *mpt::void_ptr(datasource); switch(whence) { case SEEK_SET: { if(!mpt::in_range(offset)) { return -1; } return file.Seek(mpt::saturate_cast(offset)) ? 0 : -1; } break; case SEEK_CUR: { if(offset < 0) { if(offset == std::numeric_limits::min()) { return -1; } if(!mpt::in_range(0-offset)) { return -1; } return file.SkipBack(mpt::saturate_cast(0 - offset)) ? 0 : -1; } else { if(!mpt::in_range(offset)) { return -1; } return file.Skip(mpt::saturate_cast(offset)) ? 0 : -1; } } break; case SEEK_END: { if(!mpt::in_range(offset)) { return -1; } if(!mpt::in_range(file.GetLength() + offset)) { return -1; } return file.Seek(mpt::saturate_cast(file.GetLength() + offset)) ? 0 : -1; } break; default: return -1; } } static long VorbisfileFilereaderTell(void *datasource) { FileReader &file = *mpt::void_ptr(datasource); MPT_MAYBE_CONSTANT_IF(!mpt::in_range(file.GetPosition())) { return -1; } return static_cast(file.GetPosition()); } #if defined(MPT_WITH_VORBIS) static mpt::ustring UStringFromVorbis(const char *str) { return str ? mpt::ToUnicode(mpt::Charset::UTF8, str) : mpt::ustring(); } #endif // MPT_WITH_VORBIS static FileTags GetVorbisFileTags(OggVorbis_File &vf) { FileTags tags; #if defined(MPT_WITH_VORBIS) vorbis_comment *vc = ov_comment(&vf, -1); if(!vc) { return tags; } tags.encoder = UStringFromVorbis(vorbis_comment_query(vc, "ENCODER", 0)); tags.title = UStringFromVorbis(vorbis_comment_query(vc, "TITLE", 0)); tags.comments = UStringFromVorbis(vorbis_comment_query(vc, "DESCRIPTION", 0)); tags.bpm = UStringFromVorbis(vorbis_comment_query(vc, "BPM", 0)); // non-standard tags.artist = UStringFromVorbis(vorbis_comment_query(vc, "ARTIST", 0)); tags.album = UStringFromVorbis(vorbis_comment_query(vc, "ALBUM", 0)); tags.trackno = UStringFromVorbis(vorbis_comment_query(vc, "TRACKNUMBER", 0)); tags.year = UStringFromVorbis(vorbis_comment_query(vc, "DATE", 0)); tags.url = UStringFromVorbis(vorbis_comment_query(vc, "CONTACT", 0)); tags.genre = UStringFromVorbis(vorbis_comment_query(vc, "GENRE", 0)); #else // !MPT_WITH_VORBIS MPT_UNREFERENCED_PARAMETER(vf); #endif // MPT_WITH_VORBIS return tags; } #endif // MPT_WITH_VORBISFILE bool CSoundFile::ReadVorbisSample(SAMPLEINDEX sample, FileReader &file) { #if defined(MPT_WITH_VORBISFILE) || defined(MPT_WITH_STBVORBIS) file.Rewind(); long rate = 0; int channels = 0; std::vector raw_sample_data; std::string sampleName; #endif // VORBIS #if defined(MPT_WITH_VORBISFILE) bool unsupportedSample = false; ov_callbacks callbacks = { &VorbisfileFilereaderRead, &VorbisfileFilereaderSeek, NULL, &VorbisfileFilereaderTell }; OggVorbis_File vf; MemsetZero(vf); if(ov_open_callbacks(mpt::void_ptr(&file), &vf, NULL, 0, callbacks) == 0) { if(ov_streams(&vf) == 1) { // we do not support chained vorbis samples vorbis_info *vi = ov_info(&vf, -1); if(vi && vi->rate > 0 && vi->channels > 0) { sampleName = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(GetVorbisFileTags(vf))); rate = vi->rate; channels = vi->channels; std::size_t offset = 0; int current_section = 0; long decodedSamples = 0; bool eof = false; if(auto length = ov_pcm_total(&vf, 0); length != OV_EINVAL) raw_sample_data.reserve(std::min(MAX_SAMPLE_LENGTH, mpt::saturate_cast(length)) * std::clamp(channels, 1, 2)); while(!eof) { float **output = nullptr; long ret = ov_read_float(&vf, &output, 1024, ¤t_section); if(ret == 0) { eof = true; } else if(ret < 0) { // stream error, just try to continue } else { decodedSamples = ret; if(decodedSamples > 0 && (channels == 1 || channels == 2)) { raw_sample_data.resize(raw_sample_data.size() + (channels * decodedSamples)); CopyAudio(mpt::audio_span_interleaved(raw_sample_data.data() + (offset * channels), channels, decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples)); offset += decodedSamples; if((raw_sample_data.size() / channels) > MAX_SAMPLE_LENGTH) { break; } } } } } else { unsupportedSample = true; } } else { unsupportedSample = true; } ov_clear(&vf); } else { unsupportedSample = true; } if(unsupportedSample) { return false; } #elif defined(MPT_WITH_STBVORBIS) // NOTE/TODO: stb_vorbis does not handle inferred negative PCM sample position // at stream start. (See // ). This // means that, for remuxed and re-aligned/cutted (at stream start) Vorbis // files, stb_vorbis will include superfluous samples at the beginning. FileReader::PinnedView fileView = file.GetPinnedView(); const std::byte* data = fileView.data(); std::size_t dataLeft = fileView.size(); std::size_t offset = 0; int consumed = 0; int error = 0; stb_vorbis *vorb = stb_vorbis_open_pushdata(mpt::byte_cast(data), mpt::saturate_cast(dataLeft), &consumed, &error, nullptr); file.Skip(consumed); data += consumed; dataLeft -= consumed; if(!vorb) { return false; } rate = stb_vorbis_get_info(vorb).sample_rate; channels = stb_vorbis_get_info(vorb).channels; if(rate <= 0 || channels <= 0) { return false; } while((error == VORBIS__no_error || (error == VORBIS_need_more_data && dataLeft > 0))) { int frame_channels = 0; int decodedSamples = 0; float **output = nullptr; consumed = stb_vorbis_decode_frame_pushdata(vorb, mpt::byte_cast(data), mpt::saturate_cast(dataLeft), &frame_channels, &output, &decodedSamples); file.Skip(consumed); data += consumed; dataLeft -= consumed; LimitMax(frame_channels, channels); if(decodedSamples > 0 && (frame_channels == 1 || frame_channels == 2)) { raw_sample_data.resize(raw_sample_data.size() + (channels * decodedSamples)); CopyAudio(mpt::audio_span_interleaved(raw_sample_data.data() + (offset * channels), channels, decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples)); offset += decodedSamples; if((raw_sample_data.size() / channels) > MAX_SAMPLE_LENGTH) { break; } } error = stb_vorbis_get_error(vorb); } stb_vorbis_close(vorb); #endif // VORBIS #if defined(MPT_WITH_VORBISFILE) || defined(MPT_WITH_STBVORBIS) if(rate <= 0 || channels <= 0 || raw_sample_data.empty()) { return false; } DestroySampleThreadsafe(sample); ModSample &mptSample = Samples[sample]; mptSample.Initialize(); mptSample.nC5Speed = static_cast(rate); mptSample.nLength = std::min(MAX_SAMPLE_LENGTH, mpt::saturate_cast(raw_sample_data.size() / channels)); mptSample.uFlags.set(CHN_16BIT); mptSample.uFlags.set(CHN_STEREO, channels == 2); if(!mptSample.AllocateSample()) { return false; } if(raw_sample_data.size() / channels > MAX_SAMPLE_LENGTH) { AddToLog(LogWarning, U_("Sample has been truncated!")); } std::copy(raw_sample_data.begin(), raw_sample_data.begin() + mptSample.nLength * channels, mptSample.sample16()); mptSample.Convert(MOD_TYPE_IT, GetType()); mptSample.PrecomputeLoops(*this, false); m_szNames[sample] = sampleName; return true; #else // !VORBIS MPT_UNREFERENCED_PARAMETER(sample); MPT_UNREFERENCED_PARAMETER(file); return false; #endif // VORBIS } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/pattern.h0000644000175000017500000001613115005732677017741 00000000000000/* * Pattern.h * --------- * Purpose: Module Pattern header class * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include #include "modcommand.h" #include "Snd_defs.h" OPENMPT_NAMESPACE_BEGIN class CPatternContainer; class CSoundFile; class EffectWriter; class CPattern { friend class CPatternContainer; public: CPattern(CPatternContainer &patCont) : m_rPatternContainer{patCont} {} CPattern(const CPattern &) = default; CPattern(CPattern &&) noexcept = default; CPattern& operator= (const CPattern &pat); bool operator== (const CPattern &other) const noexcept; bool operator!= (const CPattern &other) const noexcept { return !(*this == other); } public: ModCommand* GetpModCommand(const ROWINDEX r, const CHANNELINDEX c) { return &m_ModCommands[r * GetNumChannels() + c]; } const ModCommand* GetpModCommand(const ROWINDEX r, const CHANNELINDEX c) const { return &m_ModCommands[r * GetNumChannels() + c]; } ROWINDEX GetNumRows() const noexcept { return m_Rows; } ROWINDEX GetRowsPerBeat() const noexcept { return m_RowsPerBeat; } // pattern-specific rows per beat ROWINDEX GetRowsPerMeasure() const noexcept { return m_RowsPerMeasure; } // pattern-specific rows per measure bool GetOverrideSignature() const noexcept { return (m_RowsPerBeat + m_RowsPerMeasure > 0); } // override song time signature? // Returns true if pattern data can be accessed at given row, false otherwise. bool IsValidRow(const ROWINDEX row) const noexcept { return (row < GetNumRows()); } // Returns true if any pattern data is present. bool IsValid() const noexcept { return !m_ModCommands.empty(); } mpt::span GetRow(const ROWINDEX row) { return mpt::as_span(GetpModCommand(row, 0), GetNumChannels()); } mpt::span GetRow(const ROWINDEX row) const { return mpt::as_span(GetpModCommand(row, 0), GetNumChannels()); } CHANNELINDEX GetNumChannels() const noexcept; // Add or remove rows from the pattern. bool Resize(const ROWINDEX newRowCount, bool enforceFormatLimits = true, bool resizeAtEnd = true); // Check if there is any note data on a given row. bool IsEmptyRow(ROWINDEX row) const noexcept; // Check if the row contains any position jumps or pattern breaks. bool RowHasJump(ROWINDEX row) const noexcept; // Allocate new pattern memory and replace old pattern data. bool AllocatePattern(ROWINDEX rows); // Deallocate pattern data. void Deallocate(); // Empties all ModCommands in the pattern. void ClearCommands() noexcept; // Returns associated soundfile. CSoundFile& GetSoundFile() noexcept; const CSoundFile& GetSoundFile() const noexcept; const std::vector &GetData() const { return m_ModCommands; } void SetData(std::vector &&data) { MPT_ASSERT(data.size() == GetNumRows() * GetNumChannels()); m_ModCommands = std::move(data); } // Set pattern signature (rows per beat, rows per measure). Returns true on success. bool SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure) noexcept; void RemoveSignature() noexcept { m_RowsPerBeat = m_RowsPerMeasure = 0; } static bool IsValidSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure) noexcept; bool HasTempoSwing() const noexcept { return !m_tempoSwing.empty(); } const TempoSwing& GetTempoSwing() const noexcept { return m_tempoSwing; } void SetTempoSwing(const TempoSwing &swing) { m_tempoSwing = swing; m_tempoSwing.Normalize(); } void RemoveTempoSwing() noexcept { m_tempoSwing.clear(); } // Pattern name functions - bool functions return true on success. bool SetName(std::string newName); bool SetName(const char *newName, size_t maxChars); template bool SetName(const char (&buffer)[bufferSize]) { return SetName(buffer, bufferSize); } std::string GetName() const { return m_PatternName; } #ifdef MODPLUG_TRACKER // Double number of rows bool Expand(); // Halve number of rows bool Shrink(); #endif // MODPLUG_TRACKER // Write some kind of effect data to the pattern bool WriteEffect(EffectWriter &settings); using iterator = std::vector::iterator; using const_iterator = std::vector::const_iterator; iterator begin() noexcept { return m_ModCommands.begin(); } const_iterator begin() const noexcept { return m_ModCommands.begin(); } const_iterator cbegin() const noexcept { return m_ModCommands.cbegin(); } iterator end() noexcept { return m_ModCommands.end(); } const_iterator end() const noexcept { return m_ModCommands.end(); } const_iterator cend() const noexcept { return m_ModCommands.cend(); } protected: ModCommand& GetModCommand(size_t i) { return m_ModCommands[i]; } //Returns modcommand from (floor[i/channelCount], i%channelCount) ModCommand& GetModCommand(ROWINDEX r, CHANNELINDEX c) { return m_ModCommands[r * GetNumChannels() + c]; } const ModCommand& GetModCommand(ROWINDEX r, CHANNELINDEX c) const { return m_ModCommands[r * GetNumChannels() + c]; } protected: std::vector m_ModCommands; ROWINDEX m_Rows = 0; ROWINDEX m_RowsPerBeat = 0; // patterns-specific time signature. if != 0, the time signature is used automatically. ROWINDEX m_RowsPerMeasure = 0; // ditto TempoSwing m_tempoSwing; std::string m_PatternName; CPatternContainer& m_rPatternContainer; }; const char FileIdPattern[] = "mptP"; void ReadModPattern(std::istream& iStrm, CPattern& patc, const size_t nSize = 0); void WriteModPattern(std::ostream& oStrm, const CPattern& patc); // Class for conveniently writing an effect to the pattern. class EffectWriter { friend class CPattern; // Row advance mode enum RetryMode : uint8 { rmIgnore, // If effect can't be written, abort. rmTryNextRow, // If effect can't be written, try next row. rmTryPreviousRow, // If effect can't be written, try previous row. }; public: // Constructors with effect commands EffectWriter(EffectCommand cmd, ModCommand::PARAM param) : m_command(cmd), m_param(param), m_isVolEffect(false) { } EffectWriter(VolumeCommand cmd, ModCommand::VOL param) : m_volcmd(cmd), m_vol(param), m_isVolEffect(true) { } // Additional constructors: // Set row in which writing should start EffectWriter &Row(ROWINDEX row) { m_row = row; return *this; } // Set channel to which writing should be restricted to EffectWriter &Channel(CHANNELINDEX chn) { m_channel = chn; return *this; } // Allow multiple effects of the same kind to be written in the same row. EffectWriter &AllowMultiple() { m_allowMultiple = true; return *this; } // Set retry mode. EffectWriter &RetryNextRow() { m_retryMode = rmTryNextRow; return *this; } EffectWriter &RetryPreviousRow() { m_retryMode = rmTryPreviousRow; return *this; } protected: ROWINDEX m_row = 0; CHANNELINDEX m_channel = CHANNELINDEX_INVALID; // Any channel by default RetryMode m_retryMode = rmIgnore; union { EffectCommand m_command; VolumeCommand m_volcmd; }; union { ModCommand::PARAM m_param; ModCommand::VOL m_vol; }; bool m_retry = true; bool m_allowMultiple = false; bool m_isVolEffect = false; }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Snd_defs.h0000644000175000017500000011020015022626104017763 00000000000000/* * Snd_defs.h * ---------- * Purpose: Basic definitions of data types, enums, etc. for the playback engine core. * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/base/FlagSet.hpp" OPENMPT_NAMESPACE_BEGIN using ROWINDEX = uint32; inline constexpr ROWINDEX ROWINDEX_INVALID = uint32_max; using CHANNELINDEX = uint16; inline constexpr CHANNELINDEX CHANNELINDEX_INVALID = uint16_max; using ORDERINDEX = uint16; inline constexpr ORDERINDEX ORDERINDEX_INVALID = uint16_max; inline constexpr ORDERINDEX ORDERINDEX_MAX = uint16_max - 1; using PATTERNINDEX = uint16; inline constexpr PATTERNINDEX PATTERNINDEX_INVALID = uint16_max; // "---" in order list inline constexpr PATTERNINDEX PATTERNINDEX_SKIP = uint16_max - 1; // "+++" in order list using PLUGINDEX = uint8; inline constexpr PLUGINDEX PLUGINDEX_INVALID = uint8_max; using SAMPLEINDEX = uint16; inline constexpr SAMPLEINDEX SAMPLEINDEX_INVALID = uint16_max; using INSTRUMENTINDEX = uint16; inline constexpr INSTRUMENTINDEX INSTRUMENTINDEX_INVALID = uint16_max; using SEQUENCEINDEX = uint8; inline constexpr SEQUENCEINDEX SEQUENCEINDEX_INVALID = uint8_max; using SmpLength = uint32; inline constexpr SmpLength MAX_SAMPLE_LENGTH = 0x10000000; // Sample length in frames. Sample size in bytes can be more than this (= 256 MB). inline constexpr ROWINDEX MAX_ROWS_PER_MEASURE = 65536; inline constexpr ROWINDEX MAX_ROWS_PER_BEAT = 65536; inline constexpr ROWINDEX DEFAULT_ROWS_PER_BEAT = 4; inline constexpr ROWINDEX DEFAULT_ROWS_PER_MEASURE = 16; inline constexpr ROWINDEX MAX_PATTERN_ROWS = 4096; inline constexpr ORDERINDEX MAX_ORDERS = ORDERINDEX_MAX + 1; inline constexpr PATTERNINDEX MAX_PATTERNS = 4000; inline constexpr SAMPLEINDEX MAX_SAMPLES = 4000; inline constexpr INSTRUMENTINDEX MAX_INSTRUMENTS = 256; inline constexpr PLUGINDEX MAX_MIXPLUGINS = 250; inline constexpr SEQUENCEINDEX MAX_SEQUENCES = 50; inline constexpr CHANNELINDEX MAX_BASECHANNELS = 192; // Maximum pattern channels. inline constexpr CHANNELINDEX MAX_CHANNELS = 256; // Maximum number of mixing channels. enum { FREQ_FRACBITS = 4 }; // Number of fractional bits in return value of CSoundFile::GetFreqFromPeriod() using samplecount_t = uint32; // Number of rendered samples using PlugParamIndex = uint32; using PlugParamValue = float; // String lengths (including trailing null char) enum { MAX_SAMPLENAME = 32, MAX_SAMPLEFILENAME = 22, MAX_INSTRUMENTNAME = 32, MAX_INSTRUMENTFILENAME = 32, MAX_PATTERNNAME = 32, MAX_CHANNELNAME = 20, }; enum MODTYPE { MOD_TYPE_NONE = 0x00, MOD_TYPE_MOD = 0x01, MOD_TYPE_S3M = 0x02, MOD_TYPE_XM = 0x04, MOD_TYPE_MED = 0x08, MOD_TYPE_MTM = 0x10, MOD_TYPE_IT = 0x20, MOD_TYPE_669 = 0x40, MOD_TYPE_ULT = 0x80, MOD_TYPE_STM = 0x100, MOD_TYPE_FAR = 0x200, MOD_TYPE_DTM = 0x400, MOD_TYPE_AMF = 0x800, MOD_TYPE_AMS = 0x1000, MOD_TYPE_DSM = 0x2000, MOD_TYPE_MDL = 0x4000, MOD_TYPE_OKT = 0x8000, MOD_TYPE_MID = 0x10000, MOD_TYPE_DMF = 0x20000, MOD_TYPE_PTM = 0x40000, MOD_TYPE_DBM = 0x80000, MOD_TYPE_MT2 = 0x100000, MOD_TYPE_AMF0 = 0x200000, MOD_TYPE_PSM = 0x400000, MOD_TYPE_J2B = 0x800000, MOD_TYPE_MPT = 0x1000000, MOD_TYPE_IMF = 0x2000000, MOD_TYPE_DIGI = 0x4000000, MOD_TYPE_STP = 0x8000000, MOD_TYPE_PLM = 0x10000000, MOD_TYPE_SFX = 0x20000000, MOD_TYPE_MOD_PC = MOD_TYPE_MOD | MOD_TYPE_XM, }; DECLARE_FLAGSET(MODTYPE) enum class ModContainerType { None, UMX, XPK, PP20, MMCMP, WAV, // WAV as module UAX, // Unreal sample set as module Generic, // Generic CUnarchiver container }; enum class AutoSlideCommand { TonePortamento, TonePortamentoWithDuration, PortamentoUp, PortamentoDown, FinePortamentoUp, FinePortamentoDown, PortamentoFC, FineVolumeSlideUp, FineVolumeSlideDown, VolumeDownETX, VolumeSlideSTK, VolumeDownWithDuration, GlobalVolumeSlide, Vibrato, Tremolo, NumCommands }; // Module channel / sample flags enum ChannelFlags : uint32 { // Sample Flags CHN_16BIT = 0x01, // 16-bit sample CHN_LOOP = 0x02, // Looped sample CHN_PINGPONGLOOP = 0x04, // Bidi-looped sample CHN_SUSTAINLOOP = 0x08, // Sample with sustain loop CHN_PINGPONGSUSTAIN = 0x10, // Sample with bidi sustain loop CHN_PANNING = 0x20, // Sample with forced panning CHN_STEREO = 0x40, // Stereo sample CHN_REVERSE = 0x80, // Start sample playback from sample / loop end (Velvet Studio feature) CHN_SURROUND = 0x100, // Use surround channel CHN_ADLIB = 0x200, // Adlib / OPL instrument is active on this channel // Channel Flags CHN_PINGPONGFLAG = 0x80, // When flag is on, sample is processed backwards - this is intentionally the same flag as CHN_REVERSE. CHN_MUTE = 0x400, // Muted channel CHN_KEYOFF = 0x800, // Exit sustain CHN_NOTEFADE = 0x1000, // Fade note (instrument mode) CHN_WRAPPED_LOOP = 0x2000, // Loop just wrapped around to loop start (required for correct interpolation around loop points) CHN_AMIGAFILTER = 0x4000, // Apply Amiga low-pass filter CHN_FILTER = 0x8000, // Apply resonant filter on sample CHN_VOLUMERAMP = 0x10000, // Apply volume ramping CHN_VIBRATO = 0x20000, // Apply vibrato CHN_TREMOLO = 0x40000, // Apply tremolo CHN_PORTAMENTO = 0x80000, // Apply portamento CHN_GLISSANDO = 0x100000, // Glissando (force portamento to semitones) mode CHN_FASTVOLRAMP = 0x200000, // Force usage of global ramping settings instead of ramping over the complete render buffer length CHN_EXTRALOUD = 0x400000, // Force sample to play at 0dB CHN_REVERB = 0x800000, // Apply reverb on this channel CHN_NOREVERB = 0x1000000, // Disable reverb on this channel CHN_NOFX = 0x2000000, // Dry channel (no plugins) CHN_SYNCMUTE = 0x4000000, // Keep sample sync on mute // Sample flags (only present in ModSample::uFlags, may overlap with CHN_CHANNELFLAGS) SMP_MODIFIED = 0x2000, // Sample data has been edited in the tracker SMP_KEEPONDISK = 0x4000, // Sample is not saved to file, data is restored from original sample file SMP_NODEFAULTVOLUME = 0x8000, // Ignore default volume setting }; DECLARE_FLAGSET(ChannelFlags) inline constexpr ChannelFlags CHN_SAMPLEFLAGS = (CHN_16BIT | CHN_LOOP | CHN_PINGPONGLOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN | CHN_PANNING | CHN_STEREO | CHN_PINGPONGFLAG | CHN_REVERSE | CHN_SURROUND | CHN_ADLIB).as_enum(); inline constexpr ChannelFlags CHN_CHANNELFLAGS = (~CHN_SAMPLEFLAGS | CHN_SURROUND).as_enum(); // Sample flags fit into the first 16 bits, and with the current memory layout, storing them as a 16-bit integer packs struct ModSample nicely. using SampleFlags = FlagSet; // Instrument envelope-specific flags enum EnvelopeFlags : uint8 { ENV_ENABLED = 0x01, // env is enabled ENV_LOOP = 0x02, // env loop ENV_SUSTAIN = 0x04, // env sustain ENV_CARRY = 0x08, // env carry ENV_FILTER = 0x10, // filter env enabled (this has to be combined with ENV_ENABLED in the pitch envelope's flags) }; DECLARE_FLAGSET(EnvelopeFlags) // Envelope value boundaries inline constexpr uint8 ENVELOPE_MIN = 0; // Vertical min value of a point inline constexpr uint8 ENVELOPE_MID = 32; // Vertical middle line inline constexpr uint8 ENVELOPE_MAX = 64; // Vertical max value of a point inline constexpr uint8 MAX_ENVPOINTS = 240; // Maximum length of each instrument envelope // Instrument-specific flags enum InstrumentFlags : uint8 { INS_SETPANNING = 0x01, // Panning enabled INS_MUTE = 0x02, // Instrument is muted }; DECLARE_FLAGSET(InstrumentFlags) // envelope types in instrument editor enum EnvelopeType : uint8 { ENV_VOLUME = 0, ENV_PANNING, ENV_PITCH, ENV_MAXTYPES }; // Filter Modes enum class FilterMode : uint8 { Unchanged = 0xFF, LowPass = 0, HighPass = 1, }; // NNA types (New Note Action) enum class NewNoteAction : uint8 { NoteCut = 0, Continue = 1, NoteOff = 2, NoteFade = 3, }; // DCT types (Duplicate Check Types) enum class DuplicateCheckType : uint8 { None = 0, Note = 1, Sample = 2, Instrument = 3, Plugin = 4, }; // DNA types (Duplicate Note Action) enum class DuplicateNoteAction : uint8 { NoteCut = 0, NoteOff = 1, NoteFade = 2, }; enum PlayFlags : uint16 { SONG_PATTERNLOOP = 0x01, // Loop current pattern (pattern editor) SONG_STEP = 0x02, // Song is in "step" mode (pattern editor) SONG_PAUSED = 0x04, // Song is paused (no tick processing, just rendering audio) SONG_FADINGSONG = 0x08, // Song is fading out SONG_ENDREACHED = 0x10, // Song is finished SONG_FIRSTTICK = 0x20, // Is set when the current tick is the first tick of the row SONG_MPTFILTERMODE = 0x40, // Local filter mode (reset filter on each note) SONG_SURROUNDPAN = 0x80, // Pan in the rear channels SONG_POSJUMP = 0x100, // Position jump encountered SONG_BREAKTOROW = 0x200, // Break to row command encountered SONG_POSITIONCHANGED = 0x400, // Report to plugins that we jumped around in the module }; DECLARE_FLAGSET(PlayFlags) enum SongFlags { SONG_FASTPORTAS = 0x01, // Portamentos are executed on every tick SONG_FASTVOLSLIDES = 0x02, // Old Scream Tracker 3.0 volume slides (executed on every tick) SONG_ITOLDEFFECTS = 0x04, // Old Impulse Tracker effect implementations SONG_ITCOMPATGXX = 0x08, // IT "Compatible Gxx" (IT's flag to behave more like other trackers w/r/t portamento effects) SONG_LINEARSLIDES = 0x10, // Linear slides vs. Amiga slides SONG_EXFILTERRANGE = 0x20, // Cutoff Filter has double frequency range (up to ~10Khz) SONG_AMIGALIMITS = 0x40, // Enforce amiga frequency limits SONG_S3MOLDVIBRATO = 0x80, // ScreamTracker 2 vibrato in S3M files SONG_PT_MODE = 0x100, // ProTracker 1/2 playback mode SONG_ISAMIGA = 0x200, // Is an Amiga module and thus qualifies to be played using the Paula BLEP resampler SONG_IMPORTED = 0x400, // Song type does not represent actual module format / was imported from a different format (OpenMPT) SONG_PLAYALLSONGS = 0x800, // Play all subsongs consecutively (libopenmpt) SONG_AUTO_TONEPORTA = 0x1000, // Tone portamento command is continued automatically SONG_AUTO_TONEPORTA_CONT = 0x2000, // Auto tone portamento is not interruped by a tone portamento with parameter 0 SONG_AUTO_GLOBALVOL = 0x4000, // Global volume slide command is continued automatically SONG_AUTO_VIBRATO = 0x8000, // Vibrato command is continued automatically SONG_AUTO_TREMOLO = 0x1'8000, // Tremolo command is continued automatically SONG_AUTO_VOLSLIDE_STK = 0x2'0000, // Automatic volume slide command is interpreted like in STK files (rather than like in STP files) SONG_FORMAT_NO_VOLCOL = 0x4'0000, // The original (imported) format has no volume column, so it can be hidden in the pattern editor. }; DECLARE_FLAGSET(SongFlags) // Global Options (Renderer) #ifndef NO_AGC #define SNDDSP_AGC 0x40 // Automatic gain control #endif // ~NO_AGC #ifndef NO_DSP #define SNDDSP_MEGABASS 0x02 // Bass expansion #define SNDDSP_SURROUND 0x08 // Surround mix #define SNDDSP_BITCRUSH 0x01 #endif // NO_DSP #ifndef NO_REVERB #define SNDDSP_REVERB 0x20 // Apply reverb #endif // NO_REVERB #ifndef NO_EQ #define SNDDSP_EQ 0x80 // Apply EQ #endif // NO_EQ #define SNDMIX_SOFTPANNING 0x10 // Soft panning mode (this is forced with mixmode RC3 and later) // Misc Flags (can safely be turned on or off) #define SNDMIX_MAXDEFAULTPAN 0x80000 // Currently unused (should be used by Amiga MOD loaders) #define SNDMIX_MUTECHNMODE 0x100000 // Notes are not played on muted channels inline constexpr uint32 MAX_GLOBAL_VOLUME = 256; inline constexpr uint32 MAX_PREAMP = 2000; // When to execute a position override event enum class OrderTransitionMode : uint8 { AtPatternEnd, AtMeasureEnd, AtBeatEnd, AtRowEnd, }; // Resampling modes enum ResamplingMode : uint8 { // ATTENTION: Do not change ANY of these values, as they get written out to files in per instrument interpolation settings // and old files have these exact values in them which should not change meaning. SRCMODE_NEAREST = 0, // 1 tap, no AA SRCMODE_LINEAR = 1, // 2 tap, no AA SRCMODE_CUBIC = 2, // 4 tap, no AA SRCMODE_SINC8 = 4, // 8 tap, no AA (yes, index 4) (XMMS-ModPlug) SRCMODE_SINC8LP = 3, // 8 tap, with AA (yes, index 3) (Polyphase) SRCMODE_DEFAULT = 5, // Only used for instrument settings, not used inside the mixer SRCMODE_AMIGA = 0xFF, // Not explicitely user-selectable }; namespace Resampling { enum class AmigaFilter { Off = 0, A500 = 1, A1200 = 2, Unfiltered = 3, }; inline std::array AllModes() noexcept { return { { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP } }; } inline std::array AllModesWithDefault() noexcept { return { { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP, SRCMODE_DEFAULT } }; } constexpr ResamplingMode Default() noexcept { return SRCMODE_SINC8LP; } constexpr bool IsKnownMode(int mode) noexcept { return (mode >= 0) && (mode < SRCMODE_DEFAULT); } constexpr ResamplingMode ToKnownMode(int mode) noexcept { return Resampling::IsKnownMode(mode) ? static_cast(mode) : (mode == SRCMODE_AMIGA) ? SRCMODE_LINEAR : Resampling::Default(); } constexpr int Length(ResamplingMode mode) noexcept { return mode == SRCMODE_NEAREST ? 1 : mode == SRCMODE_LINEAR ? 2 : mode == SRCMODE_CUBIC ? 4 : mode == SRCMODE_SINC8 ? 8 : mode == SRCMODE_SINC8LP ? 8 : 0; } constexpr bool HasAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP); } constexpr ResamplingMode AddAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8) ? SRCMODE_SINC8LP : mode; } constexpr ResamplingMode RemoveAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP) ? SRCMODE_SINC8 : mode; } } // Release node defines #define ENV_RELEASE_NODE_UNSET 0xFF #define NOT_YET_RELEASED (-1) static_assert(ENV_RELEASE_NODE_UNSET > MAX_ENVPOINTS); enum PluginPriority { ChannelOnly, InstrumentOnly, PrioritiseInstrument, PrioritiseChannel, }; enum PluginMutePriority { EvenIfMuted, RespectMutes, }; // Plugin velocity handling options enum PlugVelocityHandling : uint8 { PLUGIN_VELOCITYHANDLING_CHANNEL = 0, PLUGIN_VELOCITYHANDLING_VOLUME }; // Plugin volumecommand handling options enum PlugVolumeHandling : uint8 { PLUGIN_VOLUMEHANDLING_MIDI = 0, PLUGIN_VOLUMEHANDLING_DRYWET, PLUGIN_VOLUMEHANDLING_IGNORE, PLUGIN_VOLUMEHANDLING_CUSTOM, PLUGIN_VOLUMEHANDLING_MAX, }; enum MidiChannel : uint8 { MidiNoChannel = 0, MidiFirstChannel = 1, MidiLastChannel = 16, MidiMappedChannel = 17, }; // Vibrato Types enum VibratoType : uint8 { VIB_SINE = 0, VIB_SQUARE, VIB_RAMP_UP, VIB_RAMP_DOWN, VIB_RANDOM }; // Tracker-specific playback behaviour // Note: The index of every flag has to be fixed, so do not remove flags. Always add new flags at the end! enum PlayBehaviour { MSF_COMPATIBLE_PLAY, // No-op - only used during loading (Old general compatibility flag for IT/MPT/XM) kMPTOldSwingBehaviour, // MPT 1.16 swing behaviour (IT/MPT, deprecated) kMIDICCBugEmulation, // Emulate broken volume MIDI CC behaviour (IT/MPT/XM, deprecated) kOldMIDIPitchBends, // Old VST MIDI pitch bend behaviour (IT/MPT/XM, deprecated) kFT2VolumeRamping, // Smooth volume ramping like in FT2 (XM) kMODVBlankTiming, // F21 and above set speed instead of tempo kSlidesAtSpeed1, // Execute normal slides at speed 1 as if they were fine slides kPeriodsAreHertz, // Compute note frequency in Hertz rather than periods kTempoClamp, // Clamp tempo to 32-255 range. kPerChannelGlobalVolSlide, // Global volume slide memory is per-channel kPanOverride, // Panning commands override surround and random pan variation kITInstrWithoutNote, // Avoid instrument handling if there is no note kITVolColFinePortamento, // Volume column portamento never does fine portamento kITArpeggio, // IT arpeggio algorithm kITOutOfRangeDelay, // Out-of-range delay command behaviour in IT kITPortaMemoryShare, // Gxx shares memory with Exx and Fxx kITPatternLoopTargetReset, // After finishing a pattern loop, set the pattern loop target to the next row kITFT2PatternLoop, // Nested pattern loop behaviour kITPingPongNoReset, // Don't reset ping pong direction with instrument numbers kITEnvelopeReset, // IT envelope reset behaviour kITClearOldNoteAfterCut, // Forget the previous note after cutting it kITVibratoTremoloPanbrello, // More IT-like Hxx / hx, Rxx, Yxx and autovibrato handling, including more precise LUTs kITTremor, // Ixx behaves like in IT kITRetrigger, // Qxx behaves like in IT kITMultiSampleBehaviour, // Properly update C-5 frequency when changing in multisampled instrument kITPortaTargetReached, // Clear portamento target after it has been reached kITPatternLoopBreak, // Don't reset loop count on pattern break. kITOffset, // IT-style Oxx edge case handling kITSwingBehaviour, // IT's swing behaviour kITNNAReset, // NNA is reset on every note change, not every instrument change kITSCxStopsSample, // SCx really stops the sample and does not just mute it kITEnvelopePositionHandling, // IT-style envelope position advance + enable/disable behaviour kITPortamentoInstrument, // No sample changes during portamento with Compatible Gxx enabled, instrument envelope reset with portamento kITPingPongMode, // Don't repeat last sample point in ping pong loop, like IT's software mixer kITRealNoteMapping, // Use triggered note rather than translated note for PPS and other effects kITHighOffsetNoRetrig, // SAx should not apply an offset effect to a note next to it kITFilterBehaviour, // User IT's filter coefficients (unless extended filter range is used) kITNoSurroundPan, // Panning and surround are mutually exclusive kITShortSampleRetrig, // Don't retrigger already stopped channels kITPortaNoNote, // Don't apply any portamento if no previous note is playing kITFT2DontResetNoteOffOnPorta, // Only reset note-off status on portamento in IT Compatible Gxx mode kITVolColMemory, // IT volume column effects share their memory with the effect column kITPortamentoSwapResetsPos, // Portamento with sample swap plays the new sample from the beginning kITEmptyNoteMapSlot, // IT ignores instrument note map entries with no note completely kITFirstTickHandling, // IT-style first tick handling kITSampleAndHoldPanbrello, // IT-style sample&hold panbrello waveform kITClearPortaTarget, // New notes reset portamento target in IT kITPanbrelloHold, // Don't reset panbrello effect until next note or panning effect kITPanningReset, // Sample and instrument panning is only applied on note change, not instrument change kITPatternLoopWithJumpsOld, // Bxx on the same row as SBx terminates the loop in IT (old implementation of kITPatternLoopWithJumps) kITInstrWithNoteOff, // Instrument number with note-off recalls default volume kFT2Arpeggio, // FT2 arpeggio algorithm kFT2Retrigger, // Rxx behaves like in FT2 kFT2VolColVibrato, // Vibrato depth in volume column does not actually execute the vibrato effect kFT2PortaNoNote, // Don't play portamento-ed note if no previous note is playing kFT2KeyOff, // FT2-style Kxx handling kFT2PanSlide, // Volume-column pan slides should be handled like fine slides kFT2ST3OffsetOutOfRange, // Offset past sample end stops the note kFT2RestrictXCommand, // Don't allow MPT extensions to Xxx command in XM kFT2RetrigWithNoteDelay, // Retrigger envelopes if there is a note delay with no note kFT2SetPanEnvPos, // Lxx only sets the pan env position if the volume envelope's sustain flag is set kFT2PortaIgnoreInstr, // Portamento plus instrument number applies the volume settings of the new sample, but not the new sample itself. kFT2VolColMemory, // No volume column memory in FT2 kFT2LoopE60Restart, // Next pattern starts on the same row as the last E60 command kFT2ProcessSilentChannels, // Keep processing silent channels for later 3xx pickup kFT2ReloadSampleSettings, // Reload sample settings even if a note-off is placed next to an instrument number kFT2PortaDelay, // Portamento with note delay next to it is ignored in FT2 kFT2Transpose, // Out-of-range transposed notes in FT2 kFT2PatternLoopWithJumps, // Bxx or Dxx on the same row as E6x terminates the loop in FT2 kFT2PortaTargetNoReset, // Portamento target is not reset with new notes in FT2 kFT2EnvelopeEscape, // FT2 sustain point at end of envelope kFT2Tremor, // Txx behaves like in FT2 kFT2OutOfRangeDelay, // Out-of-range delay command behaviour in FT2 kFT2Periods, // Use FT2's broken period handling kFT2PanWithDelayedNoteOff, // Pan command with delayed note-off kFT2VolColDelay, // FT2-style volume column handling if there is a note delay kFT2FinetunePrecision, // Only take the upper 4 bits of sample finetune. kST3NoMutedChannels, // Don't process any effects on muted S3M channels kST3EffectMemory, // Most effects share the same memory in ST3 kST3PortaSampleChange, // Portamento plus instrument number applies the volume settings of the new sample, but not the new sample itself (GUS behaviour). kST3VibratoMemory, // Do not remember vibrato type in effect memory kST3LimitPeriod, // Cut note instead of limiting final period (ModPlug Tracker style) KST3PortaAfterArpeggio, // Portamento after arpeggio continues at the note where the arpeggio left off kMODOneShotLoops, // Allow ProTracker-like oneshot loops kMODIgnorePanning, // Do not process any panning commands kMODSampleSwap, // On-the-fly sample swapping kFT2NoteOffFlags, // Set and reset the correct fade/key-off flags with note-off and instrument number after note-off kITMultiSampleInstrumentNumber, // After portamento to different sample within multi-sampled instrument, lone instrument numbers in patterns always recall the new sample's default settings kRowDelayWithNoteDelay, // Retrigger note delays on every reptition of a row kFT2MODTremoloRampWaveform, // FT2-/ProTracker-compatible tremolo ramp down / triangle waveform kFT2PortaUpDownMemory, // Portamento up and down have separate memory kMODOutOfRangeNoteDelay, // ProTracker behaviour for out-of-range note delays kMODTempoOnSecondTick, // ProTracker sets tempo after the first tick kFT2PanSustainRelease, // If the sustain point of a panning envelope is reached before key-off, FT2 does not escape it anymore kLegacyReleaseNode, // Legacy release node volume processing kOPLBeatingOscillators, // Emulate beating FM oscillators from CDFM / Composer 670 kST3OffsetWithoutInstrument, // Note without instrument uses same offset as previous note kReleaseNodePastSustainBug, // OpenMPT 1.23.01.02 / r4009 broke release nodes past the sustain point, fixed in OpenMPT 1.28 kFT2NoteDelayWithoutInstr, // Sometime between OpenMPT 1.18.03.00 and 1.19.01.00, delayed instrument-less notes in XM started recalling the default sample volume and panning kOPLFlexibleNoteOff, // Full control after note-off over OPL voices, ^^^ sends note cut instead of just note-off kITInstrWithNoteOffOldEffects, // Instrument number with note-off recalls default volume - special cases with Old Effects enabled kMIDIVolumeOnNoteOffBug, // Update MIDI channel volume on note-off (legacy bug emulation) kITDoNotOverrideChannelPan, // Sample / instrument pan does not override channel pan for following samples / instruments that are not panned kITPatternLoopWithJumps, // Bxx right of SBx terminates the loop in IT kITDCTBehaviour, // DCT="Sample" requires sample instrument, DCT="Note" checks old pattern note against new pattern note (previously was checking old pattern note against new translated note) kOPLwithNNA, // NNA note-off / fade are applied to OPL channels kST3RetrigAfterNoteCut, // Qxy does not retrigger note after it has been cut with ^^^ or SCx kST3SampleSwap, // On-the-fly sample swapping (SoundBlaster behaviour) kOPLRealRetrig, // Retrigger effect (Qxy) restarts OPL notes kOPLNoResetAtEnvelopeEnd, // Do not reset OPL channel status at end of envelope (OpenMPT 1.28 inconsistency with samples) kOPLNoteStopWith0Hz, // Set note frequency to 0 Hz to "stop" OPL notes kOPLNoteOffOnNoteChange, // Send note-off events for old note on every note change kFT2PortaResetDirection, // Reset portamento direction when reaching portamento target from below kApplyUpperPeriodLimit, // Enforce m_nMaxPeriod kApplyOffsetWithoutNote, // Offset commands even work when there's no note next to them (e.g. DMF, MDL, PLM formats) kITPitchPanSeparation, // Pitch/Pan Separation can be overridden by panning commands (this also fixes a bug where any "special" notes affect PPS) kImprecisePingPongLoops, // Use old (less precise) ping-pong overshoot calculation kPluginIgnoreTonePortamento, // Use old tone portamento behaviour for plugins (XM: no plugin pitch slides with commands E1x/E2x/X1x/X2x) kST3TonePortaWithAdlibNote, // Adlib note next to tone portamento is delayed until next row kITResetFilterOnPortaSmpChange, // Filter is reset on portamento if sample is swapped kITInitialNoteMemory, // Initial "last note memory" for each channel is C-0 and not "no note" kPluginDefaultProgramAndBank1, // Default program and bank is set to 1 for plugins, so if an instrument is set to either of those, the program / bank change event is not sent to the plugin kITNoSustainOnPortamento, // Do not re-enable sustain loop on portamento, even when switching between samples kITEmptyNoteMapSlotIgnoreCell, // IT ignores the entire pattern cell when trying to play an unmapped note of an instrument kITOffsetWithInstrNumber, // IT applies offset commands even if just an instrument number without note is present kContinueSampleWithoutInstr, // FTM: A note without instrument number continues looped samples with the new pitch instead of retriggering them kMIDINotesFromChannelPlugin, // Behaviour before OpenMPT 1.26: Channel plugin can be used to send MIDI notes kITDoublePortamentoSlides, // IT only reads parameters once per row, so if two commands sharing effect parameters are found in the two effect columns, they influence each other kS3MIgnoreCombinedFineSlides, // S3M commands Kxy and Lxy ignore fine slides kFT2AutoVibratoAbortSweep, // Key-off before auto-vibrato sweep-in is complete resets auto-vibrato depth kLegacyPPQpos, // Report fake PPQ position to VST plugins kLegacyPluginNNABehaviour, // Plugin notes with NNA=continue are affected by note-offs etc. kITCarryAfterNoteOff, // Envelope Carry continues to function as normal even after note-off kFT2OffsetMemoryRequiresNote, // Offset memory is only updated when offset command is next to a note kITNoteCutWithPorta, // Note Cut (SCx) resets note frequency and interacts with tone portamento with row delay // Add new play behaviours here. kMaxPlayBehaviours, }; // Tempo swing determines how much every row in modern tempo mode contributes to a beat. class TempoSwing : public std::vector { public: static constexpr uint32 Unity = 1u << 24; // Normalize the tempo swing coefficients so that they add up to exactly the specified tempo again void Normalize(); void resize(size_type newSize, value_type val = Unity) { std::vector::resize(newSize, val); Normalize(); } static void Serialize(std::ostream &oStrm, const TempoSwing &swing); static void Deserialize(std::istream &iStrm, TempoSwing &swing, const size_t); }; // Sample position and sample position increment value struct SamplePosition { using value_t = int64; using unsigned_value_t = uint64; protected: value_t v = 0; public: static constexpr uint32 fractMax = 0xFFFFFFFFu; MPT_CONSTEXPRINLINE SamplePosition() { } MPT_CONSTEXPRINLINE explicit SamplePosition(value_t pos) : v(pos) { } MPT_CONSTEXPRINLINE SamplePosition(int32 intPart, uint32 fractPart) : v((static_cast(intPart) * (1ll << 32)) | fractPart) { } static SamplePosition Ratio(uint32 dividend, uint32 divisor) { return SamplePosition((static_cast(dividend) << 32) / divisor); } static SamplePosition FromDouble(double pos) { return SamplePosition(static_cast(pos * 4294967296.0)); } double ToDouble() const { return static_cast(v) / 4294967296.0; } // Set integer and fractional part MPT_CONSTEXPRINLINE SamplePosition &Set(int32 intPart, uint32 fractPart = 0) { v = (static_cast(intPart) << 32) | fractPart; return *this; } // Set integer part, keep fractional part MPT_CONSTEXPRINLINE SamplePosition &SetInt(int32 intPart) { v = (static_cast(intPart) << 32) | GetFract(); return *this; } // Get integer part (as sample length / position) MPT_CONSTEXPRINLINE SmpLength GetUInt() const { return static_cast(static_cast(v) >> 32); } // Get integer part MPT_CONSTEXPRINLINE int32 GetInt() const { return static_cast(static_cast(v) >> 32); } // Get fractional part MPT_CONSTEXPRINLINE uint32 GetFract() const { return static_cast(v); } // Get the inverted fractional part MPT_CONSTEXPRINLINE SamplePosition GetInvertedFract() const { return SamplePosition(0x100000000ll - GetFract()); } // Get the raw fixed-point value MPT_CONSTEXPRINLINE int64 GetRaw() const { return v; } // Negate the current value MPT_CONSTEXPRINLINE SamplePosition &Negate() { v = -v; return *this; } // Multiply and divide by given integer scalars MPT_CONSTEXPRINLINE SamplePosition &MulDiv(uint32 mul, uint32 div) { v = (v * mul) / div; return *this; } // Removes the integer part, only keeping fractions MPT_CONSTEXPRINLINE SamplePosition &RemoveInt() { v &= fractMax; return *this; } // Check if value is 1.0 MPT_CONSTEXPRINLINE bool IsUnity() const { return v == 0x100000000ll; } // Check if value is 0 MPT_CONSTEXPRINLINE bool IsZero() const { return v == 0; } // Check if value is > 0 MPT_CONSTEXPRINLINE bool IsPositive() const { return v > 0; } // Check if value is < 0 MPT_CONSTEXPRINLINE bool IsNegative() const { return v < 0; } // Addition / subtraction of another fixed-point number SamplePosition operator+ (const SamplePosition &other) const { return SamplePosition(v + other.v); } SamplePosition operator- (const SamplePosition &other) const { return SamplePosition(v - other.v); } void operator+= (const SamplePosition &other) { v += other.v; } void operator-= (const SamplePosition &other) { v -= other.v; } // Multiplication with integer scalar template SamplePosition operator* (T other) const { return SamplePosition(static_cast(v * other)); } template void operator*= (T other) { v = static_cast(v *other); } // Division by other fractional point number; returns scalar value_t operator/ (SamplePosition other) const { return v / other.v; } // Division by scalar; returns fractional point number SamplePosition operator/ (int div) const { return SamplePosition(v / div); } MPT_CONSTEXPRINLINE bool operator==(const SamplePosition &other) const { return v == other.v; } MPT_CONSTEXPRINLINE bool operator!=(const SamplePosition &other) const { return v != other.v; } MPT_CONSTEXPRINLINE bool operator<=(const SamplePosition &other) const { return v <= other.v; } MPT_CONSTEXPRINLINE bool operator>=(const SamplePosition &other) const { return v >= other.v; } MPT_CONSTEXPRINLINE bool operator<(const SamplePosition &other) const { return v < other.v; } MPT_CONSTEXPRINLINE bool operator>(const SamplePosition &other) const { return v > other.v; } }; // Aaaand another fixed-point type, e.g. used for fractional tempos // Note that this doesn't use classical bit shifting for the fixed point part. // This is mostly for the clarity of stored values and to be able to represent any value .0000 to .9999 properly. // For easier debugging, use the Debugger Visualizers available in build/vs/debug/ // to easily display the stored values. template struct FPInt { protected: T v; MPT_CONSTEXPRINLINE FPInt(T rawValue) : v(rawValue) { } public: enum : T { fractFact = static_cast(FFact) }; using store_t = T; MPT_CONSTEXPRINLINE FPInt() : v(0) { } MPT_CONSTEXPRINLINE FPInt(T intPart, T fractPart) : v((intPart * fractFact) + (fractPart % fractFact)) { } explicit MPT_CONSTEXPRINLINE FPInt(float f) : v(mpt::saturate_round(f * float(fractFact))) { } explicit MPT_CONSTEXPRINLINE FPInt(double f) : v(mpt::saturate_round(f * double(fractFact))) { } // Set integer and fractional part MPT_CONSTEXPRINLINE FPInt &Set(T intPart, T fractPart = 0) { v = (intPart * fractFact) + (fractPart % fractFact); return *this; } // Set raw internal representation directly MPT_CONSTEXPRINLINE FPInt &SetRaw(T value) { v = value; return *this; } // Retrieve the integer part of the stored value MPT_CONSTEXPRINLINE T GetInt() const { return v / fractFact; } // Retrieve the fractional part of the stored value MPT_CONSTEXPRINLINE T GetFract() const { return v % fractFact; } // Retrieve the raw internal representation of the stored value MPT_CONSTEXPRINLINE T GetRaw() const { return v; } // Formats the stored value as a floating-point value MPT_CONSTEXPRINLINE double ToDouble() const { return v / double(fractFact); } MPT_CONSTEXPRINLINE friend FPInt operator+ (const FPInt &a, const FPInt &b) noexcept { return FPInt(a.v + b.v); } MPT_CONSTEXPRINLINE friend FPInt operator- (const FPInt &a, const FPInt &b) noexcept { return FPInt(a.v - b.v); } MPT_CONSTEXPRINLINE FPInt operator+= (const FPInt &other) noexcept { v += other.v; return *this; } MPT_CONSTEXPRINLINE FPInt operator-= (const FPInt &other) noexcept { v -= other.v; return *this; } MPT_CONSTEXPRINLINE friend bool operator== (const FPInt &a, const FPInt &b) noexcept { return a.v == b.v; } MPT_CONSTEXPRINLINE friend bool operator!= (const FPInt &a, const FPInt &b) noexcept { return a.v != b.v; } MPT_CONSTEXPRINLINE friend bool operator<= (const FPInt &a, const FPInt &b) noexcept { return a.v <= b.v; } MPT_CONSTEXPRINLINE friend bool operator>= (const FPInt &a, const FPInt &b) noexcept { return a.v >= b.v; } MPT_CONSTEXPRINLINE friend bool operator< (const FPInt &a, const FPInt &b) noexcept { return a.v < b.v; } MPT_CONSTEXPRINLINE friend bool operator> (const FPInt &a, const FPInt &b) noexcept { return a.v > b.v; } }; using TEMPO = FPInt<10000, uint32>; using OPLPatch = std::array; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MixerSettings.h0000644000175000017500000000276314052666041021067 00000000000000/* * MixerSettings.h * --------------- * Purpose: A struct containing settings for the mixer of soundlib. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" OPENMPT_NAMESPACE_BEGIN struct MixerSettings { int32 m_nStereoSeparation; enum : int32 { StereoSeparationScale = 128 }; uint32 m_nMaxMixChannels; uint32 DSPMask; uint32 MixerFlags; uint32 gdwMixingFreq; uint32 gnChannels; uint32 m_nPreAmp; std::size_t NumInputChannels; int32 VolumeRampUpMicroseconds; int32 VolumeRampDownMicroseconds; int32 GetVolumeRampUpMicroseconds() const { return VolumeRampUpMicroseconds; } int32 GetVolumeRampDownMicroseconds() const { return VolumeRampDownMicroseconds; } void SetVolumeRampUpMicroseconds(int32 rampUpMicroseconds) { VolumeRampUpMicroseconds = rampUpMicroseconds; } void SetVolumeRampDownMicroseconds(int32 rampDownMicroseconds) { VolumeRampDownMicroseconds = rampDownMicroseconds; } int32 GetVolumeRampUpSamples() const; int32 GetVolumeRampDownSamples() const; void SetVolumeRampUpSamples(int32 rampUpSamples); void SetVolumeRampDownSamples(int32 rampDownSamples); bool IsValid() const { return (gdwMixingFreq > 0) && (gnChannels == 1 || gnChannels == 2 || gnChannels == 4) && (NumInputChannels == 0 || NumInputChannels == 1 || NumInputChannels == 2 || NumInputChannels == 4); } MixerSettings(); }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_etx.cpp0000644000175000017500000001126314704715777020366 00000000000000/* * Load_etx.cpp * ------------ * Purpose: EasyTrax (ETX) module loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" OPENMPT_NAMESPACE_BEGIN struct ETXFileHeader { char magic[14]; // 'EASYTRAX 1.0\x01\x00' uint8 tempo; uint8 lastPattern; uint32le orderlistOffset; uint32le patternsOffset; uint32le sampleHeadersOffset; uint32le sampleDataOffset; bool IsValid() const { return !memcmp(magic, "EASYTRAX 1.0\x01\x00", 14) && tempo > 0 && lastPattern <= 127 && orderlistOffset >= 32 && orderlistOffset < 0x80'0000 && patternsOffset >= 32 && patternsOffset < 0x80'0000 && sampleHeadersOffset >= 32 && sampleHeadersOffset < 0x80'0000 && sampleDataOffset >= 32 && sampleDataOffset < 0x80'0000; } uint32 GetHeaderMinimumAdditionalSize() const { return 1024; // Order list } }; MPT_BINARY_STRUCT(ETXFileHeader, 32) struct ETXSampleHeader { char name[13]; uint32le offset; // Relative to fileHeader.sampleDataOffset uint32le length; uint32le loopStart; // 0xFFFFFFFF if no loop uint32le sampleRate; int8 transpose; int8 finetune; uint8 zero; void ConvertToMPT(ModSample &mptSmp) const { mptSmp.Initialize(); mptSmp.nC5Speed = sampleRate; mptSmp.nLength = length; if(loopStart != uint32_max) { mptSmp.nLoopStart = loopStart; mptSmp.nLoopEnd = mptSmp.nLength; mptSmp.uFlags.set(CHN_LOOP); } mptSmp.Transpose((transpose * 100 + finetune) / 1200.0); } }; MPT_BINARY_STRUCT(ETXSampleHeader, 32) CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderETX(MemoryFileReader file, const uint64 *pfilesize) { ETXFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); } bool CSoundFile::ReadETX(FileReader &file, ModLoadingFlags loadFlags) { ETXFileHeader fileHeader; file.Rewind(); if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) return false; if(!file.CanRead(fileHeader.GetHeaderMinimumAdditionalSize())) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_S3M, 4); m_SongFlags.set(SONG_IMPORTED); m_playBehaviour.reset(kST3EffectMemory); m_nMinPeriod = 218; // Highest possible sample playback rate appears to be 65535 Hz m_nSamples = 128; Order().SetDefaultTempoInt(fileHeader.tempo); Order().SetDefaultSpeed(6); if(!file.Seek(fileHeader.orderlistOffset)) return false; ReadOrderFromFile(Order(), file, 1024, 0xFF); for(ORDERINDEX ord = 0; ord < Order().size(); ord++) { if(Order()[ord] == PATTERNINDEX_INVALID) Order().resize(ord); else if(Order()[ord] > 127) return false; } if(!file.Seek(fileHeader.patternsOffset)) return false; Patterns.ResizeArray(fileHeader.lastPattern + 1); for(PATTERNINDEX pat = 0; pat < Patterns.Size(); pat++) { if(!(loadFlags & loadPatternData) || !file.CanRead(1024) || !Patterns.Insert(pat, 64)) break; auto m = Patterns[pat].begin(); for(ROWINDEX row = 0; row < Patterns[pat].GetNumRows(); row++) { for(CHANNELINDEX chn = 0; chn < 4; chn++, m++) { const auto [note, vol, instr, unused] = file.ReadArray(); MPT_UNUSED_VARIABLE(unused); if(note == 0xFF && !chn) { if(!Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(std::max(row, ROWINDEX(1)) - 1))) { Patterns[pat].Resize(row, false); break; } } else if(note == 0xFE) { m->SetEffectCommand(CMD_VOLUMEDOWN_ETX, vol); } else if(note > 0 && note <= 96) { m->note = NOTE_MIDDLEC - 24 + note; m->instr = instr + 1; m->SetVolumeCommand(VOLCMD_VOLUME, static_cast((std::min(vol, uint8(127)) + 1u) / 2u)); } } } } if(!file.Seek(fileHeader.sampleHeadersOffset)) return false; FileReader sampleHeaderChunk = file.ReadChunk(128 * sizeof(ETXSampleHeader)); for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { ETXSampleHeader sampleHeader; sampleHeaderChunk.ReadStruct(sampleHeader); sampleHeader.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name); if(loadFlags & loadSampleData) { if(!file.Seek(fileHeader.sampleDataOffset + sampleHeader.offset)) return false; SampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::unsignedPCM) .ReadSample(Samples[smp], file); } } m_modFormat.formatName = UL_("EasyTrax"); m_modFormat.type = UL_("etx"); m_modFormat.charset = mpt::Charset::CP437; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_puma.cpp0000644000175000017500000004155314630721373020520 00000000000000/* * Load_puma.cpp * ------------- * Purpose: PumaTracker module loader * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "InstrumentSynth.h" OPENMPT_NAMESPACE_BEGIN struct PumaPlaylistEntry { struct Entry { uint8 pattern; int8 instrTranspose; int8 noteTranspose; }; std::array channels; uint8 speed; uint8 zero; bool IsValid() const { for(const auto &chn : channels) { if(chn.pattern >= 128) return false; if((chn.noteTranspose & 1) || (chn.noteTranspose < -48 || chn.noteTranspose > 48)) return false; } return speed <= 15 && !zero; } }; MPT_BINARY_STRUCT(PumaPlaylistEntry, 14) struct PumaFileHeader { char songName[12]; uint16be lastOrder; // "LoopTrack" in GUI uint16be numPatterns; uint16be numInstruments; uint16be unknown; uint32be sampleOffset[10]; uint16be sampleLength[10]; // in words bool IsValid() const { for(int8 c : songName) { if(c != 0 && c < ' ') return false; } if(lastOrder > 255 || !numPatterns || numPatterns > 128 || !numInstruments || numInstruments > 32 || unknown) return false; const auto minSampleOffset = sizeof(PumaFileHeader) + GetHeaderMinimumAdditionalSize(); for(uint32 i = 0; i < 10; i++) { if(sampleLength[i] > 0 && !sampleOffset[i]) return false; if(sampleOffset[i] > 0x10'0000) return false; if(sampleOffset[i] > 0 && sampleOffset[i] < minSampleOffset) return false; } return true; } ORDERINDEX NumOrders() const { return lastOrder + 1; } uint32 GetHeaderMinimumAdditionalSize() const { return NumOrders() * static_cast(sizeof(PumaPlaylistEntry)) + numPatterns * 8 + 4 + numInstruments * 16 + 4; } }; MPT_BINARY_STRUCT(PumaFileHeader, 80) static bool TranslatePumaScript(InstrumentSynth::Events &events, ModInstrument &instr, FileReader &file, bool isVolume) { bool isFirst = true; while(file.CanRead(4)) { const auto data = file.ReadArray(); if(isFirst && isVolume && data[0] != 0xC0) return false; switch(data[0]) { case 0xA0: // Volume ramp / pitch ramp if(isVolume) events.push_back(InstrumentSynth::Event::Puma_VolumeRamp(std::min(data[1], uint8(64)), std::min(data[2], uint8(64)), data[3])); else events.push_back(InstrumentSynth::Event::Puma_PitchRamp(static_cast(data[1]), static_cast(data[2]), data[3])); break; case 0xB0: // Jump if(data[1] & 3) return false; events.push_back(InstrumentSynth::Event::Jump(data[1] / 4u)); return true; case 0xC0: // Set waveform / - if(isVolume) events.push_back(InstrumentSynth::Event::Puma_SetWaveform(data[1], data[2], data[3])); else return false; if(isFirst) instr.AssignSample(data[1] + 1); break; case 0xD0: // - / Set pitch // Odd values can be entered in the editor but playback will freeze if((data[1] & 1) || isVolume) return false; events.push_back(InstrumentSynth::Event::Puma_SetPitch(static_cast(data[1]), data[3])); break; case 0xE0: // Stop sound / End of script if(isVolume) events.push_back(InstrumentSynth::Event::Puma_StopVoice()); else events.push_back(InstrumentSynth::Event::StopScript()); return true; default: if(!isVolume && !memcmp(data.data(), "inst", 4)) { // vimto-02.puma has insf chunks that only consist of a single D0 00 00 01 file.SkipBack(4); return !events.empty(); } return false; } isFirst = false; } return !events.empty(); } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPuma(MemoryFileReader file, const uint64 *pfilesize) { PumaFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) return ProbeWantMoreData; if(!fileHeader.IsValid()) return ProbeFailure; const size_t probeOrders = std::min(static_cast(fileHeader.NumOrders()), (ProbeRecommendedSize - sizeof(fileHeader)) / sizeof(PumaPlaylistEntry)); for(size_t ord = 0; ord < probeOrders; ord++) { PumaPlaylistEntry entry; if(!file.ReadStruct(entry)) return ProbeWantMoreData; if(!entry.IsValid()) return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize() - probeOrders * sizeof(PumaPlaylistEntry)); } bool CSoundFile::ReadPuma(FileReader &file, ModLoadingFlags loadFlags) { PumaFileHeader fileHeader; file.Rewind(); if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) return false; if(!file.CanRead(fileHeader.GetHeaderMinimumAdditionalSize())) return false; if(loadFlags == onlyVerifyHeader) return true; InitializeGlobals(MOD_TYPE_MOD, 4); SetupMODPanning(true); m_SongFlags.set(SONG_IMPORTED | SONG_ISAMIGA | SONG_FASTPORTAS); m_nSamples = 52; m_nInstruments = fileHeader.numInstruments; m_playBehaviour.set(kMODSampleSwap); m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songName); const ORDERINDEX numOrders = fileHeader.NumOrders(); std::vector orderData; file.ReadVector(orderData, numOrders); static constexpr ROWINDEX numRows = 32; std::vector, numRows>> patternData(fileHeader.numPatterns); for(auto &pattern : patternData) { if(!file.ReadMagic("patt")) return false; size_t row = 0; while(row < pattern.size() && file.CanRead(4)) { const auto data = file.ReadArray(); if(data[0] & 1) return false; if(!data[3] || data[3] > pattern.size() - row) return false; pattern[row] = {data[0], data[1], data[2]}; row += data[3]; } } if(!file.ReadMagic("patt")) return false; Order().resize(numOrders); if(loadFlags & loadPatternData) Patterns.ResizeArray(numOrders); for(ORDERINDEX ord = 0; ord < numOrders; ord++) { if(!orderData[ord].IsValid()) return false; if(!(loadFlags & loadPatternData) || !Patterns.Insert(ord, numRows)) continue; Order()[ord] = ord; for(CHANNELINDEX chn = 0; chn < 4; chn++) { const auto &chnInfo = orderData[ord].channels[chn]; if(chnInfo.pattern >= patternData.size()) continue; ModCommand *m = Patterns[ord].GetpModCommand(0, chn); // Auto-portmentos appear to stop on pattern transitions and revert to the note's original pitch. VolumeCommand autoPorta = VOLCMD_NONE; for(const auto &p : patternData[chnInfo.pattern]) { if(p[0]) m->note = static_cast(NOTE_MIDDLEC - 49 + (p[0] + chnInfo.noteTranspose) / 2); if(uint8 instr = (p[1] & 0x1F); instr != 0) m->instr = (instr + chnInfo.instrTranspose) & 0x1F; if(!m->instr && m->note != NOTE_NONE) m->instr = 99; m->param = p[2]; switch(p[1] >> 5) { case 1: m->command = CMD_VOLUME; break; case 2: autoPorta = m->param ? VOLCMD_PORTADOWN : VOLCMD_NONE; if(autoPorta != VOLCMD_NONE) m->command = CMD_PORTAMENTODOWN; break; case 3: autoPorta = m->param ? VOLCMD_PORTAUP : VOLCMD_NONE; if(autoPorta != VOLCMD_NONE) m->command = CMD_PORTAMENTOUP; break; } if(m->command != CMD_PORTAMENTOUP && m->command != CMD_PORTAMENTODOWN) { if(m->note != NOTE_NONE) autoPorta = VOLCMD_NONE; else if(autoPorta != VOLCMD_NONE) m->volcmd = autoPorta; } m += GetNumChannels(); } } if(orderData[ord].speed) Patterns[ord].WriteEffect(EffectWriter(CMD_SPEED, orderData[ord].speed).RetryNextRow()); } for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++) { if(!file.ReadMagic("inst")) return false; ModInstrument *instr = AllocateInstrument(ins); if(!instr) return false; instr->synth.m_scripts.resize(2); if(!TranslatePumaScript(instr->synth.m_scripts[0], *instr, file, true)) return false; if(!file.ReadMagic("insf")) return false; if(!TranslatePumaScript(instr->synth.m_scripts[1], *instr, file, false)) return false; } if(!file.ReadMagic("inst")) return false; SampleIO sampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM); for(SAMPLEINDEX smp = 0; smp < 10; smp++) { if(!fileHeader.sampleLength[smp]) continue; if(!file.Seek(fileHeader.sampleOffset[smp])) return false; ModSample &mptSmp = Samples[smp + 1]; mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.nLength = fileHeader.sampleLength[smp] * 2; sampleIO.ReadSample(mptSmp, file); } static constexpr std::array SampleData[] = { {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0x3F, 0x37, 0x2F, 0x27, 0x1F, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0x37, 0x2F, 0x27, 0x1F, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0x2F, 0x27, 0x1F, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0x27, 0x1F, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0x1F, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x17, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x0F, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x07, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0xFF, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x17, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x98, 0x1F, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x98, 0xA0, 0x27, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x98, 0xA0, 0xA8, 0x2F, 0x37}, {0xC0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0xF8, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0, 0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80, 0x88, 0x90, 0x98, 0xA0, 0xA8, 0xB0, 0x37}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F, 0x7F}, {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7F, 0x7F, 0x7F}, {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F}, {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F}, {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F}, {0x80, 0x80, 0x90, 0x98, 0xA0, 0xA8, 0xB0, 0xB8, 0xC0, 0xC8, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8, 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x7F}, {0x80, 0x80, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x45, 0x45, 0x79, 0x7D, 0x7A, 0x77, 0x70, 0x66, 0x61, 0x58, 0x53, 0x4D, 0x2C, 0x20, 0x18, 0x12}, {0x04, 0xDB, 0xD3, 0xCD, 0xC6, 0xBC, 0xB5, 0xAE, 0xA8, 0xA3, 0x9D, 0x99, 0x93, 0x8E, 0x8B, 0x8A, 0x45, 0x45, 0x79, 0x7D, 0x7A, 0x77, 0x70, 0x66, 0x5B, 0x4B, 0x43, 0x37, 0x2C, 0x20, 0x18, 0x12}, {0x04, 0xF8, 0xE8, 0xDB, 0xCF, 0xC6, 0xBE, 0xB0, 0xA8, 0xA4, 0x9E, 0x9A, 0x95, 0x94, 0x8D, 0x83, 0x00, 0x00, 0x40, 0x60, 0x7F, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0xA0, 0xC0, 0xE0}, {0x00, 0x00, 0x40, 0x60, 0x7F, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0xA0, 0xC0, 0xE0, 0x80, 0x80, 0x90, 0x98, 0xA0, 0xA8, 0xB0, 0xB8, 0xC0, 0xC8, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0, 0xF8}, {0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x7F, 0x80, 0x80, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70}, }; for(SAMPLEINDEX smp = 0; smp < 42; smp++) { ModSample &mptSmp = Samples[smp + 11]; mptSmp.Initialize(MOD_TYPE_MOD); mptSmp.nLength = 32; mptSmp.nLoopStart = 0; mptSmp.nLoopEnd = 32; mptSmp.uFlags.set(CHN_LOOP); FileReader smpFile{mpt::as_span(SampleData[smp])}; sampleIO.ReadSample(mptSmp, smpFile); } m_modFormat.formatName = UL_("Puma Tracker"); m_modFormat.type = UL_("puma"); m_modFormat.madeWithTracker = UL_("Puma Tracker"); m_modFormat.charset = mpt::Charset::Amiga_no_C1; return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ITCompression.cpp0000644000175000017500000002520414723305050021341 00000000000000/* * ITCompression.cpp * ----------------- * Purpose: Code for IT sample compression and decompression. * Notes : The original Python compression code was written by GreaseMonkey and has been released into the public domain. * Authors: OpenMPT Devs * Ben "GreaseMonkey" Russell * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "ITCompression.h" #include "ModSample.h" #include "SampleCopy.h" #include "../common/misc_util.h" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include OPENMPT_NAMESPACE_BEGIN // Algorithm parameters for 16-Bit samples struct IT16BitParams { using sample_t = int16; static constexpr int16 lowerTab[] = {0, -1, -3, -7, -15, -31, -56, -120, -248, -504, -1016, -2040, -4088, -8184, -16376, -32760, -32768}; static constexpr int16 upperTab[] = {0, 1, 3, 7, 15, 31, 55, 119, 247, 503, 1015, 2039, 4087, 8183, 16375, 32759, 32767}; static constexpr int8 fetchA = 4; static constexpr int8 lowerB = -8; static constexpr int8 upperB = 7; static constexpr int8 defWidth = 17; static constexpr int mask = 0xFFFF; }; // Algorithm parameters for 8-Bit samples struct IT8BitParams { using sample_t = int8; static constexpr int8 lowerTab[] = {0, -1, -3, -7, -15, -31, -60, -124, -128}; static constexpr int8 upperTab[] = {0, 1, 3, 7, 15, 31, 59, 123, 127}; static constexpr int8 fetchA = 3; static constexpr int8 lowerB = -4; static constexpr int8 upperB = 3; static constexpr int8 defWidth = 9; static constexpr int mask = 0xFF; }; static constexpr int8 ITWidthChangeSize[] = { 4, 5, 6, 7, 8, 9, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; ////////////////////////////////////////////////////////////////////////////// // IT 2.14 compression ITCompression::ITCompression(const ModSample &sample, bool it215, std::ostream *f, SmpLength maxLength) : file(f) , mptSample(sample) , is215(it215) { if(mptSample.GetElementarySampleSize() > 1) Compress(mptSample.sample16(), maxLength); else Compress(mptSample.sample8(), maxLength); } template void ITCompression::Compress(const typename Properties::sample_t *mptSampleData, SmpLength maxLength) { packedData.resize(bufferSize); std::vector sampleData; sampleData.resize(blockSize / sizeof(typename Properties::sample_t)); if(maxLength == 0 || maxLength > mptSample.nLength) maxLength = mptSample.nLength; for(uint8 chn = 0; chn < mptSample.GetNumChannels(); chn++) { SmpLength offset = 0; SmpLength remain = maxLength; while(remain > 0) { // Initialise output buffer and bit writer positions packedLength = 2; bitPos = 0; remBits = 8; byteVal = 0; CompressBlock(mptSampleData + chn, offset, remain, sampleData.data()); if(file) mpt::IO::WriteRaw(*file, packedData.data(), packedLength); packedTotalLength += packedLength; offset += baseLength; remain -= baseLength; } } packedData.resize(0); packedData.shrink_to_fit(); } template void ITCompression::CopySample(T *target, const T *source, SmpLength offset, SmpLength length, SmpLength skip) { T *out = target; const T *in = source + offset * skip; for(SmpLength i = 0, j = 0; j < length; i += skip, j++) { out[j] = in[i]; } } // Convert sample to delta values. template void ITCompression::Deltafy(T *sampleData) { T *p = sampleData; int oldVal = 0; for(SmpLength i = 0; i < baseLength; i++) { int newVal = p[i]; p[i] = static_cast(newVal - oldVal); oldVal = newVal; } } template void ITCompression::CompressBlock(const typename Properties::sample_t *data, SmpLength offset, SmpLength actualLength, typename Properties::sample_t *sampleData) { baseLength = std::min(actualLength, SmpLength(blockSize / sizeof(typename Properties::sample_t))); CopySample(sampleData, data, offset, baseLength, mptSample.GetNumChannels()); Deltafy(sampleData); if(is215) { Deltafy(sampleData); } // Initialise bit width table with initial values bwt.assign(baseLength, Properties::defWidth); // Recurse! SquishRecurse(Properties::defWidth, Properties::defWidth, Properties::defWidth, Properties::defWidth - 2, 0, baseLength, sampleData); // Write those bits! const typename Properties::sample_t *p = sampleData; int8 width = Properties::defWidth; for(size_t i = 0; i < baseLength; i++) { if(bwt[i] != width) { MPT_ASSERT(width >= 0); if(width <= 6) { // Mode A: 1 to 6 bits MPT_ASSERT(width != 0); WriteBits(width, (1 << (width - 1))); WriteBits(Properties::fetchA, ConvertWidth(width, bwt[i])); } else if(width < Properties::defWidth) { // Mode B: 7 to 8 / 16 bits int xv = (1 << (width - 1)) + Properties::lowerB + ConvertWidth(width, bwt[i]); WriteBits(width, xv); } else { // Mode C: 9 / 17 bits MPT_ASSERT((bwt[i] - 1) >= 0); WriteBits(width, (1 << (width - 1)) + bwt[i] - 1); } width = bwt[i]; } WriteBits(width, static_cast(p[i]) & Properties::mask); } // Write last byte and update block length WriteByte(byteVal); packedData[0] = static_cast((packedLength - 2) & 0xFF); packedData[1] = static_cast((packedLength - 2) >> 8); } int8 ITCompression::GetWidthChangeSize(int8 w, bool is16) { MPT_ASSERT(w > 0 && static_cast(w) <= std::size(ITWidthChangeSize)); // cppcheck false-positive // cppcheck-suppress negativeIndex int8 wcs = ITWidthChangeSize[w - 1]; if(w <= 6 && is16) wcs++; return wcs; } template void ITCompression::SquishRecurse(int8 sWidth, int8 lWidth, int8 rWidth, int8 width, SmpLength offset, SmpLength length, const typename Properties::sample_t *sampleData) { if(width + 1 < 1) { for(SmpLength i = offset; i < offset + length; i++) bwt[i] = sWidth; return; } MPT_ASSERT(width >= 0 && static_cast(width) < std::size(Properties::lowerTab)); SmpLength i = offset; SmpLength end = offset + length; const typename Properties::sample_t *p = sampleData; while(i < end) { if(p[i] >= Properties::lowerTab[width] && p[i] <= Properties::upperTab[width]) { SmpLength start = i; // Check for how long we can keep this bit width while(i < end && p[i] >= Properties::lowerTab[width] && p[i] <= Properties::upperTab[width]) { i++; } const SmpLength blockLength = i - start; const int8 xlwidth = start == offset ? lWidth : sWidth; const int8 xrwidth = i == end ? rWidth : sWidth; const bool is16 = sizeof(typename Properties::sample_t) > 1; const int8 wcsl = GetWidthChangeSize(xlwidth, is16); const int8 wcss = GetWidthChangeSize(sWidth, is16); const int8 wcsw = GetWidthChangeSize(width + 1, is16); bool comparison; if(i == baseLength) { SmpLength keepDown = wcsl + (width + 1) * blockLength; SmpLength levelLeft = wcsl + sWidth * blockLength; if(xlwidth == sWidth) levelLeft -= wcsl; comparison = (keepDown <= levelLeft); } else { SmpLength keepDown = wcsl + (width + 1) * blockLength + wcsw; SmpLength levelLeft = wcsl + sWidth * blockLength + wcss; if(xlwidth == sWidth) levelLeft -= wcsl; if(xrwidth == sWidth) levelLeft -= wcss; comparison = (keepDown <= levelLeft); } SquishRecurse(comparison ? (width + 1) : sWidth, xlwidth, xrwidth, width - 1, start, blockLength, sampleData); } else { bwt[i] = sWidth; i++; } } } int8 ITCompression::ConvertWidth(int8 curWidth, int8 newWidth) { curWidth--; newWidth--; MPT_ASSERT(newWidth != curWidth); if(newWidth > curWidth) newWidth--; return newWidth; } void ITCompression::WriteBits(int8 width, int v) { while(width > remBits) { byteVal |= static_cast(v << bitPos); width -= remBits; v >>= remBits; bitPos = 0; remBits = 8; WriteByte(byteVal); byteVal = 0; } if(width > 0) { byteVal |= static_cast((v & ((1 << width) - 1)) << bitPos); remBits -= width; bitPos += width; } } void ITCompression::WriteByte(uint8 v) { if(packedLength < bufferSize) { packedData[packedLength++] = v; } else { // How could this happen, anyway? MPT_ASSERT_NOTREACHED(); } } ////////////////////////////////////////////////////////////////////////////// // IT 2.14 decompression ITDecompression::ITDecompression(FileReader &file, ModSample &sample, bool it215) : mptSample(sample) , is215(it215) { for(uint8 chn = 0; chn < mptSample.GetNumChannels(); chn++) { writtenSamples = writePos = 0; while(writtenSamples < sample.nLength && file.CanRead(sizeof(uint16))) { uint16 compressedSize = file.ReadUint16LE(); if(!compressedSize) continue; // Malformed sample? bitFile = file.ReadChunk(compressedSize); // Initialise bit reader mem1 = mem2 = 0; try { if(mptSample.GetElementarySampleSize() > 1) Uncompress(mptSample.sample16() + chn); else Uncompress(mptSample.sample8() + chn); } catch(const BitReader::eof &) { // Data is not sufficient to decode the block //AddToLog(LogWarning, "Truncated IT sample block"); } } } } template void ITDecompression::Uncompress(typename Properties::sample_t *target) { curLength = std::min(mptSample.nLength - writtenSamples, SmpLength(ITCompression::blockSize / sizeof(typename Properties::sample_t))); int width = Properties::defWidth; while(curLength > 0) { if(width > Properties::defWidth) { // Error! return; } int v = bitFile.ReadBits(width); const int topBit = (1 << (width - 1)); if(width <= 6) { // Mode A: 1 to 6 bits if(v == topBit) ChangeWidth(width, bitFile.ReadBits(Properties::fetchA)); else Write(v, topBit, target); } else if(width < Properties::defWidth) { // Mode B: 7 to 8 / 16 bits if(v >= topBit + Properties::lowerB && v <= topBit + Properties::upperB) ChangeWidth(width, v - (topBit + Properties::lowerB)); else Write(v, topBit, target); } else { // Mode C: 9 / 17 bits if(v & topBit) width = (v & ~topBit) + 1; else Write((v & ~topBit), 0, target); } } } void ITDecompression::ChangeWidth(int &curWidth, int width) { width++; if(width >= curWidth) width++; curWidth = width; } template void ITDecompression::Write(int v, int topBit, typename Properties::sample_t *target) { if(v & topBit) v -= (topBit << 1); mem1 += v; mem2 += mem1; target[writePos] = static_cast(static_cast(is215 ? mem2 : mem1)); writtenSamples++; writePos += mptSample.GetNumChannels(); curLength--; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ITCompression.h0000644000175000017500000000671514474332757021035 00000000000000/* * ITCompression.h * --------------- * Purpose: Code for IT sample compression and decompression. * Notes : The original Python compression code was written by GreaseMonkey and has been released into the public domain. * Authors: OpenMPT Devs * Ben "GreaseMonkey" Russell * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include #include #include "Snd_defs.h" #include "BitReader.h" OPENMPT_NAMESPACE_BEGIN struct ModSample; class ITCompression { public: ITCompression(const ModSample &sample, bool it215, std::ostream *f, SmpLength maxLength = 0); size_t GetCompressedSize() const { return packedTotalLength; } static constexpr size_t bufferSize = 2 + 0xFFFF; // Our output buffer can't be longer than this. static constexpr size_t blockSize = 0x8000; // Block size (in bytes) in which samples are being processed protected: std::vector bwt; // Bit width table for each sampling point std::vector packedData; // Compressed data for current sample block std::ostream *file = nullptr; // File to which compressed data will be written (can be nullptr if you only want to find out the sample size) const ModSample &mptSample; // Sample that is being processed size_t packedLength = 0; // Size of currently compressed sample block size_t packedTotalLength = 0; // Size of all compressed data so far SmpLength baseLength = 0; // Length of the currently compressed sample block (in samples) // Bit writer int8 bitPos = 0; // Current bit position in this byte int8 remBits = 0; // Remaining bits in this byte uint8 byteVal = 0; // Current byte value to be written const bool is215; // Use IT2.15 compression (double deltas) template void Compress(const typename Properties::sample_t *mptSampleData, SmpLength maxLength); template static void CopySample(T *target, const T *source, SmpLength offset, SmpLength length, SmpLength skip); template void Deltafy(T *sampleData); template void CompressBlock(const typename Properties::sample_t *data, SmpLength offset, SmpLength actualLength, typename Properties::sample_t *sampleData); static int8 GetWidthChangeSize(int8 w, bool is16); template void SquishRecurse(int8 sWidth, int8 lWidth, int8 rWidth, int8 width, SmpLength offset, SmpLength length, const typename Properties::sample_t *sampleData); static int8 ConvertWidth(int8 curWidth, int8 newWidth); void WriteBits(int8 width, int v); void WriteByte(uint8 v); }; class ITDecompression { public: ITDecompression(FileReader &file, ModSample &sample, bool it215); protected: BitReader bitFile; ModSample &mptSample; // Sample that is being processed SmpLength writtenSamples = 0; // Number of samples so far written on this channel SmpLength writePos = 0; // Absolut write position in sample (for stereo samples) SmpLength curLength = 0; // Length of currently processed block unsigned int mem1 = 0, mem2 = 0; // Integrator memory const bool is215; // Use IT2.15 compression (double deltas) template void Uncompress(typename Properties::sample_t *target); static void ChangeWidth(int &curWidth, int width); template void Write(int v, int topbit, typename Properties::sample_t *target); }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ITTools.cpp0000644000175000017500000005151615020413412020136 00000000000000/* * ITTools.cpp * ----------- * Purpose: Definition of IT file structures and helper functions * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "ITTools.h" #include "Loaders.h" #include "Tables.h" #include "../common/mptStringBuffer.h" #include "../common/version.h" OPENMPT_NAMESPACE_BEGIN // Convert OpenMPT's internal envelope format into an IT/MPTM envelope. void ITEnvelope::ConvertToIT(const InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 envDefault) { // Envelope Flags if(mptEnv.dwFlags[ENV_ENABLED]) flags |= ITEnvelope::envEnabled; if(mptEnv.dwFlags[ENV_LOOP]) flags |= ITEnvelope::envLoop; if(mptEnv.dwFlags[ENV_SUSTAIN]) flags |= ITEnvelope::envSustain; if(mptEnv.dwFlags[ENV_CARRY]) flags |= ITEnvelope::envCarry; // Nodes and Loops num = (uint8)std::min(mptEnv.size(), uint32(25)); lpb = (uint8)mptEnv.nLoopStart; lpe = (uint8)mptEnv.nLoopEnd; slb = (uint8)mptEnv.nSustainStart; sle = (uint8)mptEnv.nSustainEnd; // Envelope Data MemsetZero(data); if(!mptEnv.empty()) { // Attention: Full MPTM envelope is stored in extended instrument properties for(uint32 ev = 0; ev < num; ev++) { data[ev].value = static_cast(static_cast(mptEnv[ev].value) - envOffset); data[ev].tick = mptEnv[ev].tick; } } else { // Fix non-existing envelopes so that they can still be edited in Impulse Tracker. num = 2; data[0].value = data[1].value = static_cast(envDefault - envOffset); data[1].tick = 10; } } // Convert IT/MPTM envelope data into OpenMPT's internal envelope format - To be used by ITInstrToMPT() void ITEnvelope::ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 maxNodes) const { // Envelope Flags mptEnv.dwFlags.set(ENV_ENABLED, (flags & ITEnvelope::envEnabled) != 0); mptEnv.dwFlags.set(ENV_LOOP, (flags & ITEnvelope::envLoop) != 0); mptEnv.dwFlags.set(ENV_SUSTAIN, (flags & ITEnvelope::envSustain) != 0); mptEnv.dwFlags.set(ENV_CARRY, (flags & ITEnvelope::envCarry) != 0); // Nodes and Loops mptEnv.resize(std::min(num, maxNodes)); mptEnv.nLoopStart = std::min(lpb, maxNodes); mptEnv.nLoopEnd = Clamp(lpe, mptEnv.nLoopStart, maxNodes); mptEnv.nSustainStart = std::min(slb, maxNodes); mptEnv.nSustainEnd = Clamp(sle, mptEnv.nSustainStart, maxNodes); // Envelope Data // Attention: Full MPTM envelope is stored in extended instrument properties for(uint32 ev = 0; ev < std::min(uint8(25), num); ev++) { mptEnv[ev].value = Clamp(static_cast(data[ev].value + envOffset), 0, 64); mptEnv[ev].tick = data[ev].tick; if(ev > 0 && mptEnv[ev].tick < mptEnv[ev - 1].tick && !(mptEnv[ev].tick & 0xFF00)) { // Fix broken envelopes... Instruments 2 and 3 in NoGap.it by Werewolf have envelope points where the high byte of envelope nodes is missing. // NoGap.it was saved with MPT 1.07 - 1.09, which *normally* doesn't do this in IT files. // However... It turns out that MPT 1.07 omitted the high byte of envelope nodes when saving an XI instrument file, and it looks like // Instrument 2 and 3 in NoGap.it were loaded from XI files. mptEnv[ev].tick |= static_cast(mptEnv[ev - 1].tick & 0xFF00u); if(mptEnv[ev].tick < mptEnv[ev - 1].tick) mptEnv[ev].tick += 0x100; } } } // Convert an ITOldInstrument to OpenMPT's internal instrument representation. void ITOldInstrument::ConvertToMPT(ModInstrument &mptIns) const { // Header if(memcmp(id, "IMPI", 4)) { return; } mptIns.name = mpt::String::ReadBuf(mpt::String::spacePadded, name); mptIns.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename); // Volume / Panning mptIns.nFadeOut = fadeout << 6; mptIns.nGlobalVol = 64; mptIns.nPan = 128; // NNA Stuff mptIns.nNNA = static_cast(nna.get()); mptIns.nDCT = static_cast(dnc.get()); // Sample Map for(size_t i = 0; i < 120; i++) { uint8 note = keyboard[i * 2]; SAMPLEINDEX ins = keyboard[i * 2 + 1]; if(ins < MAX_SAMPLES) { mptIns.Keyboard[i] = ins; } if(note < 120) { mptIns.NoteMap[i] = note + 1u; } else { mptIns.NoteMap[i] = static_cast(i + 1); } } // Volume Envelope Flags mptIns.VolEnv.dwFlags.set(ENV_ENABLED, (flags & ITOldInstrument::envEnabled) != 0); mptIns.VolEnv.dwFlags.set(ENV_LOOP, (flags & ITOldInstrument::envLoop) != 0); mptIns.VolEnv.dwFlags.set(ENV_SUSTAIN, (flags & ITOldInstrument::envSustain) != 0); // Volume Envelope Loops mptIns.VolEnv.nLoopStart = vls; mptIns.VolEnv.nLoopEnd = vle; mptIns.VolEnv.nSustainStart = sls; mptIns.VolEnv.nSustainEnd = sle; mptIns.VolEnv.resize(25); // Volume Envelope Data for(uint32 i = 0; i < 25; i++) { if((mptIns.VolEnv[i].tick = nodes[i * 2]) == 0xFF) { mptIns.VolEnv.resize(i); break; } mptIns.VolEnv[i].value = nodes[i * 2 + 1]; } if(std::max(mptIns.VolEnv.nLoopStart, mptIns.VolEnv.nLoopEnd) >= mptIns.VolEnv.size()) mptIns.VolEnv.dwFlags.reset(ENV_LOOP); if(std::max(mptIns.VolEnv.nSustainStart, mptIns.VolEnv.nSustainEnd) >= mptIns.VolEnv.size()) mptIns.VolEnv.dwFlags.reset(ENV_SUSTAIN); } // Convert OpenMPT's internal instrument representation to an ITInstrument. uint32 ITInstrument::ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile) { MemsetZero(*this); // Header memcpy(id, "IMPI", 4); trkvers = 0x5000 | static_cast(Version::Current().GetRawVersion() >> 16); mpt::String::WriteBuf(mpt::String::nullTerminated, filename) = mptIns.filename; mpt::String::WriteBuf(mpt::String::nullTerminated, name) = mptIns.name; // Volume / Panning fadeout = static_cast(std::min(mptIns.nFadeOut >> 5, uint32(256))); gbv = static_cast(std::min(mptIns.nGlobalVol * 2u, uint32(128))); dfp = static_cast(std::min(mptIns.nPan / 4u, uint32(64))); if(!mptIns.dwFlags[INS_SETPANNING]) dfp |= ITInstrument::ignorePanning; // Random Variation rv = std::min(mptIns.nVolSwing, uint8(100)); rp = std::min(mptIns.nPanSwing, uint8(64)); // NNA Stuff nna = static_cast(mptIns.nNNA); dct = static_cast((mptIns.nDCT < DuplicateCheckType::Plugin || !compatExport) ? mptIns.nDCT : DuplicateCheckType::None); dca = static_cast(mptIns.nDNA); // Pitch / Pan Separation pps = mptIns.nPPS; ppc = mptIns.nPPC; // Filter Stuff ifc = mptIns.GetCutoff() | (mptIns.IsCutoffEnabled() ? ITInstrument::enableCutoff : 0x00); ifr = mptIns.GetResonance() | (mptIns.IsResonanceEnabled() ? ITInstrument::enableResonance : 0x00); // MIDI Setup if(mptIns.nMidiProgram > 0) mpr = static_cast(mptIns.nMidiProgram - 1u); else mpr = 0xFF; if(mptIns.wMidiBank > 0) { mbank[0] = static_cast((mptIns.wMidiBank - 1) & 0x7F); mbank[1] = static_cast((mptIns.wMidiBank - 1) >> 7); } else { mbank[0] = 0xFF; mbank[1] = 0xFF; } if(mptIns.nMidiChannel != MidiNoChannel || mptIns.nMixPlug == 0 || mptIns.nMixPlug > 127 || compatExport) { // Default. Prefer MIDI channel over mixplug to keep the semantics intact. mch = mptIns.nMidiChannel; } else { // Keep compatibility with MPT 1.16's instrument format if possible, as XMPlay / BASS also uses this. mch = mptIns.nMixPlug + 128; } // Sample Map nos = 0; // Only really relevant for ITI files std::vector smpCount(sndFile.GetNumSamples(), false); for(int i = 0; i < 120; i++) { keyboard[i * 2] = (mptIns.NoteMap[i] >= NOTE_MIN && mptIns.NoteMap[i] <= NOTE_MIN + 119) ? (mptIns.NoteMap[i] - NOTE_MIN) : static_cast(i); const SAMPLEINDEX smp = mptIns.Keyboard[i]; if(smp < MAX_SAMPLES && smp < 256) { keyboard[i * 2 + 1] = static_cast(smp); if(smp && smp <= sndFile.GetNumSamples() && !smpCount[smp - 1]) { // We haven't considered this sample yet. Update number of samples. smpCount[smp - 1] = true; nos++; } } } // Writing Volume envelope volenv.ConvertToIT(mptIns.VolEnv, 0, 64); // Writing Panning envelope panenv.ConvertToIT(mptIns.PanEnv, 32, 32); // Writing Pitch Envelope pitchenv.ConvertToIT(mptIns.PitchEnv, 32, 32); if(mptIns.PitchEnv.dwFlags[ENV_FILTER]) pitchenv.flags |= ITEnvelope::envFilter; return sizeof(ITInstrument); } // Convert an ITInstrument to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read. uint32 ITInstrument::ConvertToMPT(ModInstrument &mptIns, MODTYPE modFormat) const { if(memcmp(id, "IMPI", 4)) { return 0; } mptIns.name = mpt::String::ReadBuf(mpt::String::spacePadded, name); mptIns.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename); // Volume / Panning mptIns.nFadeOut = fadeout << 5; mptIns.nGlobalVol = gbv / 2; LimitMax(mptIns.nGlobalVol, 64u); mptIns.nPan = (dfp & 0x7F) * 4; if(mptIns.nPan > 256) mptIns.nPan = 128; mptIns.dwFlags.set(INS_SETPANNING, !(dfp & ITInstrument::ignorePanning)); // Random Variation mptIns.nVolSwing = std::min(static_cast(rv), uint8(100)); mptIns.nPanSwing = std::min(static_cast(rp), uint8(64)); // NNA Stuff mptIns.nNNA = static_cast(nna.get()); mptIns.nDCT = static_cast(dct.get()); mptIns.nDNA = static_cast(dca.get()); // Pitch / Pan Separation mptIns.nPPS = pps; mptIns.nPPC = ppc; // Filter Stuff mptIns.SetCutoff(ifc & 0x7F, (ifc & ITInstrument::enableCutoff) != 0); mptIns.SetResonance(ifr & 0x7F, (ifr & ITInstrument::enableResonance) != 0); // MIDI Setup // MPT used to have a slightly different encoding of MIDI program and banks which we are trying to fix here. // Impulse Tracker / Schism Tracker will set trkvers to 0 in IT files, // and we won't care about correctly importing MIDI programs and banks in ITI files. // Chibi Tracker sets trkvers to 0x214, but always writes mpr=mbank=0 anyway. // Old BeRoTracker versions set trkvers to 0x214 or 0x217. // <= MPT 1.07 <= MPT 1.16 OpenMPT 1.17-? <= OpenMPT 1.26 definitely not MPT if((trkvers == 0x0202 || trkvers == 0x0211 || trkvers == 0x0220 || trkvers == 0x0214) && mpr != 0xFF) { if(mpr <= 128) { mptIns.nMidiProgram = mpr; } uint16 bank = mbank[0] | (mbank[1] << 8); // These versions also ignored the high bank nibble (was only handled correctly in OpenMPT instrument extensions) if(bank <= 128) { mptIns.wMidiBank = bank; } } else { if(mpr < 128) { mptIns.nMidiProgram = mpr + 1; } uint16 bank = 0; if(mbank[0] < 128) bank = mbank[0] + 1; if(mbank[1] < 128) bank += static_cast(mbank[1] << 7); mptIns.wMidiBank = bank; } mptIns.nMidiChannel = mch; if(mptIns.nMidiChannel >= 128) { // Handle old format where MIDI channel and Plugin index are stored in the same variable mptIns.nMixPlug = mptIns.nMidiChannel - 128; mptIns.nMidiChannel = 0; } // Envelope point count. Limited to 25 in IT format. const uint8 maxNodes = (modFormat & MOD_TYPE_MPT) ? MAX_ENVPOINTS : 25; // Volume Envelope volenv.ConvertToMPT(mptIns.VolEnv, 0, maxNodes); // Panning Envelope panenv.ConvertToMPT(mptIns.PanEnv, 32, maxNodes); // Pitch Envelope pitchenv.ConvertToMPT(mptIns.PitchEnv, 32, maxNodes); mptIns.PitchEnv.dwFlags.set(ENV_FILTER, (pitchenv.flags & ITEnvelope::envFilter) != 0); // Sample Map for(int i = 0; i < 120; i++) { uint8 note = keyboard[i * 2]; SAMPLEINDEX ins = keyboard[i * 2 + 1]; if(ins < MAX_SAMPLES) { mptIns.Keyboard[i] = ins; } if(note < 120) { mptIns.NoteMap[i] = note + NOTE_MIN; } else { mptIns.NoteMap[i] = static_cast(i + NOTE_MIN); } } return sizeof(ITInstrument); } // Convert OpenMPT's internal instrument representation to an ITInstrumentEx. Returns amount of bytes that need to be written to file. uint32 ITInstrumentEx::ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile) { uint32 instSize = iti.ConvertToIT(mptIns, compatExport, sndFile); if(compatExport) { return instSize; } // Sample Map bool usedExtension = false; iti.nos = 0; std::vector smpCount(sndFile.GetNumSamples(), false); for(int i = 0; i < 120; i++) { const SAMPLEINDEX smp = mptIns.Keyboard[i]; keyboardhi[i] = 0; if(smp < MAX_SAMPLES) { if(smp >= 256) { // We need to save the upper byte for this sample index. iti.keyboard[i * 2 + 1] = static_cast(smp & 0xFF); keyboardhi[i] = static_cast(smp >> 8); usedExtension = true; } if(smp && smp <= sndFile.GetNumSamples() && !smpCount[smp - 1]) { // We haven't considered this sample yet. Update number of samples. smpCount[smp - 1] = true; iti.nos++; } } } if(usedExtension) { // If we actually had to extend the sample map, update the magic bytes and instrument size. memcpy(iti.dummy, "XTPM", 4); instSize = sizeof(ITInstrumentEx); } return instSize; } // Convert an ITInstrumentEx to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read. uint32 ITInstrumentEx::ConvertToMPT(ModInstrument &mptIns, MODTYPE fromType) const { uint32 insSize = iti.ConvertToMPT(mptIns, fromType); // Is this actually an extended instrument? // Note: OpenMPT 1.20 - 1.22 accidentally wrote "MPTX" here (since revision 1203), while previous versions wrote the reversed version, "XTPM". if(insSize == 0 || (memcmp(iti.dummy, "MPTX", 4) && memcmp(iti.dummy, "XTPM", 4))) { return insSize; } // Olivier's MPT Instrument Extension for(int i = 0; i < 120; i++) { mptIns.Keyboard[i] |= ((SAMPLEINDEX)keyboardhi[i] << 8); } return sizeof(ITInstrumentEx); } // Convert OpenMPT's internal sample representation to an ITSample. void ITSample::ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compress, bool compressIT215, bool allowExternal) { MemsetZero(*this); // Header memcpy(id, "IMPS", 4); mpt::String::WriteBuf(mpt::String::nullTerminated, filename) = mptSmp.filename; //mpt::String::WriteBuf(mpt::String::nullTerminated, name) = m_szNames[nsmp]; // Volume / Panning gvl = static_cast(mptSmp.nGlobalVol); vol = static_cast(mptSmp.nVolume / 4); dfp = static_cast(mptSmp.nPan / 4); if(mptSmp.uFlags[CHN_PANNING]) dfp |= ITSample::enablePanning; // Sample Format / Loop Flags if(mptSmp.HasSampleData() && !mptSmp.uFlags[CHN_ADLIB]) { flags = ITSample::sampleDataPresent; if(mptSmp.uFlags[CHN_LOOP]) flags |= ITSample::sampleLoop; if(mptSmp.uFlags[CHN_SUSTAINLOOP]) flags |= ITSample::sampleSustain; if(mptSmp.uFlags[CHN_PINGPONGLOOP]) flags |= ITSample::sampleBidiLoop; if(mptSmp.uFlags[CHN_PINGPONGSUSTAIN]) flags |= ITSample::sampleBidiSustain; if(mptSmp.uFlags[CHN_STEREO]) { flags |= ITSample::sampleStereo; } if(mptSmp.uFlags[CHN_16BIT]) { flags |= ITSample::sample16Bit; } cvt = ITSample::cvtSignedSample; if(compress) { flags |= ITSample::sampleCompressed; if(compressIT215) { cvt |= ITSample::cvtDelta; } } } else { flags = 0x00; } // Frequency C5Speed = mptSmp.nC5Speed ? mptSmp.nC5Speed : 8363; // Size and loops length = mpt::saturate_cast(mptSmp.nLength); loopbegin = mpt::saturate_cast(mptSmp.nLoopStart); loopend = mpt::saturate_cast(mptSmp.nLoopEnd); susloopbegin = mpt::saturate_cast(mptSmp.nSustainStart); susloopend = mpt::saturate_cast(mptSmp.nSustainEnd); // Auto Vibrato settings vit = AutoVibratoXM2IT[mptSmp.nVibType & 7]; vis = std::min(mptSmp.nVibRate, uint8(64)); vid = std::min(mptSmp.nVibDepth, uint8(32)); vir = std::min(mptSmp.nVibSweep, uint8(255)); if((vid | vis) != 0 && (fromType & MOD_TYPE_XM)) { // Sweep is upside down in XM if(mptSmp.nVibSweep != 0) vir = mpt::saturate_cast(Util::muldivr_unsigned(mptSmp.nVibDepth, 256, mptSmp.nVibSweep)); else vir = 255; } if(mptSmp.uFlags[CHN_ADLIB]) { length = 12; flags = ITSample::sampleDataPresent; cvt = ITSample::cvtOPLInstrument; } else if(mptSmp.uFlags[SMP_KEEPONDISK]) { // Save external sample (filename at sample pointer) if(mptSmp.HasSampleData()) { #if !defined(MPT_EXTERNAL_SAMPLES) allowExternal = false; #endif // MPT_EXTERNAL_SAMPLES if(allowExternal) cvt = ITSample::cvtExternalSample; } else { length = loopbegin = loopend = susloopbegin = susloopend = 0; } } } // Convert an ITSample to OpenMPT's internal sample representation. uint32 ITSample::ConvertToMPT(ModSample &mptSmp) const { // IT does not check for the IMPS magic, and some bad XM->IT converter out there doesn't write the magic bytes for empty sample slots. //if(memcmp(id, "IMPS", 4)) // return 0; mptSmp.Initialize(MOD_TYPE_IT); mptSmp.SetDefaultCuePoints(); // For old IT/MPTM files mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename); // Volume / Panning mptSmp.nVolume = vol * 4; LimitMax(mptSmp.nVolume, uint16(256)); mptSmp.nGlobalVol = gvl; LimitMax(mptSmp.nGlobalVol, uint16(64)); mptSmp.nPan = (dfp & 0x7F) * 4; LimitMax(mptSmp.nPan, uint16(256)); if(dfp & ITSample::enablePanning) mptSmp.uFlags.set(CHN_PANNING); // Loop Flags if(flags & ITSample::sampleLoop) mptSmp.uFlags.set(CHN_LOOP); if(flags & ITSample::sampleSustain) mptSmp.uFlags.set(CHN_SUSTAINLOOP); if(flags & ITSample::sampleBidiLoop) mptSmp.uFlags.set(CHN_PINGPONGLOOP); if(flags & ITSample::sampleBidiSustain) mptSmp.uFlags.set(CHN_PINGPONGSUSTAIN); // Frequency mptSmp.nC5Speed = C5Speed; if(!mptSmp.nC5Speed) mptSmp.nC5Speed = 8363; if(mptSmp.nC5Speed < 256) mptSmp.nC5Speed = 256; // Size and loops mptSmp.nLength = length; mptSmp.nLoopStart = loopbegin; mptSmp.nLoopEnd = loopend; mptSmp.nSustainStart = susloopbegin; mptSmp.nSustainEnd = susloopend; mptSmp.SanitizeLoops(); // Auto Vibrato settings mptSmp.nVibType = static_cast(AutoVibratoIT2XM[vit & 7]); mptSmp.nVibRate = vis; mptSmp.nVibDepth = vid & 0x7F; mptSmp.nVibSweep = vir; if(cvt == ITSample::cvtOPLInstrument) { // FM instrument in MPTM mptSmp.uFlags.set(CHN_ADLIB); } else if(cvt == ITSample::cvtExternalSample) { // Read external sample (filename at sample pointer) mptSmp.uFlags.set(SMP_KEEPONDISK); } return samplepointer; } // Retrieve the internal sample format flags for this instrument. SampleIO ITSample::GetSampleFormat(uint16 cwtv) const { SampleIO sampleIO( (flags & ITSample::sample16Bit) ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, (cvt & ITSample::cvtSignedSample) ? SampleIO::signedPCM: SampleIO::unsignedPCM); // Some old version of IT didn't clear the stereo flag when importing samples. Luckily, all other trackers are identifying as IT 2.14+, so let's check for old IT versions. if((flags & ITSample::sampleStereo) && cwtv >= 0x214) { sampleIO |= SampleIO::stereoSplit; } if(flags & ITSample::sampleCompressed) { // IT 2.14 packed sample sampleIO |= (cvt & ITSample::cvtDelta) ? SampleIO::IT215 : SampleIO::IT214; } else { // MODPlugin :( if(!(flags & ITSample::sample16Bit) && cvt == ITSample::cvtADPCMSample) { sampleIO |= SampleIO::ADPCM; } else { // ITTECH.TXT says these convert flags are "safe to ignore". IT doesn't ignore them, though, so why should we? :) if(cvt & ITSample::cvtBigEndian) { sampleIO |= SampleIO::bigEndian; } if(cvt & ITSample::cvtDelta) { sampleIO |= SampleIO::deltaPCM; } if((cvt & ITSample::cvtPTM8to16) && (flags & ITSample::sample16Bit)) { sampleIO |= SampleIO::PTM8Dto16; } } } return sampleIO; } // Convert an ITHistoryStruct to OpenMPT's internal edit history representation void ITHistoryStruct::ConvertToMPT(FileHistory &mptHistory) const { // Decode FAT date and time mptHistory.loadDate = mpt::Date::AnyGregorian{}; if(fatdate != 0 || fattime != 0) { mptHistory.loadDate.year = ((fatdate >> 9) & 0x7F) + 1980; mptHistory.loadDate.month = Clamp((fatdate >> 5) & 0x0F, 1, 12); mptHistory.loadDate.day = Clamp(fatdate & 0x1F, 1, 31); mptHistory.loadDate.hours = Clamp((fattime >> 11) & 0x1F, 0, 23); mptHistory.loadDate.minutes = Clamp((fattime >> 5) & 0x3F, 0, 59); mptHistory.loadDate.seconds = Clamp((fattime & 0x1F) * 2, 0, 59); } mptHistory.openTime = static_cast(runtime * (HISTORY_TIMER_PRECISION / 18.2)); } // Convert OpenMPT's internal edit history representation to an ITHistoryStruct void ITHistoryStruct::ConvertToIT(const FileHistory &mptHistory) { // Create FAT file dates if(mptHistory.HasValidDate()) { fatdate = static_cast(mptHistory.loadDate.day | (mptHistory.loadDate.month << 5) | ((mptHistory.loadDate.year - 1980) << 9)); fattime = static_cast((mptHistory.loadDate.seconds / 2) | (mptHistory.loadDate.minutes << 5) | (mptHistory.loadDate.hours << 11)); } else { fatdate = 0; fattime = 0; } runtime = static_cast(mptHistory.openTime * (18.2 / HISTORY_TIMER_PRECISION)); } uint32 DecodeITEditTimer(uint16 cwtv, uint32 editTime) { if((cwtv & 0xFFF) >= 0x0208) { editTime ^= 0x4954524B; // 'ITRK' editTime = mpt::rotr(editTime, 7); editTime = ~editTime + 1; editTime = mpt::rotl(editTime, 4); editTime ^= 0x4A54484C; // 'JTHL' } return editTime; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/RowVisitor.cpp0000644000175000017500000002277614577560356020770 00000000000000/* * RowVisitor.cpp * -------------- * Purpose: Class for recording which rows of a song has already been visited, used for detecting when a module starts to loop. * Notes : The class keeps track of rows that have been visited by the player before. * This way, we can tell when the module starts to loop, i.e. we can determine the song length, * or find out that a given point of the module can never be reached. * * In some module formats, infinite loops can be achieved through pattern loops (e.g. E60 / E61 / E61 in one channel of a ProTracker MOD). * To detect such loops, we store a set of loop counts across all channels encountered for each row. * As soon as a set of loop counts is encountered twice for a specific row, we know that the track ends up in an infinite loop. * As a result of this design, it is safe to evaluate pattern loops in CSoundFile::GetLength. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "RowVisitor.h" #include "Sndfile.h" OPENMPT_NAMESPACE_BEGIN RowVisitor::LoopState::LoopState(const ChannelStates &chnState, const bool ignoreRow) { // Rather than storing the exact loop count vector, we compute an FNV-1a 64-bit hash of it. // This means we can store the loop state in a small and fixed amount of memory. // In theory there is the possibility of hash collisions for different loop states, but in practice, // the relevant inputs for the hashing algorithm are extremely unlikely to produce collisions. // There may be better hashing algorithms, but many of them are much more complex and cannot be applied easily in an incremental way. uint64 hash = FNV1a_BASIS; if(ignoreRow) { hash = (hash ^ 0xFFu) * FNV1a_PRIME; #ifdef MPT_VERIFY_ROWVISITOR_LOOPSTATE m_counts.emplace_back(uint8(0xFF), uint8(0xFF)); #endif } for(size_t chn = 0; chn < chnState.size(); chn++) { if(chnState[chn].nPatternLoopCount) { static_assert(MAX_BASECHANNELS <= 256, "Channel index cannot be used as byte input for hash generator"); static_assert(sizeof(chnState[0].nPatternLoopCount) <= sizeof(uint8), "Loop count cannot be used as byte input for hash generator"); hash = (hash ^ chn) * FNV1a_PRIME; hash = (hash ^ chnState[chn].nPatternLoopCount) * FNV1a_PRIME; #ifdef MPT_VERIFY_ROWVISITOR_LOOPSTATE m_counts.emplace_back(static_cast(chn), chnState[chn].nPatternLoopCount); #endif } } m_hash = hash; } RowVisitor::RowVisitor(const CSoundFile &sndFile, SEQUENCEINDEX sequence) : m_sndFile(sndFile) , m_sequence(sequence) { Initialize(true); } void RowVisitor::MoveVisitedRowsFrom(RowVisitor &other) noexcept { m_visitedRows = std::move(other.m_visitedRows); m_visitedLoopStates = std::move(other.m_visitedLoopStates); } const ModSequence &RowVisitor::Order() const { if(m_sequence >= m_sndFile.Order.GetNumSequences()) return m_sndFile.Order(); else return m_sndFile.Order(m_sequence); } // Resize / clear the row vector. // If reset is true, the vector is not only resized to the required dimensions, but also completely cleared (i.e. all visited rows are reset). void RowVisitor::Initialize(bool reset) { auto &order = Order(); const ORDERINDEX endOrder = order.GetLengthTailTrimmed(); bool reserveLoopStates = true; m_visitedRows.resize(endOrder); if(reset) { reserveLoopStates = m_visitedLoopStates.empty(); for(auto &loopState : m_visitedLoopStates) { loopState.second.clear(); } m_rowsSpentInLoops = 0; } std::vector loopCount; std::vector visitedPatterns(m_sndFile.Patterns.GetNumPatterns(), ORDERINDEX_INVALID); for(ORDERINDEX ord = 0; ord < endOrder; ord++) { const PATTERNINDEX pat = order[ord]; const ROWINDEX numRows = VisitedRowsVectorSize(pat); auto &visitedRows = m_visitedRows[ord]; if(reset) visitedRows.assign(numRows, false); else visitedRows.resize(numRows, false); if(!reserveLoopStates || !order.IsValidPat(ord)) continue; const ROWINDEX startRow = std::min(static_cast(reset ? 0 : visitedRows.size()), numRows); auto insertionHint = m_visitedLoopStates.end(); if(visitedPatterns[pat] != ORDERINDEX_INVALID) { // We visited this pattern before, copy over the results const auto begin = m_visitedLoopStates.lower_bound({visitedPatterns[pat], startRow}); const auto end = (begin != m_visitedLoopStates.end()) ? m_visitedLoopStates.lower_bound({visitedPatterns[pat], numRows}) : m_visitedLoopStates.end(); for(auto pos = begin; pos != end; ++pos) { LoopStateSet loopStates; loopStates.reserve(pos->second.capacity()); insertionHint = ++m_visitedLoopStates.insert_or_assign(insertionHint, {ord, pos->first.second}, std::move(loopStates)); } continue; } // Pre-allocate loop count state const auto &pattern = m_sndFile.Patterns[pat]; loopCount.assign(pattern.GetNumChannels(), 0); for(ROWINDEX i = numRows; i != startRow; i--) { const ROWINDEX row = i - 1; uint32 maxLoopStates = 1; auto m = pattern.GetpModCommand(row, 0); // Break condition: If it's more than 16, it's probably wrong :) exact loop count depends on how loops overlap. for(CHANNELINDEX chn = 0; chn < pattern.GetNumChannels() && maxLoopStates < 16; chn++, m++) { auto count = loopCount[chn]; if((m->command == CMD_S3MCMDEX && (m->param & 0xF0) == 0xB0) || (m->command == CMD_MODCMDEX && (m->param & 0xF0) == 0x60)) { loopCount[chn] = (m->param & 0x0F); if(loopCount[chn]) count = loopCount[chn]; } if(count) maxLoopStates *= (count + 1); } if(maxLoopStates > 1) { LoopStateSet loopStates; loopStates.reserve(maxLoopStates); insertionHint = m_visitedLoopStates.insert_or_assign(insertionHint, {ord, row}, std::move(loopStates)); } } // Only use this order as a blueprint for other orders using the same pattern if we fully parsed the pattern. if(startRow == 0) visitedPatterns[pat] = ord; } } // Mark an order/row combination as visited and returns true if it was visited before. bool RowVisitor::Visit(ORDERINDEX ord, ROWINDEX row, const ChannelStates &chnState, bool ignoreRow) { auto &order = Order(); if(ord >= order.size() || row >= VisitedRowsVectorSize(order[ord])) return false; // The module might have been edited in the meantime - so we have to extend this a bit. if(ord >= m_visitedRows.size() || row >= m_visitedRows[ord].size()) { Initialize(false); // If it's still past the end of the vector, this means that ord >= order.GetLengthTailTrimmed(), i.e. we are trying to play an empty order. if(ord >= m_visitedRows.size()) return false; } MPT_ASSERT(chnState.size() >= m_sndFile.GetNumChannels()); LoopState newState{chnState.first(m_sndFile.GetNumChannels()), ignoreRow}; const auto rowLoopState = m_visitedLoopStates.find({ord, row}); const bool oldHadLoops = (rowLoopState != m_visitedLoopStates.end() && !rowLoopState->second.empty()); const bool newHasLoops = newState.HasLoops(); const bool wasVisited = m_visitedRows[ord][row]; // Check if new state is part of row state already. If so, we visited this row already and thus the module must be looping if(!oldHadLoops && !newHasLoops && wasVisited) return true; if(oldHadLoops && mpt::contains(rowLoopState->second, newState)) return true; if(newHasLoops) m_rowsSpentInLoops++; if(oldHadLoops || newHasLoops) { // Convert to set representation if it isn't already if(!oldHadLoops && wasVisited) m_visitedLoopStates[{ord, row}].emplace_back(); m_visitedLoopStates[{ord, row}].emplace_back(std::move(newState)); } m_visitedRows[ord][row] = true; return false; } // Get the needed vector size for a given pattern. ROWINDEX RowVisitor::VisitedRowsVectorSize(PATTERNINDEX pattern) const noexcept { if(m_sndFile.Patterns.IsValidPat(pattern)) return m_sndFile.Patterns[pattern].GetNumRows(); else return 1; // Non-existing patterns consist of a "fake" row. } // Find the first row that has not been played yet. // The order and row is stored in the order and row variables on success, on failure they contain invalid values. // If onlyUnplayedPatterns is true (default), only completely unplayed patterns are considered, otherwise a song can start on any unplayed row. // Function returns true on success. bool RowVisitor::GetFirstUnvisitedRow(ORDERINDEX &ord, ROWINDEX &row, bool onlyUnplayedPatterns) const { const auto &order = Order(); const ORDERINDEX endOrder = order.GetLengthTailTrimmed(); for(ORDERINDEX o = 0; o < endOrder; o++) { if(!order.IsValidPat(o)) continue; if(o >= m_visitedRows.size()) { // Not yet initialized => unvisited ord = o; row = 0; return true; } const auto &visitedRows = m_visitedRows[o]; ROWINDEX firstUnplayedRow = 0; for(; firstUnplayedRow < visitedRows.size(); firstUnplayedRow++) { if(visitedRows[firstUnplayedRow] == onlyUnplayedPatterns) break; } if(onlyUnplayedPatterns && firstUnplayedRow == visitedRows.size()) { // No row of this pattern has been played yet. ord = o; row = 0; return true; } else if(!onlyUnplayedPatterns) { // Return the first unplayed row in this pattern if(firstUnplayedRow < visitedRows.size()) { ord = o; row = firstUnplayedRow; return true; } if(visitedRows.size() < m_sndFile.Patterns[order[o]].GetNumRows()) { // History is not fully initialized ord = o; row = static_cast(visitedRows.size()); return true; } } } // Didn't find anything :( ord = ORDERINDEX_INVALID; row = ROWINDEX_INVALID; return false; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/ContainerXPK.cpp0000644000175000017500000001723114361011347021112 00000000000000/* * ContainerXPK.cpp * ---------------- * Purpose: Handling of XPK compressed modules * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "../common/FileReader.h" #include "Container.h" #include "Sndfile.h" #include OPENMPT_NAMESPACE_BEGIN #if !defined(MPT_WITH_ANCIENT) #ifdef MPT_ALL_LOGGING #define MMCMP_LOG #endif struct XPKFILEHEADER { char XPKF[4]; uint32be SrcLen; char SQSH[4]; uint32be DstLen; char Name[16]; uint32be Reserved; }; MPT_BINARY_STRUCT(XPKFILEHEADER, 36) struct XPK_error : public std::range_error { XPK_error() : std::range_error("invalid XPK data") { } }; struct XPK_BufferBounds { const uint8 *pSrcBeg; std::size_t SrcSize; inline uint8 SrcRead(std::size_t index) { if(index >= SrcSize) throw XPK_error(); return pSrcBeg[index]; } }; static int32 bfextu(std::size_t p, int32 bo, int32 bc, XPK_BufferBounds &bufs) { uint32 r; p += bo / 8; r = bufs.SrcRead(p); p++; r <<= 8; r |= bufs.SrcRead(p); p++; r <<= 8; r |= bufs.SrcRead(p); r <<= bo % 8; r &= 0xffffff; r >>= 24 - bc; return r; } static int32 bfexts(std::size_t p, int32 bo, int32 bc, XPK_BufferBounds &bufs) { uint32 r; p += bo / 8; r = bufs.SrcRead(p); p++; r <<= 8; r |= bufs.SrcRead(p); p++; r <<= 8; r |= bufs.SrcRead(p); r <<= (bo % 8) + 8; return mpt::rshift_signed(static_cast(r), 32 - bc); } static uint8 XPK_ReadTable(int32 index) { static constexpr uint8 xpk_table[] = { 2,3,4,5,6,7,8,0,3,2,4,5,6,7,8,0,4,3,5,2,6,7,8,0,5,4,6,2,3,7,8,0,6,5,7,2,3,4,8,0,7,6,8,2,3,4,5,0,8,7,6,2,3,4,5,0 }; if(index < 0) throw XPK_error(); if(static_cast(index) >= std::size(xpk_table)) throw XPK_error(); // cppcheck false-positive // cppcheck-suppress arrayIndexOutOfBoundsCond return xpk_table[index]; } static bool XPK_DoUnpack(const mpt::const_byte_span src_, std::vector &unpackedData, int32 len) { if(len <= 0) return false; int32 d0,d1,d2,d3,d4,d5,d6,a2,a5; int32 cp, cup1, type; std::size_t c; std::size_t src; std::size_t phist = 0; unpackedData.reserve(std::min(static_cast(len), std::min(mpt::saturate_cast(src_.size()), uint32_max / 20u) * 20u)); XPK_BufferBounds bufs; bufs.pSrcBeg = mpt::byte_cast(src_.data()); bufs.SrcSize = src_.size(); src = 0; c = src; while(len > 0) { type = bufs.SrcRead(c+0); cp = (bufs.SrcRead(c+4)<<8) | (bufs.SrcRead(c+5)); // packed cup1 = (bufs.SrcRead(c+6)<<8) | (bufs.SrcRead(c+7)); // unpacked //Log(" packed=%6d unpacked=%6d bytes left=%d dst=%08X(%d)\n", cp, cup1, len, dst, dst); c += 8; src = c+2; if (type == 0) { // RAW chunk if(cp < 0 || cp > len) throw XPK_error(); for(int32 i = 0; i < cp; ++i) { unpackedData.push_back(bufs.SrcRead(c + i)); } c+=cp; len -= cp; continue; } if (type != 1) { #ifdef MMCMP_LOG MPT_LOG_GLOBAL(LogDebug, "XPK", MPT_UFORMAT("Invalid XPK type! ({} bytes left)")(len)); #endif break; } LimitMax(cup1, len); len -= cup1; cp = (cp + 3) & 0xfffc; c += cp; d0 = d1 = d2 = a2 = 0; d3 = bufs.SrcRead(src); src++; unpackedData.push_back(static_cast(d3)); cup1--; while (cup1 > 0) { if (d1 >= 8) goto l6dc; if (bfextu(src,d0,1,bufs)) goto l75a; d0 += 1; d5 = 0; d6 = 8; goto l734; l6dc: if (bfextu(src,d0,1,bufs)) goto l726; d0 += 1; if (! bfextu(src,d0,1,bufs)) goto l75a; d0 += 1; if (bfextu(src,d0,1,bufs)) goto l6f6; d6 = 2; goto l708; l6f6: d0 += 1; if (!bfextu(src,d0,1,bufs)) goto l706; d6 = bfextu(src,d0,3,bufs); d0 += 3; goto l70a; l706: d6 = 3; l708: d0 += 1; l70a: d6 = XPK_ReadTable((8*a2) + d6 -17); if (d6 != 8) goto l730; l718: if (d2 >= 20) { d5 = 1; goto l732; } d5 = 0; goto l734; l726: d0 += 1; d6 = 8; if (d6 == a2) goto l718; d6 = a2; l730: d5 = 4; l732: d2 += 8; l734: while ((d5 >= 0) && (cup1 > 0)) { d4 = bfexts(src,d0,d6,bufs); d0 += d6; d3 -= d4; unpackedData.push_back(static_cast(d3)); cup1--; d5--; } if (d1 != 31) d1++; a2 = d6; l74c: d6 = d2; d6 >>= 3; d2 -= d6; } } return !unpackedData.empty(); l75a: d0 += 1; if (bfextu(src,d0,1,bufs)) goto l766; d4 = 2; goto l79e; l766: d0 += 1; if (bfextu(src,d0,1,bufs)) goto l772; d4 = 4; goto l79e; l772: d0 += 1; if (bfextu(src,d0,1,bufs)) goto l77e; d4 = 6; goto l79e; l77e: d0 += 1; if (bfextu(src,d0,1,bufs)) goto l792; d0 += 1; d6 = bfextu(src,d0,3,bufs); d0 += 3; d6 += 8; goto l7a8; l792: d0 += 1; d6 = bfextu(src,d0,5,bufs); d0 += 5; d4 = 16; goto l7a6; l79e: d0 += 1; d6 = bfextu(src,d0,1,bufs); d0 += 1; l7a6: d6 += d4; l7a8: if(bfextu(src, d0, 1, bufs)) { d5 = 12; a5 = -0x100; } else { d0 += 1; if(bfextu(src, d0, 1, bufs)) { d5 = 14; a5 = -0x1100; } else { d5 = 8; a5 = 0; } } d0 += 1; d4 = bfextu(src,d0,d5,bufs); d0 += d5; d6 -= 3; if (d6 >= 0) { if (d6 > 0) d1 -= 1; d1 -= 1; if (d1 < 0) d1 = 0; } d6 += 2; phist = unpackedData.size() + a5 - d4 - 1; if(phist >= unpackedData.size()) throw XPK_error(); while ((d6 >= 0) && (cup1 > 0)) { d3 = unpackedData[phist]; phist++; unpackedData.push_back(static_cast(d3)); cup1--; d6--; } goto l74c; } static bool ValidateHeader(const XPKFILEHEADER &header) { if(std::memcmp(header.XPKF, "XPKF", 4) != 0) { return false; } if(std::memcmp(header.SQSH, "SQSH", 4) != 0) { return false; } if(header.SrcLen == 0) { return false; } if(header.DstLen == 0) { return false; } static_assert(sizeof(XPKFILEHEADER) >= 8); if(header.SrcLen < (sizeof(XPKFILEHEADER) - 8)) { return false; } return true; } static bool ValidateHeaderFileSize(const XPKFILEHEADER &header, uint64 filesize) { if(filesize < header.SrcLen - 8) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXPK(MemoryFileReader file, const uint64 *pfilesize) { XPKFILEHEADER header; if(!file.ReadStruct(header)) { return ProbeWantMoreData; } if(!ValidateHeader(header)) { return ProbeFailure; } if(pfilesize) { if(!ValidateHeaderFileSize(header, *pfilesize)) { return ProbeFailure; } } return ProbeSuccess; } bool UnpackXPK(std::vector &containerItems, FileReader &file, ContainerLoadingFlags loadFlags) { file.Rewind(); containerItems.clear(); XPKFILEHEADER header; if(!file.ReadStruct(header)) { return false; } if(!ValidateHeader(header)) { return false; } if(loadFlags == ContainerOnlyVerifyHeader) { return true; } if(!file.CanRead(header.SrcLen - (sizeof(XPKFILEHEADER) - 8))) { return false; } containerItems.emplace_back(); containerItems.back().data_cache = std::make_unique >(); std::vector & unpackedData = *(containerItems.back().data_cache); #ifdef MMCMP_LOG MPT_LOG_GLOBAL(LogDebug, "XPK", MPT_UFORMAT("XPK detected (SrcLen={} DstLen={}) filesize={}")(static_cast(header.SrcLen), static_cast(header.DstLen), file.GetLength())); #endif bool result = false; try { FileReader::PinnedView compressedData = file.GetPinnedView(header.SrcLen - (sizeof(XPKFILEHEADER) - 8)); result = XPK_DoUnpack(compressedData.span(), unpackedData, header.DstLen); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); return false; } catch(const XPK_error &) { return false; } if(result) { containerItems.back().file = FileReader(mpt::byte_cast(mpt::as_span(unpackedData))); } return result; } #endif // !MPT_WITH_ANCIENT OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/SampleFormatOpus.cpp0000644000175000017500000001557114502511125022047 00000000000000/* * SampleFormatOpus.cpp * -------------------- * Purpose: Opus sample import. * Notes : * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Sndfile.h" #ifndef MODPLUG_NO_FILESAVE #include "../common/mptFileIO.h" #endif #include "../common/misc_util.h" #include "Tagging.h" #include "Loaders.h" #include "../common/FileReader.h" #include "modsmp_ctrl.h" #include "openmpt/soundbase/Copy.hpp" #include "../soundlib/ModSampleCopy.h" //#include "mpt/crc/crc.hpp" #include "OggStream.h" #ifdef MPT_WITH_OGG #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif // MPT_COMPILER_CLANG #include #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #endif // MPT_WITH_OGG #if defined(MPT_WITH_OPUSFILE) #include #endif // MPT_WITH_OPUSFILE OPENMPT_NAMESPACE_BEGIN //////////////////////////////////////////////////////////////////////////////// // Opus #if defined(MPT_WITH_OPUSFILE) static int OpusfileFilereaderRead(void *stream, unsigned char *ptr, int nbytes) { FileReader &file = *mpt::void_ptr(stream); return mpt::saturate_cast(file.ReadRaw(mpt::span(mpt::byte_cast(ptr), nbytes)).size()); } static int OpusfileFilereaderSeek(void *stream, opus_int64 offset, int whence) { FileReader &file = *mpt::void_ptr(stream); switch(whence) { case SEEK_SET: { if(!mpt::in_range(offset)) { return -1; } return file.Seek(mpt::saturate_cast(offset)) ? 0 : -1; } break; case SEEK_CUR: { if(offset < 0) { if(offset == std::numeric_limits::min()) { return -1; } if(!mpt::in_range(0-offset)) { return -1; } return file.SkipBack(mpt::saturate_cast(0 - offset)) ? 0 : -1; } else { if(!mpt::in_range(offset)) { return -1; } return file.Skip(mpt::saturate_cast(offset)) ? 0 : -1; } } break; case SEEK_END: { if(!mpt::in_range(offset)) { return -1; } if(!mpt::in_range(file.GetLength() + offset)) { return -1; } return file.Seek(mpt::saturate_cast(file.GetLength() + offset)) ? 0 : -1; } break; default: return -1; } } static opus_int64 OpusfileFilereaderTell(void *stream) { FileReader &file = *mpt::void_ptr(stream); MPT_MAYBE_CONSTANT_IF(!mpt::in_range(file.GetPosition())) { return -1; } return static_cast(file.GetPosition()); } static mpt::ustring UStringFromOpus(const char *str) { return str ? mpt::ToUnicode(mpt::Charset::UTF8, str) : mpt::ustring(); } static FileTags GetOpusFileTags(OggOpusFile *of) { FileTags tags; const OpusTags *ot = op_tags(of, -1); if(!ot) { return tags; } tags.encoder = UStringFromOpus(opus_tags_query(ot, "ENCODER", 0)); tags.title = UStringFromOpus(opus_tags_query(ot, "TITLE", 0)); tags.comments = UStringFromOpus(opus_tags_query(ot, "DESCRIPTION", 0)); tags.bpm = UStringFromOpus(opus_tags_query(ot, "BPM", 0)); // non-standard tags.artist = UStringFromOpus(opus_tags_query(ot, "ARTIST", 0)); tags.album = UStringFromOpus(opus_tags_query(ot, "ALBUM", 0)); tags.trackno = UStringFromOpus(opus_tags_query(ot, "TRACKNUMBER", 0)); tags.year = UStringFromOpus(opus_tags_query(ot, "DATE", 0)); tags.url = UStringFromOpus(opus_tags_query(ot, "CONTACT", 0)); tags.genre = UStringFromOpus(opus_tags_query(ot, "GENRE", 0)); return tags; } #endif // MPT_WITH_OPUSFILE bool CSoundFile::ReadOpusSample(SAMPLEINDEX sample, FileReader &file) { file.Rewind(); #if defined(MPT_WITH_OPUSFILE) int rate = 0; int channels = 0; std::vector raw_sample_data; { FileReader::PinnedView initial = file.GetPinnedView(65536); // 512 is recommended by libopusfile if(op_test(NULL, mpt::byte_cast(initial.data()), initial.size()) != 0) { return false; } } OpusFileCallbacks callbacks = {}; callbacks.read = &OpusfileFilereaderRead; callbacks.seek = &OpusfileFilereaderSeek; callbacks.tell = &OpusfileFilereaderTell; callbacks.close = NULL; OggOpusFile *of = op_open_callbacks(mpt::void_ptr(&file), &callbacks, NULL, 0, NULL); if(!of) { return false; } rate = 48000; channels = op_channel_count(of, -1); if(rate <= 0 || channels <= 0) { op_free(of); of = NULL; return false; } if(channels > 2 || op_link_count(of) != 1) { // We downmix multichannel to stereo as recommended by Opus specification in // case we are not able to handle > 2 channels. // We also decode chained files as stereo even if they start with a mono // stream, which simplifies handling of link boundaries for us. channels = 2; } std::string sampleName = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(GetOpusFileTags(of))); if(auto length = op_pcm_total(of, 0); length != OP_EINVAL) raw_sample_data.reserve(std::min(MAX_SAMPLE_LENGTH, mpt::saturate_cast(length)) * channels); std::vector decodeBuf(120 * 48000 / 1000); // 120ms (max Opus packet), 48kHz bool eof = false; while(!eof) { int framesRead = 0; if(channels == 2) { framesRead = op_read_stereo(of, &(decodeBuf[0]), static_cast(decodeBuf.size())); } else if(channels == 1) { framesRead = op_read(of, &(decodeBuf[0]), static_cast(decodeBuf.size()), NULL); } if(framesRead > 0) { mpt::append(raw_sample_data, decodeBuf.begin(), decodeBuf.begin() + (framesRead * channels)); } else if(framesRead == 0) { eof = true; } else if(framesRead == OP_HOLE) { // continue } else { // other errors are fatal, stop decoding eof = true; } if((raw_sample_data.size() / channels) > MAX_SAMPLE_LENGTH) { break; } } op_free(of); of = NULL; if(raw_sample_data.empty()) { return false; } DestroySampleThreadsafe(sample); ModSample &mptSample = Samples[sample]; mptSample.Initialize(); mptSample.nC5Speed = rate; mptSample.nLength = std::min(MAX_SAMPLE_LENGTH, mpt::saturate_cast(raw_sample_data.size() / channels)); mptSample.uFlags.set(CHN_16BIT); mptSample.uFlags.set(CHN_STEREO, channels == 2); if(!mptSample.AllocateSample()) { return false; } if(raw_sample_data.size() / channels > MAX_SAMPLE_LENGTH) { AddToLog(LogWarning, U_("Sample has been truncated!")); } std::copy(raw_sample_data.begin(), raw_sample_data.begin() + mptSample.nLength * channels, mptSample.sample16()); mptSample.Convert(MOD_TYPE_IT, GetType()); mptSample.PrecomputeLoops(*this, false); m_szNames[sample] = sampleName; return true; #else // !MPT_WITH_OPUSFILE MPT_UNREFERENCED_PARAMETER(sample); MPT_UNREFERENCED_PARAMETER(file); return false; #endif // MPT_WITH_OPUSFILE } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_mt2.cpp0000644000175000017500000007775414644610543020275 00000000000000/* * Load_mt2.cpp * ------------ * Purpose: MT2 (MadTracker 2) module loader * Notes : A couple of things are not handled properly or not at all, such as internal effects and automation envelopes * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #ifdef MPT_EXTERNAL_SAMPLES // For loading external samples #include "../common/mptPathString.h" #endif // MPT_EXTERNAL_SAMPLES #ifdef MPT_WITH_VST #include "../mptrack/Vstplug.h" #endif // MPT_WITH_VST OPENMPT_NAMESPACE_BEGIN struct MT2FileHeader { enum MT2HeaderFlags { packedPatterns = 0x01, automation = 0x02, drumsAutomation = 0x08, masterAutomation = 0x10, }; char signature[4]; // "MT20" uint32le userID; uint16le version; char trackerName[32]; // "MadTracker 2.0" char songName[64]; uint16le numOrders; uint16le restartPos; uint16le numPatterns; uint16le numChannels; uint16le samplesPerTick; uint8le ticksPerLine; uint8le linesPerBeat; uint32le flags; // See HeaderFlags uint16le numInstruments; uint16le numSamples; }; MPT_BINARY_STRUCT(MT2FileHeader, 126) struct MT2DrumsData { uint16le numDrumPatterns; uint16le DrumSamples[8]; uint8le DrumPatternOrder[256]; }; MPT_BINARY_STRUCT(MT2DrumsData, 274) struct MT2TrackSettings { uint16le volume; uint8le trackfx; // Built-in effect type is used uint8le output; uint16le fxID; uint16le trackEffectParam[64][8]; }; MPT_BINARY_STRUCT(MT2TrackSettings, 1030) struct MT2Command { uint8 note; // 0=nothing, 97=note off uint8 instr; uint8 vol; uint8 pan; uint8 fxcmd; uint8 fxparam1; uint8 fxparam2; }; MPT_BINARY_STRUCT(MT2Command, 7) struct MT2EnvPoint { uint16le x; uint16le y; }; MPT_BINARY_STRUCT(MT2EnvPoint, 4) struct MT2Instrument { enum EnvTypes { VolumeEnv = 1, PanningEnv = 2, PitchEnv = 4, FilterEnv = 8, }; uint16le numSamples; uint8le groupMap[96]; uint8le vibtype, vibsweep, vibdepth, vibrate; uint16le fadeout; uint16le nna; }; MPT_BINARY_STRUCT(MT2Instrument, 106) struct MT2IEnvelope { uint8le flags; uint8le numPoints; uint8le sustainPos; uint8le loopStart; uint8le loopEnd; uint8le reserved[3]; MT2EnvPoint points[16]; }; MPT_BINARY_STRUCT(MT2IEnvelope, 72) // Note: The order of these fields differs a bit in MTIOModule_MT2.cpp - maybe just typos, I'm not sure. // This struct follows the save format of MadTracker 2.6.1. struct MT2InstrSynth { uint8le synthID; uint8le effectID; // 0 = Lowpass filter, 1 = Highpass filter uint16le cutoff; // 100...11000 Hz uint8le resonance; // 0...128 uint8le attack; // 0...128 uint8le decay; // 0...128 uint8le midiChannel; // 0...15 int8le device; // VST slot (positive) or MIDI device (negative) int8le unknown1; // Missing in MTIOModule_MT2.cpp uint8le volume; // 0...255 int8le finetune; // -96...96 int8le transpose; // -48...48 uint8le unknown2; // Seems to be equal to instrument number. uint8le unknown3; uint8le midiProgram; uint8le reserved[16]; }; MPT_BINARY_STRUCT(MT2InstrSynth, 32) struct MT2Sample { uint32le length; uint32le frequency; uint8le depth; uint8le channels; uint8le flags; uint8le loopType; uint32le loopStart; uint32le loopEnd; uint16le volume; int8le panning; int8le note; int16le spb; }; MPT_BINARY_STRUCT(MT2Sample, 26) struct MT2Group { uint8le sample; uint8le vol; // 0...128 int8le pitch; // -128...127 uint8le reserved[5]; }; MPT_BINARY_STRUCT(MT2Group, 8) struct MT2VST { char dll[64]; char programName[28]; uint32le fxID; uint32le fxVersion; uint32le programNr; uint8le useChunks; uint8le track; int8le pan; // Not imported - could use pan mix mode for D/W ratio, but this is not implemented for instrument plugins! char reserved[17]; uint32le n; }; MPT_BINARY_STRUCT(MT2VST, 128) static bool ConvertMT2Command(CSoundFile *that, ModCommand &m, MT2Command &p) { bool hasLegacyTempo = false; // Note m.note = NOTE_NONE; if(p.note) m.note = (p.note > 96) ? NOTE_KEYOFF : (p.note + NOTE_MIN + 11); // Instrument m.instr = p.instr; // Volume Column if(p.vol >= 0x10 && p.vol <= 0x90) { m.SetVolumeCommand(VOLCMD_VOLUME, static_cast((p.vol - 0x10) / 2)); } else if(p.vol >= 0xA0 && p.vol <= 0xAF) { m.volcmd = VOLCMD_VOLSLIDEDOWN; m.vol = (p.vol & 0x0F); } else if(p.vol >= 0xB0 && p.vol <= 0xBF) { m.volcmd = VOLCMD_VOLSLIDEUP; m.vol = (p.vol & 0x0F); } else if(p.vol >= 0xC0 && p.vol <= 0xCF) { m.volcmd = VOLCMD_FINEVOLDOWN; m.vol = (p.vol & 0x0F); } else if(p.vol >= 0xD0 && p.vol <= 0xDF) { m.volcmd = VOLCMD_FINEVOLUP; m.vol = (p.vol & 0x0F); } // Effects if(p.fxcmd || p.fxparam1 || p.fxparam2) { switch(p.fxcmd) { case 0x00: // FastTracker effect CSoundFile::ConvertModCommand(m, p.fxparam2, p.fxparam1); #ifdef MODPLUG_TRACKER m.Convert(MOD_TYPE_XM, MOD_TYPE_IT, *that); #else MPT_UNREFERENCED_PARAMETER(that); #endif // MODPLUG_TRACKER if(p.fxparam2 == 0x0F) hasLegacyTempo = true; break; case 0x01: // Portamento up (on every tick) m.command = CMD_PORTAMENTOUP; m.param = mpt::saturate_cast((p.fxparam2 << 4) | (p.fxparam1 >> 4)); break; case 0x02: // Portamento down (on every tick) m.command = CMD_PORTAMENTODOWN; m.param = mpt::saturate_cast((p.fxparam2 << 4) | (p.fxparam1 >> 4)); break; case 0x03: // Tone Portamento (on every tick) m.command = CMD_TONEPORTAMENTO; m.param = mpt::saturate_cast((p.fxparam2 << 4) | (p.fxparam1 >> 4)); break; case 0x04: // Vibrato m.command = CMD_VIBRATO; m.param = (p.fxparam2 & 0xF0) | (p.fxparam1 >> 4); break; case 0x08: // Panning + Polarity (we can only import panning for now) if(p.fxparam1) { m.command = CMD_PANNING8; m.param = p.fxparam1; } else if(p.fxparam2 == 1 || p.fxparam2 == 2) { // Invert left or right channel m.command = CMD_S3MCMDEX; m.param = 0x91; } break; case 0x0C: // Set volume (0x80 = 100%) m.command = CMD_VOLUME; m.param = p.fxparam2 / 2; break; case 0x0F: // Set tempo, LPB and ticks (we can only import tempo for now) if(p.fxparam2 != 0) { m.command = CMD_TEMPO; m.param = p.fxparam2; } else { m.command = CMD_SPEED; m.param = (p.fxparam1 & 0x0F); } break; case 0x10: // Impulse Tracker effect CSoundFile::S3MConvert(m, p.fxparam2, p.fxparam1, true); if(m.command == CMD_TEMPO || m.command == CMD_SPEED) hasLegacyTempo = true; break; case 0x1D: // Gapper (like IT Tremor with old FX, i.e. 1D 00 XY = ontime X + 1 ticks, offtime Y + 1 ticks) m.command = CMD_TREMOR; m.param = p.fxparam1; break; case 0x20: // Cutoff + Resonance (we can only import cutoff for now) m.command = CMD_MIDI; m.param = p.fxparam2 >> 1; break; case 0x22: // Cutoff + Resonance + Attack + Decay (we can only import cutoff for now) m.command = CMD_MIDI; m.param = (p.fxparam2 & 0xF0) >> 1; break; case 0x24: // Reverse m.command = CMD_S3MCMDEX; m.param = 0x9F; break; case 0x80: // Track volume m.command = CMD_CHANNELVOLUME; m.param = p.fxparam2 / 4u; break; case 0x9D: // Offset + delay m.volcmd = VOLCMD_OFFSET; m.vol = p.fxparam2 >> 3; m.command = CMD_S3MCMDEX; m.param = 0xD0 | std::min(p.fxparam1, uint8(0x0F)); break; case 0xCC: // MIDI CC //m.command = CMD_MIDI; break; // TODO: More MT2 Effects } } if(p.pan) { if(m.command == CMD_NONE) { m.command = CMD_PANNING8; m.param = p.pan; } else if(m.volcmd == VOLCMD_NONE) { m.volcmd = VOLCMD_PANNING; m.vol = p.pan / 4; } } return hasLegacyTempo; } // This doesn't really do anything but skipping the envelope chunk at the moment. static void ReadMT2Automation(uint16 version, FileReader &file) { uint32 flags; uint32 trkfxid; if(version >= 0x203) { flags = file.ReadUint32LE(); trkfxid = file.ReadUint32LE(); } else { flags = file.ReadUint16LE(); trkfxid = file.ReadUint16LE(); } MPT_UNREFERENCED_PARAMETER(trkfxid); while(flags != 0) { if(flags & 1) { file.Skip(4 + sizeof(MT2EnvPoint) * 64); } flags >>= 1; } } static bool ValidateHeader(const MT2FileHeader &fileHeader) { if(std::memcmp(fileHeader.signature, "MT20", 4) || fileHeader.version < 0x200 || fileHeader.version >= 0x300 || fileHeader.numChannels < 1 || fileHeader.numChannels > 64 || fileHeader.numOrders > 256 || fileHeader.numInstruments >= MAX_INSTRUMENTS || fileHeader.numSamples >= MAX_SAMPLES ) { return false; } return true; } static uint64 GetHeaderMinimumAdditionalSize(const MT2FileHeader &fileHeader) { MPT_UNREFERENCED_PARAMETER(fileHeader); return 256; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize) { MT2FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader)); } bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); MT2FileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(!file.CanRead(mpt::saturate_cast(GetHeaderMinimumAdditionalSize(fileHeader)))) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(MOD_TYPE_MT2, fileHeader.numChannels); m_modFormat.formatName = MPT_UFORMAT("MadTracker {}.{}")(fileHeader.version >> 8, mpt::ufmt::hex0<2>(fileHeader.version & 0xFF)); m_modFormat.type = UL_("mt2"); m_modFormat.madeWithTracker = mpt::ToUnicode(mpt::Charset::Windows1252, mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.trackerName)); m_modFormat.charset = mpt::Charset::Windows1252; m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songName); Order().SetDefaultSpeed(Clamp(fileHeader.ticksPerLine, 1, 31)); Order().SetDefaultTempoInt(125); m_SongFlags = SONG_LINEARSLIDES | SONG_ITCOMPATGXX | SONG_EXFILTERRANGE; m_nInstruments = fileHeader.numInstruments; m_nSamples = fileHeader.numSamples; m_nDefaultRowsPerBeat = Clamp(fileHeader.linesPerBeat, 1, 32); m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat * 4; m_nVSTiVolume = 48; m_nSamplePreAmp = 48 * 2; // Double pre-amp because we will halve the volume of all non-drum instruments, because the volume of drum samples can exceed that of normal samples uint8 orders[256]; file.ReadArray(orders); ReadOrderFromArray(Order(), orders, fileHeader.numOrders); Order().SetRestartPos(fileHeader.restartPos); // This value is supposed to be the size of the drums data, but in old MT2.0 files it's 8 bytes too small. // MadTracker itself unconditionally reads 274 bytes here if the value is != 0, so we do the same. const bool hasDrumChannels = file.ReadUint16LE() != 0; FileReader drumData = file.ReadChunk(hasDrumChannels ? sizeof(MT2DrumsData) : 0); FileReader extraData = file.ReadChunk(file.ReadUint32LE()); const CHANNELINDEX channelsWithoutDrums = GetNumChannels(); static_assert(MAX_BASECHANNELS >= 64 + 8); if(hasDrumChannels) { ChnSettings.resize(GetNumChannels() + 8); } bool hasLegacyTempo = false; // Read patterns if(loadFlags & loadPatternData) Patterns.ResizeArray(fileHeader.numPatterns); for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++) { ROWINDEX numRows = file.ReadUint16LE(); FileReader chunk = file.ReadChunk((file.ReadUint32LE() + 1) & ~1); LimitMax(numRows, MAX_PATTERN_ROWS); if(!numRows || !(loadFlags & loadPatternData) || !Patterns.Insert(pat, numRows)) { continue; } if(fileHeader.flags & MT2FileHeader::packedPatterns) { ROWINDEX row = 0; CHANNELINDEX chn = 0; while(chunk.CanRead(1)) { MT2Command cmd; uint8 infobyte = chunk.ReadUint8(); uint8 repeatCount = 0; if(infobyte == 0xFF) { repeatCount = chunk.ReadUint8(); infobyte = chunk.ReadUint8(); } if(infobyte & 0x7F) { ModCommand *m = Patterns[pat].GetpModCommand(row, chn); MemsetZero(cmd); if(infobyte & 0x01) cmd.note = chunk.ReadUint8(); if(infobyte & 0x02) cmd.instr = chunk.ReadUint8(); if(infobyte & 0x04) cmd.vol = chunk.ReadUint8(); if(infobyte & 0x08) cmd.pan = chunk.ReadUint8(); if(infobyte & 0x10) cmd.fxcmd = chunk.ReadUint8(); if(infobyte & 0x20) cmd.fxparam1 = chunk.ReadUint8(); if(infobyte & 0x40) cmd.fxparam2 = chunk.ReadUint8(); hasLegacyTempo |= ConvertMT2Command(this, *m, cmd); const ModCommand &orig = *m; const ROWINDEX fillRows = std::min((uint32)repeatCount, (uint32)numRows - (row + 1)); for(ROWINDEX r = 0; r < fillRows; r++) { m += GetNumChannels(); // cppcheck false-positive // cppcheck-suppress selfAssignment *m = orig; } } row += repeatCount + 1; while(row >= numRows) { row -= numRows; chn++; } if(chn >= channelsWithoutDrums) break; } } else { for(ROWINDEX row = 0; row < numRows; row++) { auto rowData = Patterns[pat].GetRow(row); for(CHANNELINDEX chn = 0; chn < channelsWithoutDrums; chn++) { MT2Command cmd; chunk.ReadStruct(cmd); hasLegacyTempo |= ConvertMT2Command(this, rowData[chn], cmd); } } } } if(fileHeader.samplesPerTick > 1 && fileHeader.samplesPerTick < 5000) { if(hasLegacyTempo) { Order().SetDefaultTempo(TEMPO{}.SetRaw(Util::muldivr(110250, TEMPO::fractFact, fileHeader.samplesPerTick))); m_nTempoMode = TempoMode::Classic; } else { Order().SetDefaultTempo(TEMPO(44100.0 * 60.0 / (Order().GetDefaultSpeed() * m_nDefaultRowsPerBeat * fileHeader.samplesPerTick))); m_nTempoMode = TempoMode::Modern; } } // Read extra data uint32 numVST = 0; std::vector trackRouting(GetNumChannels(), 0); while(extraData.CanRead(8)) { uint32 id = extraData.ReadUint32LE(); FileReader chunk = extraData.ReadChunk(extraData.ReadUint32LE()); switch(id) { case MagicLE("BPM+"): if(!hasLegacyTempo) { m_nTempoMode = TempoMode::Modern; double d = chunk.ReadDoubleLE(); if(d > 0.00000001) { Order().SetDefaultTempo(TEMPO(44100.0 * 60.0 / (Order().GetDefaultSpeed() * m_nDefaultRowsPerBeat * d))); } } break; case MagicLE("TFXM"): break; case MagicLE("TRKO"): break; case MagicLE("TRKS"): m_nSamplePreAmp = chunk.ReadUint16LE() / 256u; // 131072 is 0dB... I think (that's how MTIOModule_MT2.cpp reads) // Dirty workaround for modules that use track automation for a fade-in at the song start (e.g. Rock.mt2) if(!m_nSamplePreAmp) m_nSamplePreAmp = 48; m_nVSTiVolume = m_nSamplePreAmp / 2u; for(CHANNELINDEX c = 0; c < GetNumChannels(); c++) { MT2TrackSettings trackSettings; if(chunk.ReadStruct(trackSettings)) { ChnSettings[c].nVolume = static_cast(trackSettings.volume >> 10); // 32768 is 0dB trackRouting[c] = trackSettings.output; } } break; case MagicLE("TRKL"): for(CHANNELINDEX i = 0; i < GetNumChannels() && chunk.CanRead(1); i++) { std::string name; chunk.ReadNullString(name); ChnSettings[i].szName = mpt::String::ReadBuf(mpt::String::spacePadded, name.c_str(), name.length()); } break; case MagicLE("PATN"): for(PATTERNINDEX i = 0; i < fileHeader.numPatterns && chunk.CanRead(1) && Patterns.IsValidIndex(i); i++) { std::string name; chunk.ReadNullString(name); Patterns[i].SetName(name); } break; case MagicLE("MSG\0"): chunk.Skip(1); // Show message on startup m_songMessage.Read(chunk, chunk.BytesLeft(), SongMessage::leCRLF); break; case MagicLE("PICT"): break; case MagicLE("SUM\0"): { uint8 summaryMask[6]; chunk.ReadArray(summaryMask); std::string artist; chunk.ReadNullString(artist); if(artist != "Unregistered") { m_songArtist = mpt::ToUnicode(mpt::Charset::Windows1252, artist); } } break; case MagicLE("TMAP"): break; case MagicLE("MIDI"): break; case MagicLE("TREQ"): break; case MagicLE("VST2"): numVST = chunk.ReadUint32LE(); #ifdef MPT_WITH_VST if(!(loadFlags & loadPluginData)) { break; } for(uint32 i = 0; i < std::min(numVST, uint32(MAX_MIXPLUGINS)); i++) { MT2VST vstHeader; if(chunk.ReadStruct(vstHeader)) { if(fileHeader.version >= 0x0250) chunk.Skip(16 * 4); // Parameter automation map for 16 parameters SNDMIXPLUGIN &mixPlug = m_MixPlugins[i]; mixPlug.Destroy(); std::string libraryName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, vstHeader.dll); mixPlug.Info.szName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, vstHeader.programName); if(libraryName.length() > 4 && libraryName[libraryName.length() - 4] == '.') { // Remove ".dll" from library name libraryName.resize(libraryName.length() - 4); } mixPlug.Info.szLibraryName = libraryName; mixPlug.Info.dwPluginId1 = Vst::kEffectMagic; mixPlug.Info.dwPluginId2 = vstHeader.fxID; if(vstHeader.track >= GetNumChannels()) { mixPlug.SetMasterEffect(true); } else { if(!ChnSettings[vstHeader.track].nMixPlugin) { ChnSettings[vstHeader.track].nMixPlugin = static_cast(i + 1); } else { // Channel already has plugin assignment - chain the plugins PLUGINDEX outPlug = ChnSettings[vstHeader.track].nMixPlugin - 1; while(true) { if(m_MixPlugins[outPlug].GetOutputPlugin() == PLUGINDEX_INVALID) { m_MixPlugins[outPlug].SetOutputPlugin(static_cast(i)); break; } outPlug = m_MixPlugins[outPlug].GetOutputPlugin(); } } } // Read plugin settings uint32 dataSize; if(vstHeader.useChunks) { // MT2 only ever calls effGetChunk for programs, and OpenMPT uses the defaultProgram value to determine // whether it should use effSetChunk for programs or banks... mixPlug.defaultProgram = -1; LimitMax(vstHeader.n, std::numeric_limits::max() - 4); dataSize = vstHeader.n + 4; } else { mixPlug.defaultProgram = vstHeader.programNr; LimitMax(vstHeader.n, (std::numeric_limits::max() / 4u) - 1); dataSize = vstHeader.n * 4 + 4; } mixPlug.pluginData.resize(dataSize); if(vstHeader.useChunks) { std::memcpy(mixPlug.pluginData.data(), "fEvN", 4); // 'NvEf' plugin data type chunk.ReadRaw(mpt::span(mixPlug.pluginData.data() + 4, vstHeader.n)); } else { auto memFile = std::make_pair(mpt::as_span(mixPlug.pluginData), mpt::IO::Offset(0)); mpt::IO::WriteIntLE(memFile, 0); // Plugin data type for(uint32 param = 0; param < vstHeader.n; param++) { mpt::IO::Write(memFile, IEEE754binary32LE{chunk.ReadFloatLE()}); } } } else { break; } } #endif // MPT_WITH_VST break; } } #ifndef NO_PLUGINS // Now that we have both the track settings and plugins, establish the track routing by applying the same plugins to the source track as to the target track: for(CHANNELINDEX c = 0; c < GetNumChannels(); c++) { int8 outTrack = trackRouting[c]; if(outTrack > c && outTrack < GetNumChannels() && ChnSettings[outTrack].nMixPlugin != 0) { if(ChnSettings[c].nMixPlugin == 0) { ChnSettings[c].nMixPlugin = ChnSettings[outTrack].nMixPlugin; } else { PLUGINDEX outPlug = ChnSettings[c].nMixPlugin - 1; for(;;) { if(m_MixPlugins[outPlug].GetOutputPlugin() == PLUGINDEX_INVALID) { m_MixPlugins[outPlug].SetOutputPlugin(ChnSettings[outTrack].nMixPlugin - 1); break; } outPlug = m_MixPlugins[outPlug].GetOutputPlugin(); } } } } #endif // NO_PLUGINS // Read drum channels INSTRUMENTINDEX drumMap[8] = { 0 }; uint16 drumSample[8] = { 0 }; if(hasDrumChannels) { MT2DrumsData drumHeader; drumData.ReadStruct(drumHeader); // Allocate some instruments to handle the drum samples for(INSTRUMENTINDEX i = 0; i < 8; i++) { drumMap[i] = GetNextFreeInstrument(m_nInstruments + 1); drumSample[i] = drumHeader.DrumSamples[i]; if(drumMap[i] != INSTRUMENTINDEX_INVALID) { ModInstrument *mptIns = AllocateInstrument(drumMap[i], drumHeader.DrumSamples[i] + 1); if(mptIns != nullptr) { mptIns->name = MPT_AFORMAT("Drum #{}")(i+1); } } else { drumMap[i] = 0; } } // Get all the drum pattern chunks std::vector patternChunks(drumHeader.numDrumPatterns); for(uint32 pat = 0; pat < drumHeader.numDrumPatterns; pat++) { uint16 numRows = file.ReadUint16LE(); patternChunks[pat] = file.ReadChunk(numRows * 32); } std::vector patMapping(fileHeader.numPatterns, PATTERNINDEX_INVALID); for(uint32 ord = 0; ord < fileHeader.numOrders; ord++) { if(drumHeader.DrumPatternOrder[ord] >= drumHeader.numDrumPatterns || Order()[ord] >= fileHeader.numPatterns) continue; // Figure out where to write this drum pattern PATTERNINDEX writePat = Order()[ord]; if(patMapping[writePat] == PATTERNINDEX_INVALID) { patMapping[writePat] = drumHeader.DrumPatternOrder[ord]; } else if(patMapping[writePat] != drumHeader.DrumPatternOrder[ord]) { // Damn, this pattern has previously used a different drum pattern. Duplicate it... PATTERNINDEX newPat = Patterns.Duplicate(writePat); if(newPat != PATTERNINDEX_INVALID) { writePat = newPat; Order()[ord] = writePat; } } if(!Patterns.IsValidPat(writePat)) continue; FileReader &chunk = patternChunks[drumHeader.DrumPatternOrder[ord]]; chunk.Rewind(); const ROWINDEX numRows = static_cast(chunk.GetLength() / 32u); for(ROWINDEX row = 0; row < Patterns[writePat].GetNumRows(); row++) { ModCommand *m = Patterns[writePat].GetpModCommand(row, GetNumChannels() - 8); for(CHANNELINDEX chn = 0; chn < 8; chn++, m++) { *m = ModCommand{}; if(row >= numRows) continue; uint8 drums[4]; chunk.ReadArray(drums); if(drums[0] & 0x80) { m->note = NOTE_MIDDLEC; m->instr = static_cast(drumMap[chn]); uint8 delay = drums[0] & 0x1F; if(delay) { LimitMax(delay, uint8(0x0F)); m->command = CMD_S3MCMDEX; m->param = 0xD0 | delay; } m->volcmd = VOLCMD_VOLUME; // Volume is 0...255, but 128 is equivalent to v64 - we compensate this by halving the global volume of all non-drum instruments m->vol = static_cast((static_cast(drums[1]) + 3) / 4u); } } } } } // Read automation envelopes if(fileHeader.flags & MT2FileHeader::automation) { const uint32 numEnvelopes = ((fileHeader.flags & MT2FileHeader::drumsAutomation) ? GetNumChannels() : channelsWithoutDrums) + ((fileHeader.version >= 0x0250) ? numVST : 0) + ((fileHeader.flags & MT2FileHeader::masterAutomation) ? 1 : 0); for(uint32 pat = 0; pat < fileHeader.numPatterns; pat++) { for(uint32 env = 0; env < numEnvelopes && file.CanRead(4); env++) { // TODO ReadMT2Automation(fileHeader.version, file); } } } // Read instruments std::vector instrChunks(255); for(INSTRUMENTINDEX i = 0; i < 255; i++) { char instrName[32]; file.ReadArray(instrName); uint32 dataLength = file.ReadUint32LE(); if(dataLength == 32) dataLength += 108 + sizeof(MT2IEnvelope) * 4; if(fileHeader.version > 0x0201 && dataLength) dataLength += 4; FileReader instrChunk = instrChunks[i] = file.ReadChunk(dataLength); ModInstrument *mptIns = nullptr; if(i < fileHeader.numInstruments) { // Default sample assignment if there is no data chunk? Fixes e.g. instrument 33 in Destiny - Dream Alone.mt2 mptIns = AllocateInstrument(i + 1, i + 1); } if(mptIns == nullptr) continue; mptIns->name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, instrName); if(!dataLength) continue; MT2Instrument insHeader; instrChunk.ReadStruct(insHeader); uint16 flags = 0; if(fileHeader.version >= 0x0201) flags = instrChunk.ReadUint16LE(); uint32 envMask = MT2Instrument::VolumeEnv | MT2Instrument::PanningEnv; if(fileHeader.version >= 0x0202) envMask = instrChunk.ReadUint32LE(); mptIns->nFadeOut = insHeader.fadeout; const NewNoteAction NNA[4] = { NewNoteAction::NoteCut, NewNoteAction::Continue, NewNoteAction::NoteOff, NewNoteAction::NoteFade }; const DuplicateCheckType DCT[4] = { DuplicateCheckType::None, DuplicateCheckType::Note, DuplicateCheckType::Sample, DuplicateCheckType::Instrument }; const DuplicateNoteAction DNA[4] = { DuplicateNoteAction::NoteCut, DuplicateNoteAction::NoteFade /* actually continue, but IT doesn't have that */, DuplicateNoteAction::NoteOff, DuplicateNoteAction::NoteFade }; mptIns->nNNA = NNA[insHeader.nna & 3]; mptIns->nDCT = DCT[(insHeader.nna >> 8) & 3]; mptIns->nDNA = DNA[(insHeader.nna >> 12) & 3]; // Load envelopes for(uint32 env = 0; env < 4; env++) { if(envMask & 1) { MT2IEnvelope mt2Env; instrChunk.ReadStruct(mt2Env); const EnvelopeType envType[4] = { ENV_VOLUME, ENV_PANNING, ENV_PITCH, ENV_PITCH }; InstrumentEnvelope &mptEnv = mptIns->GetEnvelope(envType[env]); mptEnv.dwFlags.set(ENV_FILTER, (env == 3) && (mt2Env.flags & 1) != 0); mptEnv.dwFlags.set(ENV_ENABLED, (mt2Env.flags & 1) != 0); mptEnv.dwFlags.set(ENV_SUSTAIN, (mt2Env.flags & 2) != 0); mptEnv.dwFlags.set(ENV_LOOP, (mt2Env.flags & 4) != 0); mptEnv.resize(std::min(mt2Env.numPoints.get(), uint8(16))); mptEnv.nSustainStart = mptEnv.nSustainEnd = mt2Env.sustainPos; mptEnv.nLoopStart = mt2Env.loopStart; mptEnv.nLoopEnd = mt2Env.loopEnd; for(uint32 p = 0; p < mptEnv.size(); p++) { mptEnv[p].tick = mt2Env.points[p].x; mptEnv[p].value = static_cast(Clamp(mt2Env.points[p].y, 0, 64)); } } envMask >>= 1; } if(!mptIns->VolEnv.dwFlags[ENV_ENABLED] && mptIns->nNNA != NewNoteAction::NoteFade) { mptIns->nFadeOut = int16_max; } mptIns->SetCutoff(0x7F, true); mptIns->SetResonance(0, true); if(flags) { MT2InstrSynth synthData; instrChunk.ReadStruct(synthData); if(flags & 2) { mptIns->SetCutoff(FrequencyToCutOff(synthData.cutoff), true); mptIns->SetResonance(synthData.resonance, true); } mptIns->filterMode = synthData.effectID == 1 ? FilterMode::HighPass : FilterMode::LowPass; if(flags & 4) { // VSTi / MIDI synth enabled mptIns->nMidiChannel = synthData.midiChannel + 1; mptIns->nMixPlug = static_cast(synthData.device + 1); if(synthData.device < 0) { // TODO: This is a MIDI device - maybe use MIDI I/O plugin to emulate those? mptIns->nMidiProgram = synthData.midiProgram + 1; // MT2 only seems to use this for MIDI devices, not VSTis! } if(synthData.transpose) { for(uint32 n = 0; n < std::size(mptIns->NoteMap); n++) { int note = NOTE_MIN + n + synthData.transpose; Limit(note, NOTE_MIN, NOTE_MAX); mptIns->NoteMap[n] = static_cast(note); } } // Instruments with plugin assignments never play samples at the same time! mptIns->AssignSample(0); } } } // Read sample headers std::bitset<256> sampleNoInterpolation; std::bitset<256> sampleSynchronized; for(SAMPLEINDEX i = 0; i < 256; i++) { char sampleName[32]; file.ReadArray(sampleName); uint32 dataLength = file.ReadUint32LE(); FileReader sampleChunk = file.ReadChunk(dataLength); if(i < fileHeader.numSamples) { m_szNames[i + 1] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleName); } if(dataLength && i < fileHeader.numSamples) { ModSample &mptSmp = Samples[i + 1]; mptSmp.Initialize(MOD_TYPE_IT); mptSmp.SetDefaultCuePoints(); MT2Sample sampleHeader; sampleChunk.ReadStruct(sampleHeader); mptSmp.nLength = sampleHeader.length; mptSmp.nC5Speed = sampleHeader.frequency; if(sampleHeader.depth > 1) { mptSmp.uFlags.set(CHN_16BIT); mptSmp.nLength /= 2u; } if(sampleHeader.channels > 1) { mptSmp.uFlags.set(CHN_STEREO); mptSmp.nLength /= 2u; } if(sampleHeader.loopType == 1) mptSmp.uFlags.set(CHN_LOOP); else if(sampleHeader.loopType == 2) mptSmp.uFlags.set(CHN_LOOP | CHN_PINGPONGLOOP); mptSmp.nLoopStart = sampleHeader.loopStart; mptSmp.nLoopEnd = sampleHeader.loopEnd; mptSmp.nVolume = sampleHeader.volume >> 7; if(sampleHeader.panning == -128) mptSmp.uFlags.set(CHN_SURROUND); else mptSmp.nPan = static_cast(sampleHeader.panning + 128); mptSmp.uFlags.set(CHN_PANNING); mptSmp.RelativeTone = sampleHeader.note; if(sampleHeader.flags & 2) { // Sample is synchronized to beat // The synchronization part is not supported in OpenMPT, but synchronized samples also always play at the same pitch as C-5, which we CAN do! sampleSynchronized[i] = true; //mptSmp.nC5Speed = Util::muldiv(mptSmp.nC5Speed, sampleHeader.spb, 22050); } if(sampleHeader.flags & 5) { // External sample mptSmp.uFlags.set(SMP_KEEPONDISK); } if(sampleHeader.flags & 8) { sampleNoInterpolation[i] = true; for(INSTRUMENTINDEX drum = 0; drum < 8; drum++) { if(drumSample[drum] == i && Instruments[drumMap[drum]] != nullptr) { Instruments[drumMap[drum]]->resampling = SRCMODE_NEAREST; } } } } } // Read sample groups for(INSTRUMENTINDEX ins = 0; ins < fileHeader.numInstruments; ins++) { if(instrChunks[ins].GetLength()) { FileReader &chunk = instrChunks[ins]; MT2Instrument insHeader; chunk.Rewind(); chunk.ReadStruct(insHeader); std::vector groups; file.ReadVector(groups, insHeader.numSamples); ModInstrument *mptIns = Instruments[ins + 1]; // Instruments with plugin assignments never play samples at the same time! if(mptIns == nullptr || mptIns->nMixPlug != 0) continue; mptIns->nGlobalVol = 32; // Compensate for extended dynamic range of drum instruments mptIns->AssignSample(0); for(uint32 note = 0; note < 96; note++) { if(insHeader.groupMap[note] < insHeader.numSamples) { const MT2Group &group = groups[insHeader.groupMap[note]]; SAMPLEINDEX sample = group.sample + 1; mptIns->Keyboard[note + 11 + NOTE_MIN] = sample; if(sample > 0 && sample <= m_nSamples) { ModSample &mptSmp = Samples[sample]; mptSmp.nVibType = static_cast(insHeader.vibtype & 3); // In fact, MT2 only implements sine vibrato mptSmp.nVibSweep = insHeader.vibsweep; mptSmp.nVibDepth = insHeader.vibdepth; mptSmp.nVibRate = insHeader.vibrate; mptSmp.nGlobalVol = uint16(group.vol) * 2; mptSmp.nFineTune = group.pitch; if(sampleNoInterpolation[sample - 1]) { mptIns->resampling = SRCMODE_NEAREST; } if(sampleSynchronized[sample - 1]) { mptIns->NoteMap[note + 11 + NOTE_MIN] = NOTE_MIDDLEC; } } // TODO: volume, finetune for duplicated samples } } } } if(!(loadFlags & loadSampleData)) return true; // Read sample data for(SAMPLEINDEX i = 0; i < m_nSamples; i++) { ModSample &mptSmp = Samples[i + 1]; mptSmp.Transpose(-(mptSmp.RelativeTone - 49 - (mptSmp.nFineTune / 128.0)) / 12.0); mptSmp.nFineTune = 0; mptSmp.RelativeTone = 0; if(!mptSmp.uFlags[SMP_KEEPONDISK]) { SampleIO( mptSmp.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, mptSmp.uFlags[CHN_STEREO] ? SampleIO::stereoSplit : SampleIO::mono, SampleIO::littleEndian, SampleIO::MT2) .ReadSample(mptSmp, file); } else { // External sample const uint32 filenameSize = file.ReadUint32LE(); file.Skip(12); // Reserved std::string filename; file.ReadString(filename, filenameSize); mptSmp.filename = filename; #if defined(MPT_EXTERNAL_SAMPLES) SetSamplePath(i + 1, mpt::PathString::FromLocale(filename)); #elif !defined(LIBOPENMPT_BUILD_TEST) AddToLog(LogWarning, MPT_UFORMAT("Loading external sample {} ('{}') failed: External samples are not supported.")(i + 1, mpt::ToUnicode(GetCharsetFile(), filename))); #endif // MPT_EXTERNAL_SAMPLES } } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/mod_specifications.cpp0000644000175000017500000004233415015401723022447 00000000000000/* * mod_specifications.cpp * ---------------------- * Purpose: Mod specifications characterise the features of every editable module format in OpenMPT, such as the number of supported channels, samples, effects, etc... * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "mod_specifications.h" #include "../common/misc_util.h" #include OPENMPT_NAMESPACE_BEGIN namespace ModSpecs { constexpr CModSpecifications mptm_ = { /* TODO: Proper, less arbitrarily chosen values here. NOTE: If changing limits, see whether: -savefile format and GUI methods can handle new values(might not be a small task :). */ MOD_TYPE_MPT, // Internal MODTYPE value "mptm", // File extension NOTE_MIN, // Minimum note index NOTE_MIN + 119, // Maximum note index 4000, // Pattern max. 4000, // Order max. MAX_SEQUENCES, // Sequences max 1, // Channel min 127, // Channel max 32, // Min tempo 1000, // Max tempo 1, // Min Speed 255, // Max Speed 1, // Min pattern rows 1024, // Max pattern rows 25, // Max mod name length 25, // Max sample name length 12, // Max sample filename length 25, // Max instrument name length 12, // Max instrument filename length 0, // Max comment line length 3999, // SamplesMax 255, // instrumentMax MixLevels::v1_17RC3, // defaultMixLevels SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX, // Supported song flags 200, // Max MIDI mapping directives MAX_ENVPOINTS, // Envelope point count true, // Has notecut. true, // Has noteoff. true, // Has notefade. true, // Has envelope release node true, // Has song comments true, // Has "+++" pattern true, // Has "---" pattern true, // Has restart position (order) true, // Supports plugins true, // Custom pattern time signatures true, // Pattern names true, // Has artist name true, // Has default resampling true, // Fixed point tempo " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z\\:#+*?????????????????????", // Supported Effects " vpcdabuh??gfe?o", // Supported Volume Column commands }; constexpr CModSpecifications mod_ = { MOD_TYPE_MOD, // Internal MODTYPE value "mod", // File extension 25, // Minimum note index 108, // Maximum note index 128, // Pattern max. 128, // Order max. 1, // Only one order list 1, // Channel min 99, // Channel max 32, // Min tempo 255, // Max tempo 1, // Min Speed 31, // Max Speed 64, // Min pattern rows 64, // Max pattern rows 20, // Max mod name length 22, // Max sample name length 0, // Max sample filename length 0, // Max instrument name length 0, // Max instrument filename length 0, // Max comment line length 31, // SamplesMax 0, // instrumentMax MixLevels::Compatible, // defaultMixLevels SONG_PT_MODE | SONG_AMIGALIMITS | SONG_ISAMIGA | SONG_FORMAT_NO_VOLCOL, // Supported song flags 0, // Max MIDI mapping directives 0, // No instrument envelopes false, // No notecut. false, // No noteoff. false, // No notefade. false, // No envelope release node false, // No song comments false, // Doesn't have "+++" pattern false, // Doesn't have "---" pattern true, // Has restart position (order) false, // Doesn't support plugins false, // No custom pattern time signatures false, // No pattern names false, // Doesn't have artist name false, // Doesn't have default resampling false, // Integer tempo " 0123456789ABCD?FF?E??????????????????????????????????????", // Supported Effects " ???????????????", // Supported Volume Column commands }; constexpr CModSpecifications xm_ = { MOD_TYPE_XM, // Internal MODTYPE value "xm", // File extension 13, // Minimum note index 108, // Maximum note index 256, // Pattern max. 255, // Order max. 1, // Only one order list 1, // Channel min 32, // Channel max 32, // Min tempo 1000, // Max tempo 1, // Min Speed 31, // Max Speed 1, // Min pattern rows 256, // Max pattern rows 20, // Max mod name length 22, // Max sample name length 0, // Max sample filename length 22, // Max instrument name length 0, // Max instrument filename length 0, // Max comment line length 128 * 16, // SamplesMax (actually 16 per instrument) 128, // instrumentMax MixLevels::CompatibleFT2, // defaultMixLevels SONG_LINEARSLIDES, // Supported song flags 0, // Max MIDI mapping directives 12, // Envelope point count false, // No notecut. true, // Has noteoff. false, // No notefade. false, // No envelope release node false, // No song comments false, // Doesn't have "+++" pattern false, // Doesn't have "---" pattern true, // Has restart position (order) false, // Doesn't support plugins false, // No custom pattern time signatures false, // No pattern names false, // Doesn't have artist name false, // Doesn't have default resampling false, // Integer tempo " 0123456789ABCDRFFTE???GHK??XPL??????W????????????????????", // Supported Effects " vpcdabuhlrg????", // Supported Volume Column commands }; // XM with MPT extensions constexpr CModSpecifications xmEx_ = { MOD_TYPE_XM, // Internal MODTYPE value "xm", // File extension 13, // Minimum note index 108, // Maximum note index 256, // Pattern max. 255, // Order max. 1, // Only one order list 1, // Channel min 128, // Channel max 32, // Min tempo 1000, // Max tempo 1, // Min Speed 31, // Max Speed 1, // Min pattern rows 1024, // Max pattern rows 20, // Max mod name length 22, // Max sample name length 0, // Max sample filename length 22, // Max instrument name length 0, // Max instrument filename length 0, // Max comment line length MAX_SAMPLES - 1, // SamplesMax (actually 32 per instrument(256 * 32 = 8192), but limited to MAX_SAMPLES = 4000) 255, // instrumentMax MixLevels::CompatibleFT2, // defaultMixLevels SONG_LINEARSLIDES | SONG_EXFILTERRANGE, // Supported song flags 200, // Max MIDI mapping directives 12, // Envelope point count false, // No notecut. true, // Has noteoff. false, // No notefade. false, // No envelope release node true, // Has song comments false, // Doesn't have "+++" pattern false, // Doesn't have "---" pattern true, // Has restart position (order) true, // Supports plugins false, // No custom pattern time signatures true, // Pattern names true, // Has artist name false, // Doesn't have default resampling false, // Integer tempo " 0123456789ABCDRFFTE???GHK?YXPLZ\\?#??W????????????????????", // Supported Effects " vpcdabuhlrg????", // Supported Volume Column commands }; constexpr CModSpecifications s3m_ = { MOD_TYPE_S3M, // Internal MODTYPE value "s3m", // File extension 13, // Minimum note index 108, // Maximum note index 100, // Pattern max. 255, // Order max. 1, // Only one order list 1, // Channel min 32, // Channel max 33, // Min tempo 255, // Max tempo 1, // Min Speed 255, // Max Speed 64, // Min pattern rows 64, // Max pattern rows 27, // Max mod name length 27, // Max sample name length 12, // Max sample filename length 0, // Max instrument name length 0, // Max instrument filename length 0, // Max comment line length 99, // SamplesMax 0, // instrumentMax MixLevels::Compatible, // defaultMixLevels SONG_FASTVOLSLIDES | SONG_AMIGALIMITS | SONG_S3MOLDVIBRATO, // Supported song flags 0, // Max MIDI mapping directives 0, // No instrument envelopes true, // Has notecut. false, // No noteoff. false, // No notefade. false, // No envelope release node false, // No song comments true, // Has "+++" pattern true, // Has "---" pattern false, // Doesn't have restart position (order) false, // Doesn't support plugins false, // No custom pattern time signatures false, // No pattern names false, // Doesn't have artist name false, // Doesn't have default resampling false, // Integer tempo " JFEGHLKRXODB?CQATI?SMNVW?U?????????? ????????????????????", // Supported Effects " vp?????????????", // Supported Volume Column commands }; // S3M with MPT extensions constexpr CModSpecifications s3mEx_ = { MOD_TYPE_S3M, // Internal MODTYPE value "s3m", // File extension 13, // Minimum note index 108, // Maximum note index 100, // Pattern max. 255, // Order max. 1, // Only one order list 1, // Channel min 32, // Channel max 33, // Min tempo 255, // Max tempo 1, // Min Speed 255, // Max Speed 64, // Min pattern rows 64, // Max pattern rows 27, // Max mod name length 27, // Max sample name length 12, // Max sample filename length 0, // Max instrument name length 0, // Max instrument filename length 0, // Max comment line length 99, // SamplesMax 0, // instrumentMax MixLevels::Compatible, // defaultMixLevels SONG_FASTVOLSLIDES | SONG_AMIGALIMITS, // Supported song flags 0, // Max MIDI mapping directives 0, // No instrument envelopes true, // Has notecut. false, // No noteoff. false, // No notefade. false, // No envelope release node false, // No song comments true, // Has "+++" pattern true, // Has "---" pattern false, // Doesn't have restart position (order) false, // Doesn't support plugins false, // No custom pattern time signatures false, // No pattern names false, // Doesn't have artist name false, // Doesn't have default resampling false, // Integer tempo " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z????? ????????????????????", // Supported Effects " vp?????????????", // Supported Volume Column commands }; constexpr CModSpecifications it_ = { MOD_TYPE_IT, // Internal MODTYPE value "it", // File extension 1, // Minimum note index 120, // Maximum note index 200, // Pattern max. 256, // Order max. 1, // Only one order list 1, // Channel min 64, // Channel max 32, // Min tempo 255, // Max tempo 1, // Min Speed 255, // Max Speed 32, // Min pattern rows 200, // Max pattern rows 25, // Max mod name length 25, // Max sample name length 12, // Max sample filename length 25, // Max instrument name length 12, // Max instrument filename length 75, // Max comment line length 99, // SamplesMax 99, // instrumentMax MixLevels::Compatible, // defaultMixLevels SONG_LINEARSLIDES | SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX, // Supported song flags 0, // Max MIDI mapping directives 25, // Envelope point count true, // Has notecut. true, // Has noteoff. true, // Has notefade. false, // No envelope release node true, // Has song comments true, // Has "+++" pattern true, // Has "--" pattern false, // Doesn't have restart position (order) false, // Doesn't support plugins false, // No custom pattern time signatures false, // No pattern names false, // Doesn't have artist name false, // Doesn't have default resampling false, // Integer tempo " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z????? ????????????????????", // Supported Effects " vpcdab?h??gfe??", // Supported Volume Column commands }; constexpr CModSpecifications itEx_ = { MOD_TYPE_IT, // Internal MODTYPE value "it", // File extension 1, // Minimum note index 120, // Maximum note index 240, // Pattern max. 256, // Order max. 1, // Only one order list 1, // Channel min 127, // Channel max 32, // Min tempo 512, // Max tempo 1, // Min Speed 255, // Max Speed 1, // Min pattern rows 1024, // Max pattern rows 25, // Max mod name length 25, // Max sample name length 12, // Max sample filename length 25, // Max instrument name length 12, // Max instrument filename length 75, // Max comment line length 3999, // SamplesMax 255, // instrumentMax MixLevels::Compatible, // defaultMixLevels SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX, // Supported song flags 200, // Max MIDI mapping directives 25, // Envelope point count true, // Has notecut. true, // Has noteoff. true, // Has notefade. false, // No envelope release node true, // Has song comments true, // Has "+++" pattern true, // Has "---" pattern false, // Doesn't have restart position (order) true, // Supports plugins false, // No custom pattern time signatures true, // Pattern names true, // Has artist name false, // Doesn't have default resampling false, // Integer tempo " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z\\?#?? ????????????????????", // Supported Effects " vpcdab?h??gfe??", // Supported Volume Column commands }; const std::array Collection = { &mptm_, &mod_, &s3m_, &s3mEx_, &xm_, &xmEx_, &it_, &itEx_ }; const CModSpecifications &mptm = mptm_; const CModSpecifications &mod = mod_; const CModSpecifications &s3m = s3m_; const CModSpecifications &s3mEx = s3mEx_; const CModSpecifications &xm = xm_; const CModSpecifications &xmEx = xmEx_; const CModSpecifications &it = it_; const CModSpecifications &itEx = itEx_; } // namespace ModSpecs MODTYPE CModSpecifications::ExtensionToType(std::string ext) { if(ext.empty()) { return MOD_TYPE_NONE; } else if(ext[0] == '.') { ext.erase(0, 1); } ext = mpt::ToLowerCaseAscii(ext); for(const auto &spec : ModSpecs::Collection) { if(ext == spec->fileExtension) { return spec->internalType; } } return MOD_TYPE_NONE; } MODTYPE CModSpecifications::ExtensionToType(mpt::ustring ext) { return ExtensionToType(mpt::ToCharset(mpt::Charset::ASCII, ext)); } bool CModSpecifications::HasNote(ModCommand::NOTE note) const { if(note >= noteMin && note <= noteMax) return true; else if(ModCommand::IsSpecialNote(note)) { if(note == NOTE_NOTECUT) return hasNoteCut; else if(note == NOTE_KEYOFF) return hasNoteOff; else if(note == NOTE_FADE) return hasNoteFade; else return (internalType == MOD_TYPE_MPT); } else if(note == NOTE_NONE) return true; return false; } bool CModSpecifications::HasVolCommand(ModCommand::VOLCMD volcmd) const { if(volcmd >= MAX_VOLCMDS) return false; return volcommands[volcmd] != '?'; } bool CModSpecifications::HasCommand(ModCommand::COMMAND cmd) const { if(cmd >= MAX_EFFECTS) return false; return commands[cmd] != '?'; } char CModSpecifications::GetVolEffectLetter(ModCommand::VOLCMD volcmd) const { if(volcmd >= MAX_VOLCMDS) return '?'; return volcommands[volcmd]; } char CModSpecifications::GetGenericVolEffectLetter(ModCommand::VOLCMD volcmd) { // Note: Remove this function if volume effect letter display is ever going to differ between formats, and update users to GetVolEffectLetter instead. static constexpr char VolCommands[] = " vpcdabuhlrgfe:o"; static_assert(std::size(VolCommands) == MAX_VOLCMDS + 1); if(volcmd >= MAX_VOLCMDS) return '?'; return VolCommands[volcmd]; } char CModSpecifications::GetEffectLetter(ModCommand::COMMAND cmd) const { if(cmd >= MAX_EFFECTS) return '?'; return commands[cmd]; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/Load_gdm.cpp0000644000175000017500000003554214644610543020327 00000000000000/* * Load_gdm.cpp * ------------ * Purpose: GDM (BWSB Soundsystem) module loader * Notes : This code is partly based on zilym's original code / specs (which are utterly wrong :P). * Thanks to the MenTaLguY for gdm.txt and ajs for gdm2s3m and some hints. * * Hint 1: Most (all?) of the unsupported features were not supported in 2GDM / BWSB either. * Hint 2: Files will be played like their original formats would be played in MPT, so no * BWSB quirks including crashes and freezes are supported. :-P * Authors: Johannes Schultz * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Loaders.h" #include "mod_specifications.h" OPENMPT_NAMESPACE_BEGIN // GDM File Header struct GDMFileHeader { char magic[4]; // ID: 'GDM\xFE' char songTitle[32]; // Music's title char songMusician[32]; // Name of music's composer char dosEOF[3]; // 13, 10, 26 char magic2[4]; // ID: 'GMFS' uint8le formatMajorVer; // Format major version uint8le formatMinorVer; // Format minor version uint16le trackerID; // Composing Tracker ID code (00 = 2GDM) uint8le trackerMajorVer; // Tracker's major version uint8le trackerMinorVer; // Tracker's minor version uint8le panMap[32]; // 0-Left to 15-Right, 16=Surround, 255-N/U uint8le masterVol; // Range: 0...64 uint8le tempo; // Initial music tempo (6) uint8le bpm; // Initial music BPM (125) uint16le originalFormat; // Original format ID: // 1-MOD, 2-MTM, 3-S3M, 4-669, 5-FAR, 6-ULT, 7-STM, 8-MED, 9-PSM // (versions of 2GDM prior to v1.15 won't set this correctly) // 2GDM v1.17 will only spit out 0-byte files when trying to convert a PSM16 file, // and fail outright when trying to convert a new PSM file. uint32le orderOffset; uint8le lastOrder; // Number of orders in module - 1 uint32le patternOffset; uint8le lastPattern; // Number of patterns in module - 1 uint32le sampleHeaderOffset; uint32le sampleDataOffset; uint8le lastSample; // Number of samples in module - 1 uint32le messageTextOffset; // Offset of song message uint32le messageTextLength; uint32le scrollyScriptOffset; // Offset of scrolly script (huh?) uint16le scrollyScriptLength; uint32le textGraphicOffset; // Offset of text graphic (huh?) uint16le textGraphicLength; uint8 GetNumChannels() const { return static_cast(std::distance(std::begin(panMap), std::find(std::begin(panMap), std::end(panMap), uint8_max))); } }; MPT_BINARY_STRUCT(GDMFileHeader, 157) // GDM Sample Header struct GDMSampleHeader { enum SampleFlags { smpLoop = 0x01, smp16Bit = 0x02, // 16-Bit samples are not handled correctly by 2GDM (not implemented) smpVolume = 0x04, // Use default volume smpPanning = 0x08, smpLZW = 0x10, // LZW-compressed samples are not implemented in 2GDM smpStereo = 0x20, // Stereo samples are not handled correctly by 2GDM (not implemented) }; char name[32]; // sample's name char fileName[12]; // sample's filename uint8le emsHandle; // useless uint32le length; // length in bytes uint32le loopBegin; // loop start in samples uint32le loopEnd; // loop end in samples uint8le flags; // see SampleFlags uint16le c4Hertz; // frequency uint8le volume; // default volume uint8le panning; // default pan }; MPT_BINARY_STRUCT(GDMSampleHeader, 62) static constexpr MODTYPE gdmFormatOrigin[] = { MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM }; static constexpr mpt::uchar gdmFormatOriginType[][4] = { UL_(""), UL_("mod"), UL_("mtm"), UL_("s3m"), UL_("669"), UL_("far"), UL_("ult"), UL_("stm"), UL_("med"), UL_("psm") }; static constexpr const mpt::uchar * gdmFormatOriginFormat[] = { UL_(""), UL_("Generic MOD"), UL_("MultiTracker"), UL_("Scream Tracker 3"), UL_("Composer 669 / UNIS 669"), UL_("Farandole Composer"), UL_("UltraTracker"), UL_("Scream Tracker 2"), UL_("OctaMED"), UL_("Epic Megagames MASI") }; static bool ValidateHeader(const GDMFileHeader &fileHeader) { if(std::memcmp(fileHeader.magic, "GDM\xFE", 4) || fileHeader.dosEOF[0] != 13 || fileHeader.dosEOF[1] != 10 || fileHeader.dosEOF[2] != 26 || std::memcmp(fileHeader.magic2, "GMFS", 4) || fileHeader.formatMajorVer != 1 || fileHeader.formatMinorVer != 0 || fileHeader.originalFormat >= std::size(gdmFormatOrigin) || fileHeader.originalFormat == 0 || !fileHeader.GetNumChannels()) { return false; } return true; } CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize) { GDMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return ProbeWantMoreData; } if(!ValidateHeader(fileHeader)) { return ProbeFailure; } MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); GDMFileHeader fileHeader; if(!file.ReadStruct(fileHeader)) { return false; } if(!ValidateHeader(fileHeader)) { return false; } if(loadFlags == onlyVerifyHeader) { return true; } InitializeGlobals(gdmFormatOrigin[fileHeader.originalFormat], fileHeader.GetNumChannels()); m_SongFlags.set(SONG_IMPORTED); m_modFormat.formatName = UL_("General Digital Music"); m_modFormat.type = UL_("gdm"); m_modFormat.madeWithTracker = MPT_UFORMAT("BWSB 2GDM {}.{}")(fileHeader.trackerMajorVer, fileHeader.formatMinorVer); m_modFormat.originalType = gdmFormatOriginType[fileHeader.originalFormat]; m_modFormat.originalFormatName = gdmFormatOriginFormat[fileHeader.originalFormat]; m_modFormat.charset = mpt::Charset::CP437; // Song name m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songTitle); // Artist name { std::string artist = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songMusician); if(artist != "Unknown") { m_songArtist = mpt::ToUnicode(mpt::Charset::CP437, artist); } } // Read channel pan map... 0...15 = channel panning, 16 = surround channel, 255 = channel does not exist for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) { if(fileHeader.panMap[i] < 16) { ChnSettings[i].nPan = static_cast(std::min((fileHeader.panMap[i] * 16) + 8, 256)); } else if(fileHeader.panMap[i] == 16) { ChnSettings[i].nPan = 128; ChnSettings[i].dwFlags = CHN_SURROUND; } } m_nDefaultGlobalVolume = std::min(fileHeader.masterVol * 4u, 256u); Order().SetDefaultSpeed(fileHeader.tempo); Order().SetDefaultTempoInt(fileHeader.bpm); // Read orders if(file.Seek(fileHeader.orderOffset)) { ReadOrderFromFile(Order(), file, fileHeader.lastOrder + 1, 0xFF, 0xFE); } // Read samples if(!file.Seek(fileHeader.sampleHeaderOffset)) { return false; } m_nSamples = fileHeader.lastSample + 1; // Sample headers for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { GDMSampleHeader gdmSample; if(!file.ReadStruct(gdmSample)) { break; } ModSample &sample = Samples[smp]; sample.Initialize(); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, gdmSample.name); sample.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, gdmSample.fileName); sample.nC5Speed = gdmSample.c4Hertz; if(UseFinetuneAndTranspose()) { // Use the same inaccurate table as 2GDM for translating back to finetune, as our own routines // give slightly different results for the provided sample rates that may result in transpose != 0. static constexpr uint16 rate2finetune[] = { 8363, 8424, 8485, 8547, 8608, 8671, 8734, 8797, 7894, 7951, 8009, 8067, 8125, 8184, 8244, 8303 }; for(uint8 i = 0; i < 16; i++) { if(sample.nC5Speed == rate2finetune[i]) { sample.nFineTune = MOD2XMFineTune(i); break; } } } sample.nGlobalVol = 64; // Not supported in this format sample.nLength = gdmSample.length; // in bytes // Sample format if(gdmSample.flags & GDMSampleHeader::smp16Bit) { sample.uFlags.set(CHN_16BIT); sample.nLength /= 2; } sample.nLoopStart = gdmSample.loopBegin; sample.nLoopEnd = gdmSample.loopEnd - 1; if(gdmSample.flags & GDMSampleHeader::smpLoop) sample.uFlags.set(CHN_LOOP); if((gdmSample.flags & GDMSampleHeader::smpVolume) && gdmSample.volume != 0xFF) sample.nVolume = std::min(static_cast(gdmSample.volume), uint8(64)) * 4; else sample.uFlags.set(SMP_NODEFAULTVOLUME); if(gdmSample.flags & GDMSampleHeader::smpPanning) { // Default panning is used sample.uFlags.set(CHN_PANNING); // 0...15, 16 = surround (not supported), 255 = no default panning sample.nPan = static_cast((gdmSample.panning > 15) ? 128 : std::min((gdmSample.panning * 16) + 8, 256)); sample.uFlags.set(CHN_SURROUND, gdmSample.panning == 16); } else { sample.nPan = 128; } } // Read sample data if((loadFlags & loadSampleData) && file.Seek(fileHeader.sampleDataOffset)) { for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { SampleIO( Samples[smp].uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::unsignedPCM) .ReadSample(Samples[smp], file); } } // Read patterns Patterns.ResizeArray(fileHeader.lastPattern + 1); const CModSpecifications &modSpecs = GetModSpecifications(GetBestSaveFormat()); bool onlyAmigaNotes = true; // We'll start at position patternsOffset and decode all patterns file.Seek(fileHeader.patternOffset); for(PATTERNINDEX pat = 0; pat <= fileHeader.lastPattern; pat++) { // Read pattern length *including* the two "length" bytes uint16 patternLength = file.ReadUint16LE(); if(patternLength <= 2) { // Huh, no pattern data present? continue; } FileReader chunk = file.ReadChunk(patternLength - 2); if(!(loadFlags & loadPatternData) || !chunk.IsValid() || !Patterns.Insert(pat, 64)) { continue; } enum { rowDone = 0x00, // Advance to next row channelMask = 0x1F, // Mask for retrieving channel information noteFlag = 0x20, // Note / instrument information present effectFlag = 0x40, // Effect information present effectMask = 0x1F, // Mask for retrieving effect command effectMore = 0x20, // Another effect follows }; for(ROWINDEX row = 0; row < 64; row++) { auto rowBase = Patterns[pat].GetRow(row); uint8 channelByte; // If channel byte is zero, advance to next row. while((channelByte = chunk.ReadUint8()) != rowDone) { CHANNELINDEX channel = channelByte & channelMask; if(channel >= GetNumChannels()) break; // Better safe than sorry! ModCommand &m = rowBase[channel]; if(channelByte & noteFlag) { // Note and sample follows auto [note, instr] = chunk.ReadArray(); if(note) { note = (note & 0x7F) - 1; // High bit = no-retrig flag (notes with portamento have this set) m.note = static_cast((note & 0x0F) + 12 * (note >> 4) + 12 + NOTE_MIN); if(!m.IsAmigaNote()) { onlyAmigaNotes = false; } } m.instr = instr; } if(channelByte & effectFlag) { // Effect(s) follow(s) m.command = CMD_NONE; m.volcmd = VOLCMD_NONE; while(chunk.CanRead(2)) { // We may want to restore the old command in some cases. const ModCommand oldCmd = m; const auto [effByte, param] = chunk.ReadArray(); m.param = param; // Effect translation LUT static constexpr EffectCommand gdmEffTrans[] = { CMD_NONE, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, CMD_TREMOR, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_POSITIONJUMP, CMD_VOLUME, CMD_PATTERNBREAK, CMD_MODCMDEX, CMD_SPEED, CMD_ARPEGGIO, CMD_NONE /* set internal flag */, CMD_RETRIG, CMD_GLOBALVOLUME, CMD_FINEVIBRATO, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_S3MCMDEX, CMD_TEMPO, }; // Translate effect uint8 command = effByte & effectMask; if(command < std::size(gdmEffTrans)) m.command = gdmEffTrans[command]; else m.command = CMD_NONE; // Fix some effects switch(m.command) { case CMD_PORTAMENTOUP: case CMD_PORTAMENTODOWN: if(m.param >= 0xE0 && m_nType != MOD_TYPE_MOD) m.param = 0xDF; // Don't spill into fine slide territory break; case CMD_TONEPORTAVOL: case CMD_VIBRATOVOL: if(m.param & 0xF0) m.param &= 0xF0; break; case CMD_VOLUME: m.param = std::min(m.param, uint8(64)); if(modSpecs.HasVolCommand(VOLCMD_VOLUME)) { m.volcmd = VOLCMD_VOLUME; m.vol = m.param; // Don't destroy old command, if there was one. m.command = oldCmd.command; m.param = oldCmd.param; } break; case CMD_MODCMDEX: switch(m.param >> 4) { case 0x8: m.command = CMD_PORTAMENTOUP; m.param = 0xE0 | (m.param & 0x0F); break; case 0x9: m.command = CMD_PORTAMENTODOWN; m.param = 0xE0 | (m.param & 0x0F); break; default: if(!modSpecs.HasCommand(CMD_MODCMDEX)) m.ExtendedMODtoS3MEffect(); break; } break; case CMD_RETRIG: if(!modSpecs.HasCommand(CMD_RETRIG) && modSpecs.HasCommand(CMD_MODCMDEX)) { // Retrig in "MOD style" m.command = CMD_MODCMDEX; m.param = 0x90 | (m.param & 0x0F); } break; case CMD_S3MCMDEX: // Some really special commands if(m.param == 0x01) { // Surround (implemented in 2GDM but not in BWSB itself) m.param = 0x91; } else if((m.param & 0xF0) == 0x80) { // 4-Bit Panning if (!modSpecs.HasCommand(CMD_S3MCMDEX)) m.command = CMD_MODCMDEX; } else { // All other effects are implemented neither in 2GDM nor in BWSB. m.command = CMD_NONE; } break; default: break; } // Move pannings to volume column - should never happen if(m.command == CMD_S3MCMDEX && ((m.param >> 4) == 0x8) && m.volcmd == VOLCMD_NONE) { m.SetVolumeCommand(VOLCMD_PANNING, static_cast(((m.param & 0x0F) * 64 + 8) / 15)); m.SetEffectCommand(oldCmd); } if(!(effByte & effectMore)) break; } } } } } m_SongFlags.set(SONG_AMIGALIMITS | SONG_ISAMIGA, GetType() == MOD_TYPE_MOD && GetNumChannels() == 4 && onlyAmigaNotes); // Read song comments if(fileHeader.messageTextLength > 0 && file.Seek(fileHeader.messageTextOffset)) { m_songMessage.Read(file, fileHeader.messageTextLength, SongMessage::leAutodetect); } return true; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/soundlib/MIDIMacroParser.h0000644000175000017500000000262714722731403021141 00000000000000/* * MIDIMacroParser.h * ----------------- * Purpose: Class for parsing IT MIDI macro strings and splitting them into individual raw MIDI messages. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "Snd_defs.h" OPENMPT_NAMESPACE_BEGIN class CSoundFile; struct PlayState; class MIDIMacroParser { public: // Parse the given MIDI macro into the out span. out needs to be at least one byte longer than the input string to support the longest possible macro translation. MIDIMacroParser(const CSoundFile &sndFile, PlayState *playState, CHANNELINDEX nChn, bool isSmooth, const mpt::span macro, mpt::span out, uint8 param = 0, PLUGINDEX plugin = 0); // Split a raw MIDI dump into multiple messages. Note that in order to support running status, NextMessage() may temporarily alter the provided data. // When the MIDIMacroParser destructor has run, the data will be back in its original state. MIDIMacroParser(mpt::span data) : m_data{data} {} ~MIDIMacroParser(); bool NextMessage(mpt::span &message, bool outputRunningStatus = true); private: mpt::span m_data; uint32 m_sendPos = 0; uint32 m_runningStatusPos = uint32_max; uint8 m_runningStatus = 0; uint8 m_runningstatusOldData = 0; }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/.clang-format0000644000175000017500000001161214275750533016645 00000000000000# clang-format 13 Language: Cpp Standard: c++20 AccessModifierOffset: -4 #? AlignAfterOpenBracket: AlwaysBreak AlignArrayOfStructures: Left AlignConsecutiveAssignments: false AlignConsecutiveBitFields: false AlignConsecutiveDeclarations: false AlignConsecutiveMacros: true AlignEscapedNewlines: DontAlign AlignOperands: AlignAfterOperator AlignTrailingComments: true AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: Always AllowShortCaseLabelsOnASingleLine: true AllowShortEnumsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: WithoutElse AllowShortLambdasOnASingleLine: Inline AllowShortLoopsOnASingleLine: false AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: Yes BinPackArguments: true BinPackParameters: false BitFieldColonSpacing: Both BraceWrapping: AfterCaseLabel: true AfterClass: true AfterControlStatement: Always AfterEnum: true AfterFunction: true AfterNamespace: true #AfterObjCDeclaration AfterStruct: true AfterUnion: true AfterExternBlock: true BeforeCatch: false BeforeElse: false BeforeLambdaBody: true BeforeWhile: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true #BreakAfterJavaFieldAnnotations BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Custom BreakBeforeConceptDeclarations: true BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeComma BreakInheritanceList: BeforeComma BreakStringLiterals: false ColumnLimit: 0 CommentPragmas: '' #? CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 #? ContinuationIndentWidth: 4 #? Cpp11BracedListStyle: true DeriveLineEnding: true DerivePointerAlignment: false EmptyLineAfterAccessModifier: Leave EmptyLineBeforeAccessModifier: Leave FixNamespaceComments: true ForEachMacros: [] IfMacros: ['MPT_MAYBE_CONSTANT_IF'] IncludeBlocks: Preserve IncludeCategories: [] #? IncludeIsMainRegex: '' #? IncludeIsMainSourceRegex: '' #? IndentAccessModifiers: false IndentCaseBlocks: true IndentCaseLabels: true IndentExternBlock: NoIndent IndentGotoLabels: false IndentPPDirectives: None #IndentRequiresClause: true #BeforeHash IndentWidth: 4 IndentWrappedFunctionNames: true InsertTrailingCommas: None #JavaImportGroups #JavaScriptQuotes #JavaScriptWrapImports KeepEmptyLinesAtTheStartOfBlocks: true LambdaBodyIndentation: OuterScope MacroBlockBegin: '^MPT_TEST_GROUP_BEGIN|BEGIN_MESSAGE_MAP$' #? MacroBlockEnd: '^MPT_TEST_GROUP_END|END_MESSAGE_MAP$' #? MaxEmptyLinesToKeep: 5 NamespaceIndentation: None NamespaceMacros: [] #? #ObjCBinPackProtocolList #ObjCBlockIndentWidth #ObjCBreakBeforeNestedBlockParam #ObjCSpaceAfterProperty #ObjCSpaceBeforeProtocolList PackConstructorInitializers: Never #PenaltyBreakAssignment #PenaltyBreakBeforeFirstCallParameter #PenaltyBreakComment #PenaltyBreakFirstLessLess #PenaltyBreakOpenParenthesis #PenaltyBreakString #PenaltyBreakTemplateDeclaration #PenaltyExcessCharacter #PenaltyIndentedWhitespace #PenaltyReturnTypeOnItsOwnLine PointerAlignment: Right PPIndentWidth: -1 QualifierAlignment: Leave #QualifierOrder: ['static', 'inline', 'constexpr', 'volatile', 'const', 'restrict', 'type'] #RawStringFormats ReferenceAlignment: Pointer ReflowComments: false RemoveBracesLLVM: false SeparateDefinitionBlocks: Leave ShortNamespaceLines: 1 SortIncludes: false #SortJavaStaticImport SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true SpaceAroundPointerQualifiers: Default SpaceBeforeAssignmentOperators: true SpaceBeforeCaseColon: false SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: Never SpaceBeforeParensOptions: AfterControlStatements: false AfterForeachMacros: false AfterFunctionDeclarationName: false AfterFunctionDefinitionName: false AfterIfMacros: false AfterOverloadedOperator: false #AfterRequiresInClause: false #AfterRequiresInExpression: false BeforeNonEmptyParentheses: false SpaceBeforeRangeBasedForLoopColon: true SpaceBeforeSquareBrackets: false SpaceInEmptyBlock: false SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInConditionalStatement: false SpacesInContainerLiterals: false SpacesInLineCommentPrefix: Minimum: 1 Maximum: -1 SpacesInParentheses: false SpacesInSquareBrackets: false StatementAttributeLikeMacros: [] StatementMacros: [ 'OPENMPT_NAMESPACE_BEGIN', 'OPENMPT_NAMESPACE_END', 'MPT_MSVC_WORKAROUND_LNK4221', 'MPT_WARNING', 'MPT_TEST_GROUP_INLINE_IDENTIFIER', 'MPT_TEST_GROUP_INLINE', 'MPT_TEST_GROUP_STATIC' ] #? TabWidth: 4 TypenameMacros: [] #? UseCRLF: false UseTab: ForContinuationAndIndentation WhitespaceSensitiveMacros: - MPT_PP_STRINGIFY libopenmpt-0.8.1+release.autotools/src/0000755000175000017500000000000015023302361015120 500000000000000libopenmpt-0.8.1+release.autotools/src/openmpt/0000755000175000017500000000000015023302361016602 500000000000000libopenmpt-0.8.1+release.autotools/src/openmpt/soundfile_write/0000755000175000017500000000000015023302363022006 500000000000000libopenmpt-0.8.1+release.autotools/src/openmpt/soundfile_write/wav_write.hpp0000644000175000017500000000273614660121125024457 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/io/base.hpp" #include "mpt/io/io_virtual_wrapper.hpp" #include "mpt/string/types.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/soundfile_data/tags.hpp" #include "openmpt/soundfile_data/wav.hpp" OPENMPT_NAMESPACE_BEGIN class WAVWriter { protected: // Output stream mpt::IO::OFileBase &s; // Currently written chunk mpt::IO::Offset chunkHeaderPos = 0; RIFFChunk chunkHeader; bool finalized = false; public: // Output to stream: Initialize with std::ostream*. WAVWriter(mpt::IO::OFileBase &stream); // Begin writing a new chunk to the file. void StartChunk(RIFFChunk::ChunkIdentifiers id); protected: // End current chunk by updating the chunk header and writing a padding byte if necessary. void FinalizeChunk(); public: // Write the WAV format to the file. void WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChannels, WAVFormatChunk::SampleFormats encoding); // Write text tags to the file. void WriteMetatags(const FileTags &tags); protected: // Write a single tag into a open idLIST chunk void WriteTag(RIFFChunk::ChunkIdentifiers id, const mpt::ustring &utext); public: // Finalize the file by closing the last open chunk and updating the file header. Returns total size of file. mpt::IO::Offset Finalize(); ~WAVWriter(); }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundfile_write/wav_write.cpp0000644000175000017500000001170414660143604024453 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #include "openmpt/all/BuildSettings.hpp" #include "openmpt/all/PlatformFixes.hpp" #include "wav_write.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/base/span.hpp" #include "mpt/base/utility.hpp" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_virtual_wrapper.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/soundfile_data/tags.hpp" #include "openmpt/soundfile_data/wav.hpp" #include #include #include OPENMPT_NAMESPACE_BEGIN WAVWriter::WAVWriter(mpt::IO::OFileBase &stream) : s(stream) { // Skip file header for now mpt::IO::SeekRelative(s, sizeof(RIFFHeader)); } void WAVWriter::StartChunk(RIFFChunk::ChunkIdentifiers id) { FinalizeChunk(); chunkHeaderPos = mpt::IO::TellWrite(s); chunkHeader.id = id; mpt::IO::SeekRelative(s, sizeof(chunkHeader)); } void WAVWriter::FinalizeChunk() { if(chunkHeaderPos != 0) { const mpt::IO::Offset position = mpt::IO::TellWrite(s); const mpt::IO::Offset chunkSize = position - (chunkHeaderPos + sizeof(RIFFChunk)); chunkHeader.length = mpt::saturate_cast(chunkSize); mpt::IO::SeekAbsolute(s, chunkHeaderPos); mpt::IO::Write(s, chunkHeader); mpt::IO::SeekAbsolute(s, position); if((chunkSize % 2u) != 0) { // Write padding uint8 padding = 0; mpt::IO::Write(s, padding); } chunkHeaderPos = 0; } } void WAVWriter::WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChannels, WAVFormatChunk::SampleFormats encoding) { StartChunk(RIFFChunk::idfmt_); WAVFormatChunk wavFormat; mpt::reset(wavFormat); bool extensible = (numChannels > 2); wavFormat.format = static_cast(extensible ? WAVFormatChunk::fmtExtensible : encoding); wavFormat.numChannels = numChannels; wavFormat.sampleRate = sampleRate; wavFormat.blockAlign = static_cast((bitDepth * numChannels + 7u) / 8u); wavFormat.byteRate = wavFormat.sampleRate * wavFormat.blockAlign; wavFormat.bitsPerSample = bitDepth; mpt::IO::Write(s, wavFormat); if(extensible) { WAVFormatChunkExtension extFormat; mpt::reset(extFormat); extFormat.size = sizeof(WAVFormatChunkExtension) - sizeof(uint16); extFormat.validBitsPerSample = bitDepth; switch(numChannels) { case 1: extFormat.channelMask = 0x0004; // FRONT_CENTER break; case 2: extFormat.channelMask = 0x0003; // FRONT_LEFT | FRONT_RIGHT break; case 3: extFormat.channelMask = 0x0103; // FRONT_LEFT | FRONT_RIGHT | BACK_CENTER break; case 4: extFormat.channelMask = 0x0033; // FRONT_LEFT | FRONT_RIGHT | BACK_LEFT | BACK_RIGHT break; default: extFormat.channelMask = 0; break; } extFormat.subFormat = mpt::UUID(static_cast(encoding), 0x0000, 0x0010, 0x800000AA00389B71ull); mpt::IO::Write(s, extFormat); } } void WAVWriter::WriteMetatags(const FileTags &tags) { StartChunk(RIFFChunk::idCSET); mpt::IO::Write(s, mpt::as_le(uint16(65001))); // code page (UTF-8) mpt::IO::Write(s, mpt::as_le(uint16(0))); // country code (unset) mpt::IO::Write(s, mpt::as_le(uint16(0))); // language (unset) mpt::IO::Write(s, mpt::as_le(uint16(0))); // dialect (unset) StartChunk(RIFFChunk::idLIST); const char info[] = {'I', 'N', 'F', 'O'}; mpt::IO::Write(s, info); WriteTag(RIFFChunk::idINAM, tags.title); WriteTag(RIFFChunk::idIART, tags.artist); WriteTag(RIFFChunk::idIPRD, tags.album); WriteTag(RIFFChunk::idICRD, tags.year); WriteTag(RIFFChunk::idICMT, tags.comments); WriteTag(RIFFChunk::idIGNR, tags.genre); WriteTag(RIFFChunk::idTURL, tags.url); WriteTag(RIFFChunk::idISFT, tags.encoder); WriteTag(RIFFChunk::idTRCK, tags.trackno); } void WAVWriter::WriteTag(RIFFChunk::ChunkIdentifiers id, const mpt::ustring &utext) { std::string text = mpt::transcode(mpt::common_encoding::utf8, utext); text = text.substr(0, std::numeric_limits::max() - 1u); if(!text.empty()) { const uint32 length = mpt::saturate_cast(text.length() + 1); RIFFChunk chunk; mpt::reset(chunk); chunk.id = static_cast(id); chunk.length = length; mpt::IO::Write(s, chunk); mpt::IO::Write(s, mpt::byte_cast(mpt::span(text.c_str(), length))); if((length % 2u) != 0) { uint8 padding = 0; mpt::IO::Write(s, padding); } } } mpt::IO::Offset WAVWriter::Finalize() { FinalizeChunk(); mpt::IO::Offset totalSize = mpt::IO::TellWrite(s); RIFFHeader fileHeader; mpt::reset(fileHeader); fileHeader.magic = RIFFHeader::idRIFF; fileHeader.length = mpt::saturate_cast(totalSize - 8); fileHeader.type = RIFFHeader::idWAVE; mpt::IO::SeekBegin(s); mpt::IO::Write(s, fileHeader); mpt::IO::SeekAbsolute(s, totalSize); finalized = true; return totalSize; } WAVWriter::~WAVWriter() { assert(finalized); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/random/0000755000175000017500000000000015023302361020062 500000000000000libopenmpt-0.8.1+release.autotools/src/openmpt/random/ModPlug.hpp0000644000175000017500000000335314650142521022073 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: Olivier Lapicque */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/bit.hpp" #include "mpt/random/random.hpp" #include "openmpt/base/Types.hpp" #include #include OPENMPT_NAMESPACE_BEGIN namespace mpt { namespace rng { template class modplug { public: typedef Tstate state_type; typedef Tvalue result_type; private: state_type state1; state_type state2; public: template explicit inline modplug(Trng &rd) : state1(mpt::random(rd)) , state2(mpt::random(rd)) { } explicit inline modplug(state_type seed1, state_type seed2) : state1(seed1) , state2(seed2) { } public: static MPT_CONSTEXPRINLINE result_type min() { return static_cast(0); } static MPT_CONSTEXPRINLINE result_type max() { return std::numeric_limits::max(); } static MPT_CONSTEXPRINLINE int result_bits() { static_assert(std::is_integral::value); static_assert(std::is_unsigned::value); return std::numeric_limits::digits; } inline result_type operator()() { state_type a = state1; state_type b = state2; a = mpt::rotl(a, rol1); a ^= x1; a += x2 + (b * x3); b += mpt::rotl(a, rol2) * x4; state1 = a; state2 = b; result_type result = static_cast(b); return result; } }; typedef modplug modplug_dither; } // namespace rng } // namespace mpt OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/all/0000755000175000017500000000000015023302361017352 500000000000000libopenmpt-0.8.1+release.autotools/src/openmpt/all/PlatformFixes.hpp0000644000175000017500000000043614660143604022602 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" // immediate quirk fixups #if defined(MPT_LIBC_QUIRK_REQUIRES_SYS_TYPES_H) #include #endif libopenmpt-0.8.1+release.autotools/src/openmpt/all/BuildSettings.hpp0000644000175000017500000000167014660143604022600 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #if defined(MODPLUG_TRACKER) || defined(LIBOPENMPT_BUILD) #include "BuildSettingsCompiler.h" #endif #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_os.hpp" #include "mpt/base/detect_quirks.hpp" #if defined(MODPLUG_TRACKER) || defined(LIBOPENMPT_BUILD) #include "BuildSettings.h" #else #include "mpt/base/namespace.hpp" #ifndef OPENMPT_NAMESPACE #define OPENMPT_NAMESPACE OpenMPT #endif #ifndef OPENMPT_NAMESPACE_BEGIN #define OPENMPT_NAMESPACE_BEGIN \ namespace OPENMPT_NAMESPACE \ { \ inline namespace MPT_INLINE_NS \ { #endif #ifndef OPENMPT_NAMESPACE_END #define OPENMPT_NAMESPACE_END \ } \ } #endif #ifdef __cplusplus OPENMPT_NAMESPACE_BEGIN namespace mpt { #ifndef MPT_NO_NAMESPACE using namespace ::mpt; #endif } // namespace mpt OPENMPT_NAMESPACE_END #endif #endif libopenmpt-0.8.1+release.autotools/src/openmpt/logging/0000755000175000017500000000000015023302361020230 500000000000000libopenmpt-0.8.1+release.autotools/src/openmpt/logging/Logger.hpp0000644000175000017500000000205214650142521022104 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/source_location.hpp" #include "mpt/string/types.hpp" OPENMPT_NAMESPACE_BEGIN enum LogLevel { LogDebug = 5, LogInformation = 4, LogNotification = 3, LogWarning = 2, LogError = 1 }; class ILogger { protected: virtual ~ILogger() = default; public: virtual bool IsLevelActive(LogLevel level) const noexcept = 0; // facility: ASCII virtual bool IsFacilityActive(const char *facility) const noexcept = 0; // facility: ASCII virtual void SendLogMessage(const mpt::source_location &loc, LogLevel level, const char *facility, const mpt::ustring &text) const = 0; }; #define MPT_LOG(logger, level, facility, text) \ do \ { \ if((logger).IsLevelActive((level))) \ { \ if((logger).IsFacilityActive((facility))) \ { \ (logger).SendLogMessage(MPT_SOURCE_LOCATION_CURRENT(), (level), (facility), (text)); \ } \ } \ } while(0) OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/0000755000175000017500000000000015023302361020565 500000000000000libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/MixSampleConvert.hpp0000644000175000017500000000424414650142521024467 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/macros.hpp" #include "openmpt/soundbase/MixSample.hpp" #include "openmpt/soundbase/SampleConvert.hpp" #include "openmpt/soundbase/SampleConvertFixedPoint.hpp" OPENMPT_NAMESPACE_BEGIN template struct ConvertMixSample; template <> struct ConvertMixSample { MPT_FORCEINLINE MixSampleInt conv(MixSampleInt src) { return src; } }; template <> struct ConvertMixSample { MPT_FORCEINLINE MixSampleFloat conv(MixSampleFloat src) { return src; } }; template struct ConvertMixSample { MPT_FORCEINLINE MixSampleInt conv(Tsrc src) { return SC::ConvertToFixedPoint{}(src); } }; template struct ConvertMixSample { MPT_FORCEINLINE Tdst conv(MixSampleInt src) { return SC::ConvertFixedPoint{}(src); } }; template struct ConvertMixSample { MPT_FORCEINLINE MixSampleFloat conv(Tsrc src) { return SC::Convert{}(src); } }; template struct ConvertMixSample { MPT_FORCEINLINE Tdst conv(MixSampleFloat src) { return SC::Convert{}(src); } }; template <> struct ConvertMixSample { MPT_FORCEINLINE MixSampleInt conv(MixSampleFloat src) { return SC::ConvertToFixedPoint{}(src); } }; template <> struct ConvertMixSample { MPT_FORCEINLINE MixSampleFloat conv(MixSampleInt src) { return SC::ConvertFixedPoint{}(src); } }; template MPT_FORCEINLINE Tdst mix_sample_cast(Tsrc src) { return ConvertMixSample{}.conv(src); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/DitherNone.hpp0000644000175000017500000000140414650142521023261 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/macros.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/soundbase/MixSample.hpp" OPENMPT_NAMESPACE_BEGIN struct Dither_None { public: using prng_type = struct { }; template static prng_type prng_init(Trd &) { return prng_type{}; } public: template MPT_FORCEINLINE MixSampleInt process(MixSampleInt sample, Trng &) { return sample; } template MPT_FORCEINLINE MixSampleFloat process(MixSampleFloat sample, Trng &) { return sample; } }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/SampleDecode.hpp0000644000175000017500000003117114657607003023563 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/float.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/memory.hpp" #include "openmpt/base/Endian.hpp" #include "openmpt/base/Types.hpp" #include #include #include OPENMPT_NAMESPACE_BEGIN // Byte offsets, from lowest significant to highest significant byte (for various functor template parameters) #define littleEndian64 0, 1, 2, 3, 4, 5, 6, 7 #define littleEndian32 0, 1, 2, 3 #define littleEndian24 0, 1, 2 #define littleEndian16 0, 1 #define bigEndian64 7, 6, 5, 4, 3, 2, 1, 0 #define bigEndian32 3, 2, 1, 0 #define bigEndian24 2, 1, 0 #define bigEndian16 1, 0 namespace SC { // SC = _S_ample_C_onversion // Every sample decoding functor has to typedef its input_t and output_t // and has to provide a static constexpr input_inc member // which describes by how many input_t elements inBuf has to be incremented between invocations. // input_inc is normally 1 except when decoding e.g. bigger sample values // from multiple std::byte values. struct DecodeInt8 { using input_t = std::byte; using output_t = int8; static constexpr std::size_t input_inc = 1; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { return mpt::byte_cast(*inBuf); } }; struct DecodeUint8 { using input_t = std::byte; using output_t = int8; static constexpr std::size_t input_inc = 1; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { return static_cast(static_cast(mpt::byte_cast(*inBuf)) - 128); } }; struct DecodeInt8Delta { using input_t = std::byte; using output_t = int8; static constexpr std::size_t input_inc = 1; uint8 delta; DecodeInt8Delta() : delta(0) { } MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { delta += mpt::byte_cast(*inBuf); return static_cast(delta); } }; struct DecodeInt16uLaw { using input_t = std::byte; using output_t = int16; static constexpr std::size_t input_inc = 1; // clang-format off static constexpr std::array uLawTable = { -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, -876, -844, -812, -780, -748, -716, -684, -652, -620, -588, -556, -524, -492, -460, -428, -396, -372, -356, -340, -324, -308, -292, -276, -260, -244, -228, -212, -196, -180, -164, -148, -132, -120, -112, -104, -96, -88, -80, -72, -64, -56, -48, -40, -32, -24, -16, -8, -1, 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, 876, 844, 812, 780, 748, 716, 684, 652, 620, 588, 556, 524, 492, 460, 428, 396, 372, 356, 340, 324, 308, 292, 276, 260, 244, 228, 212, 196, 180, 164, 148, 132, 120, 112, 104, 96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0 }; // clang-format on MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { return uLawTable[mpt::byte_cast(*inBuf)]; } }; struct DecodeInt16ALaw { using input_t = std::byte; using output_t = int16; static constexpr std::size_t input_inc = 1; // clang-format off static constexpr std::array ALawTable = { -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472, -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, -344, -328, -376, -360, -280, -264, -312, -296, -472, -456, -504, -488, -408, -392, -440, -424, -88, -72, -120, -104, -24, -8, -56, -40, -216, -200, -248, -232, -152, -136, -184, -168, -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, -688, -656, -752, -720, -560, -528, -624, -592, -944, -912, -1008, -976, -816, -784, -880, -848, 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, 344, 328, 376, 360, 280, 264, 312, 296, 472, 456, 504, 488, 408, 392, 440, 424, 88, 72, 120, 104, 24, 8, 56, 40, 216, 200, 248, 232, 152, 136, 184, 168, 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 688, 656, 752, 720, 560, 528, 624, 592, 944, 912, 1008, 976, 816, 784, 880, 848 }; // clang-format on MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { return ALawTable[mpt::byte_cast(*inBuf)]; } }; template struct DecodeInt16 { using input_t = std::byte; using output_t = int16; static constexpr std::size_t input_inc = 2; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { return static_cast((mpt::byte_cast(inBuf[loByteIndex]) | (mpt::byte_cast(inBuf[hiByteIndex]) << 8)) - offset); } }; template struct DecodeInt16Delta { using input_t = std::byte; using output_t = int16; static constexpr std::size_t input_inc = 2; uint16 delta; DecodeInt16Delta() : delta(0) { } MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { delta += static_cast(static_cast(mpt::byte_cast(inBuf[loByteIndex])) | static_cast(mpt::byte_cast(inBuf[hiByteIndex]) << 8)); return static_cast(delta); } }; struct DecodeInt16Delta8 { using input_t = std::byte; using output_t = int16; static constexpr std::size_t input_inc = 2; uint16 delta; DecodeInt16Delta8() : delta(0) { } MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { delta += mpt::byte_cast(inBuf[0]); int16 result = delta & 0xFF; delta += mpt::byte_cast(inBuf[1]); result |= static_cast(delta << 8); return result; } }; template struct DecodeInt24 { using input_t = std::byte; using output_t = int32; static constexpr std::size_t input_inc = 3; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { const uint32 tmp = (uint32(0) | (static_cast(mpt::byte_cast(inBuf[loByteIndex])) << 8) | (static_cast(mpt::byte_cast(inBuf[midByteIndex])) << 16) | (static_cast(mpt::byte_cast(inBuf[hiByteIndex])) << 24)) - offset; return static_cast(tmp); } }; template struct DecodeInt32 { using input_t = std::byte; using output_t = int32; static constexpr std::size_t input_inc = 4; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { const uint32 tmp = (uint32(0) | (static_cast(mpt::byte_cast(inBuf[loLoByteIndex])) << 0) | (static_cast(mpt::byte_cast(inBuf[loHiByteIndex])) << 8) | (static_cast(mpt::byte_cast(inBuf[hiLoByteIndex])) << 16) | (static_cast(mpt::byte_cast(inBuf[hiHiByteIndex])) << 24)) - offset; return static_cast(tmp); } }; template struct DecodeInt64 { using input_t = std::byte; using output_t = int64; static constexpr std::size_t input_inc = 8; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { const uint64 tmp = (uint64(0) | (static_cast(mpt::byte_cast(inBuf[b0])) << 0) | (static_cast(mpt::byte_cast(inBuf[b1])) << 8) | (static_cast(mpt::byte_cast(inBuf[b2])) << 16) | (static_cast(mpt::byte_cast(inBuf[b3])) << 24) | (static_cast(mpt::byte_cast(inBuf[b4])) << 32) | (static_cast(mpt::byte_cast(inBuf[b5])) << 40) | (static_cast(mpt::byte_cast(inBuf[b6])) << 48) | (static_cast(mpt::byte_cast(inBuf[b7])) << 56)) - offset; return static_cast(tmp); } }; template struct DecodeFloat32 { using input_t = std::byte; using output_t = somefloat32; static constexpr std::size_t input_inc = 4; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { somefloat32 val = IEEE754binary32LE(inBuf[loLoByteIndex], inBuf[loHiByteIndex], inBuf[hiLoByteIndex], inBuf[hiHiByteIndex]); val = mpt::sanitize_nan(val); if(std::isinf(val)) { if(val >= 0.0f) { val = 1.0f; } else { val = -1.0f; } } return val; } }; template struct DecodeScaledFloat32 { using input_t = std::byte; using output_t = somefloat32; static constexpr std::size_t input_inc = 4; float factor; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { somefloat32 val = IEEE754binary32LE(inBuf[loLoByteIndex], inBuf[loHiByteIndex], inBuf[hiLoByteIndex], inBuf[hiHiByteIndex]); val = mpt::sanitize_nan(val); if(std::isinf(val)) { if(val >= 0.0f) { val = 1.0f; } else { val = -1.0f; } } return factor * val; } MPT_FORCEINLINE DecodeScaledFloat32(float scaleFactor) : factor(scaleFactor) { return; } }; template struct DecodeFloat64 { using input_t = std::byte; using output_t = somefloat64; static constexpr std::size_t input_inc = 8; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { somefloat64 val = IEEE754binary64LE(inBuf[b0], inBuf[b1], inBuf[b2], inBuf[b3], inBuf[b4], inBuf[b5], inBuf[b6], inBuf[b7]); val = mpt::sanitize_nan(val); if(std::isinf(val)) { if(val >= 0.0) { val = 1.0; } else { val = -1.0; } } return val; } }; template struct DecodeIdentity { using input_t = Tsample; using output_t = Tsample; static constexpr std::size_t input_inc = 1; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { return *inBuf; } }; // Reads sample data with Func and passes it directly to Func2. // Func1::output_t and Func2::input_t must be identical template struct ConversionChain { using input_t = typename Func1::input_t; using output_t = typename Func2::output_t; static constexpr std::size_t input_inc = Func1::input_inc; Func1 func1; Func2 func2; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { return func2(func1(inBuf)); } MPT_FORCEINLINE ConversionChain(Func2 f2 = Func2(), Func1 f1 = Func1()) : func1(f1) , func2(f2) { return; } }; } // namespace SC OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/SampleFormat.hpp0000644000175000017500000002244614650142521023625 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/utility.hpp" #include "openmpt/base/Int24.hpp" #include "openmpt/base/Types.hpp" #include OPENMPT_NAMESPACE_BEGIN class SampleFormat { public: enum class Enum : uint8 { Unsigned8 = 9, // do not change value (for compatibility with old configuration settings) Int8 = 8, // do not change value (for compatibility with old configuration settings) Int16 = 16, // do not change value (for compatibility with old configuration settings) Int24 = 24, // do not change value (for compatibility with old configuration settings) Int32 = 32, // do not change value (for compatibility with old configuration settings) Float32 = 32 + 128, // do not change value (for compatibility with old configuration settings) Float64 = 64 + 128, // do not change value (for compatibility with old configuration settings) Default = Float32 }; static constexpr SampleFormat::Enum Unsigned8 = SampleFormat::Enum::Unsigned8; static constexpr SampleFormat::Enum Int8 = SampleFormat::Enum::Int8; static constexpr SampleFormat::Enum Int16 = SampleFormat::Enum::Int16; static constexpr SampleFormat::Enum Int24 = SampleFormat::Enum::Int24; static constexpr SampleFormat::Enum Int32 = SampleFormat::Enum::Int32; static constexpr SampleFormat::Enum Float32 = SampleFormat::Enum::Float32; static constexpr SampleFormat::Enum Float64 = SampleFormat::Enum::Float64; static constexpr SampleFormat::Enum Default = SampleFormat::Enum::Default; private: SampleFormat::Enum value; template static MPT_CONSTEXPRINLINE SampleFormat::Enum Sanitize(T x) noexcept { using uT = typename std::make_unsigned::type; uT val = static_cast(x); if(!val) { return SampleFormat::Enum::Default; } if(val == static_cast(-8)) { val = 8 + 1; } // float|64|32|16|8|?|?|unsigned val &= 0b1'1111'00'1; auto is_float = [](uT val) -> bool { return (val & 0b1'0000'00'0) ? true : false; }; auto is_unsigned = [](uT val) -> bool { return (val & 0b0'0000'00'1) ? true : false; }; auto has_size = [](uT val) -> bool { return (val & 0b0'1111'00'0) ? true : false; }; auto unique_size = [](uT val) -> bool { val &= 0b0'1111'00'0; if(val == 0b0'0001'00'0) { return true; } else if(val == 0b0'0010'00'0) { return true; } else if(val == 0b0'0011'00'0) { return true; } else if(val == 0b0'0100'00'0) { return true; } else if(val == 0b0'1000'00'0) { return true; } else { return false; } }; auto get_size = [](uT val) -> std::size_t { val &= 0b0'1111'00'0; if(val == 0b0'0001'00'0) { return 1; } else if(val == 0b0'0010'00'0) { return 2; } else if(val == 0b0'0011'00'0) { return 3; } else if(val == 0b0'0100'00'0) { return 4; } else if(val == 0b0'1000'00'0) { return 8; } else { return 2; // default to 16bit } }; if(!has_size(val)) { if(is_unsigned(val) && is_float(val)) { val = mpt::to_underlying(Enum::Default); } else if(is_unsigned(val)) { val = mpt::to_underlying(Enum::Unsigned8); } else if(is_float(val)) { val = mpt::to_underlying(Enum::Float32); } else { val = mpt::to_underlying(Enum::Default); } } else if(!unique_size(val)) { // order of size check matters if((val & 0b0'0011'00'0) == 0b0'0011'00'0) { val = mpt::to_underlying(Enum::Int24); } else if(val & 0b0'0010'00'0) { val = mpt::to_underlying(Enum::Int16); } else if(val & 0b0'0100'00'0) { if(is_float(val)) { val = mpt::to_underlying(Enum::Float32); } else { val = mpt::to_underlying(Enum::Int32); } } else if(val & 0b0'1000'00'0) { val = mpt::to_underlying(Enum::Float64); } else if(val & 0b0'0001'00'0) { if(is_unsigned(val)) { val = mpt::to_underlying(Enum::Unsigned8); } else { val = mpt::to_underlying(Enum::Int8); } } } else { if(is_unsigned(val) && (get_size(val) > 1)) { val &= ~0b0'0000'00'1; // remove unsigned } if(is_float(val) && (get_size(val) < 4)) { val &= ~0b1'0000'00'0; // remove float } if(!is_float(val) && (get_size(val) == 8)) { val |= 0b1'0000'00'0; // add float } } return static_cast(val); } public: MPT_CONSTEXPRINLINE SampleFormat() noexcept : value(SampleFormat::Default) { } MPT_CONSTEXPRINLINE SampleFormat(SampleFormat::Enum v) noexcept : value(Sanitize(v)) { } friend MPT_CONSTEXPRINLINE bool operator==(const SampleFormat &a, const SampleFormat &b) noexcept { return a.value == b.value; } friend MPT_CONSTEXPRINLINE bool operator!=(const SampleFormat &a, const SampleFormat &b) noexcept { return a.value != b.value; } friend MPT_CONSTEXPRINLINE bool operator==(const SampleFormat::Enum &a, const SampleFormat &b) noexcept { return a == b.value; } friend MPT_CONSTEXPRINLINE bool operator!=(const SampleFormat::Enum &a, const SampleFormat &b) noexcept { return a != b.value; } friend MPT_CONSTEXPRINLINE bool operator==(const SampleFormat &a, const SampleFormat::Enum &b) noexcept { return a.value == b; } friend MPT_CONSTEXPRINLINE bool operator!=(const SampleFormat &a, const SampleFormat::Enum &b) noexcept { return a.value != b; } MPT_CONSTEXPRINLINE bool IsUnsigned() const noexcept { return false || (value == SampleFormat::Unsigned8); } MPT_CONSTEXPRINLINE bool IsFloat() const noexcept { return false || (value == SampleFormat::Float32) || (value == SampleFormat::Float64); } MPT_CONSTEXPRINLINE bool IsInt() const noexcept { return false || (value == SampleFormat::Unsigned8) || (value == SampleFormat::Int8) || (value == SampleFormat::Int16) || (value == SampleFormat::Int24) || (value == SampleFormat::Int32); } MPT_CONSTEXPRINLINE uint8 GetSampleSize() const noexcept { return false ? 0 : (value == SampleFormat::Unsigned8) ? 1 : (value == SampleFormat::Int8) ? 1 : (value == SampleFormat::Int16) ? 2 : (value == SampleFormat::Int24) ? 3 : (value == SampleFormat::Int32) ? 4 : (value == SampleFormat::Float32) ? 4 : (value == SampleFormat::Float64) ? 8 : 0; } MPT_CONSTEXPRINLINE uint8 GetBitsPerSample() const noexcept { return false ? 0 : (value == SampleFormat::Unsigned8) ? 8 : (value == SampleFormat::Int8) ? 8 : (value == SampleFormat::Int16) ? 16 : (value == SampleFormat::Int24) ? 24 : (value == SampleFormat::Int32) ? 32 : (value == SampleFormat::Float32) ? 32 : (value == SampleFormat::Float64) ? 64 : 0; } MPT_CONSTEXPRINLINE operator SampleFormat::Enum() const noexcept { return value; } // backward compatibility, conversion to/from integers static MPT_CONSTEXPRINLINE SampleFormat FromInt(int x) noexcept { return SampleFormat(Sanitize(x)); } static MPT_CONSTEXPRINLINE int ToInt(SampleFormat x) noexcept { return mpt::to_underlying(x.value); } }; template Container AllSampleFormats() { return {SampleFormat::Float64, SampleFormat::Float32, SampleFormat::Int32, SampleFormat::Int24, SampleFormat::Int16, SampleFormat::Int8, SampleFormat::Unsigned8}; } template Container DefaultSampleFormats() { return {SampleFormat::Float32, SampleFormat::Int32, SampleFormat::Int24, SampleFormat::Int16, SampleFormat::Int8}; } template struct SampleFormatTraits; template <> struct SampleFormatTraits { static MPT_CONSTEXPRINLINE SampleFormat sampleFormat() { return SampleFormat::Unsigned8; } }; template <> struct SampleFormatTraits { static MPT_CONSTEXPRINLINE SampleFormat sampleFormat() { return SampleFormat::Int8; } }; template <> struct SampleFormatTraits { static MPT_CONSTEXPRINLINE SampleFormat sampleFormat() { return SampleFormat::Int16; } }; template <> struct SampleFormatTraits { static MPT_CONSTEXPRINLINE SampleFormat sampleFormat() { return SampleFormat::Int24; } }; template <> struct SampleFormatTraits { static MPT_CONSTEXPRINLINE SampleFormat sampleFormat() { return SampleFormat::Int32; } }; template <> struct SampleFormatTraits { static MPT_CONSTEXPRINLINE SampleFormat sampleFormat() { return SampleFormat::Float32; } }; template <> struct SampleFormatTraits { static MPT_CONSTEXPRINLINE SampleFormat sampleFormat() { return SampleFormat::Float64; } }; template struct SampleFormatToType; template <> struct SampleFormatToType { typedef uint8 type; }; template <> struct SampleFormatToType { typedef int8 type; }; template <> struct SampleFormatToType { typedef int16 type; }; template <> struct SampleFormatToType { typedef int24 type; }; template <> struct SampleFormatToType { typedef int32 type; }; template <> struct SampleFormatToType { typedef float type; }; template <> struct SampleFormatToType { typedef double type; }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/Copy.hpp0000644000175000017500000000500714650142521022137 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/audio/span.hpp" #include "mpt/base/macros.hpp" #include "openmpt/soundbase/SampleConvert.hpp" #include #include #include OPENMPT_NAMESPACE_BEGIN template void CopyAudio(TBufOut buf_out, TBufIn buf_in) { assert(buf_in.size_frames() == buf_out.size_frames()); assert(buf_in.size_channels() == buf_out.size_channels()); std::size_t countFrames = std::min(buf_in.size_frames(), buf_out.size_frames()); std::size_t channels = std::min(buf_in.size_channels(), buf_out.size_channels()); for(std::size_t frame = 0; frame < countFrames; ++frame) { for(std::size_t channel = 0; channel < channels; ++channel) { buf_out(channel, frame) = SC::sample_cast(buf_in(channel, frame)); } } } template void CopyAudio(TBufOut buf_out, TBufIn buf_in, std::size_t countFrames) { assert(countFrames <= buf_in.size_frames()); assert(countFrames <= buf_out.size_frames()); assert(buf_in.size_channels() == buf_out.size_channels()); std::size_t channels = std::min(buf_in.size_channels(), buf_out.size_channels()); for(std::size_t frame = 0; frame < countFrames; ++frame) { for(std::size_t channel = 0; channel < channels; ++channel) { buf_out(channel, frame) = SC::sample_cast(buf_in(channel, frame)); } } } template void CopyAudioChannels(TBufOut buf_out, TBufIn buf_in, std::size_t channels, std::size_t countFrames) { assert(countFrames <= buf_in.size_frames()); assert(countFrames <= buf_out.size_frames()); assert(channels <= buf_in.size_channels()); assert(channels <= buf_out.size_channels()); for(std::size_t frame = 0; frame < countFrames; ++frame) { for(std::size_t channel = 0; channel < channels; ++channel) { buf_out(channel, frame) = SC::sample_cast(buf_in(channel, frame)); } } } // Copy numChannels interleaved sample streams. template void CopyAudioChannelsInterleaved(Tout *MPT_RESTRICT outBuf, const Tin *MPT_RESTRICT inBuf, std::size_t numChannels, std::size_t countFrames) { CopyAudio(mpt::audio_span_interleaved(outBuf, numChannels, countFrames), mpt::audio_span_interleaved(inBuf, numChannels, countFrames)); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/Dither.hpp0000644000175000017500000000723014664604252022455 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/macros.hpp" #include "mpt/random/default_engines.hpp" #include "mpt/random/engine.hpp" #include "mpt/random/seed.hpp" #include "openmpt/soundbase/MixSample.hpp" #include #include #include OPENMPT_NAMESPACE_BEGIN template class MultiChannelDither { private: std::vector DitherChannels; typename Tdither::prng_type prng; public: template MultiChannelDither(Trd &rd, std::size_t channels) : DitherChannels(channels) , prng(Tdither::prng_init(rd)) { return; } void Reset() { for(std::size_t channel = 0; channel < DitherChannels.size(); ++channel) { DitherChannels[channel] = Tdither{}; } } std::size_t GetChannels() const { return DitherChannels.size(); } template MPT_FORCEINLINE MixSampleInt process(std::size_t channel, MixSampleInt sample) { return DitherChannels[channel].template process(sample, prng); } template MPT_FORCEINLINE MixSampleFloat process(std::size_t channel, MixSampleFloat sample) { return DitherChannels[channel].template process(sample, prng); } }; template class Dithers : public DitherNames { public: static constexpr std::size_t NoDither = noDither; static constexpr std::size_t DefaultDither = defaultDither; static constexpr std::size_t DefaultChannels = defaultChannels; private: seeding_random_engine m_PRNG; AvailableDithers m_Dithers; public: template Dithers(Trd &rd, std::size_t mode = defaultDither, std::size_t channels = defaultChannels) : m_PRNG(mpt::make_prng(rd)) , m_Dithers(std::in_place_index, m_PRNG, channels) { SetMode(mode, channels); } AvailableDithers &Variant() { return m_Dithers; } static std::size_t GetNumDithers() { return std::variant_size::value; } static std::size_t GetDefaultDither() { return defaultDither; } static std::size_t GetNoDither() { return noDither; } private: template void set_mode(std::size_t mode, std::size_t channels) { if constexpr(i < std::variant_size::value) { if(mode == i) { m_Dithers.template emplace(m_PRNG, channels); } else { this->template set_mode(mode, channels); } } else { MPT_UNUSED(mode); m_Dithers.template emplace(m_PRNG, channels); } } public: void SetMode(std::size_t mode, std::size_t channels) { if((mode == GetMode()) && (channels == GetChannels())) { std::visit([](auto &dither) { return dither.Reset(); }, m_Dithers); return; } set_mode(mode, channels); } void SetMode(std::size_t mode) { if(mode == GetMode()) { std::visit([](auto &dither) { return dither.Reset(); }, m_Dithers); return; } set_mode(mode, GetChannels()); } void SetChannels(std::size_t channels) { if(channels == GetChannels()) { return; } set_mode(GetMode(), channels); } void Reset() { std::visit([](auto &dither) { return dither.Reset(); }, m_Dithers); } std::size_t GetMode() const { return m_Dithers.index(); } std::size_t GetChannels() const { return std::visit([](auto &dither) { return dither.GetChannels(); }, m_Dithers); } }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/SampleConvertFixedPoint.hpp0000644000175000017500000001777514730244445026027 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/arithmetic_shift.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/math.hpp" #include "mpt/base/saturate_cast.hpp" #include "openmpt/base/Int24.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/soundbase/SampleConvert.hpp" #include #include OPENMPT_NAMESPACE_BEGIN namespace SC { // SC = _S_ample_C_onversion template struct ConvertFixedPoint; template struct ConvertFixedPoint { using input_t = int32; using output_t = uint8; static constexpr int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8; MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1); static_assert(shiftBits >= 1); val = mpt::rshift_signed((val + (1 << (shiftBits - 1))), shiftBits); // round if(val < std::numeric_limits::min()) val = std::numeric_limits::min(); if(val > std::numeric_limits::max()) val = std::numeric_limits::max(); return static_cast(val + 0x80); // unsigned } }; template struct ConvertFixedPoint { using input_t = int32; using output_t = int8; static constexpr int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8; MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1); static_assert(shiftBits >= 1); val = mpt::rshift_signed((val + (1 << (shiftBits - 1))), shiftBits); // round if(val < std::numeric_limits::min()) val = std::numeric_limits::min(); if(val > std::numeric_limits::max()) val = std::numeric_limits::max(); return static_cast(val); } }; template struct ConvertFixedPoint { using input_t = int32; using output_t = int16; static constexpr int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8; MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1); static_assert(shiftBits >= 1); val = mpt::rshift_signed((val + (1 << (shiftBits - 1))), shiftBits); // round if(val < std::numeric_limits::min()) val = std::numeric_limits::min(); if(val > std::numeric_limits::max()) val = std::numeric_limits::max(); return static_cast(val); } }; template struct ConvertFixedPoint { using input_t = int32; using output_t = int24; static constexpr int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8; MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1); static_assert(shiftBits >= 1); val = mpt::rshift_signed((val + (1 << (shiftBits - 1))), shiftBits); // round if(val < std::numeric_limits::min()) val = std::numeric_limits::min(); if(val > std::numeric_limits::max()) val = std::numeric_limits::max(); return static_cast(val); } }; template struct ConvertFixedPoint { using input_t = int32; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1); return static_cast(std::clamp(val, static_cast(-((1 << fractionalBits) - 1)), static_cast(1 << fractionalBits) - 1)) << (sizeof(input_t) * 8 - 1 - fractionalBits); } }; template struct ConvertFixedPoint { using input_t = int32; using output_t = somefloat32; const float factor; MPT_FORCEINLINE ConvertFixedPoint() : factor(1.0f / static_cast(1 << fractionalBits)) { return; } MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1); return static_cast(val) * factor; } }; template struct ConvertFixedPoint { using input_t = int32; using output_t = somefloat64; const double factor; MPT_FORCEINLINE ConvertFixedPoint() : factor(1.0 / static_cast(1 << fractionalBits)) { return; } MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1); return static_cast(val) * factor; } }; template struct ConvertToFixedPoint; template struct ConvertToFixedPoint { using input_t = uint8; using output_t = int32; static constexpr int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8; MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(output_t) * 8 - 1); static_assert(shiftBits >= 1); return mpt::lshift_signed(static_cast(static_cast(val) - 0x80), shiftBits); } }; template struct ConvertToFixedPoint { using input_t = int8; using output_t = int32; static constexpr int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8; MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(output_t) * 8 - 1); static_assert(shiftBits >= 1); return mpt::lshift_signed(static_cast(val), shiftBits); } }; template struct ConvertToFixedPoint { using input_t = int16; using output_t = int32; static constexpr int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8; MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(output_t) * 8 - 1); static_assert(shiftBits >= 1); return mpt::lshift_signed(static_cast(val), shiftBits); } }; template struct ConvertToFixedPoint { using input_t = int24; using output_t = int32; static constexpr int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8; MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(output_t) * 8 - 1); static_assert(shiftBits >= 1); return mpt::lshift_signed(static_cast(val), shiftBits); } }; template struct ConvertToFixedPoint { using input_t = int32; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(output_t) * 8 - 1); return mpt::rshift_signed(static_cast(val), (sizeof(input_t) * 8 - 1 - fractionalBits)); } }; template struct ConvertToFixedPoint { using input_t = somefloat32; using output_t = int32; const float factor; MPT_FORCEINLINE ConvertToFixedPoint() : factor(static_cast(1 << fractionalBits)) { return; } MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1); val = mpt::sanitize_nan(val); return mpt::saturate_trunc(SC::fastround(val * factor)); } }; template struct ConvertToFixedPoint { using input_t = somefloat64; using output_t = int32; const double factor; MPT_FORCEINLINE ConvertToFixedPoint() : factor(static_cast(1 << fractionalBits)) { return; } MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1); val = mpt::sanitize_nan(val); return mpt::saturate_trunc(SC::fastround(val * factor)); } }; } // namespace SC OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/SampleClip.hpp0000644000175000017500000000411514650142521023255 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/macros.hpp" #include "openmpt/base/Int24.hpp" #include "openmpt/base/Types.hpp" OPENMPT_NAMESPACE_BEGIN namespace SC { // SC = _S_ample_C_onversion template struct Clip; template struct Clip { using input_t = uint8; using output_t = uint8; MPT_FORCEINLINE uint8 operator()(uint8 val) { return val; } }; template struct Clip { using input_t = int8; using output_t = int8; MPT_FORCEINLINE int8 operator()(int8 val) { return val; } }; template struct Clip { using input_t = int16; using output_t = int16; MPT_FORCEINLINE int16 operator()(int16 val) { return val; } }; template struct Clip { using input_t = int24; using output_t = int24; MPT_FORCEINLINE int24 operator()(int24 val) { return val; } }; template struct Clip { using input_t = int32; using output_t = int32; MPT_FORCEINLINE int32 operator()(int32 val) { return val; } }; template struct Clip { using input_t = int64; using output_t = int64; MPT_FORCEINLINE int64 operator()(int64 val) { return val; } }; template struct Clip { using input_t = float; using output_t = float; MPT_FORCEINLINE float operator()(float val) { if constexpr(clipOutput) { if(val < -1.0f) val = -1.0f; if(val > 1.0f) val = 1.0f; return val; } else { return val; } } }; template struct Clip { using input_t = double; using output_t = double; MPT_FORCEINLINE double operator()(double val) { if constexpr(clipOutput) { if(val < -1.0) val = -1.0; if(val > 1.0) val = 1.0; return val; } else { return val; } } }; } // namespace SC OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/MixSample.hpp0000644000175000017500000000413614657607003023136 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: Olivier Lapicque */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/audio/sample.hpp" #include "mpt/base/float.hpp" #include #include OPENMPT_NAMESPACE_BEGIN template struct FixedPointSampleTraits { static_assert(std::is_integral::value); static_assert(std::is_signed::value); static_assert((sizeof(Tsample) * 8u) - 1 > MIX_HEADROOM_BITS); static_assert((sizeof(Tsample) * 8u) - 1 > FILTER_HEADROOM_BITS); using sample_type = Tsample; enum class sample_type_strong : sample_type { }; static constexpr int mix_headroom_bits = static_cast(MIX_HEADROOM_BITS); static constexpr int mix_precision_bits = static_cast((sizeof(Tsample) * 8) - MIX_HEADROOM_BITS); // including sign bit static constexpr int mix_fractional_bits = static_cast((sizeof(Tsample) * 8) - 1 - MIX_HEADROOM_BITS); // excluding sign bit static constexpr sample_type mix_clip_max = ((sample_type(1) << mix_fractional_bits) - sample_type(1)); static constexpr sample_type mix_clip_min = -((sample_type(1) << mix_fractional_bits) - sample_type(1)); static constexpr int filter_headroom_bits = static_cast(FILTER_HEADROOM_BITS); static constexpr int filter_precision_bits = static_cast((sizeof(Tsample) * 8) - FILTER_HEADROOM_BITS); // including sign bit static constexpr int filter_fractional_bits = static_cast((sizeof(Tsample) * 8) - 1 - FILTER_HEADROOM_BITS); // excluding sign bit template static constexpr Tfloat mix_scale = static_cast(sample_type(1) << mix_fractional_bits); }; using MixSampleIntTraits = FixedPointSampleTraits; using MixSampleInt = MixSampleIntTraits::sample_type; using MixSampleFloat = mpt::audio_sample_float; using MixSample = std::conditional::is_hard, MixSampleFloat, MixSampleInt>::type; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/SampleEncode.hpp0000644000175000017500000000404214650142521023562 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/bit.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/memory.hpp" #include "openmpt/base/Types.hpp" #include #include #include #include OPENMPT_NAMESPACE_BEGIN namespace SC { // SC = _S_ample_C_onversion struct EncodeuLaw { using input_t = int16; using output_t = std::byte; static constexpr uint8 exp_table[17] = {0, 7 << 4, 6 << 4, 5 << 4, 4 << 4, 3 << 4, 2 << 4, 1 << 4, 0 << 4, 0, 0, 0, 0, 0, 0, 0, 0}; static constexpr uint8 mant_table[17] = {0, 10, 9, 8, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3}; MPT_FORCEINLINE output_t operator()(input_t val) { uint16 x = static_cast(val); uint8 out = static_cast((x >> 8) & 0x80u); uint32 abs = x & 0x7fffu; if(x & 0x8000u) { abs ^= 0x7fffu; abs += 1u; } x = static_cast(std::clamp(static_cast(abs + (33 << 2)), static_cast(0), static_cast(0x7fff))); int index = mpt::countl_zero(x); out |= exp_table[index]; out |= (x >> mant_table[index]) & 0x0fu; out ^= 0xffu; return mpt::byte_cast(out); } }; struct EncodeALaw { using input_t = int16; using output_t = std::byte; static constexpr uint8 exp_table[17] = {0, 7 << 4, 6 << 4, 5 << 4, 4 << 4, 3 << 4, 2 << 4, 1 << 4, 0 << 4, 0, 0, 0, 0, 0, 0, 0, 0}; static constexpr uint8 mant_table[17] = {0, 10, 9, 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; MPT_FORCEINLINE output_t operator()(input_t val) { int16 sx = std::clamp(val, static_cast(-32767), static_cast(32767)); uint16 x = static_cast(sx); uint8 out = static_cast(((x & 0x8000u) ^ 0x8000u) >> 8); x = static_cast(std::abs(sx)); int index = mpt::countl_zero(x); out |= exp_table[index]; out |= (x >> mant_table[index]) & 0x0fu; out ^= 0x55u; return mpt::byte_cast(out); } }; } // namespace SC OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/DitherModPlug.hpp0000644000175000017500000000265514650142521023742 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: Olivier Lapicque */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/arithmetic_shift.hpp" #include "mpt/base/macros.hpp" #include "mpt/random/random.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/random/ModPlug.hpp" #include "openmpt/soundbase/MixSample.hpp" #include "openmpt/soundbase/MixSampleConvert.hpp" OPENMPT_NAMESPACE_BEGIN struct Dither_ModPlug { public: using prng_type = mpt::rng::modplug_dither; template static prng_type prng_init(Trd &) { return prng_type{0, 0}; } public: template MPT_FORCEINLINE MixSampleInt process(MixSampleInt sample, Trng &rng) { if constexpr(targetbits == 0) { MPT_UNUSED(rng); return sample; } else if constexpr(targetbits + MixSampleIntTraits::mix_headroom_bits + 1 >= 32) { MPT_UNUSED(rng); return sample; } else { sample += mpt::rshift_signed(static_cast(mpt::random(rng)), (targetbits + MixSampleIntTraits::mix_headroom_bits + 1)); return sample; } } template MPT_FORCEINLINE MixSampleFloat process(MixSampleFloat sample, Trng &prng) { return mix_sample_cast(process(mix_sample_cast(sample), prng)); } }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/SampleConvert.hpp0000644000175000017500000003713114730244445024021 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/arithmetic_shift.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/math.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/base/saturate_round.hpp" #include "openmpt/base/Int24.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/soundbase/SampleConvert.hpp" #include #include #include #include OPENMPT_NAMESPACE_BEGIN namespace SC { // SC = _S_ample_C_onversion #if MPT_COMPILER_MSVC template MPT_FORCEINLINE Tfloat fastround(Tfloat x) { static_assert(std::is_floating_point::value); return std::floor(x + static_cast(0.5)); } #else template MPT_FORCEINLINE Tfloat fastround(Tfloat x) { static_assert(std::is_floating_point::value); return mpt::round(x); } #endif // Shift input_t down by shift and saturate to output_t. template struct ConvertShift { using input_t = Tsrc; using output_t = Tdst; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::saturate_cast(mpt::rshift_signed(val, shift)); } }; // Shift input_t up by shift and saturate to output_t. template struct ConvertShiftUp { using input_t = Tsrc; using output_t = Tdst; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::saturate_cast(mpt::lshift_signed(val, shift)); } }; // Every sample conversion functor has to typedef its input_t and output_t. // The input_t argument is taken by value because we only deal with per-single-sample conversions here. // straight forward type conversions, clamping when converting from floating point. template struct Convert; template struct Convert { using input_t = Tid; using output_t = Tid; MPT_FORCEINLINE output_t operator()(input_t val) { return val; } }; template <> struct Convert { using input_t = int8; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val + 0x80); } }; template <> struct Convert { using input_t = int16; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(mpt::rshift_signed(val, 8)) + 0x80); } }; template <> struct Convert { using input_t = int24; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(mpt::rshift_signed(static_cast(val), 16)) + 0x80); } }; template <> struct Convert { using input_t = int32; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(mpt::rshift_signed(val, 24)) + 0x80); } }; template <> struct Convert { using input_t = int64; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(mpt::rshift_signed(val, 56)) + 0x80); } }; template <> struct Convert { using input_t = somefloat32; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= 128.0f; return static_cast(mpt::saturate_cast(static_cast(SC::fastround(val))) + 0x80); } }; template <> struct Convert { using input_t = double; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= 128.0; return static_cast(mpt::saturate_cast(static_cast(SC::fastround(val))) + 0x80); } }; template <> struct Convert { using input_t = uint8; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(val) - 0x80); } }; template <> struct Convert { using input_t = int16; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 8)); } }; template <> struct Convert { using input_t = int24; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(static_cast(val), 16)); } }; template <> struct Convert { using input_t = int32; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 24)); } }; template <> struct Convert { using input_t = int64; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 56)); } }; template <> struct Convert { using input_t = somefloat32; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= 128.0f; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = double; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= 128.0; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = uint8; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(static_cast(val) - 0x80, 8)); } }; template <> struct Convert { using input_t = int8; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(val, 8)); } }; template <> struct Convert { using input_t = int24; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(static_cast(val), 8)); } }; template <> struct Convert { using input_t = int32; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 16)); } }; template <> struct Convert { using input_t = int64; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 48)); } }; template <> struct Convert { using input_t = somefloat32; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= 32768.0f; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = double; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= 32768.0; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = uint8; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(static_cast(val) - 0x80, 16)); } }; template <> struct Convert { using input_t = int8; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(val, 16)); } }; template <> struct Convert { using input_t = int16; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(val, 8)); } }; template <> struct Convert { using input_t = int32; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 8)); } }; template <> struct Convert { using input_t = int64; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 40)); } }; template <> struct Convert { using input_t = somefloat32; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= 2147483648.0f; return static_cast(mpt::rshift_signed(mpt::saturate_cast(static_cast(SC::fastround(val))), 8)); } }; template <> struct Convert { using input_t = double; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= 2147483648.0; return static_cast(mpt::rshift_signed(mpt::saturate_cast(static_cast(SC::fastround(val))), 8)); } }; template <> struct Convert { using input_t = uint8; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(static_cast(val) - 0x80, 24)); } }; template <> struct Convert { using input_t = int8; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(val, 24)); } }; template <> struct Convert { using input_t = int16; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(val, 16)); } }; template <> struct Convert { using input_t = int24; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(static_cast(val), 8)); } }; template <> struct Convert { using input_t = int64; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 32)); } }; template <> struct Convert { using input_t = somefloat32; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= 2147483648.0f; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = double; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= 2147483648.0; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = uint8; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::lshift_signed(static_cast(val) - 0x80, 56); } }; template <> struct Convert { using input_t = int8; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::lshift_signed(static_cast(val), 56); } }; template <> struct Convert { using input_t = int16; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::lshift_signed(static_cast(val), 48); } }; template <> struct Convert { using input_t = int24; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::lshift_signed(static_cast(val), 40); } }; template <> struct Convert { using input_t = int32; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::lshift_signed(static_cast(val), 32); } }; template <> struct Convert { using input_t = somefloat32; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= static_cast(uint64(1) << 63); return mpt::saturate_trunc(SC::fastround(val)); } }; template <> struct Convert { using input_t = double; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= static_cast(uint64(1) << 63); return mpt::saturate_trunc(SC::fastround(val)); } }; template <> struct Convert { using input_t = uint8; using output_t = somefloat32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(val) - 0x80) * (1.0f / static_cast(static_cast(1) << 7)); } }; template <> struct Convert { using input_t = int8; using output_t = somefloat32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val) * (1.0f / static_cast(static_cast(1) << 7)); } }; template <> struct Convert { using input_t = int16; using output_t = somefloat32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val) * (1.0f / static_cast(static_cast(1) << 15)); } }; template <> struct Convert { using input_t = int24; using output_t = somefloat32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val) * (1.0f / static_cast(static_cast(1) << 23)); } }; template <> struct Convert { using input_t = int32; using output_t = somefloat32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val) * (1.0f / static_cast(static_cast(1) << 31)); } }; template <> struct Convert { using input_t = int64; using output_t = somefloat32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val) * (1.0f / static_cast(static_cast(1) << 63)); } }; template <> struct Convert { using input_t = uint8; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(val) - 0x80) * (1.0 / static_cast(static_cast(1) << 7)); } }; template <> struct Convert { using input_t = int8; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val) * (1.0 / static_cast(static_cast(1) << 7)); } }; template <> struct Convert { using input_t = int16; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val) * (1.0 / static_cast(static_cast(1) << 15)); } }; template <> struct Convert { using input_t = int24; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val) * (1.0 / static_cast(static_cast(1) << 23)); } }; template <> struct Convert { using input_t = int32; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val) * (1.0 / static_cast(static_cast(1) << 31)); } }; template <> struct Convert { using input_t = int64; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val) * (1.0 / static_cast(static_cast(1) << 63)); } }; template <> struct Convert { using input_t = float; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val); } }; template <> struct Convert { using input_t = double; using output_t = float; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val); } }; template MPT_FORCEINLINE Tdst sample_cast(Tsrc src) { return SC::Convert{}(src); } } // namespace SC OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/SampleClipFixedPoint.hpp0000644000175000017500000000160714650142521025252 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/macros.hpp" OPENMPT_NAMESPACE_BEGIN namespace SC { // SC = _S_ample_C_onversion template struct ClipFixed { using input_t = Tfixed; using output_t = Tfixed; MPT_FORCEINLINE Tfixed operator()(Tfixed val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(output_t) * 8 - 1); if constexpr(clipOutput) { constexpr Tfixed clip_max = (Tfixed(1) << fractionalBits) - Tfixed(1); constexpr Tfixed clip_min = Tfixed(0) - (Tfixed(1) << fractionalBits); if(val < clip_min) val = clip_min; if(val > clip_max) val = clip_max; return val; } else { return val; } } }; } // namespace SC OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/DitherSimple.hpp0000644000175000017500000000470714664604252023635 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/macros.hpp" #include "mpt/random/engine.hpp" #include "mpt/random/default_engines.hpp" #include "mpt/random/random.hpp" #include "mpt/random/seed.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/soundbase/MixSample.hpp" #include "openmpt/soundbase/MixSampleConvert.hpp" OPENMPT_NAMESPACE_BEGIN template struct Dither_SimpleImpl { public: using prng_type = mpt::fast_engine; template static prng_type prng_init(Trd &rd) { return mpt::make_prng(rd); } private: int32 error = 0; public: template MPT_FORCEINLINE MixSampleInt process(MixSampleInt sample, Trng &prng) { if constexpr(targetbits == 0) { MPT_UNUSED(prng); return sample; } else { static_assert(sizeof(MixSampleInt) == 4); constexpr int rshift = (32 - targetbits) - MixSampleIntTraits::mix_headroom_bits; if constexpr(rshift <= 1) { MPT_UNUSED(prng); // nothing to dither return sample; } else { constexpr int rshiftpositive = (rshift > 1) ? rshift : 1; // work-around warnings about negative shift with C++14 compilers constexpr int round_mask = ~((1 << rshiftpositive) - 1); constexpr int round_offset = 1 << (rshiftpositive - 1); constexpr int noise_bits = rshiftpositive + (ditherdepth - 1); constexpr int noise_bias = (1 << (noise_bits - 1)); int32 e = error; unsigned int unoise = 0; if constexpr(triangular) { unoise = (mpt::random(prng, noise_bits) + mpt::random(prng, noise_bits)) >> 1; } else { unoise = mpt::random(prng, noise_bits); } int noise = static_cast(unoise) - noise_bias; // un-bias int val = sample; if constexpr(shaped) { val += (e >> 1); } int rounded = (val + noise + round_offset) & round_mask; e = val - rounded; sample = rounded; error = e; return sample; } } } template MPT_FORCEINLINE MixSampleFloat process(MixSampleFloat sample, Trng &prng) { return mix_sample_cast(process(mix_sample_cast(sample), prng)); } }; using Dither_Simple = Dither_SimpleImpl<>; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundbase/CopyMix.hpp0000644000175000017500000001017514650142521022617 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/audio/span.hpp" #include "mpt/base/macros.hpp" #include "openmpt/soundbase/SampleClip.hpp" #include "openmpt/soundbase/SampleClipFixedPoint.hpp" #include "openmpt/soundbase/SampleConvert.hpp" #include "openmpt/soundbase/SampleConvertFixedPoint.hpp" #include "openmpt/soundbase/SampleFormat.hpp" #include #include #include OPENMPT_NAMESPACE_BEGIN template void ConvertBufferMixInternalFixedToBuffer(TOutBuf outBuf, TInBuf inBuf, Tdither &dither, std::size_t channels, std::size_t count) { using TOutSample = typename std::remove_const::type; using TInSample = typename std::remove_const::type; assert(inBuf.size_channels() >= channels); assert(outBuf.size_channels() >= channels); assert(inBuf.size_frames() >= count); assert(outBuf.size_frames() >= count); constexpr int ditherBits = SampleFormat(SampleFormatTraits::sampleFormat()).IsInt() ? SampleFormat(SampleFormatTraits::sampleFormat()).GetBitsPerSample() : 0; SC::ClipFixed clip; SC::ConvertFixedPoint conv; for(std::size_t i = 0; i < count; ++i) { for(std::size_t channel = 0; channel < channels; ++channel) { outBuf(channel, i) = conv(clip(dither.template process(channel, inBuf(channel, i)))); } } } template void ConvertBufferToBufferMixInternalFixed(TOutBuf outBuf, TInBuf inBuf, std::size_t channels, std::size_t count) { using TOutSample = typename std::remove_const::type; using TInSample = typename std::remove_const::type; assert(inBuf.size_channels() >= channels); assert(outBuf.size_channels() >= channels); assert(inBuf.size_frames() >= count); assert(outBuf.size_frames() >= count); SC::ConvertToFixedPoint conv; for(std::size_t i = 0; i < count; ++i) { for(std::size_t channel = 0; channel < channels; ++channel) { outBuf(channel, i) = conv(inBuf(channel, i)); } } } template void ConvertBufferMixInternalToBuffer(TOutBuf outBuf, TInBuf inBuf, Tdither &dither, std::size_t channels, std::size_t count) { using TOutSample = typename std::remove_const::type; using TInSample = typename std::remove_const::type; assert(inBuf.size_channels() >= channels); assert(outBuf.size_channels() >= channels); assert(inBuf.size_frames() >= count); assert(outBuf.size_frames() >= count); constexpr int ditherBits = SampleFormat(SampleFormatTraits::sampleFormat()).IsInt() ? SampleFormat(SampleFormatTraits::sampleFormat()).GetBitsPerSample() : 0; SC::Clip clip; SC::Convert conv; for(std::size_t i = 0; i < count; ++i) { for(std::size_t channel = 0; channel < channels; ++channel) { outBuf(channel, i) = conv(clip(dither.template process(channel, inBuf(channel, i)))); } } } template void ConvertBufferToBufferMixInternal(TOutBuf outBuf, TInBuf inBuf, std::size_t channels, std::size_t count) { using TOutSample = typename std::remove_const::type; using TInSample = typename std::remove_const::type; assert(inBuf.size_channels() >= channels); assert(outBuf.size_channels() >= channels); assert(inBuf.size_frames() >= count); assert(outBuf.size_frames() >= count); SC::Convert conv; for(std::size_t i = 0; i < count; ++i) { for(std::size_t channel = 0; channel < channels; ++channel) { outBuf(channel, i) = conv(inBuf(channel, i)); } } } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundfile_data/0000755000175000017500000000000015023302361021563 500000000000000libopenmpt-0.8.1+release.autotools/src/openmpt/soundfile_data/tags.hpp0000644000175000017500000000076614657647536023217 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/string/types.hpp" OPENMPT_NAMESPACE_BEGIN struct FileTags { mpt::ustring encoder; mpt::ustring title; mpt::ustring comments; mpt::ustring bpm; mpt::ustring artist; mpt::ustring album; mpt::ustring trackno; mpt::ustring year; mpt::ustring url; mpt::ustring genre; }; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/soundfile_data/wav.hpp0000644000175000017500000000744014660112752023027 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/uuid/uuid.hpp" #include "openmpt/base/Endian.hpp" #include "openmpt/fileformat_base/magic.hpp" #include OPENMPT_NAMESPACE_BEGIN // RIFF header struct RIFFHeader { // 32-Bit chunk identifiers enum RIFFMagic { idRIFF = MagicLE("RIFF"), // magic for WAV files idLIST = MagicLE("LIST"), // magic for samples in DLS banks idWAVE = MagicLE("WAVE"), // type for WAV files idwave = MagicLE("wave"), // type for samples in DLS banks }; uint32le magic; // RIFF (in WAV files) or LIST (in DLS banks) uint32le length; // Size of the file, not including magic and length uint32le type; // WAVE (in WAV files) or wave (in DLS banks) }; MPT_BINARY_STRUCT(RIFFHeader, 12) // General RIFF Chunk header struct RIFFChunk { // 32-Bit chunk identifiers enum ChunkIdentifiers { idfmt_ = MagicLE("fmt "), // Sample format information iddata = MagicLE("data"), // Sample data idpcm_ = MagicLE("pcm "), // IMA ADPCM samples idfact = MagicLE("fact"), // Compressed samples idsmpl = MagicLE("smpl"), // Sampler and loop information idinst = MagicLE("inst"), // Instrument information idLIST = MagicLE("LIST"), // List of chunks idxtra = MagicLE("xtra"), // OpenMPT extra infomration idcue_ = MagicLE("cue "), // Cue points idwsmp = MagicLE("wsmp"), // DLS bank samples idCSET = MagicLE("CSET"), // Character Set id____ = 0x00000000, // Found when loading buggy MPT samples // Identifiers in "LIST" chunk idINAM = MagicLE("INAM"), // title idISFT = MagicLE("ISFT"), // software idICOP = MagicLE("ICOP"), // copyright idIART = MagicLE("IART"), // artist idIPRD = MagicLE("IPRD"), // product (album) idICMT = MagicLE("ICMT"), // comment idIENG = MagicLE("IENG"), // engineer idISBJ = MagicLE("ISBJ"), // subject idIGNR = MagicLE("IGNR"), // genre idICRD = MagicLE("ICRD"), // date created idYEAR = MagicLE("YEAR"), // year idTRCK = MagicLE("TRCK"), // track number idTURL = MagicLE("TURL"), // url }; uint32le id; // See ChunkIdentifiers uint32le length; // Chunk size without header std::size_t GetLength() const { return length; } ChunkIdentifiers GetID() const { return static_cast(id.get()); } }; MPT_BINARY_STRUCT(RIFFChunk, 8) // Format Chunk struct WAVFormatChunk { // Sample formats enum SampleFormats { fmtPCM = 1, fmtFloat = 3, fmtALaw = 6, fmtULaw = 7, fmtIMA_ADPCM = 17, fmtMP3 = 85, fmtExtensible = 0xFFFE, }; uint16le format; // Sample format, see SampleFormats uint16le numChannels; // Number of audio channels uint32le sampleRate; // Sample rate in Hz uint32le byteRate; // Bytes per second (should be freqHz * blockAlign) uint16le blockAlign; // Size of a sample, in bytes (do not trust this value, it's incorrect in some files) uint16le bitsPerSample; // Bits per sample }; MPT_BINARY_STRUCT(WAVFormatChunk, 16) // Extension of the WAVFormatChunk structure, used if format == formatExtensible struct WAVFormatChunkExtension { uint16le size; uint16le validBitsPerSample; uint32le channelMask; mpt::GUIDms subFormat; }; MPT_BINARY_STRUCT(WAVFormatChunkExtension, 24) // Sample cue point structure for the "cue " chunk struct WAVCuePoint { uint32le id; // Unique identification value uint32le position; // Play order position uint32le riffChunkID; // RIFF ID of corresponding data chunk uint32le chunkStart; // Byte Offset of Data Chunk uint32le blockStart; // Byte Offset to sample of First Channel uint32le offset; // Byte Offset to sample byte of First Channel }; MPT_BINARY_STRUCT(WAVCuePoint, 24) OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/base/0000755000175000017500000000000015023302361017514 500000000000000libopenmpt-0.8.1+release.autotools/src/openmpt/base/Types.hpp0000644000175000017500000000122114657607003021262 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/float.hpp" #include "mpt/base/integer.hpp" OPENMPT_NAMESPACE_BEGIN using int8 = mpt::int8; using int16 = mpt::int16; using int32 = mpt::int32; using int64 = mpt::int64; using uint8 = mpt::uint8; using uint16 = mpt::uint16; using uint32 = mpt::uint32; using uint64 = mpt::uint64; using nativefloat = mpt::nativefloat; using somefloat32 = mpt::somefloat32; using somefloat64 = mpt::somefloat64; using namespace mpt::float_literals; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/base/Int24.hpp0000644000175000017500000000167214202246716021064 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/endian/int24.hpp" #include "openmpt/base/Types.hpp" #include OPENMPT_NAMESPACE_BEGIN using uint24 = mpt::uint24; static_assert(sizeof(uint24) == 3); inline constexpr uint32 uint24_min = std::numeric_limits::min(); inline constexpr uint32 uint24_max = std::numeric_limits::max(); using int24 = mpt::int24; static_assert(sizeof(int24) == 3); inline constexpr int32 int24_min = std::numeric_limits::min(); inline constexpr int32 int24_max = std::numeric_limits::max(); using int24le = mpt::packed; using uint24le = mpt::packed; using int24be = mpt::packed; using uint24be = mpt::packed; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/base/FlagSet.hpp0000644000175000017500000004373314650142521021511 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ /* * Originally based on . * Rewritten to be standard-conforming. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/macros.hpp" #include #include OPENMPT_NAMESPACE_BEGIN // Type-safe wrapper around an enum, that can represent all enum values and bitwise compositions thereof. // Conversions to and from plain integers as well as conversions to the base enum are always explicit. template // cppcheck-suppress copyCtorAndEqOperator class enum_value_type { public: using enum_type = enum_t; using value_type = enum_value_type; using store_type = typename std::make_unsigned::type; private: store_type bits; public: MPT_CONSTEXPRINLINE enum_value_type() noexcept : bits(0) { } MPT_CONSTEXPRINLINE enum_value_type(const enum_value_type &x) noexcept : bits(x.bits) { } MPT_CONSTEXPRINLINE enum_value_type(enum_type x) noexcept : bits(static_cast(x)) { } private: explicit MPT_CONSTEXPRINLINE enum_value_type(store_type x) noexcept : bits(x) { } // private in order to prevent accidental conversions. use from_bits. MPT_CONSTEXPRINLINE operator store_type() const noexcept { return bits; } // private in order to prevent accidental conversions. use as_bits. public: static MPT_CONSTEXPRINLINE enum_value_type from_bits(store_type bits) noexcept { return value_type(bits); } MPT_CONSTEXPRINLINE enum_type as_enum() const noexcept { return static_cast(bits); } MPT_CONSTEXPRINLINE store_type as_bits() const noexcept { return bits; } public: MPT_CONSTEXPRINLINE operator bool() const noexcept { return bits != store_type(); } MPT_CONSTEXPRINLINE bool operator!() const noexcept { return bits == store_type(); } MPT_CONSTEXPRINLINE const enum_value_type operator~() const noexcept { return enum_value_type(~bits); } friend MPT_CONSTEXPRINLINE bool operator==(enum_value_type a, enum_value_type b) noexcept { return a.bits == b.bits; } friend MPT_CONSTEXPRINLINE bool operator!=(enum_value_type a, enum_value_type b) noexcept { return a.bits != b.bits; } friend MPT_CONSTEXPRINLINE bool operator==(enum_value_type a, enum_t b) noexcept { return a == enum_value_type(b); } friend MPT_CONSTEXPRINLINE bool operator!=(enum_value_type a, enum_t b) noexcept { return a != enum_value_type(b); } friend MPT_CONSTEXPRINLINE bool operator==(enum_t a, enum_value_type b) noexcept { return enum_value_type(a) == b; } friend MPT_CONSTEXPRINLINE bool operator!=(enum_t a, enum_value_type b) noexcept { return enum_value_type(a) != b; } friend MPT_CONSTEXPRINLINE const enum_value_type operator|(enum_value_type a, enum_value_type b) noexcept { return enum_value_type(a.bits | b.bits); } friend MPT_CONSTEXPRINLINE const enum_value_type operator&(enum_value_type a, enum_value_type b) noexcept { return enum_value_type(a.bits & b.bits); } friend MPT_CONSTEXPRINLINE const enum_value_type operator^(enum_value_type a, enum_value_type b) noexcept { return enum_value_type(a.bits ^ b.bits); } friend MPT_CONSTEXPRINLINE const enum_value_type operator|(enum_value_type a, enum_t b) noexcept { return a | enum_value_type(b); } friend MPT_CONSTEXPRINLINE const enum_value_type operator&(enum_value_type a, enum_t b) noexcept { return a & enum_value_type(b); } friend MPT_CONSTEXPRINLINE const enum_value_type operator^(enum_value_type a, enum_t b) noexcept { return a ^ enum_value_type(b); } friend MPT_CONSTEXPRINLINE const enum_value_type operator|(enum_t a, enum_value_type b) noexcept { return enum_value_type(a) | b; } friend MPT_CONSTEXPRINLINE const enum_value_type operator&(enum_t a, enum_value_type b) noexcept { return enum_value_type(a) & b; } friend MPT_CONSTEXPRINLINE const enum_value_type operator^(enum_t a, enum_value_type b) noexcept { return enum_value_type(a) ^ b; } MPT_CONSTEXPRINLINE enum_value_type &operator|=(enum_value_type b) noexcept { *this = *this | b; return *this; } MPT_CONSTEXPRINLINE enum_value_type &operator&=(enum_value_type b) noexcept { *this = *this & b; return *this; } MPT_CONSTEXPRINLINE enum_value_type &operator^=(enum_value_type b) noexcept { *this = *this ^ b; return *this; } MPT_CONSTEXPRINLINE enum_value_type &operator|=(enum_t b) noexcept { *this = *this | b; return *this; } MPT_CONSTEXPRINLINE enum_value_type &operator&=(enum_t b) noexcept { *this = *this & b; return *this; } MPT_CONSTEXPRINLINE enum_value_type &operator^=(enum_t b) noexcept { *this = *this ^ b; return *this; } }; // Type-safe enum wrapper that allows type-safe bitwise testing. template class Enum { public: using self_type = Enum; using enum_type = enum_t; using value_type = enum_value_type; using store_type = typename value_type::store_type; private: enum_type value; public: explicit MPT_CONSTEXPRINLINE Enum(enum_type val) noexcept : value(val) { } MPT_CONSTEXPRINLINE operator enum_type() const noexcept { return value; } MPT_CONSTEXPRINLINE Enum &operator=(enum_type val) noexcept { value = val; return *this; } public: MPT_CONSTEXPRINLINE const value_type operator~() const { return ~value_type(value); } friend MPT_CONSTEXPRINLINE bool operator==(self_type a, self_type b) noexcept { return value_type(a) == value_type(b); } friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, self_type b) noexcept { return value_type(a) != value_type(b); } friend MPT_CONSTEXPRINLINE bool operator==(self_type a, value_type b) noexcept { return value_type(a) == value_type(b); } friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, value_type b) noexcept { return value_type(a) != value_type(b); } friend MPT_CONSTEXPRINLINE bool operator==(value_type a, self_type b) noexcept { return value_type(a) == value_type(b); } friend MPT_CONSTEXPRINLINE bool operator!=(value_type a, self_type b) noexcept { return value_type(a) != value_type(b); } friend MPT_CONSTEXPRINLINE bool operator==(self_type a, enum_type b) noexcept { return value_type(a) == value_type(b); } friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, enum_type b) noexcept { return value_type(a) != value_type(b); } friend MPT_CONSTEXPRINLINE bool operator==(enum_type a, self_type b) noexcept { return value_type(a) == value_type(b); } friend MPT_CONSTEXPRINLINE bool operator!=(enum_type a, self_type b) noexcept { return value_type(a) != value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, self_type b) noexcept { return value_type(a) | value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, self_type b) noexcept { return value_type(a) & value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, self_type b) noexcept { return value_type(a) ^ value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, value_type b) noexcept { return value_type(a) | value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, value_type b) noexcept { return value_type(a) & value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, value_type b) noexcept { return value_type(a) ^ value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator|(value_type a, self_type b) noexcept { return value_type(a) | value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator&(value_type a, self_type b) noexcept { return value_type(a) & value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator^(value_type a, self_type b) noexcept { return value_type(a) ^ value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, enum_type b) noexcept { return value_type(a) | value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, enum_type b) noexcept { return value_type(a) & value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, enum_type b) noexcept { return value_type(a) ^ value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator|(enum_type a, self_type b) noexcept { return value_type(a) | value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator&(enum_type a, self_type b) noexcept { return value_type(a) & value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator^(enum_type a, self_type b) noexcept { return value_type(a) ^ value_type(b); } }; template ::store_type> // cppcheck-suppress copyCtorAndEqOperator class FlagSet { public: using self_type = FlagSet; using enum_type = enum_t; using value_type = enum_value_type; using store_type = store_t; private: // support truncated store_type ... : store_type bits_; static MPT_CONSTEXPRINLINE store_type store_from_value(value_type bits) noexcept { return static_cast(bits.as_bits()); } static MPT_CONSTEXPRINLINE value_type value_from_store(store_type bits) noexcept { return value_type::from_bits(static_cast(bits)); } MPT_CONSTEXPRINLINE FlagSet &store(value_type bits) noexcept { bits_ = store_from_value(bits); return *this; } MPT_CONSTEXPRINLINE value_type load() const noexcept { return value_from_store(bits_); } public: // Default constructor (no flags set) MPT_CONSTEXPRINLINE FlagSet() noexcept : bits_(store_from_value(value_type())) { } // Copy constructor MPT_CONSTEXPRINLINE FlagSet(const FlagSet &flags) noexcept : bits_(flags.bits_) { } // Value constructor MPT_CONSTEXPRINLINE FlagSet(value_type flags) noexcept : bits_(store_from_value(value_type(flags))) { } MPT_CONSTEXPRINLINE FlagSet(enum_type flag) noexcept : bits_(store_from_value(value_type(flag))) { } explicit MPT_CONSTEXPRINLINE FlagSet(store_type flags) noexcept : bits_(store_from_value(value_type::from_bits(flags))) { } MPT_CONSTEXPRINLINE explicit operator bool() const noexcept { return load(); } MPT_CONSTEXPRINLINE explicit operator store_type() const noexcept { return load().as_bits(); } MPT_CONSTEXPRINLINE value_type value() const noexcept { return load(); } MPT_CONSTEXPRINLINE operator value_type() const noexcept { return load(); } // Test if one or more flags are set. Returns true if at least one of the given flags is set. MPT_CONSTEXPRINLINE bool operator[](value_type flags) const noexcept { return test(flags); } // Set one or more flags. MPT_CONSTEXPRINLINE FlagSet &set(value_type flags) noexcept { return store(load() | flags); } // Set or clear one or more flags. MPT_CONSTEXPRINLINE FlagSet &set(value_type flags, bool val) noexcept { return store((val ? (load() | flags) : (load() & ~flags))); } // Clear or flags. MPT_CONSTEXPRINLINE FlagSet &reset() noexcept { return store(value_type()); } // Clear one or more flags. MPT_CONSTEXPRINLINE FlagSet &reset(value_type flags) noexcept { return store(load() & ~flags); } // Toggle all flags. MPT_CONSTEXPRINLINE FlagSet &flip() noexcept { return store(~load()); } // Toggle one or more flags. MPT_CONSTEXPRINLINE FlagSet &flip(value_type flags) noexcept { return store(load() ^ flags); } // Returns the size of the flag set in bytes MPT_CONSTEXPRINLINE std::size_t size() const noexcept { return sizeof(store_type); } // Returns the size of the flag set in bits MPT_CONSTEXPRINLINE std::size_t size_bits() const noexcept { return size() * 8; } // Test if one or more flags are set. Returns true if at least one of the given flags is set. MPT_CONSTEXPRINLINE bool test(value_type flags) const noexcept { return (load() & flags); } // Test if all specified flags are set. MPT_CONSTEXPRINLINE bool test_all(value_type flags) const noexcept { return (load() & flags) == flags; } // Test if any but the specified flags are set. MPT_CONSTEXPRINLINE bool test_any_except(value_type flags) const noexcept { return (load() & ~flags); } // Test if any flag is set. MPT_CONSTEXPRINLINE bool any() const noexcept { return load(); } // Test if no flags are set. MPT_CONSTEXPRINLINE bool none() const noexcept { return !load(); } MPT_CONSTEXPRINLINE store_type GetRaw() const noexcept { return bits_; } MPT_CONSTEXPRINLINE FlagSet &SetRaw(store_type flags) noexcept { bits_ = flags; return *this; } MPT_CONSTEXPRINLINE FlagSet &operator=(value_type flags) noexcept { return store(flags); } MPT_CONSTEXPRINLINE FlagSet &operator=(enum_type flag) noexcept { return store(flag); } MPT_CONSTEXPRINLINE FlagSet &operator=(FlagSet flags) noexcept { return store(flags.load()); } MPT_CONSTEXPRINLINE FlagSet &operator&=(value_type flags) noexcept { return store(load() & flags); } MPT_CONSTEXPRINLINE FlagSet &operator|=(value_type flags) noexcept { return store(load() | flags); } MPT_CONSTEXPRINLINE FlagSet &operator^=(value_type flags) noexcept { return store(load() ^ flags); } friend MPT_CONSTEXPRINLINE bool operator==(self_type a, self_type b) noexcept { return a.load() == b.load(); } friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, self_type b) noexcept { return a.load() != b.load(); } friend MPT_CONSTEXPRINLINE bool operator==(self_type a, value_type b) noexcept { return a.load() == value_type(b); } friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, value_type b) noexcept { return a.load() != value_type(b); } friend MPT_CONSTEXPRINLINE bool operator==(value_type a, self_type b) noexcept { return value_type(a) == b.load(); } friend MPT_CONSTEXPRINLINE bool operator!=(value_type a, self_type b) noexcept { return value_type(a) != b.load(); } friend MPT_CONSTEXPRINLINE bool operator==(self_type a, enum_type b) noexcept { return a.load() == value_type(b); } friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, enum_type b) noexcept { return a.load() != value_type(b); } friend MPT_CONSTEXPRINLINE bool operator==(enum_type a, self_type b) noexcept { return value_type(a) == b.load(); } friend MPT_CONSTEXPRINLINE bool operator!=(enum_type a, self_type b) noexcept { return value_type(a) != b.load(); } friend MPT_CONSTEXPRINLINE bool operator==(self_type a, Enum b) noexcept { return a.load() == value_type(b); } friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, Enum b) noexcept { return a.load() != value_type(b); } friend MPT_CONSTEXPRINLINE bool operator==(Enum a, self_type b) noexcept { return value_type(a) == b.load(); } friend MPT_CONSTEXPRINLINE bool operator!=(Enum a, self_type b) noexcept { return value_type(a) != b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, self_type b) noexcept { return a.load() | b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, self_type b) noexcept { return a.load() & b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, self_type b) noexcept { return a.load() ^ b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, value_type b) noexcept { return a.load() | value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, value_type b) noexcept { return a.load() & value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, value_type b) noexcept { return a.load() ^ value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator|(value_type a, self_type b) noexcept { return value_type(a) | b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator&(value_type a, self_type b) noexcept { return value_type(a) & b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator^(value_type a, self_type b) noexcept { return value_type(a) ^ b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, enum_type b) noexcept { return a.load() | value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, enum_type b) noexcept { return a.load() & value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, enum_type b) noexcept { return a.load() ^ value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator|(enum_type a, self_type b) noexcept { return value_type(a) | b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator&(enum_type a, self_type b) noexcept { return value_type(a) & b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator^(enum_type a, self_type b) noexcept { return value_type(a) ^ b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, Enum b) noexcept { return a.load() | value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, Enum b) noexcept { return a.load() & value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, Enum b) noexcept { return a.load() ^ value_type(b); } friend MPT_CONSTEXPRINLINE const value_type operator|(Enum a, self_type b) noexcept { return value_type(a) | b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator&(Enum a, self_type b) noexcept { return value_type(a) & b.load(); } friend MPT_CONSTEXPRINLINE const value_type operator^(Enum a, self_type b) noexcept { return value_type(a) ^ b.load(); } }; // Declare typesafe logical operators for enum_t #define MPT_DECLARE_ENUM(enum_t) \ MPT_CONSTEXPRINLINE enum_value_type operator|(enum_t a, enum_t b) noexcept \ { \ return enum_value_type(a) | enum_value_type(b); \ } \ MPT_CONSTEXPRINLINE enum_value_type operator&(enum_t a, enum_t b) noexcept \ { \ return enum_value_type(a) & enum_value_type(b); \ } \ MPT_CONSTEXPRINLINE enum_value_type operator^(enum_t a, enum_t b) noexcept \ { \ return enum_value_type(a) ^ enum_value_type(b); \ } \ MPT_CONSTEXPRINLINE enum_value_type operator~(enum_t a) noexcept \ { \ return ~enum_value_type(a); \ } \ /**/ // backwards compatibility #define DECLARE_FLAGSET MPT_DECLARE_ENUM OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/base/Endian.hpp0000644000175000017500000000554014657606142021367 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/bit.hpp" #include "mpt/base/memory.hpp" #include "mpt/endian/floatingpoint.hpp" #include "mpt/endian/integer.hpp" #include "mpt/endian/type_traits.hpp" #include "openmpt/base/Types.hpp" OPENMPT_NAMESPACE_BEGIN using int64le = mpt::packed; using int32le = mpt::packed; using int16le = mpt::packed; using int8le = mpt::packed; using uint64le = mpt::packed; using uint32le = mpt::packed; using uint16le = mpt::packed; using uint8le = mpt::packed; using int64be = mpt::packed; using int32be = mpt::packed; using int16be = mpt::packed; using int8be = mpt::packed; using uint64be = mpt::packed; using uint32be = mpt::packed; using uint16be = mpt::packed; using uint8be = mpt::packed; using IEEE754binary32LE = mpt::IEEE754binary_types::is_float32 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian, mpt::endian::native>::IEEE754binary32LE; using IEEE754binary32BE = mpt::IEEE754binary_types::is_float32 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian, mpt::endian::native>::IEEE754binary32BE; using IEEE754binary64LE = mpt::IEEE754binary_types::is_float64 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian, mpt::endian::native>::IEEE754binary64LE; using IEEE754binary64BE = mpt::IEEE754binary_types::is_float64 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian, mpt::endian::native>::IEEE754binary64BE; // unaligned using float32le = mpt::IEEE754binary32EmulatedLE; using float32be = mpt::IEEE754binary32EmulatedBE; using float64le = mpt::IEEE754binary64EmulatedLE; using float64be = mpt::IEEE754binary64EmulatedBE; // potentially aligned using float32le_fast = mpt::IEEE754binary32LE; using float32be_fast = mpt::IEEE754binary32BE; using float64le_fast = mpt::IEEE754binary64LE; using float64be_fast = mpt::IEEE754binary64BE; #define MPT_BINARY_STRUCT(type, size) \ constexpr bool declare_binary_safe(const type &) \ { \ return true; \ } \ static_assert(mpt::check_binary_size(size)); \ /**/ OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/openmpt/fileformat_base/0000755000175000017500000000000015023302361021724 500000000000000libopenmpt-0.8.1+release.autotools/src/openmpt/fileformat_base/magic.hpp0000644000175000017500000000276514657647563023503 00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/macros.hpp" #include "openmpt/base/Types.hpp" OPENMPT_NAMESPACE_BEGIN // Functions to create 4-byte and 2-byte magic byte identifiers in little-endian format // Use this together with uint32le/uint16le file members. MPT_CONSTEVAL uint32 MagicLE(const char (&id)[5]) { return static_cast((static_cast(id[3]) << 24) | (static_cast(id[2]) << 16) | (static_cast(id[1]) << 8) | static_cast(id[0])); } MPT_CONSTEVAL uint16 MagicLE(const char (&id)[3]) { return static_cast((static_cast(id[1]) << 8) | static_cast(id[0])); } // Functions to create 4-byte and 2-byte magic byte identifiers in big-endian format // Use this together with uint32be/uint16be file members. // Note: Historically, some magic bytes in MPT-specific fields are reversed (due to the use of multi-char literals). // Such fields turned up reversed in files, so MagicBE is used to keep them readable in the code. MPT_CONSTEVAL uint32 MagicBE(const char (&id)[5]) { return static_cast((static_cast(id[0]) << 24) | (static_cast(id[1]) << 16) | (static_cast(id[2]) << 8) | static_cast(id[3])); } MPT_CONSTEVAL uint16 MagicBE(const char (&id)[3]) { return static_cast((static_cast(id[0]) << 8) | static_cast(id[1])); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/src/mpt/0000755000175000017500000000000015023302363015722 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/io/0000755000175000017500000000000015023302361016327 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/io/io_virtual_wrapper.hpp0000644000175000017500000002260214650142521022704 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_IO_VIRTUAL_WRAPPER_HPP #define MPT_IO_IO_VIRTUAL_WRAPPER_HPP #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/io/base.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class IFileBase { protected: IFileBase() = default; virtual ~IFileBase() = default; public: virtual bool IsValid() = 0; virtual bool IsReadSeekable() = 0; virtual IO::Offset TellRead() = 0; virtual bool SeekBegin() = 0; virtual bool SeekEnd() = 0; virtual bool SeekAbsolute(IO::Offset pos) = 0; virtual bool SeekRelative(IO::Offset off) = 0; virtual mpt::byte_span ReadRawImpl(mpt::byte_span data) = 0; virtual bool IsEof() = 0; }; template class IFile : public IFileBase { private: Tfile & f; public: IFile(Tfile & f_) : f(f_) { } ~IFile() override = default; public: bool IsValid() override { return mpt::IO::IsValid(f); } bool IsReadSeekable() override { return mpt::IO::IsReadSeekable(f); } IO::Offset TellRead() override { return mpt::IO::TellRead(f); } bool SeekBegin() override { return mpt::IO::SeekBegin(f); } bool SeekEnd() override { return mpt::IO::SeekEnd(f); } bool SeekAbsolute(IO::Offset pos) override { return mpt::IO::SeekAbsolute(f, pos); } bool SeekRelative(IO::Offset off) override { return mpt::IO::SeekRelative(f, off); } mpt::byte_span ReadRawImpl(mpt::byte_span data) override { return mpt::IO::ReadRawImpl(f, data); } bool IsEof() override { return mpt::IO::IsEof(f); } }; class OFileBase { protected: OFileBase() = default; virtual ~OFileBase() = default; public: virtual bool IsValid() = 0; virtual bool IsWriteSeekable() = 0; virtual IO::Offset TellWrite() = 0; virtual bool SeekBegin() = 0; virtual bool SeekEnd() = 0; virtual bool SeekAbsolute(IO::Offset pos) = 0; virtual bool SeekRelative(IO::Offset off) = 0; virtual bool WriteRawImpl(mpt::const_byte_span data) = 0; virtual bool Flush() = 0; }; template class OFile : public OFileBase { private: Tfile & f; public: OFile(Tfile & f_) : f(f_) { } ~OFile() override = default; public: bool IsValid() override { return mpt::IO::IsValid(f); } bool IsWriteSeekable() override { return mpt::IO::IsWriteSeekable(f); } IO::Offset TellWrite() override { return mpt::IO::TellWrite(f); } bool SeekBegin() override { return mpt::IO::SeekBegin(f); } bool SeekEnd() override { return mpt::IO::SeekEnd(f); } bool SeekAbsolute(IO::Offset pos) override { return mpt::IO::SeekAbsolute(f, pos); } bool SeekRelative(IO::Offset off) override { return mpt::IO::SeekRelative(f, off); } bool WriteRawImpl(mpt::const_byte_span data) override { return mpt::IO::WriteRawImpl(f, data); } bool Flush() override { return mpt::IO::Flush(f); } }; class IOFileBase { protected: IOFileBase() = default; virtual ~IOFileBase() = default; public: virtual bool IsValid() = 0; virtual bool IsReadSeekable() = 0; virtual bool IsWriteSeekable() = 0; virtual IO::Offset TellRead() = 0; virtual IO::Offset TellWrite() = 0; virtual bool SeekBegin() = 0; virtual bool SeekEnd() = 0; virtual bool SeekAbsolute(IO::Offset pos) = 0; virtual bool SeekRelative(IO::Offset off) = 0; virtual mpt::byte_span ReadRawImpl(mpt::byte_span data) = 0; virtual bool WriteRawImpl(mpt::const_byte_span data) = 0; virtual bool IsEof() = 0; virtual bool Flush() = 0; }; template class IOFile : public IOFileBase { private: Tfile & f; public: IOFile(Tfile & f_) : f(f_) { } ~IOFile() override = default; public: bool IsValid() override { return mpt::IO::IsValid(f); } bool IsReadSeekable() override { return mpt::IO::IsReadSeekable(f); } bool IsWriteSeekable() override { return mpt::IO::IsWriteSeekable(f); } IO::Offset TellRead() override { return mpt::IO::TellRead(f); } IO::Offset TellWrite() override { return mpt::IO::TellWrite(f); } bool SeekBegin() override { return mpt::IO::SeekBegin(f); } bool SeekEnd() override { return mpt::IO::SeekEnd(f); } bool SeekAbsolute(IO::Offset pos) override { return mpt::IO::SeekAbsolute(f, pos); } bool SeekRelative(IO::Offset off) override { return mpt::IO::SeekRelative(f, off); } mpt::byte_span ReadRawImpl(mpt::byte_span data) override { return mpt::IO::ReadRawImpl(f, data); } bool WriteRawImpl(mpt::const_byte_span data) override { return mpt::IO::WriteRawImpl(f, data); } bool IsEof() override { return mpt::IO::IsEof(f); } bool Flush() override { return mpt::IO::Flush(f); } }; template struct FileOperations::value>> { private: IFileBase & f; public: FileOperations(IFileBase & f_) : f(f_) { return; } public: // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsValid() { return f.IsValid(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsReadSeekable() { return f.IsReadSeekable(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline IO::Offset TellRead() { return f.TellRead(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekBegin() { return f.SeekBegin(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekEnd() { return f.SeekEnd(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekAbsolute(IO::Offset pos) { return f.SeekAbsolute(pos); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekRelative(IO::Offset off) { return f.SeekRelative(off); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline mpt::byte_span ReadRawImpl(mpt::byte_span data) { return f.ReadRawImpl(data); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsEof() { return f.IsEof(); } }; template struct FileOperations::value>> { private: OFileBase & f; public: FileOperations(OFileBase & f_) : f(f_) { return; } public: // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsValid() { return f.IsValid(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsWriteSeekable() { return f.IsWriteSeekable(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline IO::Offset TellWrite() { return f.TellWrite(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekBegin() { return f.SeekBegin(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekEnd() { return f.SeekEnd(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekAbsolute(IO::Offset pos) { return f.SeekAbsolute(pos); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekRelative(IO::Offset off) { return f.SeekRelative(off); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool WriteRawImpl(mpt::const_byte_span data) { return f.WriteRawImpl(data); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool Flush() { return f.Flush(); } }; template struct FileOperations::value>> { private: IOFileBase & f; public: FileOperations(IOFileBase & f_) : f(f_) { return; } public: // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsValid() { return f.IsValid(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsReadSeekable() { return f.IsReadSeekable(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsWriteSeekable() { return f.IsWriteSeekable(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline IO::Offset TellRead() { return f.TellRead(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline IO::Offset TellWrite() { return f.TellWrite(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekBegin() { return f.SeekBegin(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekEnd() { return f.SeekEnd(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekAbsolute(IO::Offset pos) { return f.SeekAbsolute(pos); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekRelative(IO::Offset off) { return f.SeekRelative(off); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline mpt::byte_span ReadRawImpl(mpt::byte_span data) { return f.ReadRawImpl(data); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool WriteRawImpl(mpt::const_byte_span data) { return f.WriteRawImpl(data); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsEof() { return f.IsEof(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool Flush() { return f.Flush(); } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_IO_VIRTUAL_WRAPPER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io/io.hpp0000644000175000017500000002551714650142521017406 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_IO_HPP #define MPT_IO_IO_HPP #include "mpt/base/array.hpp" #include "mpt/base/bit.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/span.hpp" #include "mpt/endian/integer.hpp" #include "mpt/endian/type_traits.hpp" #include "mpt/io/base.hpp" #include #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { template inline mpt::byte_span ReadRaw(Tfile & f, Tbyte * data, std::size_t size) { return mpt::IO::ReadRawImpl(f, mpt::as_span(mpt::byte_cast(data), size)); } template inline mpt::byte_span ReadRaw(Tfile & f, mpt::span data) { return mpt::IO::ReadRawImpl(f, mpt::byte_cast(data)); } template inline bool WriteRaw(Tfile & f, const Tbyte * data, std::size_t size) { return mpt::IO::WriteRawImpl(f, mpt::as_span(mpt::byte_cast(data), size)); } template inline bool WriteRaw(Tfile & f, mpt::span data) { return mpt::IO::WriteRawImpl(f, mpt::byte_cast(data)); } template inline bool Read(Tfile & f, Tbinary & v) { return mpt::IO::ReadRaw(f, mpt::as_raw_memory(v)).size() == mpt::as_raw_memory(v).size(); } template inline bool Write(Tfile & f, const Tbinary & v) { return mpt::IO::WriteRaw(f, mpt::as_raw_memory(v)); } template inline bool Write(Tfile & f, const std::vector & v) { static_assert(mpt::is_binary_safe::value); return mpt::IO::WriteRaw(f, mpt::as_raw_memory(v)); } template inline bool WritePartial(Tfile & f, const T & v, std::size_t size = sizeof(T)) { assert(size <= sizeof(T)); return mpt::IO::WriteRaw(f, mpt::as_span(mpt::as_raw_memory(v).data(), size)); } template inline bool ReadByte(Tfile & f, std::byte & v) { bool result = false; std::byte byte = mpt::as_byte(0); const std::size_t readResult = mpt::IO::ReadRaw(f, &byte, sizeof(std::byte)).size(); result = (readResult == sizeof(std::byte)); v = byte; return result; } template inline bool ReadBinaryTruncatedLE(Tfile & f, T & v, std::size_t size) { bool result = false; static_assert(std::numeric_limits::is_integer); std::array bytes = mpt::init_array(uint8{0}); const std::size_t readResult = mpt::IO::ReadRaw(f, bytes.data(), std::min(size, sizeof(T))).size(); result = (readResult == std::min(size, sizeof(T))); v = mpt::bit_cast::type>(bytes); return result; } template inline bool ReadIntLE(Tfile & f, T & v) { bool result = false; static_assert(std::numeric_limits::is_integer); std::array bytes = mpt::init_array(uint8{0}); const std::size_t readResult = mpt::IO::ReadRaw(f, mpt::as_span(bytes)).size(); result = (readResult == sizeof(T)); v = mpt::bit_cast::type>(bytes); return result; } template inline bool ReadIntBE(Tfile & f, T & v) { bool result = false; static_assert(std::numeric_limits::is_integer); std::array bytes = mpt::init_array(uint8{0}); const std::size_t readResult = mpt::IO::ReadRaw(f, mpt::as_span(bytes)).size(); result = (readResult == sizeof(T)); v = mpt::bit_cast::type>(bytes); return result; } template inline bool ReadAdaptiveInt16LE(Tfile & f, uint16 & v) { bool result = true; uint8 byte = 0; std::size_t additionalBytes = 0; v = 0; byte = 0; if (!mpt::IO::ReadIntLE(f, byte)) { result = false; } additionalBytes = (byte & 0x01); v = byte >> 1; for (std::size_t i = 0; i < additionalBytes; ++i) { byte = 0; if (!mpt::IO::ReadIntLE(f, byte)) { result = false; } v |= (static_cast(byte) << (((i + 1) * 8) - 1)); } return result; } template inline bool ReadAdaptiveInt32LE(Tfile & f, uint32 & v) { bool result = true; uint8 byte = 0; std::size_t additionalBytes = 0; v = 0; byte = 0; if (!mpt::IO::ReadIntLE(f, byte)) { result = false; } additionalBytes = (byte & 0x03); v = byte >> 2; for (std::size_t i = 0; i < additionalBytes; ++i) { byte = 0; if (!mpt::IO::ReadIntLE(f, byte)) { result = false; } v |= (static_cast(byte) << (((i + 1) * 8) - 2)); } return result; } template inline bool ReadAdaptiveInt64LE(Tfile & f, uint64 & v) { bool result = true; uint8 byte = 0; std::size_t additionalBytes = 0; v = 0; byte = 0; if (!mpt::IO::ReadIntLE(f, byte)) { result = false; } additionalBytes = (1 << (byte & 0x03)) - 1; v = byte >> 2; for (std::size_t i = 0; i < additionalBytes; ++i) { byte = 0; if (!mpt::IO::ReadIntLE(f, byte)) { result = false; } v |= (static_cast(byte) << (((i + 1) * 8) - 2)); } return result; } template inline bool ReadSizedStringLE(Tfile & f, std::string & str, Tsize maxSize = std::numeric_limits::max()) { static_assert(std::numeric_limits::is_integer); str.clear(); Tsize size = 0; if (!mpt::IO::ReadIntLE(f, size)) { return false; } if (size > maxSize) { return false; } for (Tsize i = 0; i != size; ++i) { char c = '\0'; if (!mpt::IO::ReadIntLE(f, c)) { return false; } str.push_back(c); } return true; } template inline bool WriteIntLE(Tfile & f, const T v) { static_assert(std::numeric_limits::is_integer); return mpt::IO::Write(f, mpt::as_le(v)); } template inline bool WriteIntBE(Tfile & f, const T v) { static_assert(std::numeric_limits::is_integer); return mpt::IO::Write(f, mpt::as_be(v)); } template inline bool WriteAdaptiveInt16LE(Tfile & f, const uint16 v, std::size_t fixedSize = 0) { std::size_t minSize = fixedSize; std::size_t maxSize = fixedSize; assert(minSize == 0 || minSize == 1 || minSize == 2); assert(maxSize == 0 || maxSize == 1 || maxSize == 2); assert(maxSize == 0 || maxSize >= minSize); if (maxSize == 0) { maxSize = 2; } if (v < 0x80 && minSize <= 1 && 1 <= maxSize) { return mpt::IO::WriteIntLE(f, static_cast(v << 1) | 0x00); } else if (v < 0x8000 && minSize <= 2 && 2 <= maxSize) { return mpt::IO::WriteIntLE(f, static_cast(v << 1) | 0x01); } else { assert(false); return false; } } template inline bool WriteAdaptiveInt32LE(Tfile & f, const uint32 v, std::size_t fixedSize = 0) { std::size_t minSize = fixedSize; std::size_t maxSize = fixedSize; assert(minSize == 0 || minSize == 1 || minSize == 2 || minSize == 3 || minSize == 4); assert(maxSize == 0 || maxSize == 1 || maxSize == 2 || maxSize == 3 || maxSize == 4); assert(maxSize == 0 || maxSize >= minSize); if (maxSize == 0) { maxSize = 4; } if (v < 0x40 && minSize <= 1 && 1 <= maxSize) { return mpt::IO::WriteIntLE(f, static_cast(v << 2) | 0x00); } else if (v < 0x4000 && minSize <= 2 && 2 <= maxSize) { return mpt::IO::WriteIntLE(f, static_cast(v << 2) | 0x01); } else if (v < 0x400000 && minSize <= 3 && 3 <= maxSize) { uint32 value = static_cast(v << 2) | 0x02; std::byte bytes[3]; bytes[0] = static_cast(value >> 0); bytes[1] = static_cast(value >> 8); bytes[2] = static_cast(value >> 16); return mpt::IO::WriteRaw(f, bytes, 3); } else if (v < 0x40000000 && minSize <= 4 && 4 <= maxSize) { return mpt::IO::WriteIntLE(f, static_cast(v << 2) | 0x03); } else { assert(false); return false; } } template inline bool WriteAdaptiveInt64LE(Tfile & f, const uint64 v, std::size_t fixedSize = 0) { std::size_t minSize = fixedSize; std::size_t maxSize = fixedSize; assert(minSize == 0 || minSize == 1 || minSize == 2 || minSize == 4 || minSize == 8); assert(maxSize == 0 || maxSize == 1 || maxSize == 2 || maxSize == 4 || maxSize == 8); assert(maxSize == 0 || maxSize >= minSize); if (maxSize == 0) { maxSize = 8; } if (v < 0x40 && minSize <= 1 && 1 <= maxSize) { return mpt::IO::WriteIntLE(f, static_cast(v << 2) | 0x00); } else if (v < 0x4000 && minSize <= 2 && 2 <= maxSize) { return mpt::IO::WriteIntLE(f, static_cast(v << 2) | 0x01); } else if (v < 0x40000000 && minSize <= 4 && 4 <= maxSize) { return mpt::IO::WriteIntLE(f, static_cast(v << 2) | 0x02); } else if (v < 0x4000000000000000ull && minSize <= 8 && 8 <= maxSize) { return mpt::IO::WriteIntLE(f, static_cast(v << 2) | 0x03); } else { assert(false); return false; } } // Write a variable-length integer, as found in MIDI files. The number of written bytes is placed in the bytesWritten parameter. template bool WriteVarInt(Tfile & f, const T v, std::size_t * bytesWritten = nullptr) { static_assert(std::numeric_limits::is_integer); static_assert(!std::numeric_limits::is_signed); std::byte out[(sizeof(T) * 8 + 6) / 7]; std::size_t numBytes = 0; for (uint32 n = (sizeof(T) * 8) / 7; n > 0; n--) { if (v >= (static_cast(1) << (n * 7u))) { out[numBytes++] = static_cast(((v >> (n * 7u)) & 0x7F) | 0x80); } } out[numBytes++] = static_cast(v & 0x7F); assert(numBytes <= std::size(out)); if (bytesWritten != nullptr) { *bytesWritten = numBytes; } return mpt::IO::WriteRaw(f, out, numBytes); } template inline bool WriteSizedStringLE(Tfile & f, const std::string & str) { static_assert(std::numeric_limits::is_integer); if (str.size() > std::numeric_limits::max()) { return false; } Tsize size = static_cast(str.size()); if (!mpt::IO::WriteIntLE(f, size)) { return false; } if (!mpt::IO::WriteRaw(f, str.data(), str.size())) { return false; } return true; } template inline bool WriteText(Tfile & f, const std::string & s) { return mpt::IO::WriteRaw(f, s.data(), s.size()); } template inline bool WriteTextCRLF(Tfile & f) { return mpt::IO::WriteText(f, "\r\n"); } template inline bool WriteTextLF(Tfile & f) { return mpt::IO::WriteText(f, "\n"); } template inline bool WriteTextCRLF(Tfile & f, const std::string & s) { return mpt::IO::WriteText(f, s) && mpt::IO::WriteTextCRLF(f); } template inline bool WriteTextLF(Tfile & f, const std::string & s) { return mpt::IO::WriteText(f, s) && mpt::IO::WriteTextLF(f); } } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_IO_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io/io_span.hpp0000644000175000017500000000677114650142521020430 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_IO_SPAN_HPP #define MPT_IO_IO_SPAN_HPP #include "mpt/base/macros.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/base/span.hpp" #include "mpt/io/base.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { template struct FileOperations, IO::Offset>> { private: std::pair, IO::Offset> & f; public: FileOperations(std::pair, IO::Offset> & f_) : f(f_) { return; } public: // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsValid() { return (f.second >= 0); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsReadSeekable() { MPT_UNUSED(f); return true; } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsWriteSeekable() { MPT_UNUSED(f); return true; } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline IO::Offset TellRead() { return f.second; } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline IO::Offset TellWrite() { return f.second; } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekBegin() { f.second = 0; return true; } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekEnd() { f.second = f.first.size(); return true; } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekAbsolute(IO::Offset pos) { f.second = pos; return true; } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekRelative(IO::Offset off) { if (f.second < 0) { return false; } f.second += off; return true; } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline mpt::byte_span ReadRawImpl(mpt::byte_span data) { if (f.second < 0) { return data.first(0); } if (f.second >= static_cast(f.first.size())) { return data.first(0); } std::size_t num = mpt::saturate_cast(std::min(static_cast(f.first.size()) - f.second, static_cast(data.size()))); std::copy(mpt::byte_cast(f.first.data() + f.second), mpt::byte_cast(f.first.data() + f.second + num), data.data()); f.second += num; return data.first(num); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool WriteRawImpl(mpt::const_byte_span data) { if (f.second < 0) { return false; } if (f.second > static_cast(f.first.size())) { return false; } std::size_t num = mpt::saturate_cast(std::min(static_cast(f.first.size()) - f.second, static_cast(data.size()))); if (num != data.size()) { return false; } std::copy(data.data(), data.data() + num, mpt::byte_cast(f.first.data() + f.second)); f.second += num; return true; } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsEof() { return (f.second >= static_cast(f.first.size())); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool Flush() { MPT_UNUSED(f); return true; } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_IO_SPAN_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io/base.hpp0000644000175000017500000000453614650142521017707 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_BASE_HPP #define MPT_IO_BASE_HPP #include "mpt/base/integer.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { using Offset = int64; inline constexpr std::size_t BUFFERSIZE_MINUSCULE = 1 * 256; // on stack usage, tuned for single word/line buffers inline constexpr std::size_t BUFFERSIZE_TINY = 1 * 1024; // on stack usage inline constexpr std::size_t BUFFERSIZE_SMALL = 4 * 1024; // on heap inline constexpr std::size_t BUFFERSIZE_NORMAL = 64 * 1024; // FILE I/O inline constexpr std::size_t BUFFERSIZE_LARGE = 1024 * 1024; template struct FileOperations { }; template inline FileOperations FileOps(Tfile & f) { return FileOperations{f}; } template inline bool IsValid(Tfile & f) { return FileOps(f).IsValid(); } template inline bool IsReadSeekable(Tfile & f) { return FileOps(f).IsReadSeekable(); } template inline bool IsWriteSeekable(Tfile & f) { return FileOps(f).IsWriteSeekable(); } template inline IO::Offset TellRead(Tfile & f) { return FileOps(f).TellRead(); } template inline IO::Offset TellWrite(Tfile & f) { return FileOps(f).TellWrite(); } template inline bool SeekBegin(Tfile & f) { return FileOps(f).SeekBegin(); } template inline bool SeekEnd(Tfile & f) { return FileOps(f).SeekEnd(); } template inline bool SeekAbsolute(Tfile & f, IO::Offset pos) { return FileOps(f).SeekAbsolute(pos); } template inline bool SeekRelative(Tfile & f, IO::Offset off) { return FileOps(f).SeekRelative(off); } template inline mpt::byte_span ReadRawImpl(Tfile & f, mpt::byte_span data) { return FileOps(f).ReadRawImpl(data); } template inline bool WriteRawImpl(Tfile & f, mpt::const_byte_span data) { return FileOps(f).WriteRawImpl(data); } template inline bool IsEof(Tfile & f) { return FileOps(f).IsEof(); } template inline bool Flush(Tfile & f) { return FileOps(f).Flush(); } } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_BASE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io/io_stdstream.hpp0000644000175000017500000001561714650142521021474 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_IO_STDSTREAM_HPP #define MPT_IO_IO_STDSTREAM_HPP #include "mpt/base/macros.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/base/utility.hpp" #include "mpt/io/base.hpp" #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { struct FileOperationsStdIos { private: std::ios & f; public: inline FileOperationsStdIos(std::ios & f_) : f(f_) { return; } public: inline bool IsValid() { return !f.fail(); } }; struct FileOperationsStdIstream : public FileOperationsStdIos { private: std::istream & f; public: inline FileOperationsStdIstream(std::istream & f_) : FileOperationsStdIos(f_) , f(f_) { return; } public: inline bool IsReadSeekable() { f.clear(); std::streampos oldpos = f.tellg(); if (f.fail() || oldpos == std::streampos(std::streamoff(-1))) { f.clear(); return false; } f.seekg(0, std::ios::beg); if (f.fail()) { f.clear(); f.seekg(oldpos); f.clear(); return false; } f.seekg(0, std::ios::end); if (f.fail()) { f.clear(); f.seekg(oldpos); f.clear(); return false; } std::streampos length = f.tellg(); if (f.fail() || length == std::streampos(std::streamoff(-1))) { f.clear(); f.seekg(oldpos); f.clear(); return false; } f.seekg(oldpos); f.clear(); return true; } inline IO::Offset TellRead() { return static_cast(f.tellg()); } inline bool SeekBegin() { f.seekg(0, std::ios::beg); return !f.fail(); } inline bool SeekEnd() { f.seekg(0, std::ios::end); return !f.fail(); } inline bool SeekAbsolute(IO::Offset pos) { if (!mpt::in_range(pos)) { return false; } f.seekg(static_cast(pos), std::ios::beg); return !f.fail(); } inline bool SeekRelative(IO::Offset off) { if (!mpt::in_range(off)) { return false; } f.seekg(static_cast(off), std::ios::cur); return !f.fail(); } inline mpt::byte_span ReadRawImpl(mpt::byte_span data) { std::size_t bytesToRead = data.size(); std::size_t bytesRead = 0; while (bytesToRead > 0) { std::streamsize bytesChunkToRead = mpt::saturate_cast(bytesToRead); f.read(mpt::byte_cast(data.data()) + bytesRead, bytesChunkToRead); std::streamsize bytesChunkRead = f.gcount(); bytesRead += static_cast(bytesChunkRead); bytesToRead -= static_cast(bytesChunkRead); if (bytesChunkRead != bytesChunkToRead) { break; } } return data.first(bytesRead); } inline bool IsEof() { return f.eof(); } }; struct FileOperationsStdOstream : public FileOperationsStdIos { private: std::ostream & f; public: inline FileOperationsStdOstream(std::ostream & f_) : FileOperationsStdIos(f_) , f(f_) { return; } public: inline bool IsWriteSeekable() { f.clear(); std::streampos oldpos = f.tellp(); if (f.fail() || oldpos == std::streampos(std::streamoff(-1))) { f.clear(); return false; } f.seekp(0, std::ios::beg); if (f.fail()) { f.clear(); f.seekp(oldpos); f.clear(); return false; } f.seekp(0, std::ios::end); if (f.fail()) { f.clear(); f.seekp(oldpos); f.clear(); return false; } std::streampos length = f.tellp(); if (f.fail() || length == std::streampos(std::streamoff(-1))) { f.clear(); f.seekp(oldpos); f.clear(); return false; } f.seekp(oldpos); f.clear(); return true; } inline IO::Offset TellWrite() { return static_cast(f.tellp()); } inline bool SeekBegin() { f.seekp(0, std::ios::beg); return !f.fail(); } inline bool SeekEnd() { f.seekp(0, std::ios::end); return !f.fail(); } inline bool SeekAbsolute(IO::Offset pos) { if (!mpt::in_range(pos)) { return false; } f.seekp(static_cast(pos), std::ios::beg); return !f.fail(); } inline bool SeekRelative(IO::Offset off) { if (!mpt::in_range(off)) { return false; } f.seekp(static_cast(off), std::ios::cur); return !f.fail(); } inline bool WriteRawImpl(mpt::const_byte_span data) { std::size_t bytesToWrite = data.size(); std::size_t bytesWritten = 0; while (bytesToWrite > 0) { std::streamsize bytesChunk = mpt::saturate_cast(bytesToWrite); f.write(mpt::byte_cast(data.data()) + bytesWritten, bytesChunk); if (f.fail()) { break; } bytesWritten += static_cast(bytesChunk); bytesToWrite -= static_cast(bytesChunk); } return !f.fail(); } inline bool Flush() { f.flush(); return !f.fail(); } }; struct FileOperationsStdIOstream : public FileOperationsStdIstream , public FileOperationsStdOstream { private: std::iostream & f; public: inline FileOperationsStdIOstream(std::iostream & f_) : FileOperationsStdIstream(f_) , FileOperationsStdOstream(f_) , f(f_) { return; } public: // cppcheck-suppress duplInheritedMember inline bool SeekBegin() { FileOperationsStdIstream::SeekBegin(); FileOperationsStdOstream::SeekBegin(); return !f.fail(); } // cppcheck-suppress duplInheritedMember inline bool SeekEnd() { FileOperationsStdIstream::SeekEnd(); FileOperationsStdOstream::SeekEnd(); return !f.fail(); } // cppcheck-suppress duplInheritedMember inline bool SeekAbsolute(IO::Offset pos) { if (!mpt::in_range(pos)) { return false; } FileOperationsStdIstream::SeekAbsolute(pos); FileOperationsStdOstream::SeekAbsolute(pos); return !f.fail(); } // cppcheck-suppress duplInheritedMember inline bool SeekRelative(IO::Offset off) { if (!mpt::in_range(off)) { return false; } FileOperationsStdIstream::SeekRelative(off); FileOperationsStdOstream::SeekRelative(off); return !f.fail(); } }; template struct FileOperations::value>> : public FileOperationsStdIOstream { public: inline FileOperations(Tstream & f) : FileOperationsStdIOstream(f) { return; } }; template struct FileOperations::value && !std::is_base_of::value>> : public FileOperationsStdIstream { public: inline FileOperations(Tstream & f) : FileOperationsStdIstream(f) { return; } }; template struct FileOperations::value && !std::is_base_of::value>> : public FileOperationsStdOstream { public: inline FileOperations(Tstream & f) : FileOperationsStdOstream(f) { return; } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_IO_STDSTREAM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io/tests/0000755000175000017500000000000015023302361017471 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/io/tests/tests_io.hpp0000644000175000017500000004641214375432552022001 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_TESTS_IO_HPP #define MPT_IO_TESTS_IO_HPP #include "mpt/base/alloc.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/utility.hpp" #include "mpt/endian/integer.hpp" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace io { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/io") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { // check that empty stringstream behaves correctly with our MSVC workarounds when using iostream interface directly { std::ostringstream ss; MPT_TEST_EXPECT_EQUAL(static_cast(ss.tellp()), std::streamoff(0)); } { std::ostringstream ss; ss.seekp(0); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true); } { std::ostringstream ss; ss.seekp(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!ss.fail(), true); } { std::ostringstream ss; ss.seekp(0, std::ios_base::cur); MPT_TEST_EXPECT_EQUAL(!ss.fail(), true); } { std::istringstream ss; MPT_TEST_EXPECT_EQUAL(static_cast(ss.tellg()), std::streamoff(0)); } { std::istringstream ss; ss.seekg(0, std::ios::beg); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true); } { std::istringstream ss; ss.seekg(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!ss.fail(), true); } { std::istringstream ss; ss.seekg(0, std::ios_base::cur); MPT_TEST_EXPECT_EQUAL(!ss.fail(), true); } { std::ostringstream s; char b = 23; MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellp()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekp(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellp()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.write(&b, 1); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellp()), std::streamoff(1)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekp(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellp()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekp(0, std::ios_base::end); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellp()), std::streamoff(1)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(s.str(), std::string(1, b)); } { std::istringstream s; MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekg(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekg(0, std::ios_base::end); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); } { std::istringstream s("a"); char a = 0; MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekg(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.read(&a, 1); MPT_TEST_EXPECT_EQUAL(a, 'a'); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(1)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekg(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekg(0, std::ios_base::end); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(1)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(std::string(1, a), std::string(1, 'a')); } // check that empty native and fixed stringstream both behaves correctly with out IO functions { std::ostringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(ss), 0); } { std::ostringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(ss), true); } { std::ostringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true); } { std::ostringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekRelative(ss, 0), true); } { std::istringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(ss), 0); } { std::istringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(ss), true); } { std::istringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true); } { std::istringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekRelative(ss, 0), true); } { std::ostringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(ss), 0); } { std::ostringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(ss), true); } { std::ostringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true); } { std::ostringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekRelative(ss, 0), true); } { std::istringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(ss), 0); } { std::istringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(ss), true); } { std::istringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true); } { std::istringstream ss; MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekRelative(ss, 0), true); } { std::ostringstream s; char b = 23; MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::WriteRaw(s, &b, 1), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 1); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 1); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(s.str(), std::string(1, b)); } { std::istringstream s; MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); } { std::istringstream s("a"); char a = 0; MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::ReadRaw(s, &a, 1).size(), 1u); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 1); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 1); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(std::string(1, a), std::string(1, 'a')); } { std::ostringstream s; char b = 23; MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::WriteRaw(s, &b, 1), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 1); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 1); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(s.str(), std::string(1, b)); } { std::istringstream s; MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); } { std::istringstream s("a"); char a = 0; MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::ReadRaw(s, &a, 1).size(), 1u); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 1); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 1); MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true); MPT_TEST_EXPECT_EQUAL(std::string(1, a), std::string(1, 'a')); } // General file I/O tests { // Verify that writing arrays does not confuse the compiler. // This is both, compile-time and run-time cheking. // Run-time in case some weird compiler gets confused by our templates // and only writes the first array element. std::ostringstream f; mpt::uint16be data[2]; mpt::reset(data); data[0] = 0x1234; data[1] = 0x5678; mpt::IO::Write(f, data); MPT_TEST_EXPECT_EQUAL(f.str(), std::string("\x12\x34\x56\x78")); } { std::ostringstream f; std::vector data; data.resize(3); data[0] = 0x1234; data[1] = 0x5678; data[2] = 0x1234; mpt::IO::Write(f, data); MPT_TEST_EXPECT_EQUAL(f.str(), std::string("\x12\x34\x56\x78\x12\x34")); } { std::ostringstream f; mpt::int16be data[3]; mpt::reset(data); data[0] = 0x1234; data[1] = 0x5678; data[2] = 0x1234; mpt::IO::Write(f, data); MPT_TEST_EXPECT_EQUAL(f.str(), std::string("\x12\x34\x56\x78\x12\x34")); } { auto TestAdaptive16 = [&](uint16 value, mpt::IO::Offset expected_size, std::size_t fixedSize, const char * bytes) { std::stringstream f; MPT_TEST_EXPECT_EQUAL(mpt::IO::WriteAdaptiveInt16LE(f, value, fixedSize), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(f), expected_size); if (bytes) { mpt::IO::SeekBegin(f); for (mpt::IO::Offset i = 0; i < expected_size; ++i) { uint8 val = 0; mpt::IO::ReadIntLE(f, val); MPT_TEST_EXPECT_EQUAL(val, static_cast(bytes[i])); } } mpt::IO::SeekBegin(f); uint16 result = 0; MPT_TEST_EXPECT_EQUAL(mpt::IO::ReadAdaptiveInt16LE(f, result), true); MPT_TEST_EXPECT_EQUAL(result, value); }; auto TestAdaptive32 = [&](uint32 value, mpt::IO::Offset expected_size, std::size_t fixedSize, const char * bytes) { std::stringstream f; MPT_TEST_EXPECT_EQUAL(mpt::IO::WriteAdaptiveInt32LE(f, value, fixedSize), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(f), expected_size); if (bytes) { mpt::IO::SeekBegin(f); for (mpt::IO::Offset i = 0; i < expected_size; ++i) { uint8 val = 0; mpt::IO::ReadIntLE(f, val); MPT_TEST_EXPECT_EQUAL(val, static_cast(bytes[i])); } } mpt::IO::SeekBegin(f); uint32 result = 0; MPT_TEST_EXPECT_EQUAL(mpt::IO::ReadAdaptiveInt32LE(f, result), true); MPT_TEST_EXPECT_EQUAL(result, value); }; auto TestAdaptive64 = [&](uint64 value, mpt::IO::Offset expected_size, std::size_t fixedSize, const char * bytes) { std::stringstream f; MPT_TEST_EXPECT_EQUAL(mpt::IO::WriteAdaptiveInt64LE(f, value, fixedSize), true); MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(f), expected_size); if (bytes) { mpt::IO::SeekBegin(f); for (mpt::IO::Offset i = 0; i < expected_size; ++i) { uint8 val = 0; mpt::IO::ReadIntLE(f, val); MPT_TEST_EXPECT_EQUAL(val, static_cast(bytes[i])); } } mpt::IO::SeekBegin(f); uint64 result = 0; MPT_TEST_EXPECT_EQUAL(mpt::IO::ReadAdaptiveInt64LE(f, result), true); MPT_TEST_EXPECT_EQUAL(result, value); }; TestAdaptive16(0, 1, 0, "\x00"); TestAdaptive16(1, 1, 0, "\x02"); TestAdaptive16(2, 1, 0, nullptr); TestAdaptive16(0x7f, 1, 0, nullptr); TestAdaptive16(0x80, 2, 0, "\x01\x01"); TestAdaptive16(0x81, 2, 0, "\x03\x01"); TestAdaptive16(0x7fff, 2, 0, "\xff\xff"); TestAdaptive16(0, 1, 1, nullptr); TestAdaptive16(1, 1, 1, nullptr); TestAdaptive16(2, 1, 1, nullptr); TestAdaptive16(0x7f, 1, 1, nullptr); TestAdaptive16(0x80, 2, 0, nullptr); TestAdaptive16(0x81, 2, 0, nullptr); TestAdaptive16(0x7fff, 2, 0, nullptr); TestAdaptive16(0, 2, 2, "\x01\x00"); TestAdaptive16(1, 2, 2, "\x03\x00"); TestAdaptive16(2, 2, 2, nullptr); TestAdaptive16(0x7f, 2, 2, nullptr); TestAdaptive16(0x80, 2, 2, nullptr); TestAdaptive16(0x81, 2, 2, nullptr); TestAdaptive16(0x7fff, 2, 2, nullptr); TestAdaptive32(0, 1, 0, "\x00"); TestAdaptive32(1, 1, 0, nullptr); TestAdaptive32(2, 1, 0, nullptr); TestAdaptive32(0x3f, 1, 0, nullptr); TestAdaptive32(0x40, 2, 0, "\x01\x01"); TestAdaptive32(0x41, 2, 0, "\x05\x01"); TestAdaptive32(0x7f, 2, 0, nullptr); TestAdaptive32(0x80, 2, 0, nullptr); TestAdaptive32(0x3fff, 2, 0, nullptr); TestAdaptive32(0x4000, 3, 0, "\x02\x00\x01"); TestAdaptive32(0x4001, 3, 0, nullptr); TestAdaptive32(0x3fffff, 3, 0, nullptr); TestAdaptive32(0x400000, 4, 0, "\x03\x00\x00\x01"); TestAdaptive32(0x400001, 4, 0, nullptr); TestAdaptive32(0x3fffffff, 4, 0, "\xff\xff\xff\xff"); TestAdaptive32(0, 2, 2, nullptr); TestAdaptive32(1, 2, 2, nullptr); TestAdaptive32(2, 2, 2, nullptr); TestAdaptive32(0x3f, 2, 2, nullptr); TestAdaptive32(0x40, 2, 2, nullptr); TestAdaptive32(0x41, 2, 2, nullptr); TestAdaptive32(0x7f, 2, 2, nullptr); TestAdaptive32(0x80, 2, 2, nullptr); TestAdaptive32(0x3fff, 2, 2, nullptr); TestAdaptive32(0, 3, 3, nullptr); TestAdaptive32(1, 3, 3, nullptr); TestAdaptive32(2, 3, 3, nullptr); TestAdaptive32(0x3f, 3, 3, nullptr); TestAdaptive32(0x40, 3, 3, nullptr); TestAdaptive32(0x41, 3, 3, nullptr); TestAdaptive32(0x7f, 3, 3, nullptr); TestAdaptive32(0x80, 3, 3, nullptr); TestAdaptive32(0x3fff, 3, 3, nullptr); TestAdaptive32(0x4000, 3, 3, nullptr); TestAdaptive32(0x4001, 3, 3, nullptr); TestAdaptive32(0x3fffff, 3, 3, nullptr); TestAdaptive32(0, 4, 4, nullptr); TestAdaptive32(1, 4, 4, nullptr); TestAdaptive32(2, 4, 4, nullptr); TestAdaptive32(0x3f, 4, 4, nullptr); TestAdaptive32(0x40, 4, 4, nullptr); TestAdaptive32(0x41, 4, 4, nullptr); TestAdaptive32(0x7f, 4, 4, nullptr); TestAdaptive32(0x80, 4, 4, nullptr); TestAdaptive32(0x3fff, 4, 4, nullptr); TestAdaptive32(0x4000, 4, 4, nullptr); TestAdaptive32(0x4001, 4, 4, nullptr); TestAdaptive32(0x3fffff, 4, 4, nullptr); TestAdaptive32(0x400000, 4, 4, nullptr); TestAdaptive32(0x400001, 4, 4, nullptr); TestAdaptive32(0x3fffffff, 4, 4, nullptr); TestAdaptive64(0, 1, 0, nullptr); TestAdaptive64(1, 1, 0, nullptr); TestAdaptive64(2, 1, 0, nullptr); TestAdaptive64(0x3f, 1, 0, nullptr); TestAdaptive64(0x40, 2, 0, nullptr); TestAdaptive64(0x41, 2, 0, nullptr); TestAdaptive64(0x7f, 2, 0, nullptr); TestAdaptive64(0x80, 2, 0, nullptr); TestAdaptive64(0x3fff, 2, 0, nullptr); TestAdaptive64(0x4000, 4, 0, nullptr); TestAdaptive64(0x4001, 4, 0, nullptr); TestAdaptive64(0x3fffff, 4, 0, nullptr); TestAdaptive64(0x400000, 4, 0, nullptr); TestAdaptive64(0x400001, 4, 0, nullptr); TestAdaptive64(0x3fffffff, 4, 0, nullptr); TestAdaptive64(0x40000000, 8, 0, nullptr); TestAdaptive64(0x40000001, 8, 0, nullptr); TestAdaptive64(0x3fffffffffffffffull, 8, 0, nullptr); TestAdaptive64(0, 2, 2, nullptr); TestAdaptive64(1, 2, 2, nullptr); TestAdaptive64(2, 2, 2, nullptr); TestAdaptive64(0x3f, 2, 2, nullptr); TestAdaptive64(0, 4, 4, nullptr); TestAdaptive64(1, 4, 4, nullptr); TestAdaptive64(2, 4, 4, nullptr); TestAdaptive64(0x3f, 4, 4, nullptr); TestAdaptive64(0x40, 4, 4, nullptr); TestAdaptive64(0x41, 4, 4, nullptr); TestAdaptive64(0x7f, 4, 4, nullptr); TestAdaptive64(0x80, 4, 4, nullptr); TestAdaptive64(0x3fff, 4, 4, nullptr); TestAdaptive64(0, 8, 8, nullptr); TestAdaptive64(1, 8, 8, nullptr); TestAdaptive64(2, 8, 8, nullptr); TestAdaptive64(0x3f, 8, 8, nullptr); TestAdaptive64(0x40, 8, 8, nullptr); TestAdaptive64(0x41, 8, 8, nullptr); TestAdaptive64(0x7f, 8, 8, nullptr); TestAdaptive64(0x80, 8, 8, nullptr); TestAdaptive64(0x3fff, 8, 8, nullptr); TestAdaptive64(0x4000, 8, 8, nullptr); TestAdaptive64(0x4001, 8, 8, nullptr); TestAdaptive64(0x3fffff, 8, 8, nullptr); TestAdaptive64(0x400000, 8, 8, nullptr); TestAdaptive64(0x400001, 8, 8, nullptr); TestAdaptive64(0x3fffffff, 8, 8, nullptr); TestAdaptive64(0x40000000, 8, 8, nullptr); TestAdaptive64(0x40000001, 8, 8, nullptr); TestAdaptive64(0x3fffffffffffffffull, 8, 8, nullptr); } } } // namespace io } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_TESTS_IO_HPP libopenmpt-0.8.1+release.autotools/src/mpt/.clang-format0000644000175000017500000001151614275750533020237 00000000000000# clang-format 14 Language: Cpp Standard: c++20 AccessModifierOffset: -4 #? AlignAfterOpenBracket: AlwaysBreak AlignArrayOfStructures: Left AlignConsecutiveAssignments: false AlignConsecutiveBitFields: false AlignConsecutiveDeclarations: false AlignConsecutiveMacros: true AlignEscapedNewlines: DontAlign AlignOperands: AlignAfterOperator AlignTrailingComments: true AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: Never AllowShortCaseLabelsOnASingleLine: false AllowShortEnumsOnASingleLine: false AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: false AllowShortLambdasOnASingleLine: Inline AllowShortLoopsOnASingleLine: false AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: Yes AttributeMacros: [] BinPackArguments: true BinPackParameters: false BitFieldColonSpacing: Both BraceWrapping: AfterCaseLabel: false AfterClass: false AfterControlStatement: MultiLine AfterEnum: false AfterFunction: false AfterNamespace: false #AfterObjCDeclaration AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false BeforeLambdaBody: false BeforeWhile: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: false SplitEmptyNamespace: true #BreakAfterJavaFieldAnnotations BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Custom BreakBeforeConceptDeclarations: true BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeComma BreakInheritanceList: BeforeComma BreakStringLiterals: false ColumnLimit: 0 CommentPragmas: '' #? CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 #? ContinuationIndentWidth: 4 #? Cpp11BracedListStyle: true DeriveLineEnding: true DerivePointerAlignment: false EmptyLineAfterAccessModifier: Leave EmptyLineBeforeAccessModifier: Leave FixNamespaceComments: true ForEachMacros: [] IfMacros: ['MPT_MAYBE_CONSTANT_IF'] IncludeBlocks: Preserve IncludeCategories: [] #? IncludeIsMainRegex: '' #? IncludeIsMainSourceRegex: '' #? IndentAccessModifiers: false IndentCaseLabels: true IndentCaseBlocks: true IndentExternBlock: NoIndent IndentGotoLabels: false IndentPPDirectives: None #IndentRequiresClause: true InsertTrailingCommas: None #BeforeHash IndentWidth: 4 IndentWrappedFunctionNames: true #JavaImportGroups #JavaScriptQuotes #JavaScriptWrapImports KeepEmptyLinesAtTheStartOfBlocks: true LambdaBodyIndentation: OuterScope MacroBlockBegin: '^MPT_TEST_GROUP_BEGIN$' #? MacroBlockEnd: '^MPT_TEST_GROUP_END$' #? MaxEmptyLinesToKeep: 5 NamespaceIndentation: None NamespaceMacros: [] #? #ObjCBinPackProtocolList #ObjCBlockIndentWidth #ObjCBreakBeforeNestedBlockParam #ObjCSpaceAfterProperty #ObjCSpaceBeforeProtocolList PackConstructorInitializers: Never #PenaltyBreakAssignment #PenaltyBreakBeforeFirstCallParameter #PenaltyBreakComment #PenaltyBreakFirstLessLess #PenaltyBreakOpenParenthesis #PenaltyBreakString #PenaltyBreakTemplateDeclaration #PenaltyExcessCharacter #PenaltyIndentedWhitespace #PenaltyReturnTypeOnItsOwnLine PointerAlignment: Middle PPIndentWidth: -1 #RawStringFormats QualifierAlignment: Leave #QualifierOrder: ['static', 'inline', 'constexpr', 'volatile', 'const', 'restrict', 'type'] ReferenceAlignment: Pointer ReflowComments: false RemoveBracesLLVM: false SeparateDefinitionBlocks: Leave ShortNamespaceLines: 1 SortIncludes: false #SortJavaStaticImport SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true SpaceAroundPointerQualifiers: Default SpaceBeforeAssignmentOperators: true SpaceBeforeCaseColon: false SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeParensOptions: AfterControlStatements: true AfterForeachMacros: true AfterFunctionDeclarationName: false AfterFunctionDefinitionName: false AfterIfMacros: true AfterOverloadedOperator: false #AfterRequiresInClause: false #AfterRequiresInExpression: false BeforeNonEmptyParentheses: false SpaceBeforeRangeBasedForLoopColon: true SpaceBeforeSquareBrackets: false SpaceInEmptyBlock: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInConditionalStatement: false SpacesInContainerLiterals: true SpacesInLineCommentPrefix: Minimum: 1 Maximum: -1 SpacesInParentheses: false SpacesInSquareBrackets: false StatementAttributeLikeMacros: [] StatementMacros: [ '_Pragma', '__pragma', 'MPT_WARNING', 'MPT_TEST_GROUP_INLINE_IDENTIFIER', 'MPT_TEST_GROUP_INLINE', 'MPT_TEST_GROUP_STATIC' ] #? TabWidth: 4 TypenameMacros: [] #? UseCRLF: false UseTab: ForContinuationAndIndentation WhitespaceSensitiveMacros: - MPT_PP_STRINGIFY libopenmpt-0.8.1+release.autotools/src/mpt/io_read/0000755000175000017500000000000015023302361017322 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filecursor_memory.hpp0000644000175000017500000000176514650142521023536 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILECURSOR_MEMORY_HPP #define MPT_IO_READ_FILECURSOR_MEMORY_HPP #include "mpt/base/namespace.hpp" #include "mpt/base/span.hpp" #include "mpt/io_read/filecursor.hpp" #include "mpt/io_read/filecursor_filename_traits.hpp" #include "mpt/io_read/filecursor_traits_filedata.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { // Initialize file reader object with pointer to data and data length. template inline FileCursor> make_FileCursor(mpt::span bytedata, std::shared_ptr filename = nullptr) { return FileCursor>(mpt::byte_cast(bytedata), std::move(filename)); } } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILECURSOR_STDSTREAM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filedata_base_unseekable.hpp0000644000175000017500000001022514650142521024721 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILEDATA_BASE_UNSEEKABLE_HPP #define MPT_IO_READ_FILEDATA_BASE_UNSEEKABLE_HPP #include "mpt/base/algorithm.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/numeric.hpp" #include "mpt/io/base.hpp" #include "mpt/io_read/filedata.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class FileDataUnseekable : public IFileData { private: mutable std::vector cache; mutable std::size_t cachesize; mutable bool streamFullyCached; protected: FileDataUnseekable() : cachesize(0) , streamFullyCached(false) { return; } private: enum : std::size_t { QUANTUM_SIZE = mpt::IO::BUFFERSIZE_SMALL, BUFFER_SIZE = mpt::IO::BUFFERSIZE_NORMAL }; void EnsureCacheBuffer(std::size_t requiredbuffersize) const { if (cache.size() - cachesize >= requiredbuffersize) { return; } if (cache.size() == 0) { cache.resize(mpt::saturate_align_up(cachesize + requiredbuffersize, BUFFER_SIZE)); } else if (mpt::exponential_grow(cache.size()) < cachesize + requiredbuffersize) { cache.resize(mpt::saturate_align_up(cachesize + requiredbuffersize, BUFFER_SIZE)); } else { cache.resize(mpt::exponential_grow(cache.size())); } } void CacheStream() const { if (streamFullyCached) { return; } while (!InternalEof()) { EnsureCacheBuffer(BUFFER_SIZE); std::size_t readcount = InternalReadUnseekable(mpt::span(&cache[cachesize], BUFFER_SIZE)).size(); cachesize += readcount; } streamFullyCached = true; } void CacheStreamUpTo(pos_type pos, pos_type length) const { if (streamFullyCached) { return; } if (length > std::numeric_limits::max() - pos) { length = std::numeric_limits::max() - pos; } std::size_t target = mpt::saturate_cast(pos + length); if (target <= cachesize) { return; } std::size_t alignedpos = mpt::saturate_align_up(target, QUANTUM_SIZE); while (!InternalEof() && (cachesize < alignedpos)) { EnsureCacheBuffer(BUFFER_SIZE); std::size_t readcount = InternalReadUnseekable(mpt::span(&cache[cachesize], BUFFER_SIZE)).size(); cachesize += readcount; } if (InternalEof()) { streamFullyCached = true; } } private: void ReadCached(pos_type pos, mpt::byte_span dst) const { std::copy(cache.begin() + static_cast(pos), cache.begin() + static_cast(pos + dst.size()), dst.data()); } public: bool IsValid() const override { return true; } bool HasFastGetLength() const override { return false; } bool HasPinnedView() const override { return true; // we have the cache which is required for seeking anyway } const std::byte * GetRawData() const override { CacheStream(); return cache.data(); } pos_type GetLength() const override { CacheStream(); return cachesize; } mpt::byte_span Read(pos_type pos, mpt::byte_span dst) const override { CacheStreamUpTo(pos, dst.size()); if (pos >= static_cast(cachesize)) { return dst.first(0); } pos_type cache_avail = std::min(static_cast(cachesize) - pos, static_cast(dst.size())); ReadCached(pos, dst.subspan(0, static_cast(cache_avail))); return dst.subspan(0, static_cast(cache_avail)); } bool CanRead(pos_type pos, pos_type length) const override { CacheStreamUpTo(pos, length); if ((pos == static_cast(cachesize)) && (length == 0)) { return true; } if (pos >= static_cast(cachesize)) { return false; } return length <= static_cast(cachesize) - pos; } pos_type GetReadableLength(pos_type pos, pos_type length) const override { CacheStreamUpTo(pos, length); if (pos >= cachesize) { return 0; } return std::min(static_cast(cachesize) - pos, length); } private: virtual bool InternalEof() const = 0; virtual mpt::byte_span InternalReadUnseekable(mpt::byte_span dst) const = 0; }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILEDATA_BASE_UNSEEKABLE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filedata_base_seekable.hpp0000644000175000017500000000240614650142521024360 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILEDATA_BASE_SEEKABLE_HPP #define MPT_IO_READ_FILEDATA_BASE_SEEKABLE_HPP #include "mpt/base/alloc.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/span.hpp" #include "mpt/io_read/filedata.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class FileDataSeekable : public IFileData { private: pos_type streamLength; protected: FileDataSeekable(pos_type streamLength_) : streamLength(streamLength_) { return; } public: bool IsValid() const override { return true; } bool HasFastGetLength() const override { return true; } bool HasPinnedView() const override { return false; } const std::byte * GetRawData() const override { return nullptr; } pos_type GetLength() const override { return streamLength; } mpt::byte_span Read(pos_type pos, mpt::byte_span dst) const override { return InternalReadSeekable(pos, dst); } private: virtual mpt::byte_span InternalReadSeekable(pos_type pos, mpt::byte_span dst) const = 0; }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILEDATA_BASE_SEEKABLE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filedata_base.hpp0000644000175000017500000000434514650142521022531 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILEDATA_BASE_HPP #define MPT_IO_READ_FILEDATA_BASE_HPP #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/io_read/filedata.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class FileDataDummy : public IFileData { public: FileDataDummy() { } public: bool IsValid() const override { return false; } bool HasFastGetLength() const override { return true; } bool HasPinnedView() const override { return true; } const std::byte * GetRawData() const override { return nullptr; } pos_type GetLength() const override { return 0; } mpt::byte_span Read(pos_type /* pos */, mpt::byte_span dst) const override { return dst.first(0); } }; class FileDataWindow : public IFileData { private: std::shared_ptr data; const pos_type dataOffset; const pos_type dataLength; public: FileDataWindow(std::shared_ptr src, pos_type off, pos_type len) : data(src) , dataOffset(off) , dataLength(len) { } bool IsValid() const override { return data->IsValid(); } bool HasFastGetLength() const override { return true; } bool HasPinnedView() const override { return data->HasPinnedView(); } const std::byte * GetRawData() const override { return data->GetRawData() + dataOffset; } pos_type GetLength() const override { return dataLength; } mpt::byte_span Read(pos_type pos, mpt::byte_span dst) const override { if (pos >= dataLength) { return dst.first(0); } return data->Read(dataOffset + pos, dst.first(static_cast(std::min(static_cast(dst.size()), dataLength - pos)))); } bool CanRead(pos_type pos, pos_type length) const override { if ((pos == dataLength) && (length == 0)) { return true; } if (pos >= dataLength) { return false; } return (length <= dataLength - pos); } pos_type GetReadableLength(pos_type pos, pos_type length) const override { if (pos >= dataLength) { return 0; } return std::min(length, dataLength - pos); } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILEDATA_BASE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filedata_memory.hpp0000644000175000017500000000362514650142521023127 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILEDATA_MEMORY_HPP #define MPT_IO_READ_FILEDATA_MEMORY_HPP #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/io_read/filedata.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class FileDataMemory : public IFileData { private: const std::byte * streamData; // Pointer to memory-mapped file pos_type streamLength; // Size of memory-mapped file in bytes public: FileDataMemory() : streamData(nullptr) , streamLength(0) { } FileDataMemory(mpt::const_byte_span data) : streamData(data.data()) , streamLength(data.size()) { } public: bool IsValid() const override { return streamData != nullptr; } bool HasFastGetLength() const override { return true; } bool HasPinnedView() const override { return true; } const std::byte * GetRawData() const override { return streamData; } pos_type GetLength() const override { return streamLength; } mpt::byte_span Read(pos_type pos, mpt::byte_span dst) const override { if (pos >= streamLength) { return dst.first(0); } pos_type avail = std::min(streamLength - pos, static_cast(dst.size())); std::copy(streamData + pos, streamData + static_cast(pos + avail), dst.data()); return dst.first(static_cast(avail)); } bool CanRead(pos_type pos, pos_type length) const override { if ((pos == streamLength) && (length == 0)) { return true; } if (pos >= streamLength) { return false; } return (length <= streamLength - pos); } pos_type GetReadableLength(pos_type pos, pos_type length) const override { if (pos >= streamLength) { return 0; } return std::min(length, streamLength - pos); } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILEDATA_MEMORY_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filecursor_traits_filedata.hpp0000644000175000017500000000261614650142521025361 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILECURSOR_TRAITS_FILEDATA_HPP #define MPT_IO_READ_FILECURSOR_TRAITS_FILEDATA_HPP #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/io_read/filedata.hpp" #include "mpt/io_read/filedata_base.hpp" #include "mpt/io_read/filedata_memory.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class FileCursorTraitsFileData { public: using pos_type = IFileData::pos_type; using data_type = std::shared_ptr; using ref_data_type = const IFileData &; using shared_data_type = std::shared_ptr; using value_data_type = std::shared_ptr; static shared_data_type get_shared(const data_type & data) { return data; } static ref_data_type get_ref(const data_type & data) { return *data; } static value_data_type make_data() { return std::make_shared(); } static value_data_type make_data(mpt::const_byte_span data) { return std::make_shared(data); } static value_data_type make_chunk(shared_data_type data, pos_type position, pos_type size) { return std::static_pointer_cast(std::make_shared(data, position, size)); } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILECURSOR_TRAITS_FILEDATA_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filedata_base_buffered.hpp0000644000175000017500000000732414650142521024373 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILEDATA_BASE_BUFFERED_HPP #define MPT_IO_READ_FILEDATA_BASE_BUFFERED_HPP #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/numeric.hpp" #include "mpt/io/base.hpp" #include "mpt/io_read/filedata.hpp" #include "mpt/io_read/filedata_base_seekable.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class FileDataSeekableBuffered : public FileDataSeekable { private: enum : std::size_t { CHUNK_SIZE = mpt::IO::BUFFERSIZE_SMALL, BUFFER_SIZE = mpt::IO::BUFFERSIZE_NORMAL }; enum : std::size_t { NUM_CHUNKS = BUFFER_SIZE / CHUNK_SIZE }; struct chunk_info { pos_type ChunkOffset = 0; std::size_t ChunkLength = 0; bool ChunkValid = false; }; mutable std::vector m_Buffer = std::vector(BUFFER_SIZE); mpt::byte_span chunk_data(std::size_t chunkIndex) const { return mpt::byte_span(m_Buffer.data() + (chunkIndex * CHUNK_SIZE), CHUNK_SIZE); } mutable std::array m_ChunkInfo = {}; mutable std::array m_ChunkIndexLRU = {}; std::size_t InternalFillPageAndReturnIndex(pos_type pos) const { pos = mpt::align_down(pos, static_cast(CHUNK_SIZE)); for (std::size_t chunkLRUIndex = 0; chunkLRUIndex < NUM_CHUNKS; ++chunkLRUIndex) { std::size_t chunkIndex = m_ChunkIndexLRU[chunkLRUIndex]; if (m_ChunkInfo[chunkIndex].ChunkValid && (m_ChunkInfo[chunkIndex].ChunkOffset == pos)) { std::size_t chunk = std::move(m_ChunkIndexLRU[chunkLRUIndex]); std::move_backward(m_ChunkIndexLRU.begin(), m_ChunkIndexLRU.begin() + chunkLRUIndex, m_ChunkIndexLRU.begin() + (chunkLRUIndex + 1)); m_ChunkIndexLRU[0] = std::move(chunk); return chunkIndex; } } { std::size_t chunk = std::move(m_ChunkIndexLRU[NUM_CHUNKS - 1]); std::move_backward(m_ChunkIndexLRU.begin(), m_ChunkIndexLRU.begin() + (NUM_CHUNKS - 1), m_ChunkIndexLRU.begin() + NUM_CHUNKS); m_ChunkIndexLRU[0] = std::move(chunk); } std::size_t chunkIndex = m_ChunkIndexLRU[0]; chunk_info & chunk = m_ChunkInfo[chunkIndex]; chunk.ChunkOffset = pos; chunk.ChunkLength = InternalReadBuffered(pos, chunk_data(chunkIndex)).size(); chunk.ChunkValid = true; return chunkIndex; } protected: FileDataSeekableBuffered(pos_type streamLength_) : FileDataSeekable(streamLength_) { return; } private: mpt::byte_span InternalReadSeekable(pos_type pos, mpt::byte_span dst) const override { pos_type totalRead = 0; std::byte * pdst = dst.data(); std::size_t count = dst.size(); while (count > 0) { std::size_t chunkIndex = InternalFillPageAndReturnIndex(pos); pos_type pageSkip = pos - m_ChunkInfo[chunkIndex].ChunkOffset; pos_type chunkWanted = std::min(static_cast(CHUNK_SIZE) - pageSkip, static_cast(count)); pos_type chunkGot = (static_cast(m_ChunkInfo[chunkIndex].ChunkLength) > pageSkip) ? (static_cast(m_ChunkInfo[chunkIndex].ChunkLength) - pageSkip) : 0; pos_type chunk = std::min(chunkWanted, chunkGot); std::copy(chunk_data(chunkIndex).data() + static_cast(pageSkip), chunk_data(chunkIndex).data() + static_cast(pageSkip + chunk), pdst); pos += chunk; pdst += chunk; totalRead += chunk; count -= static_cast(chunk); if (chunkWanted > chunk) { return dst.first(static_cast(totalRead)); } } return dst.first(static_cast(totalRead)); } virtual mpt::byte_span InternalReadBuffered(pos_type pos, mpt::byte_span dst) const = 0; }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILEDATA_BASE_BUFFERED_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filedata_callbackstream.hpp0000644000175000017500000001116514650142521024565 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILEDATA_CALLBACKSTREAM_HPP #define MPT_IO_READ_FILEDATA_CALLBACKSTREAM_HPP #include "mpt/base/integer.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/io_read/callbackstream.hpp" #include "mpt/io_read/filedata.hpp" #include "mpt/io_read/filedata_base_seekable.hpp" #include "mpt/io_read/filedata_base_unseekable.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { template class FileDataCallbackStreamTemplate { public: static bool IsSeekable(CallbackStreamTemplate stream) { if (!stream.stream) { return false; } if (!stream.seek) { return false; } if (!stream.tell) { return false; } int64 oldpos = stream.tell(stream.stream); if (oldpos < 0) { return false; } if (stream.seek(stream.stream, 0, CallbackStream::SeekSet) < 0) { stream.seek(stream.stream, oldpos, CallbackStream::SeekSet); return false; } if (stream.seek(stream.stream, 0, CallbackStream::SeekEnd) < 0) { stream.seek(stream.stream, oldpos, CallbackStream::SeekSet); return false; } int64 length = stream.tell(stream.stream); if (length < 0) { stream.seek(stream.stream, oldpos, CallbackStream::SeekSet); return false; } stream.seek(stream.stream, oldpos, CallbackStream::SeekSet); return true; } static IFileData::pos_type GetLength(CallbackStreamTemplate stream) { if (!stream.stream) { return 0; } if (!stream.seek) { return false; } if (!stream.tell) { return false; } int64 oldpos = stream.tell(stream.stream); if (oldpos < 0) { return 0; } if (stream.seek(stream.stream, 0, CallbackStream::SeekSet) < 0) { stream.seek(stream.stream, oldpos, CallbackStream::SeekSet); return 0; } if (stream.seek(stream.stream, 0, CallbackStream::SeekEnd) < 0) { stream.seek(stream.stream, oldpos, CallbackStream::SeekSet); return 0; } int64 length = stream.tell(stream.stream); if (length < 0) { stream.seek(stream.stream, oldpos, CallbackStream::SeekSet); return 0; } stream.seek(stream.stream, oldpos, CallbackStream::SeekSet); return mpt::saturate_cast(length); } }; using FileDataCallbackStream = FileDataCallbackStreamTemplate; template class FileDataCallbackStreamSeekableTemplate : public FileDataSeekable { private: CallbackStreamTemplate stream; public: FileDataCallbackStreamSeekableTemplate(CallbackStreamTemplate s) : FileDataSeekable(FileDataCallbackStream::GetLength(s)) , stream(s) { return; } private: mpt::byte_span InternalReadSeekable(pos_type pos, mpt::byte_span dst) const override { if (!stream.read) { return dst.first(0); } if (stream.seek(stream.stream, pos, CallbackStream::SeekSet) < 0) { return dst.first(0); } int64 totalread = 0; std::byte * pdst = dst.data(); std::size_t count = dst.size(); while (count > 0) { int64 readcount = stream.read(stream.stream, pdst, count); if (readcount <= 0) { break; } pdst += static_cast(readcount); count -= static_cast(readcount); totalread += readcount; } return dst.first(static_cast(totalread)); } }; using FileDataCallbackStreamSeekable = FileDataCallbackStreamSeekableTemplate; template class FileDataCallbackStreamUnseekableTemplate : public FileDataUnseekable { private: CallbackStreamTemplate stream; mutable bool eof_reached; public: FileDataCallbackStreamUnseekableTemplate(CallbackStreamTemplate s) : FileDataUnseekable() , stream(s) , eof_reached(false) { return; } private: bool InternalEof() const override { return eof_reached; } mpt::byte_span InternalReadUnseekable(mpt::byte_span dst) const override { if (eof_reached) { return dst.first(0); } if (!stream.read) { eof_reached = true; return dst.first(0); } int64 totalread = 0; std::byte * pdst = dst.data(); std::size_t count = dst.size(); while (count > 0) { int64 readcount = stream.read(stream.stream, pdst, count); if (readcount <= 0) { eof_reached = true; break; } pdst += static_cast(readcount); count -= static_cast(readcount); totalread += readcount; } return dst.first(static_cast(totalread)); } }; using FileDataCallbackStreamUnseekable = FileDataCallbackStreamUnseekableTemplate; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILEDATA_CALLBACKSTREAM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filecursor_traits_memory.hpp0000644000175000017500000000246214650142521025117 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILECURSOR_TRAITS_MEMORY_HPP #define MPT_IO_READ_FILECURSOR_TRAITS_MEMORY_HPP #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/span.hpp" #include "mpt/io_read/filedata.hpp" #include "mpt/io_read/filedata_memory.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class FileCursorTraitsMemory { public: using pos_type = FileDataMemory::pos_type; using data_type = FileDataMemory; using ref_data_type = const FileDataMemory &; using shared_data_type = const FileDataMemory &; using value_data_type = FileDataMemory; static shared_data_type get_shared(const data_type & data) { return data; } static ref_data_type get_ref(const data_type & data) { return data; } static value_data_type make_data() { return mpt::const_byte_span(); } static value_data_type make_data(mpt::const_byte_span data) { return data; } static value_data_type make_chunk(shared_data_type data, pos_type position, pos_type size) { return mpt::as_span(data.GetRawData() + static_cast(position), static_cast(size)); } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILECURSOR_TRAITS_MEMORY_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filecursor.hpp0000644000175000017500000002601014650142521022134 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILECURSOR_HPP #define MPT_IO_READ_FILECURSOR_HPP #include "mpt/base/alloc.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/span.hpp" #include "mpt/base/utility.hpp" #include "mpt/out_of_memory/out_of_memory.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { // change to show warnings for functions which trigger pre-caching the whole file for unseekable streams //#define MPT_FILECURSOR_DEPRECATED [[deprecated]] #define MPT_FILECURSOR_DEPRECATED template class FileCursor { private: using traits_type = Ttraits; using filename_traits_type = Tfilenametraits; public: using pos_type = typename traits_type::pos_type; using data_type = typename traits_type::data_type; using ref_data_type = typename traits_type::ref_data_type; using shared_data_type = typename traits_type::shared_data_type; using value_data_type = typename traits_type::value_data_type; using filename_type = typename filename_traits_type::filename_type; using shared_filename_type = typename filename_traits_type::shared_filename_type; protected: shared_data_type SharedDataContainer() const { return traits_type::get_shared(m_data); } ref_data_type DataContainer() const { return traits_type::get_ref(m_data); } static value_data_type DataInitializer() { return traits_type::make_data(); } static value_data_type DataInitializer(mpt::const_byte_span data) { return traits_type::make_data(data); } static value_data_type CreateChunkImpl(shared_data_type data, pos_type position, pos_type size) { return traits_type::make_chunk(data, position, size); } private: data_type m_data; pos_type streamPos; // Cursor location in the file shared_filename_type m_fileName; // Filename that corresponds to this FileCursor. It is only set if this FileCursor represents the whole contents of fileName. May be nullopt. public: // Initialize invalid file reader object. FileCursor() : m_data(DataInitializer()) , streamPos(0) , m_fileName(nullptr) { return; } // Initialize file reader object with pointer to data and data length. template explicit FileCursor(mpt::span bytedata, shared_filename_type filename = shared_filename_type{}) : m_data(DataInitializer(mpt::byte_cast(bytedata))) , streamPos(0) , m_fileName(std::move(filename)) { return; } // Initialize file reader object based on an existing file reader object window. explicit FileCursor(value_data_type other, shared_filename_type filename = shared_filename_type{}) : m_data(std::move(other)) , streamPos(0) , m_fileName(std::move(filename)) { return; } public: std::optional GetOptionalFileName() const { return filename_traits_type::get_optional_filename(m_fileName); } // Returns true if the object points to a valid (non-empty) stream. operator bool() const { return IsValid(); } // Returns true if the object points to a valid (non-empty) stream. bool IsValid() const { return DataContainer().IsValid(); } // Reset cursor to first byte in file. void Rewind() { streamPos = 0; } // Seek to a position in the mapped file. // Returns false if position is invalid. bool Seek(pos_type position) { if (position <= streamPos) { streamPos = position; return true; } if (DataContainer().CanRead(0, position)) { streamPos = position; return true; } else { return false; } } // Increases position by skipBytes. // Returns true if skipBytes could be skipped or false if the file end was reached earlier. bool Skip(pos_type skipBytes) { if (CanRead(skipBytes)) { streamPos += skipBytes; return true; } else { streamPos = DataContainer().GetLength(); return false; } } // Decreases position by skipBytes. // Returns true if skipBytes could be skipped or false if the file start was reached earlier. bool SkipBack(pos_type skipBytes) { if (streamPos >= skipBytes) { streamPos -= skipBytes; return true; } else { streamPos = 0; return false; } } // Returns cursor position in the mapped file. pos_type GetPosition() const { return streamPos; } // Return true IFF seeking and GetLength() is fast. // In particular, it returns false for unseekable stream where GetLength() // requires pre-caching. bool HasFastGetLength() const { return DataContainer().HasFastGetLength(); } // Returns size of the mapped file in bytes. MPT_FILECURSOR_DEPRECATED pos_type GetLength() const { // deprecated because in case of an unseekable std::istream, this triggers caching of the whole file return DataContainer().GetLength(); } // Return byte count between cursor position and end of file, i.e. how many bytes can still be read. MPT_FILECURSOR_DEPRECATED pos_type BytesLeft() const { // deprecated because in case of an unseekable std::istream, this triggers caching of the whole file return DataContainer().GetLength() - streamPos; } bool EndOfFile() const { return !CanRead(1); } bool NoBytesLeft() const { return !CanRead(1); } // Check if "amount" bytes can be read from the current position in the stream. bool CanRead(pos_type amount) const { return DataContainer().CanRead(streamPos, amount); } // Check if file size is at least size, without potentially caching the whole file to query the exact file length. bool LengthIsAtLeast(pos_type size) const { return DataContainer().CanRead(0, size); } // Check if file size is exactly size, without potentially caching the whole file if it is larger. bool LengthIs(pos_type size) const { return DataContainer().CanRead(0, size) && !DataContainer().CanRead(size, 1); } protected: FileCursor CreateChunk(pos_type position, pos_type length) const { pos_type readableLength = DataContainer().GetReadableLength(position, length); if (readableLength == 0) { return FileCursor(); } return FileCursor(CreateChunkImpl(SharedDataContainer(), position, readableLength)); } public: // Create a new FileCursor object for parsing a sub chunk at a given position with a given length. // The file cursor is not modified. FileCursor GetChunkAt(pos_type position, pos_type length) const { return CreateChunk(position, length); } // Create a new FileCursor object for parsing a sub chunk at the current position with a given length. // The file cursor is not advanced. FileCursor GetChunk(pos_type length) { return CreateChunk(streamPos, length); } // Create a new FileCursor object for parsing a sub chunk at the current position with a given length. // The file cursor is advanced by "length" bytes. FileCursor ReadChunk(pos_type length) { pos_type position = streamPos; Skip(length); return CreateChunk(position, length); } class PinnedView { private: std::size_t size_; const std::byte * pinnedData; std::vector cache; private: void Init(const FileCursor & file, std::size_t size) { size_ = 0; pinnedData = nullptr; if (!file.CanRead(size)) { size = static_cast(file.BytesLeft()); } size_ = size; if (file.DataContainer().HasPinnedView()) { pinnedData = file.DataContainer().GetRawData() + file.GetPosition(); } else { cache.resize(size_); if (!cache.empty()) { file.GetRaw(mpt::as_span(cache)); } } } public: PinnedView() : size_(0) , pinnedData(nullptr) { } PinnedView(const FileCursor & file) { MPT_MAYBE_CONSTANT_IF (!mpt::in_range(file.BytesLeft())) { mpt::throw_out_of_memory(); } Init(file, static_cast(file.BytesLeft())); } PinnedView(const FileCursor & file, std::size_t size) { Init(file, size); } PinnedView(FileCursor & file, bool advance) { MPT_MAYBE_CONSTANT_IF (!mpt::in_range(file.BytesLeft())) { mpt::throw_out_of_memory(); } Init(file, static_cast(file.BytesLeft())); if (advance) { file.Skip(size_); } } PinnedView(FileCursor & file, std::size_t size, bool advance) { Init(file, size); if (advance) { file.Skip(size_); } } public: mpt::const_byte_span GetSpan() const { if (pinnedData) { return mpt::as_span(pinnedData, size_); } else if (!cache.empty()) { return mpt::as_span(cache); } else { return mpt::const_byte_span(); } } mpt::const_byte_span span() const { return GetSpan(); } void invalidate() { size_ = 0; pinnedData = nullptr; cache = std::vector(); } const std::byte * data() const { return span().data(); } std::size_t size() const { return size_; } mpt::const_byte_span::pointer begin() const { return span().data(); } mpt::const_byte_span::pointer end() const { return span().data() + span().size(); } mpt::const_byte_span::const_pointer cbegin() const { return span().data(); } mpt::const_byte_span::const_pointer cend() const { return span().data() + span().size(); } }; // Returns a pinned view into the remaining raw data from cursor position. PinnedView GetPinnedView() const { return PinnedView(*this); } // Returns a pinned view into the remeining raw data from cursor position, clamped at size. PinnedView GetPinnedView(std::size_t size) const { return PinnedView(*this, size); } // Returns a pinned view into the remeining raw data from cursor position. // File cursor is advaned by the size of the returned pinned view. PinnedView ReadPinnedView() { return PinnedView(*this, true); } // Returns a pinned view into the remeining raw data from cursor position, clamped at size. // File cursor is advaned by the size of the returned pinned view. PinnedView ReadPinnedView(std::size_t size) { return PinnedView(*this, size, true); } template Tspan GetRawWithOffset(std::size_t offset, Tspan dst) const { return mpt::byte_cast(DataContainer().Read(streamPos + offset, mpt::byte_cast(dst))); } template Tspan GetRaw(Tspan dst) const { return mpt::byte_cast(DataContainer().Read(streamPos, mpt::byte_cast(dst))); } template Tspan ReadRaw(Tspan dst) { Tspan result = mpt::byte_cast(DataContainer().Read(streamPos, mpt::byte_cast(dst))); streamPos += result.size(); return result; } std::vector GetRawDataAsByteVector() const { PinnedView view = GetPinnedView(); return mpt::make_vector(view.span()); } std::vector ReadRawDataAsByteVector() { PinnedView view = ReadPinnedView(); return mpt::make_vector(view.span()); } std::vector GetRawDataAsByteVector(std::size_t size) const { PinnedView view = GetPinnedView(size); return mpt::make_vector(view.span()); } std::vector ReadRawDataAsByteVector(std::size_t size) { PinnedView view = ReadPinnedView(size); return mpt::make_vector(view.span()); } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILECURSOR_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filedata_stdstream.hpp0000644000175000017500000000654414650142521023630 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILEDATA_STDSTREAM_HPP #define MPT_IO_READ_FILEDATA_STDSTREAM_HPP #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/io/base.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/io_read/filedata.hpp" #include "mpt/io_read/filedata_base_buffered.hpp" #include "mpt/io_read/filedata_base_unseekable.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class FileDataStdStream { public: static bool IsSeekable(std::istream & stream) { return mpt::IO::IsReadSeekable(stream); } static IFileData::pos_type GetLength(std::istream & stream) { stream.clear(); std::streampos oldpos = stream.tellg(); stream.seekg(0, std::ios::end); std::streamoff length = static_cast(stream.tellg()); stream.seekg(oldpos); return mpt::saturate_cast(static_cast(length)); } }; class FileDataStdStreamSeekable : public FileDataSeekableBuffered { private: std::istream & stream; public: FileDataStdStreamSeekable(std::istream & s) : FileDataSeekableBuffered(FileDataStdStream::GetLength(s)) , stream(s) { return; } private: mpt::byte_span InternalReadBuffered(pos_type pos, mpt::byte_span dst) const override { stream.clear(); // tellg needs eof and fail bits unset std::streampos currentpos = stream.tellg(); if ((currentpos == std::streampos(std::streamoff(-1))) || (static_cast(pos) != static_cast(currentpos))) { // inefficient istream implementations might invalidate their buffer when seeking, even when seeking to the current position stream.seekg(static_cast(pos), std::ios::beg); } std::size_t bytesToRead = dst.size(); std::size_t bytesRead = 0; while (bytesToRead > 0) { std::streamsize bytesChunkToRead = mpt::saturate_cast(bytesToRead); stream.read(mpt::byte_cast(dst.data()) + bytesRead, bytesChunkToRead); std::streamsize bytesChunkRead = stream.gcount(); bytesRead += static_cast(bytesChunkRead); bytesToRead -= static_cast(bytesChunkRead); if (bytesChunkRead != bytesChunkToRead) { break; } } return dst.first(bytesRead); } }; class FileDataStdStreamUnseekable : public FileDataUnseekable { private: std::istream & stream; public: FileDataStdStreamUnseekable(std::istream & s) : stream(s) { return; } private: bool InternalEof() const override { if (stream) { return false; } else { return true; } } mpt::byte_span InternalReadUnseekable(mpt::byte_span dst) const override { std::size_t bytesToRead = dst.size(); std::size_t bytesRead = 0; while (bytesToRead > 0) { std::streamsize bytesChunkToRead = mpt::saturate_cast(bytesToRead); stream.read(mpt::byte_cast(dst.data()) + bytesRead, bytesChunkToRead); std::streamsize bytesChunkRead = stream.gcount(); bytesRead += static_cast(bytesChunkRead); bytesToRead -= static_cast(bytesChunkRead); if (bytesChunkRead != bytesChunkToRead) { break; } } return dst.first(bytesRead); } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILEDATA_STDSTREAM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filedata_base_unseekable_buffer.hpp0000644000175000017500000000663714607427151026275 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILEDATA_BASE_UNSEEKABLE_BUFFER_HPP #define MPT_IO_READ_FILEDATA_BASE_UNSEEKABLE_BUFFER_HPP #include "mpt/base/algorithm.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/numeric.hpp" #include "mpt/io/base.hpp" #include "mpt/io_read/filedata.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class FileDataUnseekableBuffer : public IFileData { private: mutable std::vector cache; mutable bool streamFullyCached; protected: FileDataUnseekableBuffer() : streamFullyCached(false) { return; } private: enum : std::size_t { QUANTUM_SIZE = mpt::IO::BUFFERSIZE_SMALL, BUFFER_SIZE = mpt::IO::BUFFERSIZE_NORMAL }; void CacheStream() const { if (streamFullyCached) { return; } while (!InternalEof()) { InternalReadContinue(cache, BUFFER_SIZE); } streamFullyCached = true; } void CacheStreamUpTo(pos_type pos, pos_type length) const { if (streamFullyCached) { return; } if (length > std::numeric_limits::max() - pos) { length = std::numeric_limits::max() - pos; } std::size_t target = mpt::saturate_cast(pos + length); if (target <= cache.size()) { return; } while (!InternalEof() && (cache.size() < target)) { std::size_t readsize = ((target - cache.size()) > QUANTUM_SIZE) ? BUFFER_SIZE : QUANTUM_SIZE; InternalReadContinue(cache, readsize); } } private: void ReadCached(pos_type pos, mpt::byte_span dst) const { std::copy(cache.begin() + static_cast(pos), cache.begin() + static_cast(pos + dst.size()), dst.data()); } public: bool IsValid() const override { return true; } bool HasFastGetLength() const override { return false; } bool HasPinnedView() const override { return true; // we have the cache which is required for seeking anyway } const std::byte * GetRawData() const override { CacheStream(); return cache.data(); } pos_type GetLength() const override { CacheStream(); return cache.size(); } mpt::byte_span Read(pos_type pos, mpt::byte_span dst) const override { CacheStreamUpTo(pos, dst.size()); if (pos >= static_cast(cache.size())) { return dst.first(0); } pos_type cache_avail = std::min(static_cast(cache.size()) - pos, static_cast(dst.size())); ReadCached(pos, dst.subspan(0, static_cast(cache_avail))); return dst.subspan(0, static_cast(cache_avail)); } bool CanRead(pos_type pos, pos_type length) const override { CacheStreamUpTo(pos, length); if ((pos == static_cast(cache.size())) && (length == 0)) { return true; } if (pos >= static_cast(cache.size())) { return false; } return length <= static_cast(cache.size()) - pos; } pos_type GetReadableLength(pos_type pos, pos_type length) const override { CacheStreamUpTo(pos, length); if (pos >= cache.size()) { return 0; } return std::min(static_cast(cache.size()) - pos, length); } private: virtual bool InternalEof() const = 0; virtual void InternalReadContinue(std::vector & streamCache, std::size_t suggestedCount) const = 0; }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILEDATA_BASE_UNSEEKABLE_BUFFER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filereader.hpp0000644000175000017500000006037214726074370022104 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILEREADER_HPP #define MPT_IO_READ_FILEREADER_HPP #include "mpt/base/alloc.hpp" #include "mpt/base/bit.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/base/span.hpp" #include "mpt/base/utility.hpp" #include "mpt/io/base.hpp" #include "mpt/endian/floatingpoint.hpp" #include "mpt/endian/integer.hpp" #include "mpt/endian/type_traits.hpp" #include "mpt/string/utility.hpp" #include #include #include #include #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { namespace FileReader { // change to show warnings for functions which trigger pre-caching the whole file for unseekable streams //#define MPT_FILEREADER_DEPRECATED [[deprecated]] #define MPT_FILEREADER_DEPRECATED // TFileCursor members begin template std::optional GetOptionalFileName(const TFileCursor & f) { return f.GetOptionalFileName(); } // Returns true if the object points to a valid (non-empty) stream. template bool IsValid(const TFileCursor & f) { return f.IsValid(); } // Reset cursor to first byte in file. template void Rewind(TFileCursor & f) { f.Rewind(); } // Seek to a position in the mapped file. // Returns false if position is invalid. template bool Seek(TFileCursor & f, typename TFileCursor::pos_type position) { return f.Seek(position); } // Increases position by skipBytes. // Returns true if skipBytes could be skipped or false if the file end was reached earlier. template bool Skip(TFileCursor & f, typename TFileCursor::pos_type skipBytes) { return f.Skip(skipBytes); } // Decreases position by skipBytes. // Returns true if skipBytes could be skipped or false if the file start was reached earlier. template bool SkipBack(TFileCursor & f, typename TFileCursor::pos_type skipBytes) { return f.SkipBack(skipBytes); } // Returns cursor position in the mapped file. template typename TFileCursor::pos_type GetPosition(const TFileCursor & f) { return f.GetPosition(); } // Return true IFF seeking and GetLength() is fast. // In particular, it returns false for unseekable stream where GetLength() // requires pre-caching. template bool HasFastGetLength(const TFileCursor & f) { return f.HasFastGetLength(); } // Returns size of the mapped file in bytes. template MPT_FILEREADER_DEPRECATED typename TFileCursor::pos_type GetLength(const TFileCursor & f) { return f.GetLength(); } // Return byte count between cursor position and end of file, i.e. how many bytes can still be read. template MPT_FILEREADER_DEPRECATED typename TFileCursor::pos_type BytesLeft(const TFileCursor & f) { return f.BytesLeft(); } template bool EndOfFile(const TFileCursor & f) { return f.EndOfFile(); } template bool NoBytesLeft(const TFileCursor & f) { return f.NoBytesLeft(); } // Check if "amount" bytes can be read from the current position in the stream. template bool CanRead(const TFileCursor & f, typename TFileCursor::pos_type amount) { return f.CanRead(amount); } // Check if file size is at least size, without potentially caching the whole file to query the exact file length. template bool LengthIsAtLeast(const TFileCursor & f, typename TFileCursor::pos_type size) { return f.LengthIsAtLesat(size); } // Check if file size is exactly size, without potentially caching the whole file if it is larger. template bool LengthIs(const TFileCursor & f, typename TFileCursor::pos_type size) { return f.LengthIs(size); } // Create a new FileCursor object for parsing a sub chunk at a given position with a given length. // The file cursor is not modified. template TFileCursor GetChunkAt(const TFileCursor & f, typename TFileCursor::pos_type position, typename TFileCursor::pos_type length) { return f.GetChunkAt(position, length); } // Create a new FileCursor object for parsing a sub chunk at the current position with a given length. // The file cursor is not advanced. template TFileCursor GetChunk(TFileCursor & f, typename TFileCursor::pos_type length) { return f.GetChunk(length); } // Create a new FileCursor object for parsing a sub chunk at the current position with a given length. // The file cursor is advanced by "length" bytes. template TFileCursor ReadChunk(TFileCursor & f, typename TFileCursor::pos_type length) { return f.ReadChunk(length); } // Returns a pinned view into the remaining raw data from cursor position. template typename TFileCursor::PinnedView GetPinnedView(const TFileCursor & f) { return f.GetPinnedView(); } // Returns a pinned view into the remeining raw data from cursor position, clamped at size. template typename TFileCursor::PinnedView GetPinnedView(const TFileCursor & f, std::size_t size) { return f.GetPinnedView(size); } // Returns a pinned view into the remeining raw data from cursor position. // File cursor is advaned by the size of the returned pinned view. template typename TFileCursor::PinnedView ReadPinnedView(TFileCursor & f) { return f.ReadPinnedView(); } // Returns a pinned view into the remeining raw data from cursor position, clamped at size. // File cursor is advaned by the size of the returned pinned view. template typename TFileCursor::PinnedView ReadPinnedView(TFileCursor & f, std::size_t size) { return f.ReadPinnedView(size); } template Tspan GetRawWithOffset(const TFileCursor & f, std::size_t offset, Tspan dst) { return f.template GetRawWithOffset(offset, dst); } template Tspan GetRaw(const TFileCursor & f, Tspan dst) { return f.template GetRaw(dst); } template Tspan ReadRaw(TFileCursor & f, Tspan dst) { return f.template ReadRaw(dst); } template std::vector GetRawDataAsByteVector(const TFileCursor & f) { return f.GetRawDataAsByteVector(); } template std::vector ReadRawDataAsByteVector(TFileCursor & f) { return f.ReadRawDataAsByteVector(); } template std::vector GetRawDataAsByteVector(const TFileCursor & f, std::size_t size) { return f.GetRawDataAsByteVector(size); } template std::vector ReadRawDataAsByteVector(TFileCursor & f, std::size_t size) { return f.ReadRawDataAsByteVector(size); } // TFileCursor members end // Read a "T" object from the stream. // If not enough bytes can be read, false is returned. // If successful, the file cursor is advanced by the size of "T". template bool Read(TFileCursor & f, T & target) { // cppcheck false-positive // cppcheck-suppress uninitvar mpt::byte_span dst = mpt::as_raw_memory(target); if (dst.size() != f.GetRaw(dst).size()) { return false; } f.Skip(dst.size()); return true; } // Read an array of binary-safe T values. // If successful, the file cursor is advanced by the size of the array. // Otherwise, the target is zeroed. template bool ReadArray(TFileCursor & f, T (&destArray)[destSize]) { static_assert(mpt::is_binary_safe::value); if (!f.CanRead(sizeof(destArray))) { mpt::reset(destArray); return false; } f.ReadRaw(mpt::as_raw_memory(destArray)); return true; } // Read an array of binary-safe T values. // If successful, the file cursor is advanced by the size of the array. // Otherwise, the target is zeroed. template bool ReadArray(TFileCursor & f, std::array & destArray) { static_assert(mpt::is_binary_safe::value); if (!f.CanRead(sizeof(destArray))) { mpt::reset(destArray); return false; } f.ReadRaw(mpt::as_raw_memory(destArray)); return true; } // Read destSize elements of binary-safe type T into a vector. // If successful, the file cursor is advanced by the size of the vector. // Otherwise, the vector is resized to destSize, but possibly existing contents are not cleared. template bool ReadVector(TFileCursor & f, std::vector & destVector, size_t destSize) { static_assert(mpt::is_binary_safe::value); destVector.resize(destSize); if (!f.CanRead(sizeof(T) * destSize)) { return false; } f.ReadRaw(mpt::as_raw_memory(destVector)); return true; } template std::array ReadArray(TFileCursor & f) { std::array destArray; ReadArray(f, destArray); return destArray; } // Read some kind of integer in little-endian format. // If successful, the file cursor is advanced by the size of the integer. template T ReadIntLE(TFileCursor & f) { static_assert(std::numeric_limits::is_integer == true, "Target type is a not an integer"); typename mpt::make_le::type target; if (!FileReader::Read(f, target)) { return 0; } return target; } // Read some kind of integer in big-endian format. // If successful, the file cursor is advanced by the size of the integer. template T ReadIntBE(TFileCursor & f) { static_assert(std::numeric_limits::is_integer == true, "Target type is a not an integer"); typename mpt::make_be::type target; if (!FileReader::Read(f, target)) { return 0; } return target; } // Read a integer in little-endian format which has some of its higher bytes not stored in file. // If successful, the file cursor is advanced by the given size. template T ReadTruncatedIntLE(TFileCursor & f, std::size_t size) { static_assert(std::numeric_limits::is_integer == true, "Target type is a not an integer"); assert(sizeof(T) >= size); if (size == 0) { return 0; } if (!f.CanRead(size)) { return 0; } uint8 buf[sizeof(T)]; bool negative = false; for (std::size_t i = 0; i < sizeof(T); ++i) { uint8 byte = 0; if (i < size) { FileReader::Read(f, byte); negative = std::numeric_limits::is_signed && ((byte & 0x80) != 0x00); } else { // sign or zero extend byte = negative ? 0xff : 0x00; } buf[i] = byte; } return mpt::bit_cast::type>(buf); } // Read a supplied-size little endian integer to a fixed size variable. // The data is properly sign-extended when fewer bytes are stored. // If more bytes are stored, higher order bytes are silently ignored. // If successful, the file cursor is advanced by the given size. template T ReadSizedIntLE(TFileCursor & f, std::size_t size) { static_assert(std::numeric_limits::is_integer == true, "Target type is a not an integer"); if (size == 0) { return 0; } if (!f.CanRead(size)) { return 0; } if (size < sizeof(T)) { return FileReader::ReadTruncatedIntLE(f, size); } T retval = FileReader::ReadIntLE(f); f.Skip(size - sizeof(T)); return retval; } // Read unsigned 32-Bit integer in little-endian format. // If successful, the file cursor is advanced by the size of the integer. template uint32 ReadUint32LE(TFileCursor & f) { return FileReader::ReadIntLE(f); } // Read unsigned 32-Bit integer in big-endian format. // If successful, the file cursor is advanced by the size of the integer. template uint32 ReadUint32BE(TFileCursor & f) { return FileReader::ReadIntBE(f); } // Read signed 32-Bit integer in little-endian format. // If successful, the file cursor is advanced by the size of the integer. template int32 ReadInt32LE(TFileCursor & f) { return FileReader::ReadIntLE(f); } // Read signed 32-Bit integer in big-endian format. // If successful, the file cursor is advanced by the size of the integer. template int32 ReadInt32BE(TFileCursor & f) { return FileReader::ReadIntBE(f); } // Read unsigned 24-Bit integer in little-endian format. // If successful, the file cursor is advanced by the size of the integer. template uint32 ReadUint24LE(TFileCursor & f) { const auto arr = FileReader::ReadArray(f); return arr[0] | (arr[1] << 8) | (arr[2] << 16); } // Read unsigned 24-Bit integer in big-endian format. // If successful, the file cursor is advanced by the size of the integer. template uint32 ReadUint24BE(TFileCursor & f) { const auto arr = FileReader::ReadArray(f); return (arr[0] << 16) | (arr[1] << 8) | arr[2]; } // Read unsigned 16-Bit integer in little-endian format. // If successful, the file cursor is advanced by the size of the integer. template uint16 ReadUint16LE(TFileCursor & f) { return FileReader::ReadIntLE(f); } // Read unsigned 16-Bit integer in big-endian format. // If successful, the file cursor is advanced by the size of the integer. template uint16 ReadUint16BE(TFileCursor & f) { return FileReader::ReadIntBE(f); } // Read signed 16-Bit integer in little-endian format. // If successful, the file cursor is advanced by the size of the integer. template int16 ReadInt16LE(TFileCursor & f) { return FileReader::ReadIntLE(f); } // Read signed 16-Bit integer in big-endian format. // If successful, the file cursor is advanced by the size of the integer. template int16 ReadInt16BE(TFileCursor & f) { return FileReader::ReadIntBE(f); } // Read a single 8bit character. // If successful, the file cursor is advanced by the size of the integer. template char ReadChar(TFileCursor & f) { char target; if (!FileReader::Read(f, target)) { return 0; } return target; } // Read unsigned 8-Bit integer. // If successful, the file cursor is advanced by the size of the integer. template uint8 ReadUint8(TFileCursor & f) { uint8 target; if (!FileReader::Read(f, target)) { return 0; } return target; } // Read signed 8-Bit integer. If successful, the file cursor is advanced by the size of the integer. template int8 ReadInt8(TFileCursor & f) { int8 target; if (!FileReader::Read(f, target)) { return 0; } return target; } // Read 32-Bit float in little-endian format. // If successful, the file cursor is advanced by the size of the float. template float ReadFloatLE(TFileCursor & f) { IEEE754binary32LE target; if (!FileReader::Read(f, target)) { return 0.0f; } return target; } // Read 32-Bit float in big-endian format. // If successful, the file cursor is advanced by the size of the float. template float ReadFloatBE(TFileCursor & f) { IEEE754binary32BE target; if (!FileReader::Read(f, target)) { return 0.0f; } return target; } // Read 64-Bit float in little-endian format. // If successful, the file cursor is advanced by the size of the float. template double ReadDoubleLE(TFileCursor & f) { IEEE754binary64LE target; if (!FileReader::Read(f, target)) { return 0.0; } return target; } // Read 64-Bit float in big-endian format. // If successful, the file cursor is advanced by the size of the float. template double ReadDoubleBE(TFileCursor & f) { IEEE754binary64BE target; if (!FileReader::Read(f, target)) { return 0.0; } return target; } // Read a struct. // If successful, the file cursor is advanced by the size of the struct. Otherwise, the target is zeroed. template bool ReadStruct(TFileCursor & f, T & target) { static_assert(mpt::is_binary_safe::value); if (!FileReader::Read(f, target)) { mpt::reset(target); return false; } return true; } // Allow to read a struct partially (if there's less memory available than the struct's size, fill it up with zeros). // The file cursor is advanced by "partialSize" bytes. template std::size_t ReadStructPartial(TFileCursor & f, T & target, std::size_t partialSize = sizeof(T)) { static_assert(mpt::is_binary_safe::value); std::size_t copyBytes = std::min(partialSize, sizeof(T)); if (!f.CanRead(copyBytes)) { copyBytes = mpt::saturate_cast(f.BytesLeft()); } f.GetRaw(mpt::span(mpt::as_raw_memory(target).data(), copyBytes)); std::memset(mpt::as_raw_memory(target).data() + copyBytes, 0, sizeof(target) - copyBytes); f.Skip(partialSize); return copyBytes; } // Read a null-terminated string into a std::string template bool ReadNullString(TFileCursor & f, std::string & dest, const std::size_t maxLength = std::numeric_limits::max()) { dest.clear(); if (!f.CanRead(1)) { return false; } char buffer[mpt::IO::BUFFERSIZE_MINUSCULE]; std::size_t avail = 0; while ((avail = std::min(f.GetRaw(mpt::as_span(buffer)).size(), maxLength - dest.length())) != 0) { auto end = std::find(buffer, buffer + avail, '\0'); dest.insert(dest.end(), buffer, end); f.Skip(end - buffer); if (end < buffer + avail) { // Found null char f.Skip(1); break; } } return dest.length() != 0; } // Read a string up to the next line terminator into a std::string template bool ReadLine(TFileCursor & f, std::string & dest, const std::size_t maxLength = std::numeric_limits::max()) { dest.clear(); if (!f.CanRead(1)) { return false; } char buffer[mpt::IO::BUFFERSIZE_MINUSCULE]; char c = '\0'; std::size_t avail = 0; while ((avail = std::min(f.GetRaw(mpt::as_span(buffer)).size(), maxLength - dest.length())) != 0) { auto end = std::find_if(buffer, buffer + avail, mpt::is_any_line_ending); dest.insert(dest.end(), buffer, end); f.Skip(end - buffer); if (end < buffer + avail) { // Found line ending f.Skip(1); // Handle CRLF line ending if (*end == '\r') { if (FileReader::Read(f, c) && c != '\n') { f.SkipBack(1); } } break; } } return true; } // Compare a magic string with the current stream position. // Returns true if they are identical and advances the file cursor by the the length of the "magic" string. // Returns false if the string could not be found. The file cursor is not advanced in this case. template bool ReadMagic(TFileCursor & f, const char (&magic)[N]) { assert(magic[N - 1] == '\0'); for (std::size_t i = 0; i < N - 1; ++i) { assert(magic[i] != '\0'); } constexpr std::size_t magicLength = N - 1; std::byte buffer[magicLength] = {}; if (f.GetRaw(mpt::span(buffer, magicLength)).size() != magicLength) { return false; } if (std::memcmp(buffer, magic, magicLength)) { return false; } f.Skip(magicLength); return true; } // Read variable-length unsigned integer (as found in MIDI files). // If successful, the file cursor is advanced by the size of the integer and true is returned. // False is returned if not enough bytes were left to finish reading of the integer or if an overflow happened (source doesn't fit into target integer). // In case of an overflow, the target is also set to the maximum value supported by its data type. template bool ReadVarInt(TFileCursor & f, T & target) { static_assert(std::numeric_limits::is_integer == true && std::numeric_limits::is_signed == false, "Target type is not an unsigned integer"); if (f.NoBytesLeft()) { target = 0; return false; } std::byte bytes[16]; // More than enough for any valid VarInt std::size_t avail = f.GetRaw(mpt::as_span(bytes)).size(); std::size_t readPos = 1; uint8 b = mpt::byte_cast(bytes[0]); target = (b & 0x7F); std::size_t writtenBits = static_cast(mpt::bit_width(target)); // Bits used in the most significant byte while (readPos < avail && (b & 0x80) != 0) { b = mpt::byte_cast(bytes[readPos++]); target <<= 7; target |= (b & 0x7F); writtenBits += 7; if (readPos == avail) { f.Skip(readPos); avail = f.GetRaw(mpt::as_span(bytes)).size(); readPos = 0; } } f.Skip(readPos); if (writtenBits > sizeof(target) * 8u) { // Overflow target = std::numeric_limits::max(); return false; } else if ((b & 0x80) != 0) { // Reached EOF return false; } return true; } template struct ChunkHeader { using id_type = Tid; using size_type = Tsize; friend constexpr bool declare_binary_safe(const ChunkHeader &) noexcept { return true; } id_type id{}; size_type size{}; id_type GetID() const { return id; } size_type GetLength() const { return size; } }; template struct Chunk { TChunkHeader header; TFileCursor data; TChunkHeader GetHeader() const { return header; } TFileCursor GetData() const { return data; } }; template struct ChunkList { using id_type = decltype(TChunkHeader().GetID()); using size_type = decltype(TChunkHeader().GetLength()); std::vector> chunks; // Check if the list contains a given chunk. bool ChunkExists(id_type id) const { return std::find_if(chunks.begin(), chunks.end(), [id](const Chunk & chunk) { return chunk.GetHeader().GetID() == id; }) != chunks.end(); } // Retrieve the first chunk with a given ID. TFileCursor GetChunk(id_type id) const { auto chunk = std::find_if(chunks.begin(), chunks.end(), [id](const Chunk & chunk) { return chunk.GetHeader().GetID() == id; }); if (chunk == chunks.end()) { return TFileCursor(); } return chunk->GetData(); } // Retrieve all chunks with a given ID. std::vector GetAllChunks(id_type id) const { std::vector result; for (const auto & chunk : chunks) { if (chunk.GetHeader().GetID() == id) { result.push_back(chunk.GetData()); } } return result; } }; // Read a single "TChunkHeader" chunk. // T is required to have the methods GetID() and GetLength(). // GetLength() must return the chunk size in bytes, and GetID() the chunk ID. template Chunk ReadNextChunk(TFileCursor & f, typename TFileCursor::pos_type alignment) { Chunk result; if (!FileReader::Read(f, result.header)) { return Chunk(); } typename TFileCursor::pos_type dataSize = result.header.GetLength(); result.data = f.ReadChunk(dataSize); if (alignment > 1) { if ((dataSize % alignment) != 0) { f.Skip(alignment - (dataSize % alignment)); } } return result; } // Read a series of "TChunkHeader" chunks until the end of file is reached. // T is required to have the methods GetID() and GetLength(). // GetLength() must return the chunk size in bytes, and GetID() the chunk ID. template ChunkList ReadChunks(TFileCursor & f, typename TFileCursor::pos_type alignment) { ChunkList result; while (f.CanRead(sizeof(TChunkHeader))) { result.chunks.push_back(FileReader::ReadNextChunk(f, alignment)); } return result; } // Read a series of "TChunkHeader" chunks until a given chunk ID is found. // T is required to have the methods GetID() and GetLength(). // GetLength() must return the chunk size in bytes, and GetID() the chunk ID. template ChunkList ReadChunksUntil(TFileCursor & f, typename TFileCursor::pos_type alignment, decltype(TChunkHeader().GetID()) lastID) { ChunkList result; while (f.CanRead(sizeof(TChunkHeader))) { result.chunks.push_back(FileReader::ReadNextChunk(f, alignment)); if (result.chunks.back().GetHeader().GetID() == lastID) { break; } } return result; } } // namespace FileReader } // namespace IO namespace FR = mpt::IO::FileReader; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILEREADER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filecursor_callbackstream.hpp0000644000175000017500000000263714650142521025175 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILECURSOR_CALLBACKSTREAM_HPP #define MPT_IO_READ_FILECURSOR_CALLBACKSTREAM_HPP #include "mpt/base/namespace.hpp" #include "mpt/io_read/callbackstream.hpp" #include "mpt/io_read/filecursor.hpp" #include "mpt/io_read/filecursor_filename_traits.hpp" #include "mpt/io_read/filecursor_traits_filedata.hpp" #include "mpt/io_read/filedata_callbackstream.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { // Initialize file reader object with a CallbackStream. template inline FileCursor> make_FileCursor(CallbackStreamTemplate s, std::shared_ptr filename = nullptr) { if (FileDataCallbackStreamTemplate::IsSeekable(s)) { return FileCursor>(std::static_pointer_cast(std::make_shared>(s)), std::move(filename)); } else { return FileCursor>(std::static_pointer_cast(std::make_shared>(s)), std::move(filename)); } } } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILECURSOR_CALLBACKSTREAM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/callbackstream.hpp0000644000175000017500000000143614650142521022734 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_CALLBACKSTREAM_HPP #define MPT_IO_READ_CALLBACKSTREAM_HPP #include "mpt/base/integer.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { template struct CallbackStreamTemplate { enum : int { SeekSet = 0, SeekCur = 1, SeekEnd = 2 }; Tstream stream; std::size_t (*read)(Tstream stream, void * dst, std::size_t bytes); int (*seek)(Tstream stream, int64 offset, int whence); int64 (*tell)(Tstream stream); }; using CallbackStream = CallbackStreamTemplate; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_CALLBACKSTREAM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filecursor_stdstream.hpp0000644000175000017500000000241514650142521024225 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILECURSOR_STDSTREAM_HPP #define MPT_IO_READ_FILECURSOR_STDSTREAM_HPP #include "mpt/base/namespace.hpp" #include "mpt/io_read/filecursor.hpp" #include "mpt/io_read/filecursor_filename_traits.hpp" #include "mpt/io_read/filecursor_traits_filedata.hpp" #include "mpt/io_read/filedata_stdstream.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { // Initialize file reader object with a std::istream. template inline FileCursor> make_FileCursor(std::istream & s, std::shared_ptr filename = nullptr) { if (FileDataStdStream::IsSeekable(s)) { return FileCursor>(std::static_pointer_cast(std::make_shared(s)), std::move(filename)); } else { return FileCursor>(std::static_pointer_cast(std::make_shared(s)), std::move(filename)); } } } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILECURSOR_STDSTREAM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filedata.hpp0000644000175000017500000000347014657436172021554 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILEDATA_HPP #define MPT_IO_READ_FILEDATA_HPP #if !defined(MPT_CONFIGURATION_IO_READ_FILEDATA_NO_64BIT) #include "mpt/base/integer.hpp" #endif // !MPT_CONFIGURATION_IO_READ_FILEDATA_NO_64BIT #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include #if defined(MPT_CONFIGURATION_IO_READ_FILEDATA_NO_64BIT) #include #endif // MPT_CONFIGURATION_IO_READ_FILEDATA_NO_64BIT namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class IFileData { public: #if !defined(MPT_CONFIGURATION_IO_READ_FILEDATA_NO_64BIT) using pos_type = uint64; #else // MPT_CONFIGURATION_IO_READ_FILEDATA_NO_64BIT using pos_type = std::size_t; #endif // MPT_CONFIGURATION_IO_READ_FILEDATA_NO_64BIT protected: IFileData() = default; public: IFileData(const IFileData &) = default; IFileData & operator=(const IFileData &) = default; virtual ~IFileData() = default; public: virtual bool IsValid() const = 0; virtual bool HasFastGetLength() const = 0; virtual bool HasPinnedView() const = 0; virtual const std::byte * GetRawData() const = 0; virtual pos_type GetLength() const = 0; virtual mpt::byte_span Read(pos_type pos, mpt::byte_span dst) const = 0; virtual bool CanRead(pos_type pos, pos_type length) const { pos_type dataLength = GetLength(); if ((pos == dataLength) && (length == 0)) { return true; } if (pos >= dataLength) { return false; } return length <= dataLength - pos; } virtual pos_type GetReadableLength(pos_type pos, pos_type length) const { pos_type dataLength = GetLength(); if (pos >= dataLength) { return 0; } return std::min(length, dataLength - pos); } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILEDATA_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_read/filecursor_filename_traits.hpp0000644000175000017500000000211214650142521025357 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_READ_FILECURSOR_FILENAME_TRAITS_HPP #define MPT_IO_READ_FILECURSOR_FILENAME_TRAITS_HPP #include "mpt/base/namespace.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class FileCursorFilenameTraitsNone { public: struct empty_type { }; using filename_type = empty_type; using shared_filename_type = empty_type; static std::optional get_optional_filename(shared_filename_type /* filename */) { return std::nullopt; } }; template class FileCursorFilenameTraits { public: using filename_type = Tpath; using shared_filename_type = std::shared_ptr; static std::optional get_optional_filename(const shared_filename_type & filename) { if (!filename) { return std::nullopt; } if ((*filename) == Tpath{}) { return std::nullopt; } return *filename; } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_READ_FILECURSOR_FILENAME_TRAITS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/random/0000755000175000017500000000000015023302361017200 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/random/engine_lcg.hpp0000644000175000017500000000563614665015200021741 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_RANDOM_ENGINE_LCG_HPP #define MPT_RANDOM_ENGINE_LCG_HPP #include "mpt/base/detect.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/numeric.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_COMPILER_MSVC #pragma warning(push) #pragma warning(disable : 4724) // potential mod by 0 #endif // MPT_COMPILER_MSVC template class lcg_engine { public: typedef Tstate state_type; typedef Tvalue result_type; static inline constexpr std::size_t seed_bits = sizeof(state_type) * 8; private: state_type state; private: static inline state_type seed_state(std::seed_seq & seed) { state_type result = 0; std::array(seed_bits, sizeof(unsigned int) * 8) / (sizeof(unsigned int) * 8)> seeds = {}; seed.generate(seeds.begin(), seeds.end()); for (const auto & seed_value : seeds) { result <<= 16; result <<= 16; result |= static_cast(seed_value); } return result; } public: explicit inline lcg_engine(std::seed_seq & seed) : state(seed_state(seed)) { operator()(); // we return results from the current state and update state after returning. results in better pipelining. } explicit inline lcg_engine(state_type seed) : state(seed) { operator()(); // we return results from the current state and update state after returning. results in better pipelining. } public: static MPT_CONSTEXPRINLINE result_type min() { return static_cast(0); } static MPT_CONSTEXPRINLINE result_type max() { static_assert(((result_mask >> result_shift) << result_shift) == result_mask); return static_cast(result_mask >> result_shift); } static MPT_CONSTEXPRINLINE int result_bits() { static_assert(((static_cast(1) << result_bits_) - 1) == (result_mask >> result_shift)); return result_bits_; } inline result_type operator()() { // we return results from the current state and update state after returning. results in better pipelining. state_type s = state; result_type result = static_cast((s & result_mask) >> result_shift); s = mpt::modulo_if_not_zero((a * s) + c); state = s; return result; } }; #if MPT_COMPILER_MSVC #pragma warning(pop) #endif // MPT_COMPILER_MSVC typedef lcg_engine lcg_msvc; typedef lcg_engine lcg_c99; typedef lcg_engine lcg_musl; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_RANDOM_ENGINE_LCG_HPP libopenmpt-0.8.1+release.autotools/src/mpt/random/seed.hpp0000644000175000017500000000270014664604252020566 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_RANDOM_SEED_HPP #define MPT_RANDOM_SEED_HPP #include "mpt/base/namespace.hpp" #include "mpt/base/numeric.hpp" #include "mpt/random/engine.hpp" #include "mpt/random/random.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { template class seed_seq_values { private: std::array seeds; public: template explicit seed_seq_values(Trd & rd) { for (std::size_t i = 0; i < N; ++i) { seeds[i] = mpt::random(rd); } } const unsigned int * begin() const { return seeds.data(); } const unsigned int * end() const { return seeds.data() + N; } }; template inline Trng make_prng(Trd & rd) { constexpr std::size_t num_seed_values = mpt::align_up(mpt::engine_seed_traits::seed_bits, sizeof(unsigned int) * 8) / (sizeof(unsigned int) * 8); if constexpr (num_seed_values > 128) { std::unique_ptr> values = std::make_unique>(rd); std::seed_seq seed(values.begin(), values.end()); return Trng(seed); } else { mpt::seed_seq_values values(rd); std::seed_seq seed(values.begin(), values.end()); return Trng(seed); } } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_RANDOM_SEED_HPP libopenmpt-0.8.1+release.autotools/src/mpt/random/any_engine.hpp0000644000175000017500000000262414660351364021766 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_RANDOM_ANY_ENGINE_HPP #define MPT_RANDOM_ANY_ENGINE_HPP #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/random/random.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { template class any_engine { public: using result_type = Tvalue; protected: any_engine() = default; public: static MPT_CONSTEXPRINLINE result_type min() { return static_cast(std::numeric_limits::min()); } static MPT_CONSTEXPRINLINE result_type max() { return static_cast(std::numeric_limits::max()); } static MPT_CONSTEXPRINLINE int result_bits() { return static_cast(sizeof(result_type) * 8); } public: virtual result_type operator()() = 0; public: virtual ~any_engine() = default; }; template class any_engine_wrapper : public any_engine { private: Trng & m_prng; public: any_engine_wrapper(Trng & prng) : m_prng(prng) { return; } public: typename any_engine::result_type operator()() override { return mpt::random::result_type>(m_prng); } public: virtual ~any_engine_wrapper() = default; }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_RANDOM_ANY_ENGINE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/random/random.hpp0000644000175000017500000001152315022304420021110 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_RANDOM_RANDOM_HPP #define MPT_RANDOM_RANDOM_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/random/engine.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { template inline T random(Trng & rng) { static_assert(std::numeric_limits::is_integer); typedef typename std::make_unsigned::type unsigned_T; const unsigned int rng_bits = mpt::engine_traits::result_bits(); unsigned_T result = 0; for (std::size_t entropy = 0; entropy < (sizeof(T) * 8); entropy += rng_bits) { if constexpr (rng_bits < (sizeof(T) * 8)) { constexpr unsigned int shift_bits = rng_bits % (sizeof(T) * 8); // silence utterly stupid MSVC and GCC warnings about shifting by too big amount (in which case this branch is not even taken however) result = (result << shift_bits) ^ static_cast(rng()); } else { result = static_cast(rng()); } } return static_cast(result); } template inline T random(Trng & rng) { static_assert(std::numeric_limits::is_integer); typedef typename std::make_unsigned::type unsigned_T; const unsigned int rng_bits = mpt::engine_traits::result_bits(); unsigned_T result = 0; for (std::size_t entropy = 0; entropy < std::min(required_entropy_bits, sizeof(T) * 8); entropy += rng_bits) { if constexpr (rng_bits < (sizeof(T) * 8)) { constexpr unsigned int shift_bits = rng_bits % (sizeof(T) * 8); // silence utterly stupid MSVC and GCC warnings about shifting by too big amount (in which case this branch is not even taken however) result = (result << shift_bits) ^ static_cast(rng()); } else { result = static_cast(rng()); } } if constexpr (required_entropy_bits >= (sizeof(T) * 8)) { return static_cast(result); } else { return static_cast(result & ((static_cast(1) << required_entropy_bits) - static_cast(1))); } } template inline T random(Trng & rng, std::size_t required_entropy_bits) { static_assert(std::numeric_limits::is_integer); typedef typename std::make_unsigned::type unsigned_T; const unsigned int rng_bits = mpt::engine_traits::result_bits(); unsigned_T result = 0; for (std::size_t entropy = 0; entropy < std::min(required_entropy_bits, sizeof(T) * 8); entropy += rng_bits) { if constexpr (rng_bits < (sizeof(T) * 8)) { constexpr unsigned int shift_bits = rng_bits % (sizeof(T) * 8); // silence utterly stupid MSVC and GCC warnings about shifting by too big amount (in which case this branch is not even taken however) result = (result << shift_bits) ^ static_cast(rng()); } else { result = static_cast(rng()); } } if (required_entropy_bits >= (sizeof(T) * 8)) { return static_cast(result); } else { return static_cast(result & ((static_cast(1) << required_entropy_bits) - static_cast(1))); } } template struct uniform_real_distribution { private: T a; T b; public: inline uniform_real_distribution(T a_, T b_) : a(a_) , b(b_) { return; } template inline T operator()(Trng & rng) const { const int mantissa_bits = std::numeric_limits::digits; return ((b - a) * static_cast(mpt::random(rng)) / static_cast((static_cast(1u) << mantissa_bits))) + a; } }; template ::value, bool>::type = true> inline T random(Trng & rng, T min, T max) { #if MPT_COMPILER_MSVC #pragma warning(push) #pragma warning(disable : 4018) // '<': signed/unsigned mismatch #endif // MPT_COMPILER_MSVC static_assert(std::numeric_limits::is_integer); if constexpr (std::is_same::value) { using dis_type = std::uniform_int_distribution; dis_type dis(min, max); return static_cast(dis(rng)); } else if constexpr (std::is_same::value) { using dis_type = std::uniform_int_distribution; dis_type dis(min, max); return static_cast(dis(rng)); } else { using dis_type = std::uniform_int_distribution; dis_type dis(min, max); return static_cast(dis(rng)); } #if MPT_COMPILER_MSVC #pragma warning(pop) #endif // MPT_COMPILER_MSVC } template ::value, bool>::type = true> inline T random(Trng & rng, T min, T max) { static_assert(!std::numeric_limits::is_integer); using dis_type = mpt::uniform_real_distribution; dis_type dis(min, max); return static_cast(dis(rng)); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_RANDOM_RANDOM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/random/device.hpp0000644000175000017500000002252115017364242021103 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_RANDOM_DEVICE_HPP #define MPT_RANDOM_DEVICE_HPP #include "mpt/base/bit.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/math.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/crc/crc.hpp" #include "mpt/endian/integer.hpp" #include "mpt/mutex/mutex.hpp" #include "mpt/out_of_memory/out_of_memory.hpp" #include "mpt/random/engine.hpp" #include "mpt/random/engine_lcg.hpp" #include "mpt/random/random.hpp" #if !defined(MPT_LIBCXX_QUIRK_NO_CHRONO) #include #endif // !MPT_LIBCXX_QUIRK_NO_CHRONO #include #include #include #include #include #include #include #if defined(MPT_LIBCXX_QUIRK_NO_CHRONO) #include #endif // MPT_LIBCXX_QUIRK_NO_CHRONO namespace mpt { inline namespace MPT_INLINE_NS { inline constexpr uint32 DETERMINISTIC_RNG_SEED = 3141592653u; // pi template struct default_random_seed_hash { }; template <> struct default_random_seed_hash { using type = mpt::crc16; }; template <> struct default_random_seed_hash { using type = mpt::crc16; }; template <> struct default_random_seed_hash { using type = mpt::crc32c; }; template <> struct default_random_seed_hash { using type = mpt::crc64_jones; }; class prng_random_device_time_seeder { public: template inline T generate_seed() { // Note: CRC is actually not that good a choice here, but it is simple and we // already have an implementaion available. Better choices for mixing entropy // would be a hash function with proper avalanche characteristics or a block // or stream cipher with any pre-choosen random key and IV. The only aspect we // really need here is whitening of the bits. typename mpt::default_random_seed_hash::type hash; #if !defined(MPT_LIBCXX_QUIRK_NO_CHRONO) { uint64be time; time = std::chrono::duration_cast(std::chrono::system_clock().now().time_since_epoch()).count(); std::byte bytes[sizeof(time)]; std::memcpy(bytes, &time, sizeof(time)); hash(std::begin(bytes), std::end(bytes)); } #if !defined(MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK) // Avoid std::chrono::high_resolution_clock on Emscripten because availability is problematic in AudioWorklet context. { uint64be time; time = std::chrono::duration_cast(std::chrono::high_resolution_clock().now().time_since_epoch()).count(); std::byte bytes[sizeof(time)]; std::memcpy(bytes, &time, sizeof(time)); hash(std::begin(bytes), std::end(bytes)); } #endif // !MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK #else // MPT_LIBCXX_QUIRK_NO_CHRONO { uint64be time; time = static_cast(std::time(nullptr)); std::byte bytes[sizeof(time)]; std::memcpy(bytes, &time, sizeof(time)); hash(std::begin(bytes), std::end(bytes)); } #endif // !MPT_LIBCXX_QUIRK_NO_CHRONO return static_cast(hash.result()); } public: prng_random_device_time_seeder() = default; }; // C++11 std::random_device may be implemented as a deterministic PRNG. // There is no way to seed this PRNG and it is allowed to be seeded with the // same value on each program invocation. This makes std::random_device // completely useless even as a non-cryptographic entropy pool. // We fallback to time-seeded std::mt19937 if std::random_device::entropy() is // 0 or less. class sane_random_device { private: mpt::mutex m; std::string token; #if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE) std::unique_ptr prd; #endif // !MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE std::unique_ptr rd_fallback; public: using result_type = unsigned int; private: void init_fallback() { if (!rd_fallback) { if (token.length() > 0) { uint64 seed_val = mpt::prng_random_device_time_seeder().generate_seed(); std::vector seeds; seeds.push_back(static_cast(seed_val >> 32)); seeds.push_back(static_cast(seed_val >> 0)); for (std::size_t i = 0; i < token.length(); ++i) { seeds.push_back(static_cast(static_cast(token[i]))); } std::seed_seq seed(seeds.begin(), seeds.end()); rd_fallback = std::make_unique(seed); } else { uint64 seed_val = mpt::prng_random_device_time_seeder().generate_seed(); unsigned int seeds[2]; seeds[0] = static_cast(seed_val >> 32); seeds[1] = static_cast(seed_val >> 0); std::seed_seq seed(seeds + 0, seeds + 2); rd_fallback = std::make_unique(seed); } } } public: sane_random_device() { #if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE) try { prd = std::make_unique(); if (!((*prd).entropy() > 0.0)) { init_fallback(); } } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (const std::exception &) { init_fallback(); } #else // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE init_fallback(); #endif // !MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE } sane_random_device(const std::string & token_) : token(token_) { #if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE) try { prd = std::make_unique(token); if (!((*prd).entropy() > 0.0)) { init_fallback(); } } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (const std::exception &) { init_fallback(); } #else // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE init_fallback(); #endif // !MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE } static MPT_CONSTEXPRINLINE result_type min() { return std::numeric_limits::min(); } static MPT_CONSTEXPRINLINE result_type max() { return std::numeric_limits::max(); } static MPT_CONSTEXPRINLINE int result_bits() { return sizeof(result_type) * 8; } result_type operator()() { mpt::lock_guard l(m); result_type result = 0; #if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE) if (prd) { try { if constexpr (std::random_device::min() != 0 || !mpt::is_mask(std::random_device::max())) { // insane std::random_device // This implementation is not exactly uniformly distributed but good enough // for OpenMPT. constexpr double rd_min = static_cast(std::random_device::min()); constexpr double rd_max = static_cast(std::random_device::max()); constexpr double rd_range = rd_max - rd_min; constexpr double rd_size = rd_range + 1.0; const double rd_entropy = mpt::log2(rd_size); const int iterations = static_cast(std::ceil(result_bits() / rd_entropy)); double tmp = 0.0; for (int i = 0; i < iterations; ++i) { tmp = (tmp * rd_size) + (static_cast((*prd)()) - rd_min); } double result_01 = std::floor(tmp / std::pow(rd_size, iterations)); result = static_cast(std::floor(result_01 * (static_cast(max() - min()) + 1.0))) + min(); } else { // sane std::random_device result = 0; std::size_t rd_bits = mpt::lower_bound_entropy_bits(std::random_device::max()); for (std::size_t entropy = 0; entropy < (sizeof(result_type) * 8); entropy += rd_bits) { if (rd_bits < (sizeof(result_type) * 8)) { result = (result << rd_bits) | static_cast((*prd)()); } else { result = result | static_cast((*prd)()); } } } } catch (const std::exception &) { init_fallback(); } } if (rd_fallback) { // std::random_device is unreliable // XOR the generated random number with more entropy from the time-seeded // PRNG. // Note: This is safe even if the std::random_device itself is implemented // as a std::mt19937 PRNG because we are very likely using a different // seed. result ^= mpt::random(*rd_fallback); } #else // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE result ^= mpt::random(*rd_fallback); #endif // !MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE return result; } }; class prng_random_device_deterministic_seeder { protected: template constexpr T generate_seed() noexcept { return static_cast(mpt::DETERMINISTIC_RNG_SEED); } protected: prng_random_device_deterministic_seeder() = default; }; template class prng_random_device : private seeder { public: using result_type = unsigned int; private: mpt::mutex m; Trng rng; public: prng_random_device() : rng(seeder::template generate_seed()) { return; } prng_random_device(const std::string &) : rng(seeder::template generate_seed()) { return; } static MPT_CONSTEXPRINLINE result_type min() { return std::numeric_limits::min(); } static MPT_CONSTEXPRINLINE result_type max() { return std::numeric_limits::max(); } static MPT_CONSTEXPRINLINE int result_bits() { return sizeof(unsigned int) * 8; } result_type operator()() { mpt::lock_guard l(m); return mpt::random(rng); } }; using deterministic_random_device = mpt::prng_random_device; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_RANDOM_DEVICE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/random/engine.hpp0000644000175000017500000000600414664605174021120 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_RANDOM_ENGINE_HPP #define MPT_RANDOM_ENGINE_HPP #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { template struct engine_seed_traits { static inline constexpr std::size_t seed_bits = Trng::seed_bits; }; template struct engine_traits { using result_type = typename Trng::result_type; static MPT_CONSTEXPRINLINE int result_bits() { return Trng::result_bits(); } }; // C++11 random does not provide any sane way to determine the amount of entropy // required to seed a particular engine. VERY STUPID. // List the ones we are likely to use. template <> struct engine_seed_traits { static inline constexpr std::size_t seed_bits = sizeof(std::mt19937::result_type) * 8 * std::mt19937::state_size; }; template <> struct engine_traits { using rng_type = std::mt19937; using result_type = rng_type::result_type; static MPT_CONSTEXPRINLINE int result_bits() { return rng_type::word_size; } }; template <> struct engine_seed_traits { static inline constexpr std::size_t seed_bits = sizeof(std::mt19937_64::result_type) * 8 * std::mt19937_64::state_size; }; template <> struct engine_traits { using rng_type = std::mt19937_64; using result_type = rng_type::result_type; static MPT_CONSTEXPRINLINE int result_bits() { return rng_type::word_size; } }; template <> struct engine_seed_traits { static inline constexpr std::size_t seed_bits = std::ranlux24_base::word_size; }; template <> struct engine_traits { using rng_type = std::ranlux24_base; using result_type = rng_type::result_type; static MPT_CONSTEXPRINLINE int result_bits() { return rng_type::word_size; } }; template <> struct engine_seed_traits { static inline constexpr std::size_t seed_bits = std::ranlux48_base::word_size; }; template <> struct engine_traits { using rng_type = std::ranlux48_base; using result_type = rng_type::result_type; static MPT_CONSTEXPRINLINE int result_bits() { return rng_type::word_size; } }; template <> struct engine_seed_traits { static inline constexpr std::size_t seed_bits = std::ranlux24_base::word_size; }; template <> struct engine_traits { using rng_type = std::ranlux24; using result_type = rng_type::result_type; static MPT_CONSTEXPRINLINE int result_bits() { return std::ranlux24_base::word_size; } }; template <> struct engine_seed_traits { static inline constexpr std::size_t seed_bits = std::ranlux48_base::word_size; }; template <> struct engine_traits { using rng_type = std::ranlux48; using result_type = rng_type::result_type; static MPT_CONSTEXPRINLINE int result_bits() { return std::ranlux48_base::word_size; } }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_RANDOM_ENGINE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/random/default_engines.hpp0000644000175000017500000000146614044173026023002 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_RANDOM_DEFAULT_ENGINES_HPP #define MPT_RANDOM_DEFAULT_ENGINES_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/random/engine.hpp" #include "mpt/random/engine_lcg.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { using deterministic_fast_engine = mpt::lcg_msvc; using deterministic_good_engine = mpt::lcg_musl; // We cannot use std::minstd_rand here because it has not a power-of-2 sized // output domain which we rely upon. using fast_engine = mpt::lcg_msvc; // about 3 ALU operations, ~32bit of state, suited for inner loops using good_engine = std::ranlux48; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_RANDOM_DEFAULT_ENGINES_HPP libopenmpt-0.8.1+release.autotools/src/mpt/random/crand.hpp0000644000175000017500000000175114044173026020732 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_RANDOM_CRAND_HPP #define MPT_RANDOM_CRAND_HPP #include "mpt/base/namespace.hpp" #include "mpt/base/numeric.hpp" #include "mpt/random/random.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { class crand { public: using state_type = void; using result_type = int; private: static void reseed(uint32 seed) { std::srand(seed); } public: template static void reseed(Trd & rd) { reseed(mpt::random(rd)); } public: crand() = default; explicit crand(const std::string &) { return; } public: static MPT_CONSTEXPRINLINE result_type min() { return 0; } static MPT_CONSTEXPRINLINE result_type max() { return RAND_MAX; } static MPT_CONSTEXPRINLINE int result_bits() { return mpt::lower_bound_entropy_bits(RAND_MAX); } result_type operator()() { return std::rand(); } }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_RANDOM_CRAND_HPP libopenmpt-0.8.1+release.autotools/src/mpt/random/tests/0000755000175000017500000000000015023302361020342 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/random/tests/tests_random.hpp0000644000175000017500000001720614664604252023521 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TESTS_RANDOM_HPP #define MPT_BASE_TESTS_RANDOM_HPP #include "mpt/base/algorithm.hpp" #include "mpt/base/detect_compiler.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/random/any_engine.hpp" #include "mpt/random/default_engines.hpp" #include "mpt/random/device.hpp" #include "mpt/random/random.hpp" #include "mpt/random/seed.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace random { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/random") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { mpt::sane_random_device rd; mpt::good_engine prng = mpt::make_prng(rd); mpt::any_engine_wrapper prng64{prng}; mpt::any_engine_wrapper prng8{prng}; bool failed = false; for (std::size_t i = 0; i < 10000; ++i) { failed = failed || !mpt::is_in_range(mpt::random(prng), 0u, 127u); failed = failed || !mpt::is_in_range(mpt::random(prng), 0u, 255u); failed = failed || !mpt::is_in_range(mpt::random(prng), 0u, 511u); failed = failed || !mpt::is_in_range(mpt::random(prng), 0u, 1u); failed = failed || !mpt::is_in_range(mpt::random(prng, 7), 0u, 127u); failed = failed || !mpt::is_in_range(mpt::random(prng, 8), 0u, 255u); failed = failed || !mpt::is_in_range(mpt::random(prng, 9), 0u, 511u); failed = failed || !mpt::is_in_range(mpt::random(prng, 1), 0u, 1u); failed = failed || !mpt::is_in_range(mpt::random(prng), 0, 127); failed = failed || !mpt::is_in_range(mpt::random(prng), 0, 255); failed = failed || !mpt::is_in_range(mpt::random(prng), 0, 511); failed = failed || !mpt::is_in_range(mpt::random(prng), 0, 1); failed = failed || !mpt::is_in_range(mpt::random(prng, 7), 0, 127); failed = failed || !mpt::is_in_range(mpt::random(prng, 8), 0, 255); failed = failed || !mpt::is_in_range(mpt::random(prng, 9), 0, 511); failed = failed || !mpt::is_in_range(mpt::random(prng, 1), 0, 1); failed = failed || !mpt::is_in_range(mpt::random(prng, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng, 0.0f, 1.0f), 0.0f, 1.0f); failed = failed || !mpt::is_in_range(mpt::random(prng, 0.0, 1.0), 0.0, 1.0); failed = failed || !mpt::is_in_range(mpt::random(prng, -1.0, 1.0), -1.0, 1.0); failed = failed || !mpt::is_in_range(mpt::random(prng, -1.0, 0.0), -1.0, 0.0); failed = failed || !mpt::is_in_range(mpt::random(prng, 1.0, 2.0), 1.0, 2.0); failed = failed || !mpt::is_in_range(mpt::random(prng, 1.0, 3.0), 1.0, 3.0); } for (std::size_t i = 0; i < 10000; ++i) { failed = failed || !mpt::is_in_range(mpt::random(prng64), 0u, 127u); failed = failed || !mpt::is_in_range(mpt::random(prng64), 0u, 255u); failed = failed || !mpt::is_in_range(mpt::random(prng64), 0u, 511u); failed = failed || !mpt::is_in_range(mpt::random(prng64), 0u, 1u); failed = failed || !mpt::is_in_range(mpt::random(prng64, 7), 0u, 127u); failed = failed || !mpt::is_in_range(mpt::random(prng64, 8), 0u, 255u); failed = failed || !mpt::is_in_range(mpt::random(prng64, 9), 0u, 511u); failed = failed || !mpt::is_in_range(mpt::random(prng64, 1), 0u, 1u); failed = failed || !mpt::is_in_range(mpt::random(prng64), 0, 127); failed = failed || !mpt::is_in_range(mpt::random(prng64), 0, 255); failed = failed || !mpt::is_in_range(mpt::random(prng64), 0, 511); failed = failed || !mpt::is_in_range(mpt::random(prng64), 0, 1); failed = failed || !mpt::is_in_range(mpt::random(prng64, 7), 0, 127); failed = failed || !mpt::is_in_range(mpt::random(prng64, 8), 0, 255); failed = failed || !mpt::is_in_range(mpt::random(prng64, 9), 0, 511); failed = failed || !mpt::is_in_range(mpt::random(prng64, 1), 0, 1); failed = failed || !mpt::is_in_range(mpt::random(prng64, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng64, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng64, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng64, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng64, 0.0f, 1.0f), 0.0f, 1.0f); failed = failed || !mpt::is_in_range(mpt::random(prng64, 0.0, 1.0), 0.0, 1.0); failed = failed || !mpt::is_in_range(mpt::random(prng64, -1.0, 1.0), -1.0, 1.0); failed = failed || !mpt::is_in_range(mpt::random(prng64, -1.0, 0.0), -1.0, 0.0); failed = failed || !mpt::is_in_range(mpt::random(prng64, 1.0, 2.0), 1.0, 2.0); failed = failed || !mpt::is_in_range(mpt::random(prng64, 1.0, 3.0), 1.0, 3.0); } for (std::size_t i = 0; i < 10000; ++i) { failed = failed || !mpt::is_in_range(mpt::random(prng8), 0u, 127u); failed = failed || !mpt::is_in_range(mpt::random(prng8), 0u, 255u); failed = failed || !mpt::is_in_range(mpt::random(prng8), 0u, 511u); failed = failed || !mpt::is_in_range(mpt::random(prng8), 0u, 1u); failed = failed || !mpt::is_in_range(mpt::random(prng8, 7), 0u, 127u); failed = failed || !mpt::is_in_range(mpt::random(prng8, 8), 0u, 255u); failed = failed || !mpt::is_in_range(mpt::random(prng8, 9), 0u, 511u); failed = failed || !mpt::is_in_range(mpt::random(prng8, 1), 0u, 1u); failed = failed || !mpt::is_in_range(mpt::random(prng8), 0, 127); failed = failed || !mpt::is_in_range(mpt::random(prng8), 0, 255); failed = failed || !mpt::is_in_range(mpt::random(prng8), 0, 511); failed = failed || !mpt::is_in_range(mpt::random(prng8), 0, 1); failed = failed || !mpt::is_in_range(mpt::random(prng8, 7), 0, 127); failed = failed || !mpt::is_in_range(mpt::random(prng8, 8), 0, 255); failed = failed || !mpt::is_in_range(mpt::random(prng8, 9), 0, 511); failed = failed || !mpt::is_in_range(mpt::random(prng8, 1), 0, 1); failed = failed || !mpt::is_in_range(mpt::random(prng8, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng8, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng8, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng8, -42, 69), -42, 69); failed = failed || !mpt::is_in_range(mpt::random(prng8, 0.0f, 1.0f), 0.0f, 1.0f); failed = failed || !mpt::is_in_range(mpt::random(prng8, 0.0, 1.0), 0.0, 1.0); failed = failed || !mpt::is_in_range(mpt::random(prng8, -1.0, 1.0), -1.0, 1.0); failed = failed || !mpt::is_in_range(mpt::random(prng8, -1.0, 0.0), -1.0, 0.0); failed = failed || !mpt::is_in_range(mpt::random(prng8, 1.0, 2.0), 1.0, 2.0); failed = failed || !mpt::is_in_range(mpt::random(prng8, 1.0, 3.0), 1.0, 3.0); } MPT_TEST_EXPECT_EXPR(!failed); } } // namespace random } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TESTS_RANDOM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/mutex/0000755000175000017500000000000015023302361017062 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/mutex/mutex.hpp0000644000175000017500000000657114354032307020674 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_MUTEX_MUTEX_HPP #define MPT_MUTEX_MUTEX_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #if !MPT_PLATFORM_MULTITHREADED #define MPT_MUTEX_NONE 1 #elif MPT_COMPILER_GENERIC #define MPT_MUTEX_STD 1 #elif MPT_OS_WINDOWS && MPT_LIBCXX_GNU && !defined(_GLIBCXX_HAS_GTHREADS) #define MPT_MUTEX_WIN32 1 #else #define MPT_MUTEX_STD 1 #endif #ifndef MPT_MUTEX_STD #define MPT_MUTEX_STD 0 #endif #ifndef MPT_MUTEX_WIN32 #define MPT_MUTEX_WIN32 0 #endif #ifndef MPT_MUTEX_NONE #define MPT_MUTEX_NONE 0 #endif #if MPT_MUTEX_STD #include #ifdef MPT_COMPILER_QUIRK_COMPLEX_STD_MUTEX #include #include #endif #elif MPT_MUTEX_WIN32 #include #endif // MPT_MUTEX namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_MUTEX_STD #ifdef MPT_COMPILER_QUIRK_COMPLEX_STD_MUTEX using mutex = std::conditional::type; #else using mutex = std::mutex; #endif using recursive_mutex = std::recursive_mutex; #elif MPT_MUTEX_WIN32 #if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) // compatible with c++11 std::mutex, can eventually be replaced without touching any usage site class mutex { private: SRWLOCK impl = SRWLOCK_INIT; public: mutex() = default; ~mutex() = default; void lock() { AcquireSRWLockExclusive(&impl); } bool try_lock() { return TryAcquireSRWLockExclusive(&impl) ? true : false; } void unlock() { ReleaseSRWLockExclusive(&impl); } }; #else // !_WIN32_WINNT_VISTA // compatible with c++11 std::mutex, can eventually be replaced without touching any usage site class mutex { private: CRITICAL_SECTION impl; public: mutex() { InitializeCriticalSection(&impl); } ~mutex() { DeleteCriticalSection(&impl); } void lock() { EnterCriticalSection(&impl); } bool try_lock() { return TryEnterCriticalSection(&impl) ? true : false; } void unlock() { LeaveCriticalSection(&impl); } }; #endif // _WIN32_WINNT_VISTA // compatible with c++11 std::recursive_mutex, can eventually be replaced without touching any usage site class recursive_mutex { private: CRITICAL_SECTION impl; public: recursive_mutex() { InitializeCriticalSection(&impl); } ~recursive_mutex() { DeleteCriticalSection(&impl); } void lock() { EnterCriticalSection(&impl); } bool try_lock() { return TryEnterCriticalSection(&impl) ? true : false; } void unlock() { LeaveCriticalSection(&impl); } }; #else // MPT_MUTEX_NONE class mutex { public: mutex() { return; } ~mutex() { return; } void lock() { return; } bool try_lock() { return true; } void unlock() { return; } }; class recursive_mutex { public: recursive_mutex() { return; } ~recursive_mutex() { return; } void lock() { return; } bool try_lock() { return true; } void unlock() { return; } }; #endif // MPT_MUTEX #if MPT_MUTEX_STD template using lock_guard = std::lock_guard; #else // !MPT_MUTEX_STD // compatible with c++11 std::lock_guard, can eventually be replaced without touching any usage site template class lock_guard { private: mutex_type & mutex; public: lock_guard(mutex_type & m) : mutex(m) { mutex.lock(); } ~lock_guard() { mutex.unlock(); } }; #endif // MPT_MUTEX_STD } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_MUTEX_MUTEX_HPP libopenmpt-0.8.1+release.autotools/src/mpt/endian/0000755000175000017500000000000015023302361017156 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/endian/int24.hpp0000644000175000017500000002025014413325246020557 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_ENDIAN_INT24_HPP #define MPT_ENDIAN_INT24_HPP #include "mpt/base/bit.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/endian/integer.hpp" #include "mpt/endian/type_traits.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { struct uint24 { std::array bytes; uint24() = default; template ::value, bool>::type = true> explicit uint24(T other) noexcept { using Tunsigned = typename std::make_unsigned::type; MPT_MAYBE_CONSTANT_IF (mpt::endian_is_big()) { bytes[0] = mpt::byte_cast(static_cast((static_cast(other) >> 16) & 0xff)); bytes[1] = mpt::byte_cast(static_cast((static_cast(other) >> 8) & 0xff)); bytes[2] = mpt::byte_cast(static_cast((static_cast(other) >> 0) & 0xff)); } else { bytes[0] = mpt::byte_cast(static_cast((static_cast(other) >> 0) & 0xff)); bytes[1] = mpt::byte_cast(static_cast((static_cast(other) >> 8) & 0xff)); bytes[2] = mpt::byte_cast(static_cast((static_cast(other) >> 16) & 0xff)); } } operator unsigned int() const noexcept { MPT_MAYBE_CONSTANT_IF (mpt::endian_is_big()) { return (mpt::byte_cast(bytes[0]) * 65536) + (mpt::byte_cast(bytes[1]) * 256) + mpt::byte_cast(bytes[2]); } else { return (mpt::byte_cast(bytes[2]) * 65536) + (mpt::byte_cast(bytes[1]) * 256) + mpt::byte_cast(bytes[0]); } } friend bool operator==(uint24 a, uint24 b) noexcept { return static_cast(a) == static_cast(b); } friend bool operator!=(uint24 a, uint24 b) noexcept { return static_cast(a) != static_cast(b); } }; static_assert(sizeof(uint24) == 3); struct int24 { std::array bytes; int24() = default; template ::value, bool>::type = true> explicit int24(T other) noexcept { using Tunsigned = typename std::make_unsigned::type; MPT_MAYBE_CONSTANT_IF (mpt::endian_is_big()) { bytes[0] = mpt::byte_cast(static_cast((static_cast(other) >> 16) & 0xff)); bytes[1] = mpt::byte_cast(static_cast((static_cast(other) >> 8) & 0xff)); bytes[2] = mpt::byte_cast(static_cast((static_cast(other) >> 0) & 0xff)); } else { bytes[0] = mpt::byte_cast(static_cast((static_cast(other) >> 0) & 0xff)); bytes[1] = mpt::byte_cast(static_cast((static_cast(other) >> 8) & 0xff)); bytes[2] = mpt::byte_cast(static_cast((static_cast(other) >> 16) & 0xff)); } } operator int() const noexcept { MPT_MAYBE_CONSTANT_IF (mpt::endian_is_big()) { return (static_cast(mpt::byte_cast(bytes[0])) * 65536) + (mpt::byte_cast(bytes[1]) * 256) + mpt::byte_cast(bytes[2]); } else { return (static_cast(mpt::byte_cast(bytes[2])) * 65536) + (mpt::byte_cast(bytes[1]) * 256) + mpt::byte_cast(bytes[0]); } } friend bool operator==(int24 a, int24 b) noexcept { return static_cast(a) == static_cast(b); } friend bool operator!=(int24 a, int24 b) noexcept { return static_cast(a) != static_cast(b); } }; static_assert(sizeof(int24) == 3); template <> struct packed_int_type { using type = int32; }; template <> struct packed_int_type { using type = uint32; }; template MPT_CONSTEXPRINLINE std::array EndianEncode24(base_type val) noexcept { static_assert(std::is_same::value || std::is_same::value); static_assert(endian == mpt::endian::little || endian == mpt::endian::big); static_assert(std::numeric_limits::is_integer); if constexpr (endian == mpt::endian::native) { std::array data{}; for (std::size_t i = 0; i < sizeof(base_type); ++i) { data[i] = val.bytes[i]; } return data; } else { return EndianEncodeImpl(val); } } template MPT_CONSTEXPRINLINE base_type EndianDecode24(std::array data) noexcept { static_assert(std::is_same::value || std::is_same::value); static_assert(endian == mpt::endian::little || endian == mpt::endian::big); static_assert(std::numeric_limits::is_integer); if constexpr (endian == mpt::endian::native) { base_type val = base_type(); for (std::size_t i = 0; i < sizeof(base_type); ++i) { val.bytes[i] = data[i]; } return val; } else { return EndianDecodeImpl(data); } } template <> MPT_CONSTEXPRINLINE std::array EndianEncode(int24 val) noexcept { return mpt::EndianEncode24(val); } template <> MPT_CONSTEXPRINLINE int24 EndianDecode(std::array data) noexcept { return mpt::EndianDecode24(data); } template <> MPT_CONSTEXPRINLINE std::array EndianEncode(int24 val) noexcept { return mpt::EndianEncode24(val); } template <> MPT_CONSTEXPRINLINE int24 EndianDecode(std::array data) noexcept { return mpt::EndianDecode24(data); } template <> MPT_CONSTEXPRINLINE std::array EndianEncode(uint24 val) noexcept { return mpt::EndianEncode24(val); } template <> MPT_CONSTEXPRINLINE uint24 EndianDecode(std::array data) noexcept { return mpt::EndianDecode24(data); } template <> MPT_CONSTEXPRINLINE std::array EndianEncode(uint24 val) noexcept { return mpt::EndianEncode24(val); } template <> MPT_CONSTEXPRINLINE uint24 EndianDecode(std::array data) noexcept { return mpt::EndianDecode24(data); } using int24le = packed; using uint24le = packed; using int24be = packed; using uint24be = packed; constexpr bool declare_binary_safe(const int24le &) { return true; } constexpr bool declare_binary_safe(const uint24le &) { return true; } constexpr bool declare_binary_safe(const int24be &) { return true; } constexpr bool declare_binary_safe(const uint24be &) { return true; } static_assert(mpt::check_binary_size(3)); static_assert(mpt::check_binary_size(3)); static_assert(mpt::check_binary_size(3)); static_assert(mpt::check_binary_size(3)); } // namespace MPT_INLINE_NS } // namespace mpt #if !defined(CPPCHECK) // work-around crash in cppcheck 2.4.1 namespace std { template <> class numeric_limits : public std::numeric_limits { public: static constexpr mpt::uint32 min() noexcept { return 0; } static constexpr mpt::uint32 lowest() noexcept { return 0; } static constexpr mpt::uint32 max() noexcept { return 0x00ffffff; } }; template <> class numeric_limits : public std::numeric_limits { public: static constexpr mpt::int32 min() noexcept { return 0 - 0x00800000; } static constexpr mpt::int32 lowest() noexcept { return 0 - 0x00800000; } static constexpr mpt::int32 max() noexcept { return 0 + 0x007fffff; } }; } // namespace std #endif // !CPPCHECK #endif // MPT_ENDIAN_INT24_HPP libopenmpt-0.8.1+release.autotools/src/mpt/endian/floatingpoint.hpp0000644000175000017500000004276514730567024022517 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_ENDIAN_FLOATINGPOINT_HPP #define MPT_ENDIAN_FLOATINGPOINT_HPP #include "mpt/base/bit.hpp" #include "mpt/base/float.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/endian/type_traits.hpp" #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { // 1.0f --> 0x3f800000u MPT_FORCEINLINE uint32 EncodeIEEE754binary32(somefloat32 f) { if constexpr (mpt::float_traits::is_float32 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian) { return mpt::bit_cast(f); } else { int e = 0; float m = std::frexp(f, &e); if (e == 0 && std::fabs(m) == 0.0f) { uint32 expo = 0u; uint32 sign = std::signbit(m) ? 0x01u : 0x00u; uint32 mant = 0u; uint32 i = 0u; i |= (mant << 0) & 0x007fffffu; i |= (expo << 23) & 0x7f800000u; i |= (sign << 31) & 0x80000000u; return i; } else { uint32 expo = e + 127 - 1; uint32 sign = std::signbit(m) ? 0x01u : 0x00u; uint32 mant = static_cast(std::fabs(std::ldexp(m, 24))); uint32 i = 0u; i |= (mant << 0) & 0x007fffffu; i |= (expo << 23) & 0x7f800000u; i |= (sign << 31) & 0x80000000u; return i; } } } MPT_FORCEINLINE uint64 EncodeIEEE754binary64(somefloat64 f) { if constexpr (mpt::float_traits::is_float64 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian) { return mpt::bit_cast(f); } else { int e = 0; double m = std::frexp(f, &e); if (e == 0 && std::fabs(m) == 0.0) { uint64 expo = 0u; uint64 sign = std::signbit(m) ? 0x01u : 0x00u; uint64 mant = 0u; uint64 i = 0u; i |= (mant << 0) & 0x000fffffffffffffull; i |= (expo << 52) & 0x7ff0000000000000ull; i |= (sign << 63) & 0x8000000000000000ull; return i; } else { uint64 expo = static_cast(e) + 1023 - 1; uint64 sign = std::signbit(m) ? 0x01u : 0x00u; uint64 mant = static_cast(std::fabs(std::ldexp(m, 53))); uint64 i = 0u; i |= (mant << 0) & 0x000fffffffffffffull; i |= (expo << 52) & 0x7ff0000000000000ull; i |= (sign << 63) & 0x8000000000000000ull; return i; } } } // 0x3f800000u --> 1.0f MPT_FORCEINLINE somefloat32 DecodeIEEE754binary32(uint32 i) { if constexpr (mpt::float_traits::is_float32 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian) { return mpt::bit_cast(i); } else { uint32 mant = (i & 0x007fffffu) >> 0; uint32 expo = (i & 0x7f800000u) >> 23; uint32 sign = (i & 0x80000000u) >> 31; if (expo == 0) { float m = sign ? -static_cast(mant) : static_cast(mant); int e = static_cast(expo) - 127 + 1 - 24; float f = std::ldexp(m, e); return static_cast(f); } else { mant |= 0x00800000u; float m = sign ? -static_cast(mant) : static_cast(mant); int e = static_cast(expo) - 127 + 1 - 24; float f = std::ldexp(m, e); return static_cast(f); } } } MPT_FORCEINLINE somefloat64 DecodeIEEE754binary64(uint64 i) { if constexpr (mpt::float_traits::is_float64 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian) { return mpt::bit_cast(i); } else { uint64 mant = (i & 0x000fffffffffffffull) >> 0; uint64 expo = (i & 0x7ff0000000000000ull) >> 52; uint64 sign = (i & 0x8000000000000000ull) >> 63; if (expo == 0) { double m = sign ? -static_cast(mant) : static_cast(mant); int e = static_cast(expo) - 1023 + 1 - 53; double f = std::ldexp(m, e); return static_cast(f); } else { mant |= 0x0010000000000000ull; double m = sign ? -static_cast(mant) : static_cast(mant); int e = static_cast(expo) - 1023 + 1 - 53; double f = std::ldexp(m, e); return static_cast(f); } } } // template parameters are byte indices corresponding to the individual bytes of iee754 in memory template struct IEEE754binary32Emulated { public: using self_t = IEEE754binary32Emulated; std::byte bytes[4]; public: MPT_FORCEINLINE std::byte GetByte(std::size_t i) const { return bytes[i]; } IEEE754binary32Emulated() = default; MPT_FORCEINLINE explicit IEEE754binary32Emulated(somefloat32 f) { SetInt32(EncodeIEEE754binary32(f)); } MPT_FORCEINLINE IEEE754binary32Emulated & operator=(somefloat32 f) { SetInt32(EncodeIEEE754binary32(f)); return *this; } // b0...b3 are in memory order, i.e. depend on the endianness of this type // little endian: (0x00,0x00,0x80,0x3f) // big endian: (0x3f,0x80,0x00,0x00) MPT_FORCEINLINE explicit IEEE754binary32Emulated(std::byte b0, std::byte b1, std::byte b2, std::byte b3) { bytes[0] = b0; bytes[1] = b1; bytes[2] = b2; bytes[3] = b3; } MPT_FORCEINLINE operator somefloat32() const { return DecodeIEEE754binary32(GetInt32()); } MPT_FORCEINLINE self_t & set(somefloat32 f) { SetInt32(EncodeIEEE754binary32(f)); return *this; } MPT_FORCEINLINE somefloat32 get() const { return DecodeIEEE754binary32(GetInt32()); } MPT_FORCEINLINE self_t & SetInt32(uint32 i) { bytes[hihi] = static_cast(i >> 24); bytes[hilo] = static_cast(i >> 16); bytes[lohi] = static_cast(i >> 8); bytes[lolo] = static_cast(i >> 0); return *this; } MPT_FORCEINLINE uint32 GetInt32() const { return 0u | (static_cast(bytes[hihi]) << 24) | (static_cast(bytes[hilo]) << 16) | (static_cast(bytes[lohi]) << 8) | (static_cast(bytes[lolo]) << 0); } MPT_FORCEINLINE bool operator==(const self_t & cmp) const { return true && bytes[0] == cmp.bytes[0] && bytes[1] == cmp.bytes[1] && bytes[2] == cmp.bytes[2] && bytes[3] == cmp.bytes[3]; } MPT_FORCEINLINE bool operator!=(const self_t & cmp) const { return !(*this == cmp); } }; template struct IEEE754binary64Emulated { public: using self_t = IEEE754binary64Emulated; std::byte bytes[8]; public: MPT_FORCEINLINE std::byte GetByte(std::size_t i) const { return bytes[i]; } IEEE754binary64Emulated() = default; MPT_FORCEINLINE explicit IEEE754binary64Emulated(somefloat64 f) { SetInt64(EncodeIEEE754binary64(f)); } MPT_FORCEINLINE IEEE754binary64Emulated & operator=(somefloat64 f) { SetInt64(EncodeIEEE754binary64(f)); return *this; } MPT_FORCEINLINE explicit IEEE754binary64Emulated(std::byte b0, std::byte b1, std::byte b2, std::byte b3, std::byte b4, std::byte b5, std::byte b6, std::byte b7) { bytes[0] = b0; bytes[1] = b1; bytes[2] = b2; bytes[3] = b3; bytes[4] = b4; bytes[5] = b5; bytes[6] = b6; bytes[7] = b7; } MPT_FORCEINLINE operator somefloat64() const { return DecodeIEEE754binary64(GetInt64()); } MPT_FORCEINLINE self_t & set(somefloat64 f) { SetInt64(EncodeIEEE754binary64(f)); return *this; } MPT_FORCEINLINE somefloat64 get() const { return DecodeIEEE754binary64(GetInt64()); } MPT_FORCEINLINE self_t & SetInt64(uint64 i) { bytes[hihihi] = static_cast(i >> 56); bytes[hihilo] = static_cast(i >> 48); bytes[hilohi] = static_cast(i >> 40); bytes[hilolo] = static_cast(i >> 32); bytes[lohihi] = static_cast(i >> 24); bytes[lohilo] = static_cast(i >> 16); bytes[lolohi] = static_cast(i >> 8); bytes[lololo] = static_cast(i >> 0); return *this; } MPT_FORCEINLINE uint64 GetInt64() const { return 0u | (static_cast(bytes[hihihi]) << 56) | (static_cast(bytes[hihilo]) << 48) | (static_cast(bytes[hilohi]) << 40) | (static_cast(bytes[hilolo]) << 32) | (static_cast(bytes[lohihi]) << 24) | (static_cast(bytes[lohilo]) << 16) | (static_cast(bytes[lolohi]) << 8) | (static_cast(bytes[lololo]) << 0); } MPT_FORCEINLINE bool operator==(const self_t & cmp) const { return true && bytes[0] == cmp.bytes[0] && bytes[1] == cmp.bytes[1] && bytes[2] == cmp.bytes[2] && bytes[3] == cmp.bytes[3] && bytes[4] == cmp.bytes[4] && bytes[5] == cmp.bytes[5] && bytes[6] == cmp.bytes[6] && bytes[7] == cmp.bytes[7]; } MPT_FORCEINLINE bool operator!=(const self_t & cmp) const { return !(*this == cmp); } }; using IEEE754binary32EmulatedBE = IEEE754binary32Emulated<0, 1, 2, 3>; using IEEE754binary32EmulatedLE = IEEE754binary32Emulated<3, 2, 1, 0>; using IEEE754binary64EmulatedBE = IEEE754binary64Emulated<0, 1, 2, 3, 4, 5, 6, 7>; using IEEE754binary64EmulatedLE = IEEE754binary64Emulated<7, 6, 5, 4, 3, 2, 1, 0>; constexpr bool declare_binary_safe(const IEEE754binary32EmulatedBE &) { return true; } constexpr bool declare_binary_safe(const IEEE754binary32EmulatedLE &) { return true; } constexpr bool declare_binary_safe(const IEEE754binary64EmulatedBE &) { return true; } constexpr bool declare_binary_safe(const IEEE754binary64EmulatedLE &) { return true; } static_assert(mpt::check_binary_size(4)); static_assert(mpt::check_binary_size(4)); static_assert(mpt::check_binary_size(8)); static_assert(mpt::check_binary_size(8)); template struct IEEE754binary32Native { public: somefloat32 value; public: MPT_FORCEINLINE std::byte GetByte(std::size_t i) const { static_assert(endian == mpt::endian::little || endian == mpt::endian::big); if constexpr (endian == mpt::endian::little) { return static_cast(EncodeIEEE754binary32(value) >> (i * 8)); } if constexpr (endian == mpt::endian::big) { return static_cast(EncodeIEEE754binary32(value) >> ((4 - 1 - i) * 8)); } } IEEE754binary32Native() = default; MPT_FORCEINLINE explicit IEEE754binary32Native(somefloat32 f) { value = f; } MPT_FORCEINLINE IEEE754binary32Native & operator=(somefloat32 f) { value = f; return *this; } // b0...b3 are in memory order, i.e. depend on the endianness of this type // little endian: (0x00,0x00,0x80,0x3f) // big endian: (0x3f,0x80,0x00,0x00) MPT_FORCEINLINE explicit IEEE754binary32Native(std::byte b0, std::byte b1, std::byte b2, std::byte b3) { static_assert(endian == mpt::endian::little || endian == mpt::endian::big); if constexpr (endian == mpt::endian::little) { value = DecodeIEEE754binary32(0u | (static_cast(b0) << 0) | (static_cast(b1) << 8) | (static_cast(b2) << 16) | (static_cast(b3) << 24)); } if constexpr (endian == mpt::endian::big) { value = DecodeIEEE754binary32(0u | (static_cast(b0) << 24) | (static_cast(b1) << 16) | (static_cast(b2) << 8) | (static_cast(b3) << 0)); } } MPT_FORCEINLINE operator somefloat32() const { return value; } MPT_FORCEINLINE IEEE754binary32Native & set(somefloat32 f) { value = f; return *this; } MPT_FORCEINLINE somefloat32 get() const { return value; } MPT_FORCEINLINE IEEE754binary32Native & SetInt32(uint32 i) { value = DecodeIEEE754binary32(i); return *this; } MPT_FORCEINLINE uint32 GetInt32() const { return EncodeIEEE754binary32(value); } MPT_FORCEINLINE bool operator==(const IEEE754binary32Native & cmp) const { return value == cmp.value; } MPT_FORCEINLINE bool operator!=(const IEEE754binary32Native & cmp) const { return value != cmp.value; } }; template struct IEEE754binary64Native { public: somefloat64 value; public: MPT_FORCEINLINE std::byte GetByte(std::size_t i) const { static_assert(endian == mpt::endian::little || endian == mpt::endian::big); if constexpr (endian == mpt::endian::little) { return mpt::byte_cast(static_cast(EncodeIEEE754binary64(value) >> (i * 8))); } if constexpr (endian == mpt::endian::big) { return mpt::byte_cast(static_cast(EncodeIEEE754binary64(value) >> ((8 - 1 - i) * 8))); } } IEEE754binary64Native() = default; MPT_FORCEINLINE explicit IEEE754binary64Native(somefloat64 f) { value = f; } MPT_FORCEINLINE IEEE754binary64Native & operator=(somefloat64 f) { value = f; return *this; } MPT_FORCEINLINE explicit IEEE754binary64Native(std::byte b0, std::byte b1, std::byte b2, std::byte b3, std::byte b4, std::byte b5, std::byte b6, std::byte b7) { static_assert(endian == mpt::endian::little || endian == mpt::endian::big); if constexpr (endian == mpt::endian::little) { value = DecodeIEEE754binary64(0ull | (static_cast(b0) << 0) | (static_cast(b1) << 8) | (static_cast(b2) << 16) | (static_cast(b3) << 24) | (static_cast(b4) << 32) | (static_cast(b5) << 40) | (static_cast(b6) << 48) | (static_cast(b7) << 56)); } if constexpr (endian == mpt::endian::big) { value = DecodeIEEE754binary64(0ull | (static_cast(b0) << 56) | (static_cast(b1) << 48) | (static_cast(b2) << 40) | (static_cast(b3) << 32) | (static_cast(b4) << 24) | (static_cast(b5) << 16) | (static_cast(b6) << 8) | (static_cast(b7) << 0)); } } MPT_FORCEINLINE operator somefloat64() const { return value; } MPT_FORCEINLINE IEEE754binary64Native & set(somefloat64 f) { value = f; return *this; } MPT_FORCEINLINE somefloat64 get() const { return value; } MPT_FORCEINLINE IEEE754binary64Native & SetInt64(uint64 i) { value = DecodeIEEE754binary64(i); return *this; } MPT_FORCEINLINE uint64 GetInt64() const { return EncodeIEEE754binary64(value); } MPT_FORCEINLINE bool operator==(const IEEE754binary64Native & cmp) const { return value == cmp.value; } MPT_FORCEINLINE bool operator!=(const IEEE754binary64Native & cmp) const { return value != cmp.value; } }; static_assert((sizeof(IEEE754binary32Native<>) == 4)); static_assert((sizeof(IEEE754binary64Native<>) == 8)); constexpr bool declare_binary_safe(const IEEE754binary32Native<> &) noexcept { return true; } constexpr bool declare_binary_safe(const IEEE754binary64Native<> &) noexcept { return true; } template struct IEEE754binary_types { using IEEE754binary32LE = IEEE754binary32EmulatedLE; using IEEE754binary32BE = IEEE754binary32EmulatedBE; using IEEE754binary64LE = IEEE754binary64EmulatedLE; using IEEE754binary64BE = IEEE754binary64EmulatedBE; }; template <> struct IEEE754binary_types { using IEEE754binary32LE = IEEE754binary32Native<>; using IEEE754binary32BE = IEEE754binary32EmulatedBE; using IEEE754binary64LE = IEEE754binary64Native<>; using IEEE754binary64BE = IEEE754binary64EmulatedBE; }; template <> struct IEEE754binary_types { using IEEE754binary32LE = IEEE754binary32EmulatedLE; using IEEE754binary32BE = IEEE754binary32Native<>; using IEEE754binary64LE = IEEE754binary64EmulatedLE; using IEEE754binary64BE = IEEE754binary64Native<>; }; using IEEE754binary32LE = IEEE754binary_types::is_float32 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian, mpt::endian::native>::IEEE754binary32LE; using IEEE754binary32BE = IEEE754binary_types::is_float32 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian, mpt::endian::native>::IEEE754binary32BE; using IEEE754binary64LE = IEEE754binary_types::is_float64 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian, mpt::endian::native>::IEEE754binary64LE; using IEEE754binary64BE = IEEE754binary_types::is_float64 && mpt::float_traits::is_ieee754_binary && mpt::float_traits::is_native_endian, mpt::endian::native>::IEEE754binary64BE; static_assert(sizeof(IEEE754binary32LE) == 4); static_assert(sizeof(IEEE754binary32BE) == 4); static_assert(sizeof(IEEE754binary64LE) == 8); static_assert(sizeof(IEEE754binary64BE) == 8); // unaligned using float32le = IEEE754binary32EmulatedLE; using float32be = IEEE754binary32EmulatedBE; using float64le = IEEE754binary64EmulatedLE; using float64be = IEEE754binary64EmulatedBE; static_assert(sizeof(float32le) == 4); static_assert(sizeof(float32be) == 4); static_assert(sizeof(float64le) == 8); static_assert(sizeof(float64be) == 8); // potentially aligned using float32le_fast = IEEE754binary32LE; using float32be_fast = IEEE754binary32BE; using float64le_fast = IEEE754binary64LE; using float64be_fast = IEEE754binary64BE; static_assert(sizeof(float32le_fast) == 4); static_assert(sizeof(float32be_fast) == 4); static_assert(sizeof(float64le_fast) == 8); static_assert(sizeof(float64be_fast) == 8); template <> struct make_endian { using type = IEEE754binary32LE; }; template <> struct make_endian { using type = IEEE754binary32BE; }; template <> struct make_endian { using type = IEEE754binary64LE; }; template <> struct make_endian { using type = IEEE754binary64BE; }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_ENDIAN_FLOATINGPOINT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/endian/type_traits.hpp0000644000175000017500000000116414325277343022177 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_ENDIAN_TYPE_TRAITS_HPP #define MPT_ENDIAN_TYPE_TRAITS_HPP #include "mpt/base/bit.hpp" #include "mpt/base/namespace.hpp" namespace mpt { inline namespace MPT_INLINE_NS { template struct make_endian { }; template struct make_le { using type = typename mpt::make_endian::type; }; template struct make_be { using type = typename mpt::make_endian::type; }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_ENDIAN_TYPE_TRAITS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/endian/integer.hpp0000644000175000017500000002622314413325246021262 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_ENDIAN_INTEGER_HPP #define MPT_ENDIAN_INTEGER_HPP #include "mpt/base/detect.hpp" #include "mpt/base/bit.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/endian/type_traits.hpp" #include #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { template MPT_CONSTEXPRINLINE std::array EndianEncodeImpl(base_type val) noexcept { static_assert(endian == mpt::endian::little || endian == mpt::endian::big); static_assert(std::numeric_limits::is_integer); using unsigned_int_type = typename std::make_unsigned::type; unsigned_int_type uval = static_cast(static_cast(val)); std::array data{}; if constexpr (endian == mpt::endian::little) { for (std::size_t i = 0; i < sizeof(base_type); ++i) { data[i] = static_cast(static_cast((uval >> (i * 8)) & 0xffu)); } } else { for (std::size_t i = 0; i < sizeof(base_type); ++i) { data[(sizeof(base_type) - 1) - i] = static_cast(static_cast((uval >> (i * 8)) & 0xffu)); } } return data; } template MPT_CONSTEXPRINLINE std::array EndianEncode(base_type val) noexcept { return EndianEncodeImpl(val); } template MPT_CONSTEXPRINLINE base_type EndianDecodeImpl(std::array data) noexcept { static_assert(endian == mpt::endian::little || endian == mpt::endian::big); static_assert(std::numeric_limits::is_integer); using unsigned_int_type = typename std::make_unsigned::type; base_type val = base_type(); unsigned_int_type uval = unsigned_int_type(); if constexpr (endian == mpt::endian::little) { for (std::size_t i = 0; i < sizeof(base_type); ++i) { uval |= static_cast(static_cast(static_cast(data[i])) << (i * 8)); } } else { for (std::size_t i = 0; i < sizeof(base_type); ++i) { uval |= static_cast(static_cast(static_cast(data[(sizeof(base_type) - 1) - i])) << (i * 8)); } } val = static_cast(static_cast(uval)); return val; } template MPT_CONSTEXPRINLINE base_type EndianDecode(std::array data) noexcept { return EndianDecodeImpl(data); } template struct packed_int_type { using type = T; }; // On-disk integer types with defined endianness and no alignemnt requirements // Note: To easily debug module loaders (and anything else that uses this // wrapper struct), you can use the Debugger Visualizers available in // build/vs/debug/ to conveniently view the wrapped contents. template ::type> struct packed { public: using base_type = T; using int_type = Tint; public: std::array data; public: MPT_CONSTEXPR20_FUN void set(base_type val) noexcept { static_assert(std::numeric_limits::is_integer); MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { if constexpr (endian == mpt::endian::big) { typename std::make_unsigned::type uval = val; for (std::size_t i = 0; i < sizeof(base_type); ++i) { data[i] = static_cast((uval >> (8 * (sizeof(base_type) - 1 - i))) & 0xffu); } } else { typename std::make_unsigned::type uval = val; for (std::size_t i = 0; i < sizeof(base_type); ++i) { data[i] = static_cast((uval >> (8 * i)) & 0xffu); } } } else { if constexpr (std::is_integral::value && (mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)) { if constexpr (mpt::endian::native != endian) { val = mpt::byteswap(val); } std::memcpy(data.data(), &val, sizeof(val)); } else { data = EndianEncode(val); } } } MPT_CONSTEXPR20_FUN base_type get() const noexcept { static_assert(std::numeric_limits::is_integer); MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { if constexpr (endian == mpt::endian::big) { typename std::make_unsigned::type uval = 0; for (std::size_t i = 0; i < sizeof(base_type); ++i) { uval |= static_cast::type>(static_cast::type>(data[i]) << (8 * (sizeof(base_type) - 1 - i))); } return static_cast(uval); } else { typename std::make_unsigned::type uval = 0; for (std::size_t i = 0; i < sizeof(base_type); ++i) { uval |= static_cast::type>(static_cast::type>(data[i]) << (8 * i)); } return static_cast(uval); } } else { if constexpr (std::is_integral::value && (mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)) { base_type val = base_type(); std::memcpy(&val, data.data(), sizeof(val)); if constexpr (mpt::endian::native != endian) { val = mpt::byteswap(val); } return val; } else { return EndianDecode(data); } } } MPT_CONSTEXPR20_FUN packed & operator=(const base_type & val) noexcept { set(val); return *this; } MPT_CONSTEXPR20_FUN operator base_type() const noexcept { return get(); } public: MPT_CONSTEXPR20_FUN packed & operator&=(base_type val) noexcept { set(get() & val); return *this; } MPT_CONSTEXPR20_FUN packed & operator|=(base_type val) noexcept { set(get() | val); return *this; } MPT_CONSTEXPR20_FUN packed & operator^=(base_type val) noexcept { set(get() ^ val); return *this; } MPT_CONSTEXPR20_FUN packed & operator+=(base_type val) noexcept { set(get() + val); return *this; } MPT_CONSTEXPR20_FUN packed & operator-=(base_type val) noexcept { set(get() - val); return *this; } MPT_CONSTEXPR20_FUN packed & operator*=(base_type val) noexcept { set(get() * val); return *this; } MPT_CONSTEXPR20_FUN packed & operator/=(base_type val) noexcept { set(get() / val); return *this; } MPT_CONSTEXPR20_FUN packed & operator%=(base_type val) noexcept { set(get() % val); return *this; } MPT_CONSTEXPR20_FUN packed & operator++() noexcept { // prefix set(get() + 1); return *this; } MPT_CONSTEXPR20_FUN packed & operator--() noexcept { // prefix set(get() - 1); return *this; } MPT_CONSTEXPR20_FUN base_type operator++(int) noexcept { // postfix base_type old = get(); set(old + 1); return old; } MPT_CONSTEXPR20_FUN base_type operator--(int) noexcept { // postfix base_type old = get(); set(old - 1); return old; } }; using int64le = packed; using int32le = packed; using int16le = packed; using int8le = packed; using uint64le = packed; using uint32le = packed; using uint16le = packed; using uint8le = packed; using int64be = packed; using int32be = packed; using int16be = packed; using int8be = packed; using uint64be = packed; using uint32be = packed; using uint16be = packed; using uint8be = packed; constexpr bool declare_binary_safe(const int64le &) { return true; } constexpr bool declare_binary_safe(const int32le &) { return true; } constexpr bool declare_binary_safe(const int16le &) { return true; } constexpr bool declare_binary_safe(const int8le &) { return true; } constexpr bool declare_binary_safe(const uint64le &) { return true; } constexpr bool declare_binary_safe(const uint32le &) { return true; } constexpr bool declare_binary_safe(const uint16le &) { return true; } constexpr bool declare_binary_safe(const uint8le &) { return true; } constexpr bool declare_binary_safe(const int64be &) { return true; } constexpr bool declare_binary_safe(const int32be &) { return true; } constexpr bool declare_binary_safe(const int16be &) { return true; } constexpr bool declare_binary_safe(const int8be &) { return true; } constexpr bool declare_binary_safe(const uint64be &) { return true; } constexpr bool declare_binary_safe(const uint32be &) { return true; } constexpr bool declare_binary_safe(const uint16be &) { return true; } constexpr bool declare_binary_safe(const uint8be &) { return true; } static_assert(mpt::check_binary_size(8)); static_assert(mpt::check_binary_size(4)); static_assert(mpt::check_binary_size(2)); static_assert(mpt::check_binary_size(1)); static_assert(mpt::check_binary_size(8)); static_assert(mpt::check_binary_size(4)); static_assert(mpt::check_binary_size(2)); static_assert(mpt::check_binary_size(1)); static_assert(mpt::check_binary_size(8)); static_assert(mpt::check_binary_size(4)); static_assert(mpt::check_binary_size(2)); static_assert(mpt::check_binary_size(1)); static_assert(mpt::check_binary_size(8)); static_assert(mpt::check_binary_size(4)); static_assert(mpt::check_binary_size(2)); static_assert(mpt::check_binary_size(1)); template struct make_endian { using type = packed::type, mpt::endian::little>; }; template struct make_endian { using type = packed::type, mpt::endian::big>; }; template MPT_CONSTEXPR20_FUN auto as_le(T v) noexcept -> typename mpt::make_le::type>::type { typename mpt::make_le::type>::type res{}; res = v; return res; } template MPT_CONSTEXPR20_FUN auto as_be(T v) noexcept -> typename mpt::make_be::type>::type { typename mpt::make_be::type>::type res{}; res = v; return res; } template MPT_CONSTEXPR20_FUN Tpacked as_endian(typename Tpacked::base_type v) noexcept { Tpacked res{}; res = v; return res; } } // namespace MPT_INLINE_NS } // namespace mpt namespace std { template class numeric_limits> : public std::numeric_limits { }; template class numeric_limits> : public std::numeric_limits { }; } // namespace std #endif // MPT_ENDIAN_INTEGER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/endian/tests/0000755000175000017500000000000015023302361020320 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/endian/tests/tests_endian_int24.hpp0000644000175000017500000001001014202246716024452 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_ENDIAN_TESTS_ENDIAN_INT24_HPP #define MPT_ENDIAN_TESTS_ENDIAN_INT24_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/endian/int24.hpp" #include "mpt/endian/integer.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace endian { namespace integer { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/endian/int24") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { static_assert(std::numeric_limits::min() == std::numeric_limits::min()); static_assert(std::numeric_limits::min() == std::numeric_limits::min()); { int24le le24; le24.set(int24(0x123456)); int24be be24; be24.set(int24(0x123456)); MPT_TEST_EXPECT_EQUAL(le24, int24(0x123456)); MPT_TEST_EXPECT_EQUAL(be24, int24(0x123456)); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\x56\x34\x12", 3), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x12\x34\x56", 3), 0); } { int24le le24; le24.set(int24(-0x7fffff)); int24be be24; be24.set(int24(-0x7fffff)); MPT_TEST_EXPECT_EQUAL(le24, int24(-0x7fffff)); MPT_TEST_EXPECT_EQUAL(be24, int24(-0x7fffff)); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\x01\x00\x80", 3), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x80\x00\x01", 3), 0); } { int24le le24; le24.set(int24(-0x000001)); int24be be24; be24.set(int24(-0x000001)); MPT_TEST_EXPECT_EQUAL(le24, int24(-0x000001)); MPT_TEST_EXPECT_EQUAL(be24, int24(-0x000001)); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\xff\xff\xff", 3), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\xff\xff\xff", 3), 0); } { int24le le24; le24.set(int24(0x7fffff)); int24be be24; be24.set(int24(0x7fffff)); MPT_TEST_EXPECT_EQUAL(le24, int24(0x7fffff)); MPT_TEST_EXPECT_EQUAL(be24, int24(0x7fffff)); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\xff\xff\x7f", 3), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x7f\xff\xff", 3), 0); } { int24le le24; le24.set(int24(-0x800000)); int24be be24; be24.set(int24(-0x800000)); MPT_TEST_EXPECT_EQUAL(le24, int24(-0x800000)); MPT_TEST_EXPECT_EQUAL(be24, int24(-0x800000)); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\x00\x00\x80", 3), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x80\x00\x00", 3), 0); } { uint24le le24; le24.set(uint24(0x123456)); uint24be be24; be24.set(uint24(0x123456)); MPT_TEST_EXPECT_EQUAL(le24, uint24(0x123456)); MPT_TEST_EXPECT_EQUAL(be24, uint24(0x123456)); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\x56\x34\x12", 3), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x12\x34\x56", 3), 0); } { uint24le le24; le24.set(uint24(0xffffff)); uint24be be24; be24.set(uint24(0xffffff)); MPT_TEST_EXPECT_EQUAL(le24, uint24(0xffffff)); MPT_TEST_EXPECT_EQUAL(be24, uint24(0xffffff)); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\xff\xff\xff", 3), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\xff\xff\xff", 3), 0); } { uint24le le24; le24.set(uint24(0x7fffff)); uint24be be24; be24.set(uint24(0x7fffff)); MPT_TEST_EXPECT_EQUAL(le24, uint24(0x7fffff)); MPT_TEST_EXPECT_EQUAL(be24, uint24(0x7fffff)); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\xff\xff\x7f", 3), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x7f\xff\xff", 3), 0); } { uint24le le24; le24.set(uint24(0x800000)); uint24be be24; be24.set(uint24(0x800000)); MPT_TEST_EXPECT_EQUAL(le24, uint24(0x800000)); MPT_TEST_EXPECT_EQUAL(be24, uint24(0x800000)); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\x00\x00\x80", 3), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x80\x00\x00", 3), 0); } } } // namespace integer } // namespace endian } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_ENDIAN_TESTS_ENDIAN_INT24_HPP libopenmpt-0.8.1+release.autotools/src/mpt/endian/tests/tests_endian_floatingpoint.hpp0000644000175000017500000001011214044173026026367 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_ENDIAN_TESTS_ENDIAN_FLOATINGPOINT_HPP #define MPT_ENDIAN_TESTS_ENDIAN_FLOATINGPOINT_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/endian/floatingpoint.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace endian { namespace floatingpoint { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/endian/floatingpoint") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { MPT_TEST_EXPECT_EQUAL(mpt::EncodeIEEE754binary32(1.0f), 0x3f800000u); MPT_TEST_EXPECT_EQUAL(mpt::EncodeIEEE754binary32(-1.0f), 0xbf800000u); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary32(0x00000000u), 0.0f); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary32(0x41840000u), 16.5f); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary32(0x3faa0000u), 1.328125f); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary32(0xbfaa0000u), -1.328125f); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary32(0x3f800000u), 1.0f); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary32(0x00000000u), 0.0f); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary32(0xbf800000u), -1.0f); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary32(0x3f800000u), 1.0f); MPT_TEST_EXPECT_EQUAL(IEEE754binary32LE(1.0f).GetInt32(), 0x3f800000u); MPT_TEST_EXPECT_EQUAL(IEEE754binary32BE(1.0f).GetInt32(), 0x3f800000u); MPT_TEST_EXPECT_EQUAL(IEEE754binary32LE(mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x80), mpt::as_byte(0x3f)), 1.0f); MPT_TEST_EXPECT_EQUAL(IEEE754binary32BE(mpt::as_byte(0x3f), mpt::as_byte(0x80), mpt::as_byte(0x00), mpt::as_byte(0x00)), 1.0f); MPT_TEST_EXPECT_EQUAL(IEEE754binary32LE(1.0f), IEEE754binary32LE(mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x80), mpt::as_byte(0x3f))); MPT_TEST_EXPECT_EQUAL(IEEE754binary32BE(1.0f), IEEE754binary32BE(mpt::as_byte(0x3f), mpt::as_byte(0x80), mpt::as_byte(0x00), mpt::as_byte(0x00))); MPT_TEST_EXPECT_EQUAL(mpt::EncodeIEEE754binary64(1.0), 0x3ff0000000000000ull); MPT_TEST_EXPECT_EQUAL(mpt::EncodeIEEE754binary64(-1.0), 0xbff0000000000000ull); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary64(0x0000000000000000ull), 0.0); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary64(0x4030800000000000ull), 16.5); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary64(0x3FF5400000000000ull), 1.328125); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary64(0xBFF5400000000000ull), -1.328125); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary64(0x3ff0000000000000ull), 1.0); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary64(0x0000000000000000ull), 0.0); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary64(0xbff0000000000000ull), -1.0); MPT_TEST_EXPECT_EQUAL(mpt::DecodeIEEE754binary64(0x3ff0000000000000ull), 1.0); MPT_TEST_EXPECT_EQUAL(IEEE754binary64LE(1.0).GetInt64(), 0x3ff0000000000000ull); MPT_TEST_EXPECT_EQUAL(IEEE754binary64BE(1.0).GetInt64(), 0x3ff0000000000000ull); MPT_TEST_EXPECT_EQUAL(IEEE754binary64LE(mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0xf0), mpt::as_byte(0x3f)), 1.0); MPT_TEST_EXPECT_EQUAL(IEEE754binary64BE(mpt::as_byte(0x3f), mpt::as_byte(0xf0), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00)), 1.0); MPT_TEST_EXPECT_EQUAL(IEEE754binary64LE(1.0), IEEE754binary64LE(mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0xf0), mpt::as_byte(0x3f))); MPT_TEST_EXPECT_EQUAL(IEEE754binary64BE(1.0), IEEE754binary64BE(mpt::as_byte(0x3f), mpt::as_byte(0xf0), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00), mpt::as_byte(0x00))); } } // namespace floatingpoint } // namespace endian } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_ENDIAN_TESTS_ENDIAN_FLOATINGPOINT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/endian/tests/tests_endian_integer.hpp0000644000175000017500000000746414161652513025172 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_ENDIAN_TESTS_ENDIAN_INTEGER_HPP #define MPT_ENDIAN_TESTS_ENDIAN_INTEGER_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/endian/integer.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace endian { namespace integer { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/endian/integer") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { static_assert(std::numeric_limits::min() == std::numeric_limits::min()); static_assert(std::numeric_limits::min() == std::numeric_limits::min()); static_assert(std::numeric_limits::min() == std::numeric_limits::min()); static_assert(std::numeric_limits::min() == std::numeric_limits::min()); static_assert(std::numeric_limits::min() == std::numeric_limits::min()); static_assert(std::numeric_limits::min() == std::numeric_limits::min()); static_assert(std::numeric_limits::min() == std::numeric_limits::min()); static_assert(std::numeric_limits::min() == std::numeric_limits::min()); static_assert(std::numeric_limits::max() == std::numeric_limits::max()); static_assert(std::numeric_limits::max() == std::numeric_limits::max()); static_assert(std::numeric_limits::max() == std::numeric_limits::max()); static_assert(std::numeric_limits::max() == std::numeric_limits::max()); static_assert(std::numeric_limits::max() == std::numeric_limits::max()); static_assert(std::numeric_limits::max() == std::numeric_limits::max()); static_assert(std::numeric_limits::max() == std::numeric_limits::max()); static_assert(std::numeric_limits::max() == std::numeric_limits::max()); struct test_endian_constexpr { static MPT_CONSTEXPR20_FUN int32le test(uint32 x) { int32le foo{}; foo = x; return foo; } }; MPT_CONSTEXPR20_VAR int32le foo = test_endian_constexpr::test(23); static_cast(foo); // Packed integers with defined endianness { int8le le8; le8.set(-128); int8be be8; be8.set(-128); MPT_TEST_EXPECT_EQUAL(le8, -128); MPT_TEST_EXPECT_EQUAL(be8, -128); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le8, "\x80", 1), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be8, "\x80", 1), 0); int16le le16; le16.set(0x1234); int16be be16; be16.set(0x1234); MPT_TEST_EXPECT_EQUAL(le16, 0x1234); MPT_TEST_EXPECT_EQUAL(be16, 0x1234); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le16, "\x34\x12", 2), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be16, "\x12\x34", 2), 0); uint32le le32; le32.set(0xFFEEDDCCu); uint32be be32; be32.set(0xFFEEDDCCu); MPT_TEST_EXPECT_EQUAL(le32, 0xFFEEDDCCu); MPT_TEST_EXPECT_EQUAL(be32, 0xFFEEDDCCu); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le32, "\xCC\xDD\xEE\xFF", 4), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be32, "\xFF\xEE\xDD\xCC", 4), 0); uint64le le64; le64.set(0xDEADC0DE15C0FFEEull); uint64be be64; be64.set(0xDEADC0DE15C0FFEEull); MPT_TEST_EXPECT_EQUAL(le64, 0xDEADC0DE15C0FFEEull); MPT_TEST_EXPECT_EQUAL(be64, 0xDEADC0DE15C0FFEEull); MPT_TEST_EXPECT_EQUAL(std::memcmp(&le64, "\xEE\xFF\xC0\x15\xDE\xC0\xAD\xDE", 8), 0); MPT_TEST_EXPECT_EQUAL(std::memcmp(&be64, "\xDE\xAD\xC0\xDE\x15\xC0\xFF\xEE", 8), 0); } } } // namespace integer } // namespace endian } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_ENDIAN_TESTS_ENDIAN_INTEGER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/binary/0000755000175000017500000000000015023302361017204 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/binary/base64.hpp0000644000175000017500000000733614203145061020733 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BINARY_BASE64_HPP #define MPT_BINARY_BASE64_HPP #include "mpt/base/integer.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { class base64_parse_error : public std::runtime_error { public: base64_parse_error() : std::runtime_error("invalid Base64 encoding") { } }; inline constexpr std::array base64 = { {MPT_UCHAR('A'), MPT_UCHAR('B'), MPT_UCHAR('C'), MPT_UCHAR('D'), MPT_UCHAR('E'), MPT_UCHAR('F'), MPT_UCHAR('G'), MPT_UCHAR('H'), MPT_UCHAR('I'), MPT_UCHAR('J'), MPT_UCHAR('K'), MPT_UCHAR('L'), MPT_UCHAR('M'), MPT_UCHAR('N'), MPT_UCHAR('O'), MPT_UCHAR('P'), MPT_UCHAR('Q'), MPT_UCHAR('R'), MPT_UCHAR('S'), MPT_UCHAR('T'), MPT_UCHAR('U'), MPT_UCHAR('V'), MPT_UCHAR('W'), MPT_UCHAR('X'), MPT_UCHAR('Y'), MPT_UCHAR('Z'), MPT_UCHAR('a'), MPT_UCHAR('b'), MPT_UCHAR('c'), MPT_UCHAR('d'), MPT_UCHAR('e'), MPT_UCHAR('f'), MPT_UCHAR('g'), MPT_UCHAR('h'), MPT_UCHAR('i'), MPT_UCHAR('j'), MPT_UCHAR('k'), MPT_UCHAR('l'), MPT_UCHAR('m'), MPT_UCHAR('n'), MPT_UCHAR('o'), MPT_UCHAR('p'), MPT_UCHAR('q'), MPT_UCHAR('r'), MPT_UCHAR('s'), MPT_UCHAR('t'), MPT_UCHAR('u'), MPT_UCHAR('v'), MPT_UCHAR('w'), MPT_UCHAR('x'), MPT_UCHAR('y'), MPT_UCHAR('z'), MPT_UCHAR('0'), MPT_UCHAR('1'), MPT_UCHAR('2'), MPT_UCHAR('3'), MPT_UCHAR('4'), MPT_UCHAR('5'), MPT_UCHAR('6'), MPT_UCHAR('7'), MPT_UCHAR('8'), MPT_UCHAR('9'), MPT_UCHAR('+'), MPT_UCHAR('/')} }; template inline mpt::ustring encode_base64(mpt::span src_) { mpt::const_byte_span src = mpt::byte_cast(src_); mpt::ustring result; result.reserve(4 * ((src.size() + 2) / 3)); uint32 bits = 0; std::size_t bytes = 0; for (std::byte byte : src) { bits <<= 8; bits |= mpt::byte_cast(byte); bytes++; if (bytes == 3) { result.push_back(base64[(bits >> 18) & 0x3f]); result.push_back(base64[(bits >> 12) & 0x3f]); result.push_back(base64[(bits >> 6) & 0x3f]); result.push_back(base64[(bits >> 0) & 0x3f]); bits = 0; bytes = 0; } } std::size_t padding = 0; while (bytes != 0) { bits <<= 8; padding++; bytes++; if (bytes == 3) { result.push_back(base64[(bits >> 18) & 0x3f]); result.push_back(base64[(bits >> 12) & 0x3f]); if (padding > 1) { result.push_back(MPT_UCHAR('=')); } else { result.push_back(base64[(bits >> 6) & 0x3f]); } if (padding > 0) { result.push_back(MPT_UCHAR('=')); } else { result.push_back(base64[(bits >> 0) & 0x3f]); } bits = 0; bytes = 0; } } return result; } inline uint8 decode_base64_bits(mpt::uchar c) { for (uint8 i = 0; i < 64; ++i) { if (base64[i] == c) { return i; } } throw base64_parse_error(); } inline std::vector decode_base64(const mpt::ustring & src) { std::vector result; result.reserve(3 * (src.length() / 4)); uint32 bits = 0; std::size_t chars = 0; std::size_t padding = 0; for (mpt::uchar c : src) { bits <<= 6; if (c == MPT_UCHAR('=')) { padding++; } else { bits |= decode_base64_bits(c); } chars++; if (chars == 4) { result.push_back(mpt::byte_cast(static_cast((bits >> 16) & 0xff))); if (padding < 2) { result.push_back(mpt::byte_cast(static_cast((bits >> 8) & 0xff))); } if (padding < 1) { result.push_back(mpt::byte_cast(static_cast((bits >> 0) & 0xff))); } bits = 0; chars = 0; padding = 0; } } if (chars != 0) { throw base64_parse_error(); } return result; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BINARY_BASE64_HPP libopenmpt-0.8.1+release.autotools/src/mpt/binary/hex.hpp0000644000175000017500000000451414203145061020426 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BINARY_HEX_HPP #define MPT_BINARY_HEX_HPP #include "mpt/base/integer.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { inline constexpr std::array encode_nibble = { {MPT_UCHAR('0'), MPT_UCHAR('1'), MPT_UCHAR('2'), MPT_UCHAR('3'), MPT_UCHAR('4'), MPT_UCHAR('5'), MPT_UCHAR('6'), MPT_UCHAR('7'), MPT_UCHAR('8'), MPT_UCHAR('9'), MPT_UCHAR('A'), MPT_UCHAR('B'), MPT_UCHAR('C'), MPT_UCHAR('D'), MPT_UCHAR('E'), MPT_UCHAR('F')} }; inline bool decode_byte(uint8 & byte, mpt::uchar c1, mpt::uchar c2) { byte = 0; if (MPT_UCHAR('0') <= c1 && c1 <= MPT_UCHAR('9')) { byte += static_cast((c1 - MPT_UCHAR('0')) << 4); } else if (MPT_UCHAR('A') <= c1 && c1 <= MPT_UCHAR('F')) { byte += static_cast((c1 - MPT_UCHAR('A') + 10) << 4); } else if (MPT_UCHAR('a') <= c1 && c1 <= MPT_UCHAR('f')) { byte += static_cast((c1 - MPT_UCHAR('a') + 10) << 4); } else { return false; } if (MPT_UCHAR('0') <= c2 && c2 <= MPT_UCHAR('9')) { byte += static_cast(c2 - MPT_UCHAR('0')); } else if (MPT_UCHAR('A') <= c2 && c2 <= MPT_UCHAR('F')) { byte += static_cast(c2 - MPT_UCHAR('A') + 10); } else if (MPT_UCHAR('a') <= c2 && c2 <= MPT_UCHAR('f')) { byte += static_cast(c2 - MPT_UCHAR('a') + 10); } else { return false; } return true; } template inline mpt::ustring encode_hex(mpt::span src_) { mpt::const_byte_span src = mpt::byte_cast(src_); mpt::ustring result; result.reserve(src.size() * 2); for (std::byte byte : src) { result.push_back(encode_nibble[(mpt::byte_cast(byte) & 0xf0) >> 4]); result.push_back(encode_nibble[mpt::byte_cast(byte) & 0x0f]); } return result; } inline std::vector decode_hex(const mpt::ustring & src) { std::vector result; result.reserve(src.size() / 2); for (std::size_t i = 0; (i + 1) < src.size(); i += 2) { uint8 byte = 0; if (!decode_byte(byte, src[i], src[i + 1])) { return result; } result.push_back(mpt::byte_cast(byte)); } return result; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BINARY_HEX_HPP libopenmpt-0.8.1+release.autotools/src/mpt/binary/base64url.hpp0000644000175000017500000001001414203145061021441 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BINARY_BASE64URL_HPP #define MPT_BINARY_BASE64URL_HPP #include "mpt/base/integer.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { class base64url_parse_error : public std::runtime_error { public: base64url_parse_error() : std::runtime_error("invalid Base64URL encoding") { } }; inline constexpr std::array base64url = { {MPT_UCHAR('A'), MPT_UCHAR('B'), MPT_UCHAR('C'), MPT_UCHAR('D'), MPT_UCHAR('E'), MPT_UCHAR('F'), MPT_UCHAR('G'), MPT_UCHAR('H'), MPT_UCHAR('I'), MPT_UCHAR('J'), MPT_UCHAR('K'), MPT_UCHAR('L'), MPT_UCHAR('M'), MPT_UCHAR('N'), MPT_UCHAR('O'), MPT_UCHAR('P'), MPT_UCHAR('Q'), MPT_UCHAR('R'), MPT_UCHAR('S'), MPT_UCHAR('T'), MPT_UCHAR('U'), MPT_UCHAR('V'), MPT_UCHAR('W'), MPT_UCHAR('X'), MPT_UCHAR('Y'), MPT_UCHAR('Z'), MPT_UCHAR('a'), MPT_UCHAR('b'), MPT_UCHAR('c'), MPT_UCHAR('d'), MPT_UCHAR('e'), MPT_UCHAR('f'), MPT_UCHAR('g'), MPT_UCHAR('h'), MPT_UCHAR('i'), MPT_UCHAR('j'), MPT_UCHAR('k'), MPT_UCHAR('l'), MPT_UCHAR('m'), MPT_UCHAR('n'), MPT_UCHAR('o'), MPT_UCHAR('p'), MPT_UCHAR('q'), MPT_UCHAR('r'), MPT_UCHAR('s'), MPT_UCHAR('t'), MPT_UCHAR('u'), MPT_UCHAR('v'), MPT_UCHAR('w'), MPT_UCHAR('x'), MPT_UCHAR('y'), MPT_UCHAR('z'), MPT_UCHAR('0'), MPT_UCHAR('1'), MPT_UCHAR('2'), MPT_UCHAR('3'), MPT_UCHAR('4'), MPT_UCHAR('5'), MPT_UCHAR('6'), MPT_UCHAR('7'), MPT_UCHAR('8'), MPT_UCHAR('9'), MPT_UCHAR('-'), MPT_UCHAR('_')} }; template inline mpt::ustring encode_base64url(mpt::span src_) { mpt::const_byte_span src = mpt::byte_cast(src_); mpt::ustring result; result.reserve(4 * ((src.size() + 2) / 3)); uint32 bits = 0; std::size_t bytes = 0; for (std::byte byte : src) { bits <<= 8; bits |= mpt::byte_cast(byte); bytes++; if (bytes == 3) { result.push_back(base64url[(bits >> 18) & 0x3f]); result.push_back(base64url[(bits >> 12) & 0x3f]); result.push_back(base64url[(bits >> 6) & 0x3f]); result.push_back(base64url[(bits >> 0) & 0x3f]); bits = 0; bytes = 0; } } std::size_t padding = 0; while (bytes != 0) { bits <<= 8; padding++; bytes++; if (bytes == 3) { result.push_back(base64url[(bits >> 18) & 0x3f]); result.push_back(base64url[(bits >> 12) & 0x3f]); if (padding <= 1) { result.push_back(base64url[(bits >> 6) & 0x3f]); } if (padding <= 0) { result.push_back(base64url[(bits >> 0) & 0x3f]); } bits = 0; bytes = 0; } } return result; } inline uint8 decode_base64url_bits(mpt::uchar c) { for (uint8 i = 0; i < 64; ++i) { if (base64url[i] == c) { return i; } } throw base64url_parse_error(); } inline std::vector decode_base64url(const mpt::ustring & src) { std::vector result; result.reserve(3 * ((src.length() + 2) / 4)); uint32 bits = 0; std::size_t chars = 0; for (mpt::uchar c : src) { bits <<= 6; bits |= decode_base64url_bits(c); chars++; if (chars == 4) { result.push_back(mpt::byte_cast(static_cast((bits >> 16) & 0xff))); result.push_back(mpt::byte_cast(static_cast((bits >> 8) & 0xff))); result.push_back(mpt::byte_cast(static_cast((bits >> 0) & 0xff))); bits = 0; chars = 0; } } uint32 padding = 0; if (chars != 0 && chars < 2) { throw base64url_parse_error(); } while (chars != 0) { bits <<= 6; padding++; chars++; if (chars == 4) { result.push_back(mpt::byte_cast(static_cast((bits >> 16) & 0xff))); if (padding < 2) { result.push_back(mpt::byte_cast(static_cast((bits >> 8) & 0xff))); } if (padding < 1) { result.push_back(mpt::byte_cast(static_cast((bits >> 0) & 0xff))); } bits = 0; chars = 0; padding = 0; } } return result; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BINARY_BASE64URL_HPP libopenmpt-0.8.1+release.autotools/src/mpt/binary/tests/0000755000175000017500000000000015023302361020346 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/binary/tests/tests_binary.hpp0000644000175000017500000001310214364574534023526 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TESTS_BINARY_HPP #define MPT_BASE_TESTS_BINARY_HPP #include "mpt/base/alloc.hpp" #include "mpt/base/detect_compiler.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/span.hpp" #include "mpt/binary/base64.hpp" #include "mpt/binary/base64url.hpp" #include "mpt/string/types.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace binary { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/binary") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { { std::string expecteds = std::string("pleasure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(mpt::encode_base64(mpt::as_span(expected)), MPT_USTRING("cGxlYXN1cmUu")); } { std::string expecteds = std::string("leasure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(mpt::encode_base64(mpt::as_span(expected)), MPT_USTRING("bGVhc3VyZS4=")); } { std::string expecteds = std::string("easure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(mpt::encode_base64(mpt::as_span(expected)), MPT_USTRING("ZWFzdXJlLg==")); } { std::string expecteds = std::string("pleasure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(expected, mpt::decode_base64(MPT_USTRING("cGxlYXN1cmUu"))); } { std::string expecteds = std::string("leasure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(expected, mpt::decode_base64(MPT_USTRING("bGVhc3VyZS4="))); } { std::string expecteds = std::string("easure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(expected, mpt::decode_base64(MPT_USTRING("ZWFzdXJlLg=="))); } { std::string expecteds = std::string("pleasure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(mpt::encode_base64url(mpt::as_span(expected)), MPT_USTRING("cGxlYXN1cmUu")); } { std::string expecteds = std::string("leasure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(mpt::encode_base64url(mpt::as_span(expected)), MPT_USTRING("bGVhc3VyZS4")); } { std::string expecteds = std::string("easure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(mpt::encode_base64url(mpt::as_span(expected)), MPT_USTRING("ZWFzdXJlLg")); } { std::string expecteds = std::string("pleasure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(expected, mpt::decode_base64url(MPT_USTRING("cGxlYXN1cmUu"))); } { std::string expecteds = std::string("leasure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(expected, mpt::decode_base64url(MPT_USTRING("bGVhc3VyZS4"))); } { std::string expecteds = std::string("easure."); std::vector expected(mpt::byte_cast(mpt::as_span(expecteds)).data(), mpt::byte_cast(mpt::as_span(expecteds)).data() + mpt::byte_cast(mpt::as_span(expecteds)).size()); MPT_TEST_EXPECT_EQUAL(expected, mpt::decode_base64url(MPT_USTRING("ZWFzdXJlLg"))); } } } // namespace binary } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TESTS_BINARY_HPP libopenmpt-0.8.1+release.autotools/src/mpt/LICENSE.BSL-1.0.txt0000644000175000017500000000247214044173026020411 00000000000000Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. libopenmpt-0.8.1+release.autotools/src/mpt/io_file_unique/0000755000175000017500000000000015023302361020714 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/io_file_unique/unique_basename.hpp0000644000175000017500000000353214664604252024527 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_FILE_UNIQUE_UNIQUE_BASENAME_HPP #define MPT_IO_FILE_UNIQUE_UNIQUE_BASENAME_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/path/os_path.hpp" #include "mpt/random/default_engines.hpp" #include "mpt/random/device.hpp" #include "mpt/random/seed.hpp" #include "mpt/string_transcode/transcode.hpp" #include "mpt/uuid/uuid.hpp" namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class unique_basename { private: mpt::os_path m_Basename; private: static mpt::good_engine make_prng() { mpt::sane_random_device rd; return mpt::make_prng(rd); } static mpt::UUID make_uuid() { mpt::good_engine rng = make_prng(); return mpt::UUID::Generate(rng); } public: explicit unique_basename(mpt::UUID uuid) : m_Basename(mpt::transcode(uuid.ToUString())) { return; } explicit unique_basename(const mpt::os_path & prefix, mpt::UUID uuid) : m_Basename((prefix.empty() ? prefix : prefix + MPT_OS_PATH("-")) + mpt::transcode(uuid.ToUString())) { return; } template explicit unique_basename(Trng & rng) : m_Basename(mpt::transcode(mpt::UUID::Generate(rng).ToUString())) { return; } template explicit unique_basename(const mpt::os_path & prefix, Trng & rng) : m_Basename((prefix.empty() ? prefix : prefix + MPT_OS_PATH("-")) + mpt::transcode(mpt::UUID::Generate(rng).ToUString())) { return; } explicit unique_basename() : m_Basename(mpt::transcode(make_uuid().ToUString())) { return; } public: operator mpt::os_path() const { return m_Basename; } }; // class unique_basename } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_FILE_UNIQUE_UNIQUE_BASENAME_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_file_unique/unique_tempfilename.hpp0000644000175000017500000000210314344404261025404 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_FILE_UNIQUE_UNIQUE_TEMPFILENAME_HPP #define MPT_IO_FILE_UNIQUE_UNIQUE_TEMPFILENAME_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/io_file_unique/unique_basename.hpp" #include "mpt/fs/common_directories.hpp" #include "mpt/fs/fs.hpp" #include "mpt/path/native_path.hpp" #include "mpt/path/os_path.hpp" namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class unique_tempfilename { private: mpt::os_path m_Filename; public: unique_tempfilename(const unique_basename & basename, const mpt::os_path & extension = MPT_OS_PATH("tmp")) : m_Filename(mpt::common_directories::get_temp_directory().WithTrailingSlash() + static_cast(basename) + (extension.empty() ? extension : MPT_OS_PATH(".") + extension)) { return; } public: operator mpt::os_path() const { return m_Filename; } }; // class unique_tempfilename } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_FILE_UNIQUE_UNIQUE_TEMPFILENAME_HPP libopenmpt-0.8.1+release.autotools/src/mpt/audio/0000755000175000017500000000000015023302361017021 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/audio/span.hpp0000644000175000017500000003162414250360612020425 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_AUDIO_SPAN_HPP #define MPT_AUDIO_SPAN_HPP #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { // LRLRLRLRLR template struct audio_span_interleaved { public: using sample_type = SampleType; private: sample_type * const m_buffer; std::size_t m_channels; std::size_t m_frames; public: MPT_CONSTEXPRINLINE audio_span_interleaved(sample_type * buffer, std::size_t channels, std::size_t frames) noexcept : m_buffer(buffer) , m_channels(channels) , m_frames(frames) { return; } MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { return nullptr; } MPT_FORCEINLINE sample_type * data() const noexcept { return m_buffer; } MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { return m_buffer[m_channels * frame + channel]; } MPT_FORCEINLINE bool is_contiguous() const noexcept { return true; } MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { return false; } MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { return true; } MPT_FORCEINLINE std::size_t size_channels() const noexcept { return m_channels; } MPT_FORCEINLINE std::size_t size_frames() const noexcept { return m_frames; } MPT_FORCEINLINE std::size_t size_samples() const noexcept { return m_channels * m_frames; } MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { return m_channels; } }; struct audio_span_frames_are_contiguous_t { }; inline constexpr audio_span_frames_are_contiguous_t audio_span_frames_are_contiguous; // LLLLLRRRRR template struct audio_span_contiguous { public: using sample_type = SampleType; private: sample_type * const m_buffer; std::size_t m_channels; std::size_t m_frames; public: MPT_CONSTEXPRINLINE audio_span_contiguous(sample_type * buffer, std::size_t channels, std::size_t frames) noexcept : m_buffer(buffer) , m_channels(channels) , m_frames(frames) { return; } MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { return nullptr; } MPT_FORCEINLINE sample_type * data() const noexcept { return m_buffer; } MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { return m_buffer[(m_frames * channel) + frame]; } MPT_FORCEINLINE bool is_contiguous() const noexcept { return true; } MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { return true; } MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { return false; } MPT_FORCEINLINE std::size_t size_channels() const noexcept { return m_channels; } MPT_FORCEINLINE std::size_t size_frames() const noexcept { return m_frames; } MPT_FORCEINLINE std::size_t size_samples() const noexcept { return m_channels * m_frames; } MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { return 1; } }; struct audio_span_channels_are_contiguous_t { }; inline constexpr audio_span_channels_are_contiguous_t audio_span_channels_are_contiguous; // LLLLL RRRRR template struct audio_span_planar { public: using sample_type = SampleType; private: sample_type * const * m_buffers; std::size_t m_channels; std::size_t m_frames; public: MPT_CONSTEXPRINLINE audio_span_planar(sample_type * const * buffers, std::size_t channels, std::size_t frames) noexcept : m_buffers(buffers) , m_channels(channels) , m_frames(frames) { return; } MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { return m_buffers; } MPT_FORCEINLINE sample_type * data() const noexcept { return nullptr; } MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { return m_buffers[channel][frame]; } MPT_FORCEINLINE bool is_contiguous() const noexcept { return false; } MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { return true; } MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { return false; } MPT_FORCEINLINE std::size_t size_channels() const noexcept { return m_channels; } MPT_FORCEINLINE std::size_t size_frames() const noexcept { return m_frames; } MPT_FORCEINLINE std::size_t size_samples() const noexcept { return m_channels * m_frames; } MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { return 1; } }; struct audio_span_channels_are_planar_t { }; inline constexpr audio_span_channels_are_planar_t audio_span_channels_are_planar; // LxxxLxxxLxxxLxxxLxxx xRxxxRxxxRxxxRxxxRxx template struct audio_span_planar_strided { public: using sample_type = SampleType; private: sample_type * const * m_buffers; std::ptrdiff_t m_frame_stride; std::size_t m_channels; std::size_t m_frames; public: MPT_CONSTEXPRINLINE audio_span_planar_strided(sample_type * const * buffers, std::size_t channels, std::size_t frames, std::ptrdiff_t frame_stride) noexcept : m_buffers(buffers) , m_frame_stride(frame_stride) , m_channels(channels) , m_frames(frames) { return; } MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { return m_buffers; } MPT_FORCEINLINE sample_type * data() const noexcept { return nullptr; } MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { return m_buffers[channel][static_cast(frame) * m_frame_stride]; } MPT_FORCEINLINE bool is_contiguous() const noexcept { return false; } MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { return false; } MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { return false; } MPT_FORCEINLINE std::size_t size_channels() const noexcept { return m_channels; } MPT_FORCEINLINE std::size_t size_frames() const noexcept { return m_frames; } MPT_FORCEINLINE std::size_t size_samples() const noexcept { return m_channels * m_frames; } MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { return m_frame_stride; } }; struct audio_span_channels_are_planar_and_strided_t { }; inline constexpr audio_span_channels_are_planar_and_strided_t audio_span_channels_are_planar_and_strided; template struct audio_span { public: using sample_type = SampleType; private: union { sample_type * const contiguous; sample_type * const * const planes; } m_buffer; std::ptrdiff_t m_frame_stride; std::ptrdiff_t m_channel_stride; std::size_t m_channels; std::size_t m_frames; public: MPT_CONSTEXPRINLINE audio_span(audio_span_interleaved buffer) noexcept : m_frame_stride(static_cast(buffer.size_channels())) , m_channel_stride(1) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.contiguous = buffer.data(); } MPT_CONSTEXPRINLINE audio_span(sample_type * buffer, std::size_t channels, std::size_t frames, audio_span_frames_are_contiguous_t) noexcept : m_frame_stride(static_cast(channels)) , m_channel_stride(1) , m_channels(channels) , m_frames(frames) { m_buffer.contiguous = buffer; } MPT_CONSTEXPRINLINE audio_span(audio_span_contiguous buffer) noexcept : m_frame_stride(1) , m_channel_stride(buffer.size_frames()) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.contiguous = buffer.data(); } MPT_CONSTEXPRINLINE audio_span(sample_type * buffer, std::size_t channels, std::size_t frames, audio_span_channels_are_contiguous_t) noexcept : m_frame_stride(1) , m_channel_stride(static_cast(frames)) , m_channels(channels) , m_frames(frames) { m_buffer.contiguous = buffer; } MPT_CONSTEXPRINLINE audio_span(audio_span_planar buffer) noexcept : m_frame_stride(1) , m_channel_stride(0) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.planes = buffer.data_planar(); } MPT_CONSTEXPRINLINE audio_span(sample_type * const * planes, std::size_t channels, std::size_t frames, audio_span_channels_are_planar_t) noexcept : m_frame_stride(1) , m_channel_stride(0) , m_channels(channels) , m_frames(frames) { m_buffer.planes = planes; } MPT_CONSTEXPRINLINE audio_span(audio_span_planar_strided buffer) noexcept : m_frame_stride(static_cast(buffer.frame_stride())) , m_channel_stride(0) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.planes = buffer.data_planar(); } MPT_CONSTEXPRINLINE audio_span(sample_type * const * planes, std::size_t channels, std::size_t frames, std::ptrdiff_t frame_stride, audio_span_channels_are_planar_and_strided_t) noexcept : m_frame_stride(frame_stride) , m_channel_stride(0) , m_channels(channels) , m_frames(frames) { m_buffer.planes = planes; } MPT_FORCEINLINE bool is_contiguous() const noexcept { return (m_channel_stride != 0); } MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { return (!is_contiguous()) ? m_buffer.planes : nullptr; } MPT_FORCEINLINE sample_type * data() const noexcept { return is_contiguous() ? m_buffer.contiguous : nullptr; } MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { return is_contiguous() ? m_buffer.contiguous[(m_channel_stride * static_cast(channel)) + (m_frame_stride * static_cast(frame))] : m_buffer.planes[channel][frame * static_cast(m_frame_stride)]; } MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { return (m_frame_stride == 1); } MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { return (m_channel_stride == 1); } MPT_FORCEINLINE std::size_t size_channels() const noexcept { return m_channels; } MPT_FORCEINLINE std::size_t size_frames() const noexcept { return m_frames; } MPT_FORCEINLINE std::size_t size_samples() const noexcept { return m_channels * m_frames; } MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { return m_frame_stride; } }; template struct audio_span_with_offset { public: using sample_type = typename Taudio_span::sample_type; private: Taudio_span m_buffer; std::size_t m_offset; public: MPT_CONSTEXPRINLINE audio_span_with_offset(Taudio_span buffer, std::size_t offsetFrames) noexcept : m_buffer(buffer) , m_offset(offsetFrames) { return; } MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { return nullptr; } MPT_FORCEINLINE sample_type * data() const noexcept { if (!is_contiguous()) { return nullptr; } return m_buffer.data() + (size_channels() * m_offset); } MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { return m_buffer(channel, m_offset + frame); } MPT_FORCEINLINE bool is_contiguous() const noexcept { return m_buffer.is_contiguous() && m_buffer.frames_are_contiguous(); } MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { return m_buffer.channels_are_contiguous(); } MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { return m_buffer.frames_are_contiguous(); } MPT_FORCEINLINE std::size_t size_channels() const noexcept { return m_buffer.size_channels(); } MPT_FORCEINLINE std::size_t size_frames() const noexcept { return m_buffer.size_frames() - m_offset; } MPT_FORCEINLINE std::size_t size_samples() const noexcept { return size_channels() * size_frames(); } MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { return m_buffer.frame_stride(); } }; template MPT_FORCEINLINE auto audio_span_optimized_visit(Tspan span, Tfunc && f) -> decltype(std::forward(f)(span)) const { using sample_type = typename Tspan::sample_type; std::variant, audio_span_contiguous, audio_span_planar, audio_span_planar_strided> v{span}; if (span.data() && span.is_contiguous() && span.frames_are_contiguous()) { v = audio_span_interleaved{span.data(), span.size_channels(), span.size_frames()}; } else if (span.data() && span.is_contiguous() && span.channels_are_contiguous()) { v = audio_span_contiguous{span.data(), span.size_channels(), span.size_frames()}; } else if (span.data_planar() && span.channels_are_contiguous()) { v = audio_span_planar{span.data_planar(), span.size_channels(), span.size_frames()}; } else if (span.data_planar()) { v = audio_span_planar_strided{span.data_planar(), span.size_channels(), span.size_frames(), span.frame_stride()}; } return std::visit(std::forward(f), v); } template inline audio_span_with_offset make_audio_span_with_offset(BufferType buf, std::size_t offsetFrames) noexcept { assert(offsetFrames <= buf.size_frames()); return audio_span_with_offset{buf, offsetFrames}; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_AUDIO_SPAN_HPP libopenmpt-0.8.1+release.autotools/src/mpt/audio/sample.hpp0000644000175000017500000000112714657607003020751 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_AUDIO_SAMPLE_HPP #define MPT_AUDIO_SAMPLE_HPP #include "mpt/base/float.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { using audio_sample_int = int16; using audio_sample_float = nativefloat; using audio_sample = std::conditional::is_hard, audio_sample_float, audio_sample_int>::type; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BINARY_HEX_HPP libopenmpt-0.8.1+release.autotools/src/mpt/exception/0000755000175000017500000000000015023302361017716 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/exception/runtime_error.hpp0000644000175000017500000000071314406300415023246 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_EXCEPTION_RUNTIME_ERROR_HPP #define MPT_EXCEPTION_RUNTIME_ERROR_HPP #include "mpt/base/namespace.hpp" #include "mpt/exception/exception.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { using runtime_error = mpt::exception_ustring_wrapper; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_EXCEPTION_RUNTIME_ERROR_HPP libopenmpt-0.8.1+release.autotools/src/mpt/exception/exception.hpp0000644000175000017500000000175514406300415022357 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_EXCEPTION_EXCEPTION_HPP #define MPT_EXCEPTION_EXCEPTION_HPP #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" namespace mpt { inline namespace MPT_INLINE_NS { class exception_ustring_wrapper_base { protected: exception_ustring_wrapper_base() = default; virtual ~exception_ustring_wrapper_base() = default; public: virtual mpt::ustring uwhat() const = 0; }; template class exception_ustring_wrapper : public T , public virtual mpt::exception_ustring_wrapper_base { private: mpt::ustring m_what; public: exception_ustring_wrapper(mpt::ustring str) : T(mpt::transcode(mpt::exception_encoding, str)) , m_what(str) { return; } ~exception_ustring_wrapper() override = default; mpt::ustring uwhat() const override { return m_what; } }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_EXCEPTION_EXCEPTION_HPP libopenmpt-0.8.1+release.autotools/src/mpt/exception/logic_error.hpp0000644000175000017500000000070114406300415022655 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_EXCEPTION_LOGIC_ERROR_HPP #define MPT_EXCEPTION_LOGIC_ERROR_HPP #include "mpt/base/namespace.hpp" #include "mpt/exception/exception.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { using logic_error = mpt::exception_ustring_wrapper; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_EXCEPTION_LOGIC_ERROR_HPP libopenmpt-0.8.1+release.autotools/src/mpt/exception/exception_text.hpp0000644000175000017500000000443714406300415023423 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_EXCEPTION_EXCEPTION_TEXT_HPP #define MPT_EXCEPTION_EXCEPTION_TEXT_HPP #include "mpt/base/namespace.hpp" #include "mpt/exception/exception.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { template inline Tstring get_exception_text(const std::exception & e) { if (const mpt::exception_ustring_wrapper_base * pue = dynamic_cast(&e)) { const mpt::exception_ustring_wrapper_base & ue = *pue; mpt::ustring what = ue.uwhat(); if (what.length() > 0) { return mpt::transcode(std::move(what)); } else if (typeid(ue).name() && (std::strlen(typeid(ue).name()) > 0)) { return mpt::transcode(mpt::source_string{typeid(ue).name()}); } else { return mpt::transcode(mpt::source_string{"unknown exception name"}); } } else if (e.what() && (std::strlen(e.what()) > 0)) { return mpt::transcode(mpt::exception_string{e.what()}); } else if (typeid(e).name() && (std::strlen(typeid(e).name()) > 0)) { return mpt::transcode(mpt::source_string{typeid(e).name()}); } else { return mpt::transcode(mpt::source_string{"unknown exception name"}); } } template <> inline std::string get_exception_text(const std::exception & e) { if (e.what() && (std::strlen(e.what()) > 0)) { return std::string{e.what()}; } else if (typeid(e).name() && (std::strlen(typeid(e).name()) > 0)) { return std::string{typeid(e).name()}; } else { return std::string{"unknown exception name"}; } } template inline Tstring get_current_exception_text() { try { throw; } catch (const std::exception & e) { return mpt::get_exception_text(e); } catch (...) { return mpt::transcode(mpt::source_string{"unknown exception"}); } } template <> inline std::string get_current_exception_text() { try { throw; } catch (const std::exception & e) { return mpt::get_exception_text(e); } catch (...) { return std::string{"unknown exception"}; } } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_EXCEPTION_EXCEPTION_TEXT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_file_read/0000755000175000017500000000000015023302361020321 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/io_file_read/inputfile_filecursor.hpp0000644000175000017500000000442014344404261025215 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_FILE_READ_INPUTFILE_FILECURSOR_HPP #define MPT_IO_FILE_READ_INPUTFILE_FILECURSOR_HPP #include "mpt/base/namespace.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/io_file/inputfile.hpp" #include "mpt/io_read/filecursor_filename_traits.hpp" #include "mpt/io_read/filecursor_memory.hpp" #include "mpt/io_read/filecursor_stdstream.hpp" #include "mpt/io_read/filecursor_traits_filedata.hpp" #include "mpt/io_read/filedata_memory.hpp" #include "mpt/io_read/filedata_stdstream.hpp" namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { // templated in order to reduce header inter-dependencies template inline FileCursor> make_FileCursor(UncachedInputFile & file) { if (!file.IsValid()) { return FileCursor>(); } return mpt::IO::make_FileCursor(file.GetStream(), std::make_shared(file.GetFilename())); } // templated in order to reduce header inter-dependencies template inline FileCursor> make_FileCursor(CachedInputFile & file) { if (!file.IsValid()) { return FileCursor>(); } if (file.IsCached()) { return mpt::IO::make_FileCursor(file.GetCache(), std::make_shared(file.GetFilename())); } else { return mpt::IO::make_FileCursor(file.GetStream(), std::make_shared(file.GetFilename())); } } // templated in order to reduce header inter-dependencies template inline FileCursor> make_FileCursor(InputFile & file) { if (!file.IsValid()) { return FileCursor>(); } if (file.IsCached()) { return mpt::IO::make_FileCursor(file.GetCache(), std::make_shared(file.GetFilename())); } else { return mpt::IO::make_FileCursor(file.GetStream(), std::make_shared(file.GetFilename())); } } } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_FILE_READ_INPUTFILE_FILECURSOR_HPP libopenmpt-0.8.1+release.autotools/src/mpt/main/0000755000175000017500000000000015023302361016644 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/main/main.hpp0000644000175000017500000001006014674746472020250 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_MAIN_MAIN_HPP #define MPT_MAIN_MAIN_HPP #include "mpt/base/check_platform.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include #include #if MPT_OS_DJGPP #include #endif // MPT_OS_DJGPP #if MPT_OS_DJGPP #include #endif // MPT_OS_DJGPP #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { namespace main { #if MPT_OS_DJGPP /* Work-around */ /* clang-format off */ #define MPT_MAIN_PREFIX \ extern "C" { \ int _crt0_startup_flags = 0 \ | _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */ \ | _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */ \ | _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */ \ | 0; \ } \ /* clang-format on */ #endif /* MPT_OS_DJGPP */ #if !defined(MPT_MAIN_PREFIX) #define MPT_MAIN_PREFIX #endif #if MPT_OS_WINDOWS && defined(UNICODE) #define MPT_MAIN_NAME wmain #elif defined(MPT_OS_WINDOWS) #define MPT_MAIN_NAME main #endif #if !defined(MPT_MAIN_NAME) #define MPT_MAIN_NAME main #endif #if MPT_OS_WINDOWS && defined(UNICODE) #define MPT_MAIN_ARGV_TYPE wchar_t #elif defined(MPT_OS_WINDOWS) #define MPT_MAIN_ARGV_TYPE char #endif #if !defined(MPT_MAIN_NAME) #define MPT_MAIN_ARGV_TYPE char #endif #if MPT_OS_WINDOWS && (MPT_COMPILER_GCC || MPT_COMPILER_CLANG) #if defined(UNICODE) // mingw64 does only default to special C linkage for "main", but not for "wmain". #define MPT_MAIN_DECL extern "C" int wmain(int argc, wchar_t * argv[]); #endif #endif #if !defined(MPT_MAIN_DECL) #define MPT_MAIN_DECL #endif #if MPT_OS_DJGPP /* clang-format off */ #define MPT_MAIN_PROLOG() \ do { \ assert(mpt::platform::libc().is_ok()); \ _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; \ } while (0) \ /**/ /* clang-format on */ #endif // MPT_OS_DJGPP #if !defined(MPT_MAIN_PROLOG) /* clang-format off */ #define MPT_MAIN_PROLOG() do { } while(0) /* clang-format on */ #endif #if MPT_OS_WINDOWS && (MPT_COMPILER_GCC || MPT_COMPILER_CLANG) #if defined(UNICODE) #define MPT_MAIN_DEF_PREFIX extern "C" #endif #endif // MPT_OS_WINDOWS && (MPT_COMPILER_GCC || MPT_COMPILER_CLANG) #if !defined(MPT_MAIN_DEF_PREFIX) #define MPT_MAIN_DEF_PREFIX #endif inline mpt::ustring transcode_arg(char * arg) { return mpt::transcode(mpt::logical_encoding::locale, arg); } #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) inline mpt::ustring transcode_arg(wchar_t * arg) { return mpt::transcode(arg); } #endif template inline std::vector transcode_argv(int argc, Tchar * argv[]) { std::vector args; args.reserve(argc); for (int arg = 0; arg < argc; ++arg) { args.push_back(transcode_arg(argv[arg])); } return args; } #if !defined(MPT_MAIN_POSTFIX) #define MPT_MAIN_POSTFIX #endif /* clang-format off */ #define MPT_MAIN_IMPLEMENT_MAIN(ns) \ MPT_MAIN_PREFIX \ MPT_MAIN_DECL \ MPT_MAIN_DEF_PREFIX int MPT_MAIN_NAME(int argc, MPT_MAIN_ARGV_TYPE * argv[]) { \ MPT_MAIN_PROLOG(); \ static_assert(std::is_same)>::value); \ return static_cast(ns::main(mpt::main::transcode_argv(argc, argv))); \ } \ MPT_MAIN_POSTFIX \ /**/ /* clang-format on */ /* clang-format off */ #define MPT_MAIN_IMPLEMENT_MAIN_NO_ARGS(ns) \ MPT_MAIN_PREFIX \ MPT_MAIN_DECL \ MPT_MAIN_DEF_PREFIX int MPT_MAIN_NAME(int argc, MPT_MAIN_ARGV_TYPE * argv[]) { \ MPT_MAIN_PROLOG(); \ static_assert(std::is_same::value); \ MPT_UNUSED(argc); \ MPT_UNUSED(argv); \ return static_cast(ns::main()); \ } \ MPT_MAIN_POSTFIX \ /**/ /* clang-format on */ } // namespace main } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_MAIN_MAIN_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_file_adapter/0000755000175000017500000000000015023302361021026 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/io_file_adapter/fileadapter.hpp0000644000175000017500000001113414733325141023747 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_FILE_ADAPTER_FILEADAPTER_HPP #define MPT_IO_FILE_ADAPTER_FILEADAPTER_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/io/base.hpp" #if !MPT_OS_WINDOWS #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/io_file/fstream.hpp" #endif // !MPT_OS_WINDOWS #include "mpt/io_file_unique/unique_basename.hpp" #include "mpt/io_file_unique/unique_tempfilename.hpp" #if MPT_OS_WINDOWS #include "mpt/path/os_path.hpp" #endif // MPT_OS_WINDOWS #include "mpt/string_transcode/transcode.hpp" #if MPT_OS_WINDOWS #include "mpt/system_error/system_error.hpp" #endif // MPT_OS_WINDOWS #include #if !MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS #include #if !MPT_OS_WINDOWS #include #endif // !MPT_OS_WINDOWS #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS #if MPT_OS_WINDOWS #if MPT_OS_WINDOWS_WINRT #if MPT_WINRT_AT_LEAST(MPT_WIN_8) #define MPT_IO_FILE_ONDISKFILEWRAPPER_USE_CREATEFILE #endif #else // !MPT_OS_WINDOWS_WINRT #define MPT_IO_FILE_ONDISKFILEWRAPPER_USE_CREATEFILE #endif // MPT_OS_WINDOWS_WINRT #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { template class FileAdapter { private: mpt::os_path m_Filename; bool m_IsTempFile; public: FileAdapter(TFileCursor & file, const mpt::os_path & tempName = unique_tempfilename{unique_basename{}, MPT_OS_PATH("tmp")}) : m_IsTempFile(false) { try { file.Rewind(); if (!file.GetOptionalFileName()) { #ifdef MPT_IO_FILE_ONDISKFILEWRAPPER_USE_CREATEFILE HANDLE hFile = NULL; #if MPT_OS_WINDOWS_WINRT hFile = mpt::windows::CheckFileHANDLE(CreateFile2(mpt::support_long_path(tempName).c_str(), GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, NULL)); #else hFile = mpt::windows::CheckFileHANDLE(CreateFile(mpt::support_long_path(tempName).c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL)); #endif while (!file.EndOfFile()) { typename TFileCursor::PinnedView view = file.ReadPinnedView(mpt::IO::BUFFERSIZE_NORMAL); std::size_t towrite = view.size(); std::size_t written = 0; do { DWORD chunkSize = mpt::saturate_cast(towrite); DWORD chunkDone = 0; try { mpt::windows::CheckBOOL(WriteFile(hFile, view.data() + written, chunkSize, &chunkDone, NULL)); } catch (...) { CloseHandle(hFile); hFile = NULL; throw; } if (chunkDone != chunkSize) { CloseHandle(hFile); hFile = NULL; throw std::runtime_error("Incomplete WriteFile()."); } towrite -= chunkDone; written += chunkDone; } while (towrite > 0); } CloseHandle(hFile); hFile = NULL; #else // !MPT_IO_FILE_ONDISKFILEWRAPPER_USE_CREATEFILE mpt::IO::ofstream f(tempName, std::ios::binary); if (!f) { throw std::runtime_error("Error creating temporary file."); } while (!file.EndOfFile()) { typename TFileCursor::PinnedView view = file.ReadPinnedView(mpt::IO::BUFFERSIZE_NORMAL); std::size_t towrite = view.size(); std::size_t written = 0; do { std::size_t chunkSize = mpt::saturate_cast(towrite); bool chunkOk = false; chunkOk = mpt::IO::WriteRaw(f, mpt::const_byte_span(view.data() + written, chunkSize)); if (!chunkOk) { throw std::runtime_error("Incomplete Write."); } towrite -= chunkSize; written += chunkSize; } while (towrite > 0); } f.close(); #endif // MPT_ONDISKFILEWRAPPER_NO_CREATEFILE m_Filename = tempName; m_IsTempFile = true; } else { #if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE) m_Filename = *(file.GetOptionalFileName()); #else m_Filename = file.GetOptionalFileName().value(); #endif } } catch (const std::runtime_error &) { m_Filename = mpt::os_path{}; m_IsTempFile = false; } } ~FileAdapter() { if (m_IsTempFile) { #if MPT_OS_WINDOWS DeleteFile(m_Filename.c_str()); #else // !MPT_OS_WINDOWS std::remove(m_Filename.c_str()); //std::error_code ec{}; //std::filesystem::remove(mpt::transcode(m_Filename.AsNative()), ec); #endif // MPT_OS_WINDOWS m_IsTempFile = false; } m_Filename = mpt::os_path{}; } public: bool IsValid() const { return !m_Filename.empty(); } mpt::os_path GetFilename() const { return m_Filename; } }; // class FileAdapter } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_FILE_ADAPTER_FILEADAPTER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/detect/0000755000175000017500000000000015023302361017170 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/detect/mfc.hpp0000644000175000017500000000101714044247307020377 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_DETECT_MFC_HPP #define MPT_DETECT_MFC_HPP #include "mpt/base/compiletime_warning.hpp" #if defined(MPT_WITH_MFC) #if !defined(CPPCHECK) #if !__has_include() #error "MPT_WITH_MFC defined but not found." #endif #endif #if !MPT_COMPILER_GENERIC && !MPT_COMPILER_MSVC && !MPT_COMPILER_CLANG MPT_WARNING("Using MFC with unsupported compiler.") #endif #define MPT_DETECTED_MFC 1 #else #define MPT_DETECTED_MFC 0 #endif #endif // MPT_DETECT_MFC_HPP libopenmpt-0.8.1+release.autotools/src/mpt/detect/nlohmann_json.hpp0000644000175000017500000000113714044247307022500 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_DETECT_NLOHMANN_JSON_HPP #define MPT_DETECT_NLOHMANN_JSON_HPP #if defined(MPT_WITH_NLOHMANN_JSON) #if !defined(CPPCHECK) #if !__has_include() #error "MPT_WITH_NLOHMANN_JSON defined but not found." #endif #endif #define MPT_DETECTED_NLOHMANN_JSON 1 #else #if defined(CPPCHECK) #define MPT_DETECTED_NLOHMANN_JSON 1 #else #if __has_include() #define MPT_DETECTED_NLOHMANN_JSON 1 #else #define MPT_DETECTED_NLOHMANN_JSON 0 #endif #endif #endif #endif // MPT_DETECT_NLOHMANN_JSON_HPP libopenmpt-0.8.1+release.autotools/src/mpt/detect/dl.hpp0000644000175000017500000000101314047510526020224 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_DETECT_DL_HPP #define MPT_DETECT_DL_HPP #include "mpt/base/compiletime_warning.hpp" #if defined(MPT_WITH_DL) #if !defined(CPPCHECK) #if !__has_include() #error "MPT_WITH_DL defined but not found." #endif #endif #define MPT_DETECTED_DL 1 #else #if defined(CPPCHECK) #define MPT_DETECTED_DL 1 #else #if __has_include() #define MPT_DETECTED_DL 1 #else #define MPT_DETECTED_DL 0 #endif #endif #endif #endif // MPT_DETECT_DL_HPP libopenmpt-0.8.1+release.autotools/src/mpt/detect/ltdl.hpp0000644000175000017500000000103214047510526020565 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_DETECT_LTDL_HPP #define MPT_DETECT_LTDL_HPP #include "mpt/base/compiletime_warning.hpp" #if defined(MPT_WITH_LTDL) #if !defined(CPPCHECK) #if !__has_include() #error "MPT_WITH_LTDL defined but not found." #endif #endif #define MPT_DETECTED_LTDL 1 #else #if defined(CPPCHECK) #define MPT_DETECTED_LTDL 1 #else #if __has_include() #define MPT_DETECTED_LTDL 1 #else #define MPT_DETECTED_LTDL 0 #endif #endif #endif #endif // MPT_DETECT_LTDL_HPP libopenmpt-0.8.1+release.autotools/src/mpt/osinfo/0000755000175000017500000000000015023302361017215 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/osinfo/dos_memory.hpp0000644000175000017500000001440414223757270022044 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_OSINFO_DOS_MEMORY_HPP #define MPT_OSINFO_DOS_MEMORY_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #if MPT_OS_DJGPP #include "mpt/string/buffer.hpp" #endif // MPT_OS_DJGPP #if MPT_OS_DJGPP #include #include #include #include #endif // MPT_OS_DJGPP #if MPT_OS_DJGPP #include #endif // MPT_OS_DJGPP #if MPT_OS_DJGPP #include #endif // MPT_OS_DJGPP namespace mpt { inline namespace MPT_INLINE_NS { namespace osinfo { namespace dos { #if MPT_OS_DJGPP struct memory_info { std::optional total_virtual; std::optional free_virtual; std::optional free_contiguous_virtual; std::optional total_physical; std::optional free_physical; std::optional free_contiguous_physical; std::optional unlocked_physical; std::optional total_swap; inline std::optional get_virtual_total() const noexcept { if (!total_virtual) { if (total_physical && total_swap) { return *total_physical + *total_swap; } else if (total_physical) { return total_physical; } else { return std::nullopt; } } return total_virtual; } inline std::optional get_virtual_used() const noexcept { if (!get_virtual_total() || !get_virtual_free()) { return std::nullopt; } if (*get_virtual_total() < *get_virtual_free()) { return 0; } return *get_virtual_total() - *get_virtual_free(); } inline std::optional get_virtual_free() const noexcept { if (free_virtual) { return free_virtual; } else if (free_contiguous_virtual) { return free_contiguous_virtual; } else { return std::nullopt; } } inline std::optional get_virtual_external_fragmentation() const noexcept { if (!get_virtual_free() || !free_contiguous_virtual) { return std::nullopt; } if (*get_virtual_free() < *free_contiguous_virtual) { return 0; } return *get_virtual_free() - *free_contiguous_virtual; } inline std::optional get_virtual_free_contiguous() const noexcept { return free_contiguous_virtual; } inline std::optional get_physical_total() const noexcept { return total_physical; } inline std::optional get_physical_used() const noexcept { if (!total_physical || !get_physical_free()) { return std::nullopt; } if (*total_physical < *get_physical_free()) { return 0; } return *total_physical - *get_physical_free(); } inline std::optional get_physical_free() const noexcept { if (free_physical) { return free_physical; } else if (free_contiguous_physical) { return free_contiguous_physical; } else { return std::nullopt; } } inline std::optional get_physical_external_fragmentation() const noexcept { if (!get_physical_free() || !free_contiguous_physical) { return std::nullopt; } if (*get_physical_free() < *free_contiguous_physical) { return 0; } return *get_physical_free() - *free_contiguous_physical; } inline std::optional get_physical_free_contiguous() const noexcept { return free_contiguous_physical; } inline std::optional get_physical_used_locked() const noexcept { if (!total_physical || !unlocked_physical) { return std::nullopt; } if (*total_physical < *unlocked_physical) { return 0; } return *total_physical - *unlocked_physical; } inline std::optional get_physical_freeable() const noexcept { if (!unlocked_physical) { return get_physical_free(); } return unlocked_physical; } inline std::optional get_swap_total() const noexcept { return total_swap; } }; inline memory_info get_memory_info() { memory_info result; __dpmi_free_mem_info dpmi_free_mem_info{}; if (__dpmi_get_free_memory_information(&dpmi_free_mem_info) == 0) { unsigned long page_size = 0; if (__dpmi_get_page_size(&page_size) != 0) { page_size = 0; } if (dpmi_free_mem_info.largest_available_free_block_in_bytes != 0xffffffffu) { result.free_contiguous_virtual = dpmi_free_mem_info.largest_available_free_block_in_bytes; } else if ((dpmi_free_mem_info.maximum_unlocked_page_allocation_in_pages != 0xffffffffu) && (page_size > 0)) { result.free_contiguous_virtual = dpmi_free_mem_info.maximum_unlocked_page_allocation_in_pages * page_size; } if (page_size > 0) { if (dpmi_free_mem_info.maximum_locked_page_allocation_in_pages != 0xffffffffu) { result.free_contiguous_physical = dpmi_free_mem_info.maximum_locked_page_allocation_in_pages * page_size; } if (dpmi_free_mem_info.linear_address_space_size_in_pages != 0xffffffffu) { result.total_virtual = dpmi_free_mem_info.linear_address_space_size_in_pages * page_size; } if (dpmi_free_mem_info.total_number_of_unlocked_pages != 0xffffffffu) { result.unlocked_physical = dpmi_free_mem_info.total_number_of_unlocked_pages * page_size; int dpmi_flags = 0; std::array dpmi_vendor = {}; if (__dpmi_get_capabilities(&dpmi_flags, dpmi_vendor.data()) == 0) { char buf[126] = {}; std::memcpy(buf, dpmi_vendor.data() + 2, 126); // CWSDPMI does not track locked memory, thus all physical is reported unlocked if (std::string_view(mpt::ReadAutoBuf(buf)) == std::string_view("CWSDPMI")) { result.unlocked_physical = std::nullopt; } } } if (dpmi_free_mem_info.total_number_of_free_pages != 0xffffffffu) { result.free_physical = dpmi_free_mem_info.total_number_of_free_pages * page_size; } if (dpmi_free_mem_info.total_number_of_physical_pages != 0xffffffffu) { result.total_physical = dpmi_free_mem_info.total_number_of_physical_pages * page_size; } if (dpmi_free_mem_info.free_linear_address_space_in_pages != 0xffffffffu) { result.free_virtual = dpmi_free_mem_info.free_linear_address_space_in_pages * page_size; } if (dpmi_free_mem_info.size_of_paging_file_partition_in_pages != 0xffffffffu) { result.total_swap = dpmi_free_mem_info.size_of_paging_file_partition_in_pages * page_size; } } } return result; } #endif // MPT_OS_DJGPP } // namespace dos } // namespace osinfo } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_OSINFO_DOS_MEMORY_HPP libopenmpt-0.8.1+release.autotools/src/mpt/osinfo/class.hpp0000644000175000017500000000567414563661661021012 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_OSINFO_CLASS_HPP #define MPT_OSINFO_CLASS_HPP #include "mpt/base/detect_os.hpp" #include "mpt/base/namespace.hpp" #if !MPT_OS_WINDOWS #include "mpt/string/buffer.hpp" #endif // !MPT_OS_WINDOWS #include #if !MPT_OS_WINDOWS #include #endif // !MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { namespace osinfo { enum class osclass { Unknown, Windows, Linux, Darwin, BSD_, Haiku, DOS, }; inline mpt::osinfo::osclass get_class_from_sysname(const std::string & sysname) { mpt::osinfo::osclass result = mpt::osinfo::osclass::Unknown; if (sysname == "") { result = mpt::osinfo::osclass::Unknown; } else if (sysname == "Windows" || sysname == "WindowsNT" || sysname == "Windows_NT") { result = mpt::osinfo::osclass::Windows; } else if (sysname == "Linux") { result = mpt::osinfo::osclass::Linux; } else if (sysname == "Darwin") { result = mpt::osinfo::osclass::Darwin; } else if (sysname == "FreeBSD" || sysname == "DragonFly" || sysname == "NetBSD" || sysname == "OpenBSD" || sysname == "MidnightBSD") { result = mpt::osinfo::osclass::BSD_; } else if (sysname == "Haiku") { result = mpt::osinfo::osclass::Haiku; } else if (sysname == "IBMPcDos" || sysname == "CompqDOS" || sysname == "MsoftDOS" || sysname == "AT&T DOS" || sysname == "ZenitDOS" || sysname == "HP DOS" || sysname == "GrBulDOS" || sysname == "PBellDOS" || sysname == "DEC DOS" || sysname == "OlivtDOS" || sysname == "TI DOS" || sysname == "Toshiba" || sysname == "NWin3Dev" || sysname == "MSWinDev" || sysname == "RxDOS" || sysname == "PTS-DOS" || sysname == "GenSoft" || sysname == "DR-DOS" || sysname == "NovelDOS" || sysname == "FreeDOS" || sysname == "MS-DOS") { result = mpt::osinfo::osclass::DOS; } return result; } inline std::string get_sysname() { #if MPT_OS_WINDOWS return "Windows"; #else // !MPT_OS_WINDOWS utsname uname_result; if (uname(&uname_result) != 0) { return {}; } return mpt::ReadAutoBuf(uname_result.sysname); #endif // MPT_OS_WINDOWS } inline mpt::osinfo::osclass get_class() { #if MPT_OS_WINDOWS return mpt::osinfo::osclass::Windows; #else // !MPT_OS_WINDOWS return mpt::osinfo::get_class_from_sysname(mpt::osinfo::get_sysname()); #endif // MPT_OS_WINDOWS } inline std::string get_class_name(mpt::osinfo::osclass c) { std::string result; switch (c) { case mpt::osinfo::osclass::Unknown: result = "unknown"; break; case mpt::osinfo::osclass::Windows: result = "Windows"; break; case mpt::osinfo::osclass::Linux: result = "Linux"; break; case mpt::osinfo::osclass::Darwin: result = "Darwin"; break; case mpt::osinfo::osclass::BSD_: result = "BSD"; break; case mpt::osinfo::osclass::Haiku: result = "Haiku"; break; case mpt::osinfo::osclass::DOS: result = "DOS"; break; } return result; } } // namespace osinfo } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_OSINFO_CLASS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/osinfo/windows_wine_version.hpp0000644000175000017500000000612414264300426024140 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_OSINFO_WINDOWS_WINE_VERSION_HPP #define MPT_OSINFO_WINDOWS_WINE_VERSION_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/osinfo/windows_version.hpp" #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { namespace osinfo { namespace windows { inline bool current_is_wine() { bool result = false; #if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT bool hasKB2533623 = false; mpt::osinfo::windows::Version WindowsVersion = mpt::osinfo::windows::Version::Current(); if (WindowsVersion.IsAtLeast(mpt::osinfo::windows::Version::Win8)) { hasKB2533623 = true; } else if (WindowsVersion.IsAtLeast(mpt::osinfo::windows::Version::WinVista)) { HMODULE hKernel32DLL = ::LoadLibrary(TEXT("kernel32.dll")); if (hKernel32DLL) { if (::GetProcAddress(hKernel32DLL, "SetDefaultDllDirectories") != nullptr) { hasKB2533623 = true; } ::FreeLibrary(hKernel32DLL); hKernel32DLL = NULL; } } HMODULE hNTDLL = NULL; MPT_MAYBE_CONSTANT_IF (hasKB2533623) { #if defined(LOAD_LIBRARY_SEARCH_SYSTEM32) hNTDLL = ::LoadLibraryEx(TEXT("ntdll.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); #else hNTDLL = ::LoadLibraryEx(TEXT("ntdll.dll"), NULL, 0x00000800); #endif } else { hNTDLL = ::LoadLibrary(TEXT("ntdll.dll")); } if (hNTDLL) { result = (::GetProcAddress(hNTDLL, "wine_get_version") != NULL); ::FreeLibrary(hNTDLL); } #endif // MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT return result; } namespace wine { class version { protected: bool valid = false; uint8 vmajor = 0; uint8 vminor = 0; uint8 vupdate = 0; public: version() { return; } version(uint8 vmajor_, uint8 vminor_, uint8 vupdate_) : valid(true) , vmajor(vmajor_) , vminor(vminor_) , vupdate(vupdate_) { return; } public: bool IsValid() const { return valid; } private: static mpt::osinfo::windows::wine::version FromInteger(uint32 version) { mpt::osinfo::windows::wine::version result; result.valid = (version <= 0xffffff); result.vmajor = static_cast(version >> 16); result.vminor = static_cast(version >> 8); result.vupdate = static_cast(version >> 0); return result; } uint32 AsInteger() const { uint32 version = 0; version |= static_cast(vmajor) << 16; version |= static_cast(vminor) << 8; version |= static_cast(vupdate) << 0; return version; } public: bool IsBefore(mpt::osinfo::windows::wine::version other) const { if (!IsValid()) { return false; } return (AsInteger() < other.AsInteger()); } bool IsAtLeast(mpt::osinfo::windows::wine::version other) const { if (!IsValid()) { return false; } return (AsInteger() >= other.AsInteger()); } uint8 GetMajor() const { return vmajor; } uint8 GetMinor() const { return vminor; } uint8 GetUpdate() const { return vupdate; } }; } // namespace wine } // namespace windows } // namespace osinfo } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_OSINFO_WINDOWS_WINE_VERSION_HPP libopenmpt-0.8.1+release.autotools/src/mpt/osinfo/windows_version.hpp0000644000175000017500000003401714657446344023140 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_OSINFO_WINDOWS_VERSION_HPP #define MPT_OSINFO_WINDOWS_VERSION_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { namespace osinfo { namespace windows { class Version { public: enum Number : uint64 { WinNT4 = 0x0000000400000000ull, Win2000 = 0x0000000500000000ull, WinXP = 0x0000000500000001ull, WinXP64 = 0x0000000500000002ull, WinVista = 0x0000000600000000ull, Win7 = 0x0000000600000001ull, Win8 = 0x0000000600000002ull, Win81 = 0x0000000600000003ull, Win10Pre = 0x0000000600000004ull, Win10 = 0x0000000a00000000ull, WinNewer = Win10 + 1ull }; struct System { uint32 Major = 0; uint32 Minor = 0; constexpr System() noexcept : Major(0) , Minor(0) { } constexpr System(Number number) noexcept : Major(static_cast((static_cast(number) >> 32) & 0xffffffffu)) , Minor(static_cast((static_cast(number) >> 0) & 0xffffffffu)) { } explicit constexpr System(uint64 number) noexcept : Major(static_cast((number >> 32) & 0xffffffffu)) , Minor(static_cast((number >> 0) & 0xffffffffu)) { } explicit constexpr System(uint32 major, uint32 minor) noexcept : Major(major) , Minor(minor) { } constexpr operator uint64() const noexcept { return (static_cast(Major) << 32) | (static_cast(Minor) << 0); } }; struct ServicePack { uint16 Major = 0; uint16 Minor = 0; constexpr ServicePack() noexcept : Major(0) , Minor(0) { } explicit constexpr ServicePack(uint16 major, uint16 minor) noexcept : Major(major) , Minor(minor) { } constexpr bool HasServicePack() const noexcept { return Major != 0 || Minor != 0; } constexpr operator uint32() const noexcept { return (static_cast(Major) << 16) | (static_cast(Minor) << 0); } }; typedef uint32 Build; typedef uint32 TypeId; private: bool m_SystemIsWindows; System m_System; ServicePack m_ServicePack; Build m_Build; TypeId m_Type; private: constexpr Version() noexcept : m_SystemIsWindows(false) , m_System() , m_ServicePack() , m_Build() , m_Type() { } public: static constexpr Version NoWindows() noexcept { return Version(); } static constexpr Version AnyWindows() noexcept { Version result = Version(); result.m_SystemIsWindows = true; return result; } constexpr Version(mpt::osinfo::windows::Version::System system, mpt::osinfo::windows::Version::ServicePack servicePack, mpt::osinfo::windows::Version::Build build, mpt::osinfo::windows::Version::TypeId type) noexcept : m_SystemIsWindows(true) , m_System(system) , m_ServicePack(servicePack) , m_Build(build) , m_Type(type) { } public: #if MPT_OS_WINDOWS static mpt::osinfo::windows::Version FromSDK() noexcept { // Initialize to used SDK version #if MPT_WINNT_AT_LEAST(MPT_WIN_11_23H2) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 22631, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_11_22H2) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 22621, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_11) // 21H2 return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 22000, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_22H2) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19045, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_21H2) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19044, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_21H1) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19043, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_20H2) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19042, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_2004) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19041, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1909) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 18363, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1903) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 18362, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1809) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 17763, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1803) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 17134, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1709) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 16299, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1703) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 15063, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1607) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 14393, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1511) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 10586, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10) // 1507 return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 10240, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_PRE) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10Pre, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_81) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win81, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_8) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win8, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_7) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win7, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::WinVista, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_XP64) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::WinXP64, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_XP) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::WinXP, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_2000) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win2000, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_NT4) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::WinNT4, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); #else return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::System((static_cast(MPT_WIN_VERSION) & 0xff000000u) >> 24, (static_cast(MPT_WIN_VERSION) & 0x00ff0000u) >> 16), mpt::osinfo::windows::Version::ServicePack((static_cast(MPT_WIN_VERSION) & 0x0000ff00u) >> 8, (static_cast(MPT_WIN_VERSION) & 0x000000ffu) >> 0), 0, 0); #endif } static mpt::osinfo::windows::Version GatherWindowsVersion() noexcept { #if MPT_OS_WINDOWS_WINRT return mpt::osinfo::windows::Version::FromSDK(); #else // !MPT_OS_WINDOWS_WINRT OSVERSIONINFOEXW versioninfoex{}; versioninfoex.dwOSVersionInfoSize = sizeof(versioninfoex); #if MPT_COMPILER_MSVC #pragma warning(push) #pragma warning(disable : 4996) // 'GetVersionExW': was declared deprecated #pragma warning(disable : 28159) // Consider using 'IsWindows*' instead of 'GetVersionExW'. Reason: Deprecated. Use VerifyVersionInfo* or IsWindows* macros from VersionHelpers. #endif // MPT_COMPILER_MSVC #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif // MPT_COMPILER_CLANG if (GetVersionExW((LPOSVERSIONINFOW)&versioninfoex) == FALSE) { return mpt::osinfo::windows::Version::FromSDK(); } #if MPT_COMPILER_MSVC #pragma warning(pop) #endif // MPT_COMPILER_MSVC #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG if (versioninfoex.dwPlatformId != VER_PLATFORM_WIN32_NT) { return mpt::osinfo::windows::Version::FromSDK(); } DWORD dwProductType = 0; #if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) dwProductType = PRODUCT_UNDEFINED; if (GetProductInfo(versioninfoex.dwMajorVersion, versioninfoex.dwMinorVersion, versioninfoex.wServicePackMajor, versioninfoex.wServicePackMinor, &dwProductType) == FALSE) { dwProductType = PRODUCT_UNDEFINED; } #endif return mpt::osinfo::windows::Version( mpt::osinfo::windows::Version::System(versioninfoex.dwMajorVersion, versioninfoex.dwMinorVersion), mpt::osinfo::windows::Version::ServicePack(versioninfoex.wServicePackMajor, versioninfoex.wServicePackMinor), versioninfoex.dwBuildNumber, dwProductType); #endif // MPT_OS_WINDOWS_WINRT } #endif // MPT_OS_WINDOWS public: static inline mpt::osinfo::windows::Version Current() noexcept { #if MPT_OS_WINDOWS static mpt::osinfo::windows::Version s_cachedVersion = GatherWindowsVersion(); return s_cachedVersion; #else // !MPT_OS_WINDOWS return mpt::osinfo::windows::Version::NoWindows(); #endif // MPT_OS_WINDOWS } public: bool IsWindows() const noexcept { return m_SystemIsWindows; } bool IsBefore(mpt::osinfo::windows::Version::System version) const noexcept { if (!m_SystemIsWindows) { return false; } return m_System < version; } bool IsBefore(mpt::osinfo::windows::Version::System version, mpt::osinfo::windows::Version::ServicePack servicePack) const noexcept { if (!m_SystemIsWindows) { return false; } if (m_System > version) { return false; } if (m_System < version) { return true; } return m_ServicePack < servicePack; } bool IsBefore(mpt::osinfo::windows::Version::System version, mpt::osinfo::windows::Version::Build build) const noexcept { if (!m_SystemIsWindows) { return false; } if (m_System > version) { return false; } if (m_System < version) { return true; } return m_Build < build; } bool IsBefore(mpt::osinfo::windows::Version::System version, mpt::osinfo::windows::Version::ServicePack servicePack, mpt::osinfo::windows::Version::Build build) const noexcept { if (!m_SystemIsWindows) { return false; } if (m_System > version) { return false; } if (m_System < version) { return true; } if (m_ServicePack > servicePack) { return false; } if (m_ServicePack < servicePack) { return true; } return m_Build < build; } bool IsBefore(mpt::osinfo::windows::Version version) const noexcept { return IsBefore(version.GetSystem(), version.GetServicePack(), version.GetBuild()); } bool IsAtLeast(mpt::osinfo::windows::Version::System version) const noexcept { if (!m_SystemIsWindows) { return false; } return m_System >= version; } bool IsAtLeast(mpt::osinfo::windows::Version::System version, mpt::osinfo::windows::Version::ServicePack servicePack) const noexcept { if (!m_SystemIsWindows) { return false; } if (m_System < version) { return false; } if (m_System > version) { return true; } return m_ServicePack >= servicePack; } bool IsAtLeast(mpt::osinfo::windows::Version::System version, mpt::osinfo::windows::Version::Build build) const noexcept { if (!m_SystemIsWindows) { return false; } if (m_System < version) { return false; } if (m_System > version) { return true; } return m_Build >= build; } bool IsAtLeast(mpt::osinfo::windows::Version::System version, mpt::osinfo::windows::Version::ServicePack servicePack, mpt::osinfo::windows::Version::Build build) const noexcept { if (!m_SystemIsWindows) { return false; } if (m_System < version) { return false; } if (m_System > version) { return true; } if (m_ServicePack < servicePack) { return false; } if (m_ServicePack > servicePack) { return true; } return m_Build >= build; } bool IsAtLeast(mpt::osinfo::windows::Version version) const noexcept { return IsAtLeast(version.GetSystem(), version.GetServicePack(), version.GetBuild()); } mpt::osinfo::windows::Version::System GetSystem() const noexcept { return m_System; } mpt::osinfo::windows::Version::ServicePack GetServicePack() const noexcept { return m_ServicePack; } mpt::osinfo::windows::Version::Build GetBuild() const noexcept { return m_Build; } mpt::osinfo::windows::Version::TypeId GetTypeId() const noexcept { return m_Type; } }; // class Version } // namespace windows } // namespace osinfo } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_OSINFO_WINDOWS_VERSION_HPP libopenmpt-0.8.1+release.autotools/src/mpt/osinfo/dos_version.hpp0000644000175000017500000002151214223755715022221 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_OSINFO_DOS_VERSION_HPP #define MPT_OSINFO_DOS_VERSION_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/buffer.hpp" #include #if MPT_OS_DJGPP #include #include #include #include #include #endif // MPT_OS_DJGPP namespace mpt { inline namespace MPT_INLINE_NS { namespace osinfo { namespace dos { class Version { public: enum class Host { DOS, Win2, Win3, Win95, Win98, WinME, WinNT, OS2, OS2Warp, DOSEmu, }; struct System { uint8 Major = 0; uint8 Minor = 0; constexpr System() noexcept : Major(0) , Minor(0) { } explicit constexpr System(uint16 number) noexcept : Major(static_cast((number >> 8) & 0xffu)) , Minor(static_cast((number >> 0) & 0xffu)) { } explicit constexpr System(uint8 major, uint8 minor) noexcept : Major(major) , Minor(minor) { } constexpr operator uint16() const noexcept { return (static_cast(Major) << 8) | (static_cast(Minor) << 0); } }; struct DPMI { uint8 Major = 0; uint8 Minor = 0; constexpr DPMI() noexcept : Major(0) , Minor(0) { } explicit constexpr DPMI(uint8 major, uint8 minor) noexcept : Major(major) , Minor(minor) { } }; private: bool m_SystemIsDos = false; std::string m_OEM{}; System m_System; System m_SystemEmulated; DPMI m_DPMI; std::string m_DPMIVendor{}; DPMI m_DPMIHost; Host m_Host = Host::DOS; int m_HostVersion = 0; int m_HostRevision = 0; int m_HostPatch = 0; bool m_HostMultitasking = false; bool m_HostFixedTimer = false; std::string m_BIOSDate{}; private: Version() { return; } public: static Version NoDos() { return Version(); } Version(std::string oem, System version, System version_emulated, DPMI dpmi, std::string dpmi_vendor, DPMI dpmi_host, Host host, int host_version, int host_revision, int host_patch, bool multitasking, bool fixedtimer, std::string bios_date) : m_SystemIsDos(true) , m_OEM(oem) , m_System(version) , m_SystemEmulated(version_emulated) , m_DPMI(dpmi) , m_DPMIVendor(dpmi_vendor) , m_DPMIHost(dpmi_host) , m_Host(host) , m_HostVersion(host_version) , m_HostRevision(host_revision) , m_HostPatch(host_patch) , m_HostMultitasking(multitasking) , m_HostFixedTimer(fixedtimer) , m_BIOSDate(bios_date) { return; } public: #if MPT_OS_DJGPP static mpt::osinfo::dos::Version GatherDosVersion() { uint16 dos_version = _get_dos_version(0); uint16 dos_version_emulated = dos_version; if (dos_version >= 0x0500) { dos_version = _get_dos_version(1); } uint8 dpmi_version_major = 0; uint8 dpmi_version_minor = 0; __dpmi_version_ret dpmi_version{}; if (__dpmi_get_version(&dpmi_version) == 0) { dpmi_version_major = dpmi_version.major; dpmi_version_minor = dpmi_version.minor; } std::string dpmi_host_vendor; uint8 dpmi_host_major = 0; uint8 dpmi_host_minor = 0; /* if (dpmi_version_major >= 1) */ { int dpmi_flags = 0; std::array dpmi_vendor = {}; if (__dpmi_get_capabilities(&dpmi_flags, dpmi_vendor.data()) == 0) { char buf[126] = {}; std::memcpy(buf, dpmi_vendor.data() + 2, 126); dpmi_host_vendor = mpt::ReadAutoBuf(buf); dpmi_host_major = dpmi_vendor[0]; dpmi_host_minor = dpmi_vendor[1]; } } if (dpmi_host_vendor.empty()) { dpmi_host_vendor = "unknown"; } bool detected = false; Host host = Host::DOS; int host_version = 0; int host_revision = 0; int host_patch = 0; bool host_multitasking = false; bool host_fixedtimer = false; if (!detected) { char * os = std::getenv("OS"); if (os) { if (std::string(os) == std::string("Windows_NT")) { host = Host::WinNT; host_version = 0; host_revision = 0; host_patch = 0; host_multitasking = true; host_fixedtimer = true; detected = true; } } } if (!detected) { __dpmi_regs r{}; r.x.ax = 0x1600; __dpmi_int(0x2f, &r); if ((r.h.al == 0x01) || (r.h.al == 0xFF)) { host = Host::Win2; host_version = 2; host_revision = 0; host_patch = 0; host_multitasking = true; host_fixedtimer = true; detected = true; } else if ((r.h.al != 0x00) && (r.h.al != 0x01) && (r.h.al != 0x80) && (r.h.al != 0xFF)) { host_version = r.h.al; host_revision = r.h.ah; host_patch = 0; if (host_version > 4) { host = Host::WinME; } else if ((host_version == 4) && (host_revision >= 90)) { host = Host::WinME; } else if ((host_version == 4) && (host_revision >= 10)) { host = Host::Win98; } else if (host_version == 4) { host = Host::Win95; } else { host = Host::Win3; } host_multitasking = true; host_fixedtimer = true; detected = true; } } if (!detected) { __dpmi_regs r{}; r.x.ax = 0x4010; __dpmi_int(0x2f, &r); if (r.x.ax != 0x4010) { if (r.x.ax == 0x0000u) { host = Host::OS2Warp; } else { host = Host::OS2; } host_version = r.h.bh; host_revision = r.h.bl; host_patch = 0; host_multitasking = true; host_fixedtimer = true; detected = true; } } if (!detected) { char buf[9] = {}; for (uint32 i = 0; i < 8; ++i) { buf[i] = _farpeekb(_dos_ds, (0xF000u * 16) + (0xfff5u + i)); } buf[8] = '\0'; if (std::string(mpt::ReadAutoBuf(buf)) == std::string("02/25/93")) { __dpmi_regs r{}; r.x.ax = 0; __dpmi_int(0xe6, &r); if (r.x.ax == 0xaa55u) { host = Host::DOSEmu; host_version = r.h.bh; host_revision = r.h.bl; host_patch = r.x.cx; host_multitasking = true; host_fixedtimer = true; detected = true; } } } if (!detected) { __dpmi_regs r{}; r.x.ax = 0x3000; __dpmi_int(0x21, &r); host = Host::DOS; host_version = r.h.al; host_revision = r.h.ah; host_patch = 0; host_multitasking = false; host_fixedtimer = false; detected = true; } if (!host_multitasking) { errno = 0; __dpmi_yield(); if (errno == 0) { host_multitasking = true; } errno = 0; } std::string bios_date{}; { { char buf[8 + 1] = {}; for (uint32 i = 0; i < 8; ++i) { buf[i] = _farpeekb(_dos_ds, (0xf000u * 16) + (0xfff5u + i)); } bios_date = mpt::ReadAutoBuf(buf); } } return mpt::osinfo::dos::Version( _os_flavor, mpt::osinfo::dos::Version::System(dos_version), mpt::osinfo::dos::Version::System(dos_version_emulated), mpt::osinfo::dos::Version::DPMI(dpmi_version_major, dpmi_version_minor), dpmi_host_vendor, mpt::osinfo::dos::Version::DPMI(dpmi_host_major, dpmi_host_minor), host, host_version, host_revision, host_patch, host_multitasking, host_fixedtimer, bios_date); } #endif // MPT_OS_DJGPP public: static inline mpt::osinfo::dos::Version Current() { #if MPT_OS_DJGPP static mpt::osinfo::dos::Version s_cachedVersion = GatherDosVersion(); return s_cachedVersion; #else // !MPT_OS_DJGPP return mpt::osinfo::dos::Version::NoDos(); #endif // MPT_OS_DJGPP } public: bool IsDos() const noexcept { return m_SystemIsDos; } std::string GetOEM() const { return m_OEM; } mpt::osinfo::dos::Version::System GetSystem() const noexcept { return m_System; } mpt::osinfo::dos::Version::System GetSystemEmulated() const noexcept { return m_SystemEmulated; } mpt::osinfo::dos::Version::DPMI GetDPMI() const noexcept { return m_DPMI; } std::string GetDPMIVendor() const { return m_DPMIVendor; } mpt::osinfo::dos::Version::DPMI GetDPMIHost() const noexcept { return m_DPMIHost; } mpt::osinfo::dos::Version::Host GetHost() const noexcept { return m_Host; } std::string GetHostName() const { std::string result{}; switch (m_Host) { case Host::DOS: result = "DOS"; break; case Host::Win2: result = "Windows/386 2.x"; break; case Host::Win3: result = "Windows 3.x"; break; case Host::Win95: result = "Windows 95"; break; case Host::Win98: result = "Windows 98"; break; case Host::WinME: result = "Windows ME"; break; case Host::WinNT: result = "Windows NT"; break; case Host::OS2: result = "OS/2"; break; case Host::OS2Warp: result = "OS/2 Warp"; break; case Host::DOSEmu: result = "DOSEmu"; break; } return result; } int GetHostVersion() const noexcept { return m_HostVersion; } int GetHostRevision() const noexcept { return m_HostRevision; } int GetHostPatch() const noexcept { return m_HostPatch; } bool IsHostMultitasking() const noexcept { return m_HostMultitasking; } bool HasHostFixedTimer() const noexcept { return m_HostFixedTimer; } std::string GetBIOSDate() const { return m_BIOSDate; } }; // class Version } // namespace dos } // namespace osinfo } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_OSINFO_DOS_VERSION_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_file/0000755000175000017500000000000015023302361017326 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/io_file/inputfile.hpp0000644000175000017500000001054214364567331022001 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_FILE_INPUTFILE_HPP #define MPT_IO_FILE_INPUTFILE_HPP #include "mpt/base/alloc.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/base/span.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/io_file/fstream.hpp" #include "mpt/path/os_path.hpp" #include #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { class UncachedInputFile { private: mpt::os_path m_Filename; mpt::IO::ifstream m_File; bool m_IsValid; public: UncachedInputFile(const mpt::os_path & filename) : m_Filename(filename) , m_File(m_Filename, std::ios::binary | std::ios::in) , m_IsValid(true) { assert(!m_Filename.empty()); } ~UncachedInputFile() = default; bool IsValid() const { return m_IsValid && m_File.good(); } mpt::os_path GetFilename() const { return m_Filename; } std::istream & GetStream() { return m_File; } }; class CachedInputFile { private: mpt::os_path m_Filename; mpt::IO::ifstream m_File; bool m_IsValid; bool m_IsCached; std::vector m_Cache; public: CachedInputFile(const mpt::os_path & filename) : m_Filename(filename) , m_File(m_Filename, std::ios::binary | std::ios::in) , m_IsValid(false) , m_IsCached(false) { assert(!filename.empty()); if (mpt::IO::IsReadSeekable(m_File)) { if (!mpt::IO::SeekEnd(m_File)) { m_File.close(); return; } mpt::IO::Offset filesize = mpt::IO::TellRead(m_File); if (!mpt::IO::SeekBegin(m_File)) { m_File.close(); return; } if (mpt::in_range(filesize)) { std::size_t buffersize = mpt::saturate_cast(filesize); m_Cache.resize(buffersize); if (mpt::IO::ReadRaw(m_File, mpt::as_span(m_Cache)).size() != mpt::saturate_cast(filesize)) { m_File.close(); return; } if (!mpt::IO::SeekBegin(m_File)) { m_File.close(); return; } m_IsCached = true; m_IsValid = true; return; } } m_IsValid = true; return; } ~CachedInputFile() = default; bool IsValid() const { return m_IsValid && m_File.good(); } bool IsCached() const { return m_IsCached; } mpt::os_path GetFilename() const { return m_Filename; } std::istream & GetStream() { assert(!m_IsCached); return m_File; } mpt::const_byte_span GetCache() { assert(m_IsCached); return mpt::as_span(m_Cache); } }; class InputFile { private: std::variant m_impl; public: InputFile(const mpt::os_path & filename, bool enable_cache = false) { if (enable_cache) { m_impl.emplace(filename); } else { m_impl.emplace(filename); } } ~InputFile() = default; bool IsValid() const { if (std::holds_alternative(m_impl)) { return std::get(m_impl).IsValid(); } else if (std::holds_alternative(m_impl)) { return std::get(m_impl).IsValid(); } return false; } bool IsCached() const { if (std::holds_alternative(m_impl)) { return false; } else if (std::holds_alternative(m_impl)) { return std::get(m_impl).IsCached(); } throw false; } mpt::os_path GetFilename() const { if (std::holds_alternative(m_impl)) { return std::get(m_impl).GetFilename(); } else if (std::holds_alternative(m_impl)) { return std::get(m_impl).GetFilename(); } return {}; } std::istream & GetStream() { if (std::holds_alternative(m_impl)) { return std::get(m_impl).GetStream(); } else if (std::holds_alternative(m_impl)) { return std::get(m_impl).GetStream(); } throw std::bad_variant_access(); } mpt::const_byte_span GetCache() { if (std::holds_alternative(m_impl)) { throw std::bad_variant_access(); } else if (std::holds_alternative(m_impl)) { return std::get(m_impl).GetCache(); } throw std::bad_variant_access(); } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_FILE_INPUTFILE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_file/fstream.hpp0000644000175000017500000001303314344405373021434 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_FILE_FSTREAM_HPP #define MPT_IO_FILE_FSTREAM_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/span.hpp" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/path/os_path.hpp" #include "mpt/path/os_path_long.hpp" #include "mpt/string_transcode/transcode.hpp" #if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR) #if MPT_GCC_AT_LEAST(9, 1, 0) && !defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) #include #endif // MPT_GCC_AT_LEAST(9,1,0) && !defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) #endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR #include #include #include #include #if MPT_LIBCXX_MS #include #endif // MPT_LIBCXX_MS namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { namespace detail { template inline void fstream_open(Tbase & base, const mpt::os_path & filename, std::ios_base::openmode mode) { #if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR) #if MPT_GCC_AT_LEAST(9, 1, 0) && !defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) base.open(static_cast(mpt::support_long_path(filename)), mode); #else // !MPT_GCC_AT_LEAST(9,1,0) || MPT_COMPILER_QUIRK_NO_FILESYSTEM // Warning: MinGW with GCC earlier than 9.1 detected. Standard library does neither provide std::fstream wchar_t overloads nor std::filesystem with wchar_t support. Unicode filename support is thus unavailable. base.open(mpt::transcode(mpt::logical_encoding::locale, mpt::support_long_path(filename)).c_str(), mode); #endif // MPT_GCC_AT_LEAST(9,1,0) && !MPT_COMPILER_QUIRK_NO_FILESYSTEM #else // !MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR base.open(mpt::support_long_path(filename).c_str(), mode); #endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR } } // namespace detail // We cannot rely on implicit conversion of mpt::path to std::filesystem::path when constructing std::fstream // because of broken overload implementation in GCC libstdc++ 8, 9, 10. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95642 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90704 class fstream : public std::fstream { private: using base_type = std::fstream; public: explicit fstream(const mpt::os_path & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { detail::fstream_open(*this, filename, mode); } #if MPT_LIBCXX_MS protected: fstream(std::FILE * file) : std::fstream(file) { } #endif // MPT_LIBCXX_MS public: void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; void open(const std::string_view & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; void open(const std::wstring_view & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; #endif }; class ifstream : public std::ifstream { private: using base_type = std::ifstream; public: explicit ifstream(const mpt::os_path & filename, std::ios_base::openmode mode = std::ios_base::in) { detail::fstream_open(*this, filename, mode); } #if MPT_LIBCXX_MS protected: ifstream(std::FILE * file) : std::ifstream(file) { } #endif // MPT_LIBCXX_MS public: void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in) = delete; void open(const std::string_view & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in) = delete; void open(const std::wstring_view & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; #endif }; class ofstream : public std::ofstream { private: using base_type = std::ofstream; public: explicit ofstream(const mpt::os_path & filename, std::ios_base::openmode mode = std::ios_base::out) { detail::fstream_open(*this, filename, mode); } #if MPT_LIBCXX_MS protected: ofstream(std::FILE * file) : std::ofstream(file) { } #endif // MPT_LIBCXX_MS public: void open(const char * filename, std::ios_base::openmode mode = std::ios_base::out) = delete; void open(const std::string_view & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::out) = delete; void open(const std::wstring_view & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; #endif }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_FILE_FSTREAM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_file/outputfile.hpp0000644000175000017500000001360214262227615022175 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_FILE_OUTPUTFILE_HPP #define MPT_IO_FILE_OUTPUTFILE_HPP #include "mpt/base/namespace.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/io_file/fstream.hpp" #include "mpt/path/os_path.hpp" #include "mpt/string/types.hpp" #include #include #include #if MPT_LIBCXX_MS #include #endif // MPT_LIBCXX_MS #if MPT_LIBCXX_MS #include #endif // MPT_LIBCXX_MS namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { enum class FlushMode { None = 0, // no explicit flushes at all Single = 1, // explicitly flush higher-leverl API layers Full = 2, // explicitly flush *all* layers, up to and including disk write caches }; inline FlushMode FlushModeFromBool(bool flush) { return flush ? FlushMode::Full : FlushMode::None; } class SafeOutputFile { private: FlushMode m_FlushMode; #if MPT_LIBCXX_MS std::FILE * m_f = nullptr; #else // !MPT_LIBCXX_MS mpt::IO::ofstream m_s; #endif // MPT_LIBCXX_MS #if MPT_LIBCXX_MS class FILEostream : public mpt::IO::ofstream { public: FILEostream(std::FILE * file) : mpt::IO::ofstream(file) { return; } }; FILEostream m_s; static mpt::tstring convert_mode(std::ios_base::openmode mode, FlushMode flushMode) { mpt::tstring fopen_mode; switch (mode & ~(std::ios_base::ate | std::ios_base::binary)) { case std::ios_base::in: fopen_mode = _T("r"); break; case std::ios_base::out: [[fallthrough]]; case std::ios_base::out | std::ios_base::trunc: fopen_mode = _T("w"); break; case std::ios_base::app: [[fallthrough]]; case std::ios_base::out | std::ios_base::app: fopen_mode = _T("a"); break; case std::ios_base::out | std::ios_base::in: fopen_mode = _T("r+"); break; case std::ios_base::out | std::ios_base::in | std::ios_base::trunc: fopen_mode = _T("w+"); break; case std::ios_base::out | std::ios_base::in | std::ios_base::app: [[fallthrough]]; case std::ios_base::in | std::ios_base::app: fopen_mode = _T("a+"); break; } if (fopen_mode.empty()) { return fopen_mode; } if (mode & std::ios_base::binary) { fopen_mode += _T("b"); } if (flushMode == FlushMode::Full) { fopen_mode += _T("c"); // force commit on fflush (MSVC specific) } return fopen_mode; } std::FILE * internal_fopen(const mpt::os_path & filename, std::ios_base::openmode mode, FlushMode flushMode) { m_f = nullptr; mpt::tstring fopen_mode = convert_mode(mode, flushMode); if (fopen_mode.empty()) { return nullptr; } std::FILE * f = #ifdef UNICODE _wfopen(mpt::support_long_path(mpt::transcode(filename)).c_str(), fopen_mode.c_str()) #else std::fopen(mpt::support_long_path(mpt::transcode(filename)).c_str(), fopen_mode.c_str()) #endif ; if (!f) { return nullptr; } if (mode & std::ios_base::ate) { if (std::fseek(f, 0, SEEK_END) != 0) { std::fclose(f); f = nullptr; return nullptr; } } m_f = f; return f; } #endif // MPT_LIBCXX_MS public: SafeOutputFile() = delete; explicit SafeOutputFile(const mpt::os_path & filename, std::ios_base::openmode mode = std::ios_base::out, FlushMode flushMode = FlushMode::Full) : m_FlushMode(flushMode) #if MPT_LIBCXX_MS , m_s(internal_fopen(filename, mode | std::ios_base::out, flushMode)) #else // !MPT_LIBCXX_MS , m_s(filename, mode) #endif // MPT_LIBCXX_MS { if (!stream().is_open()) { stream().setstate(mpt::IO::ofstream::failbit); } } mpt::IO::ofstream & stream() { return m_s; } operator mpt::IO::ofstream &() { return stream(); } const mpt::IO::ofstream & stream() const { return m_s; } operator const mpt::IO::ofstream &() const { return stream(); } operator bool() const { return stream() ? true : false; } bool operator!() const { return stream().operator!(); } // cppcheck-suppress exceptThrowInDestructor ~SafeOutputFile() noexcept(false) { const bool mayThrow = (std::uncaught_exceptions() == 0); if (!stream()) { #if MPT_LIBCXX_MS if (m_f) { std::fclose(m_f); } #endif // MPT_LIBCXX_MS if (mayThrow && (stream().exceptions() & (std::ios::badbit | std::ios::failbit))) { // cppcheck-suppress exceptThrowInDestructor throw std::ios_base::failure(std::string("Error before flushing file buffers.")); } return; } if (!stream().rdbuf()) { #if MPT_LIBCXX_MS if (m_f) { std::fclose(m_f); } #endif // MPT_LIBCXX_MS if (mayThrow && (stream().exceptions() & (std::ios::badbit | std::ios::failbit))) { // cppcheck-suppress exceptThrowInDestructor throw std::ios_base::failure(std::string("Error before flushing file buffers.")); } return; } #if MPT_LIBCXX_MS if (!m_f) { return; } #endif // MPT_LIBCXX_MS bool errorOnFlush = false; if (m_FlushMode != FlushMode::None) { try { if (stream().rdbuf()->pubsync() != 0) { errorOnFlush = true; } } catch (const std::exception &) { errorOnFlush = true; #if MPT_LIBCXX_MS if (m_FlushMode != FlushMode::None) { if (std::fflush(m_f) != 0) { errorOnFlush = true; } } if (std::fclose(m_f) != 0) { errorOnFlush = true; } #endif // MPT_LIBCXX_MS if (mayThrow) { // ignore errorOnFlush here, and re-throw the earlier exception // cppcheck-suppress exceptThrowInDestructor throw; } } } #if MPT_LIBCXX_MS if (m_FlushMode != FlushMode::None) { if (std::fflush(m_f) != 0) { errorOnFlush = true; } } if (std::fclose(m_f) != 0) { errorOnFlush = true; } #endif // MPT_LIBCXX_MS if (mayThrow && errorOnFlush && (stream().exceptions() & (std::ios::badbit | std::ios::failbit))) { // cppcheck-suppress exceptThrowInDestructor throw std::ios_base::failure(std::string("Error flushing file buffers.")); } } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_FILE_OUTPUTFILE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_file/fileref.hpp0000644000175000017500000000611714364567331021421 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_FILE_FILEREF_HPP #define MPT_IO_FILE_FILEREF_HPP #include "mpt/base/alloc.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/base/span.hpp" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/io_file/fstream.hpp" #include "mpt/path/os_path.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { // FileRef is a simple reference to an on-disk file by the means of a // filename which allows easy assignment of the whole file contents to and from // byte buffers. class FileRef { private: const mpt::os_path m_Filename; public: FileRef(const mpt::os_path & filename) : m_Filename(filename) { return; } public: FileRef & operator=(const std::vector & data) { mpt::IO::ofstream file(m_Filename, std::ios::binary); file.exceptions(std::ios_base::failbit | std::ios_base::badbit); mpt::IO::WriteRaw(file, mpt::as_span(data)); mpt::IO::Flush(file); return *this; } FileRef & operator=(const std::vector & data) { mpt::IO::ofstream file(m_Filename, std::ios::binary); file.exceptions(std::ios_base::failbit | std::ios_base::badbit); mpt::IO::WriteRaw(file, mpt::as_span(data)); mpt::IO::Flush(file); return *this; } FileRef & operator=(const std::string & data) { mpt::IO::ofstream file(m_Filename, std::ios::binary); file.exceptions(std::ios_base::failbit | std::ios_base::badbit); mpt::IO::WriteRaw(file, mpt::as_span(data)); mpt::IO::Flush(file); return *this; } operator std::vector() const { mpt::IO::ifstream file(m_Filename, std::ios::binary); if (!mpt::IO::IsValid(file)) { return std::vector(); } file.exceptions(std::ios_base::failbit | std::ios_base::badbit); mpt::IO::SeekEnd(file); std::vector buf(mpt::saturate_cast(mpt::IO::TellRead(file))); mpt::IO::SeekBegin(file); mpt::IO::ReadRaw(file, mpt::as_span(buf)); return buf; } operator std::vector() const { mpt::IO::ifstream file(m_Filename, std::ios::binary); if (!mpt::IO::IsValid(file)) { return std::vector(); } file.exceptions(std::ios_base::failbit | std::ios_base::badbit); mpt::IO::SeekEnd(file); std::vector buf(mpt::saturate_cast(mpt::IO::TellRead(file))); mpt::IO::SeekBegin(file); mpt::IO::ReadRaw(file, mpt::as_span(buf)); return buf; } operator std::string() const { mpt::IO::ifstream file(m_Filename, std::ios::binary); if (!mpt::IO::IsValid(file)) { return std::string(); } file.exceptions(std::ios_base::failbit | std::ios_base::badbit); mpt::IO::SeekEnd(file); std::vector buf(mpt::saturate_cast(mpt::IO::TellRead(file))); mpt::IO::SeekBegin(file); mpt::IO::ReadRaw(file, mpt::as_span(buf)); return mpt::buffer_cast(buf); } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_FILE_FILEREF_HPP libopenmpt-0.8.1+release.autotools/src/mpt/check/0000755000175000017500000000000015023302361016775 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/check/mfc.hpp0000644000175000017500000000102114044173026020173 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_CHECK_MFC_HPP #define MPT_CHECK_MFC_HPP #include "mpt/base/compiletime_warning.hpp" #include "mpt/detect/mfc.hpp" #if MPT_DETECTED_MFC #ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION #ifndef MPT_CHECK_MFC_IGNORE_WARNING_NO_CSTRING_DISABLE_NARROW_WIDE_CONVERSION MPT_WARNING("MFC uses CString with automatic encoding conversions. Please #define _CSTRING_DISABLE_NARROW_WIDE_CONVERSION.") #endif #endif #endif // MPT_DETECTED_MFC #endif // MPT_CHECK_MFC_HPP libopenmpt-0.8.1+release.autotools/src/mpt/check/libc.hpp0000644000175000017500000000215514735607461020364 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_CHECK_LIBC_HPP #define MPT_CHECK_LIBC_HPP #include "mpt/base/detect_libc.hpp" #include "mpt/base/detect_os.hpp" #include "mpt/base/detect_quirks.hpp" #include "mpt/base/compiletime_warning.hpp" #ifndef MPT_CHECK_LIBC_IGNORE_WARNING_NO_MTRT #if MPT_PLATFORM_MULTITHREADED #if MPT_LIBC_MINGW // MinGW only has `#define _MT` in header files instead of `#define _MT 1`. #if !defined(_MT) MPT_WARNING("C stdlib is not multi-threaded.") #endif #elif MPT_LIBC_MS #if defined(_MT) #if (_MT != 1) MPT_WARNING("C stdlib is not multi-threaded.") #endif #else MPT_WARNING("C stdlib is not multi-threaded.") #endif //#elif !MPT_LIBC_MS && !MPT_LIBC_MINGW && !MPT_LIBC_GENERIC //#if (!defined(_REENTRANT) || (_REENTRANT != 1)) //MPT_WARNING("C stdlib is not multi-threaded.") //#endif #endif #endif #endif #ifndef MPT_CHECK_LIBC_IGNORE_WARNING_UNICODE_MISMATCH #if MPT_OS_WINDOWS #ifdef UNICODE #ifndef _UNICODE MPT_WARNING("UNICODE is defined but _UNICODE is not defined. Please #define _UNICODE.") #endif #endif #endif // MPT_OS_WINDOWS #endif #endif // MPT_CHECK_LIBC_HPP libopenmpt-0.8.1+release.autotools/src/mpt/check/compiler.hpp0000644000175000017500000000766314754563426021301 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_CHECK_COMPILER_HPP #define MPT_CHECK_COMPILER_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_quirks.hpp" #include "mpt/base/compiletime_warning.hpp" #ifndef MPT_CHECK_CXX_IGNORE_PREPROCESSOR #if defined(MPT_COMPILER_QUIRK_MSVC_OLD_PREPROCESSOR) MPT_WARNING("C++ preprocessor is not standard conformings.") #endif #endif #ifndef MPT_CHECK_CXX_IGNORE_WARNING_FASTMATH #if MPT_COMPILER_MSVC #if (defined(_M_FP_FAST) && (_M_FP_FAST == 1)) MPT_WARNING("C++ compiler has fast-math support enabled. This is not standard-conforming.") #endif #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG #if (defined(__FAST_MATH__) && (__FAST_MATH__ == 1)) MPT_WARNING("C++ compiler has fast-math support enabled. This is not standard-conforming.") #endif #endif #endif #ifndef MPT_CHECK_CXX_IGNORE_WARNING_FINITEMATH #if MPT_COMPILER_MSVC #if (defined(_M_FP_FAST) && (_M_FP_FAST == 1)) MPT_WARNING("C++ compiler assumes finite math only. This is not standard-conforming.") #endif #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG #if (defined(__FINITE_MATH_ONLY__) && (__FINITE_MATH_ONLY__ == 1)) MPT_WARNING("C++ compiler assumes finite math only. This is not standard-conforming.") #endif #endif #endif #ifndef MPT_CHECK_CXX_IGNORE_WARNING_NO_EXCEPTIONS #if MPT_COMPILER_MSVC #if !defined(_CPPUNWIND) MPT_WARNING("C++ compiler has no exception support.") #endif #elif MPT_COMPILER_GCC #if (!defined(__EXCEPTIONS) || (__EXCEPTIONS != 1)) MPT_WARNING("C++ compiler has no exception support.") #endif #elif MPT_COMPILER_CLANG #if (!__has_feature(cxx_exceptions) && (!defined(__EXCEPTIONS) || (__EXCEPTIONS != 1)) && !defined(_CPPUNWIND)) MPT_WARNING("C++ compiler has no exception support.") #else #if (MPT_CXX_AT_LEAST(20) && !defined(__cpp_exceptions)) MPT_WARNING("C++ compiler has no exception support.") #endif #endif #endif #endif #ifndef MPT_CHECK_CXX_IGNORE_WARNING_NO_RTTI #if MPT_COMPILER_MSVC #if (!defined(_CPPRTTI) || (_CPPRTTI != 1)) MPT_WARNING("C++ compiler has no RTTI support.") #endif #elif MPT_COMPILER_GCC #if (!defined(__GXX_RTTI) || (__GXX_RTTI != 1)) MPT_WARNING("C++ compiler has no RTTI support.") #endif #elif MPT_COMPILER_CLANG && !defined(_MSC_VER) #if (!defined(__GXX_RTTI) || (__GXX_RTTI != 1)) MPT_WARNING("C++ compiler has no RTTI support.") #endif #endif #endif #ifndef MPT_CHECK_CXX_IGNORE_WARNING_NO_UNICODE #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) #if (!defined(__STDC_ISO_10646__) || (__STDC_ISO_10646__ <= 198700L)) #if !MPT_COMPILER_MSVC && !MPT_COMPILER_GCC && !MPT_COMPILER_CLANG // Disabled for all known compilers, as none of them defines __STDC_ISO_10646__, even though all of them provide Unicode wchar_t. MPT_WARNING("C++ compiler uses non-Unicode wchar_t.") #endif #endif #endif #endif #ifndef MPT_CHECK_CXX_IGNORE_WARNING_EBCDIC #if defined(__STDC_MB_MIGHT_NEQ_WC__) && (__STDC_MB_MIGHT_NEQ_WC__ == 1) #if !(MPT_COMPILER_CLANG && MPT_OS_FREEBSD) // Disabled on FreeBSD because . MPT_WARNING("C++ compiler uses a weird 8bit charset, maybe EBCDIC.") #endif #endif #endif #ifndef MPT_CHECK_CXX_IGNORE_WARNING_NO_STDCPP_THREADS #if MPT_PLATFORM_MULTITHREADED #if !defined(MPT_COMPILER_QUIRK_NO_STDCPP_THREADS) #if !defined(__STDCPP_THREADS__) MPT_WARNING("C++ __STDCPP_THREADS__ is not defined. Non-conforming compiler detected.") #else #if (__STDCPP_THREADS__ != 1) MPT_WARNING("C++ compiler has no thread support.") #endif #endif #endif #endif #endif #ifndef MPT_CHECK_CXX_IGNORE_WARNING_SINGLETHREADED_THREADSAFE_STATICS #if !MPT_PLATFORM_MULTITHREADED #if MPT_CXX_AT_LEAST(20) && MPT_COMPILER_GCC #if (defined(__cpp_threadsafe_static_init) && (__cpp_threadsafe_static_init >= 200806L)) MPT_WARNING("C++ compiler provides threadsafe initialization of static variables, however the platform is single-threaded.") #endif #endif #endif #endif #endif // MPT_CHECK_COMPILER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/check/windows.hpp0000644000175000017500000000201014735605630021127 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_CHECK_WINDOWS_HPP #define MPT_CHECK_WINDOWS_HPP #include "mpt/base/detect_os.hpp" #include "mpt/base/compiletime_warning.hpp" #if MPT_OS_WINDOWS #ifndef MPT_CHECK_WINDOWS_IGNORE_WARNING_NO_UNICODE #if MPT_OS_WINDOWS_WINNT #ifndef UNICODE MPT_WARNING("windows.h uses MBCS TCHAR. Please #define UNICODE.") #endif #elif MPT_OS_WINDOWS_WIN9X #ifdef UNICODE MPT_WARNING("Targeting Win9x but windows.h uses UNICODE TCHAR. Please do not #define UNICODE.") #endif #endif #endif #ifndef MPT_CHECK_WINDOWS_IGNORE_WARNING_UNICODE_MISMATCH #ifdef _UNICODE #ifndef UNICODE MPT_WARNING("_UNICODE is defined but UNICODE is not defined. Please enable UNICODE support in your compiler, or do not #define _UNICODE.") #endif #endif #endif #ifndef NOMINMAX #ifndef MPT_CHECK_WINDOWS_IGNORE_WARNING_NO_NOMINMAX MPT_WARNING("windows.h defines min and max which conflicts with C++. Please #define NOMINMAX.") #endif #endif #endif // MPT_OS_WINDOWS #endif // MPT_CHECK_WINDOWS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/check/libcxx.hpp0000644000175000017500000000127614736713725020751 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_CHECK_LIBCXX_HPP #define MPT_CHECK_LIBCXX_HPP #include "mpt/base/detect_libcxx.hpp" #include "mpt/base/detect_os.hpp" #include "mpt/base/detect_quirks.hpp" #ifndef MPT_CHECK_LIBCXX_IGNORE_WARNING_NO_THREADS #if MPT_OS_WINDOWS && MPT_WIN_BEFORE(MPT_WIN_7) && MPT_LIBCXX_GNU_AT_LEAST(13) && !defined(_GLIBCXX_HAS_GTHREADS) #error "GNU libstdc++ is compiled without gthreads support (likely due to using Win32 threading model as opposed to POSIX or mcfgthread threading model. This a severely crippled C++11 implementation and no is no longer supported for libstdc++ version 13 or later." #endif #endif #endif // MPT_CHECK_LIBCXX_HPP libopenmpt-0.8.1+release.autotools/src/mpt/path/0000755000175000017500000000000015023302361016654 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/path/native_path.hpp0000644000175000017500000000242514253061630021617 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_PATH_NATIVE_PATH_HPP #define MPT_PATH_NATIVE_PATH_HPP #include "mpt/base/detect.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/path/basic_path.hpp" #include "mpt/path/os_path.hpp" #include "mpt/string/types.hpp" namespace mpt { inline namespace MPT_INLINE_NS { struct NativePathStyleTag { #if MPT_OS_WINDOWS_WINNT static inline constexpr mpt::PathStyle path_style = mpt::PathStyle::WindowsNT; #elif MPT_OS_WINDOWS_WIN9X static inline constexpr mpt::PathStyle path_style = mpt::PathStyle::Windows9x; #elif MPT_OS_WINDOWS static inline constexpr mpt::PathStyle path_style = mpt::PathStyle::Windows9x; #elif MPT_OS_DJGPP static inline constexpr mpt::PathStyle path_style = mpt::PathStyle::DOS_DJGPP; #else static inline constexpr mpt::PathStyle path_style = mpt::PathStyle::Posix; #endif }; struct NativePathTraits : public PathTraits { }; struct Utf8PathTraits : public PathTraits { }; using native_path = BasicPathString; #define MPT_NATIVE_PATH(x) \ mpt::native_path { \ MPT_OS_PATH(x) \ } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_PATH_NATIVE_PATH_HPP libopenmpt-0.8.1+release.autotools/src/mpt/path/path.hpp0000644000175000017500000003426714315063706020267 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_PATH_PATH_HPP #define MPT_PATH_PATH_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/path/os_path.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #if !defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) #include #endif // !MPT_COMPILER_QUIRK_NO_FILESYSTEM #include #include #if MPT_OS_WINDOWS && defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) #include #endif // MPT_OS_WINDOWS && MPT_COMPILER_QUIRK_NO_FILESYSTEM #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { #if defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) using path = mpt::os_path; #define MPT_PATH_CHAR(x) MPT_OSPATH_CHAR(x) #define MPT_PATH_LITERAL(x) MPT_OSPATH_LITERAL(x) #define MPT_PATH(x) MPT_OSPATH(x) #else // !MPT_COMPILER_QUIRK_NO_FILESYSTEM template <> struct make_string_type { using type = std::filesystem::path; }; template <> struct is_string_type : public std::true_type { }; template <> struct string_transcoder { using string_type = std::filesystem::path; static inline mpt::widestring decode(const string_type & src) { if constexpr (std::is_same::value) { // In contrast to standard recommendation and cppreference, // native encoding on unix-like systems with libstdc++ or libc++ is actually *NOT* UTF8, // but instead the conventional std::locale::locale("") encoding (which happens to be UTF8 on all modern systems, but this is not guaranteed). // Note: libstdc++ and libc++ however assume that their internal representation is UTF8, // which implies that wstring/u32string/u16string/u8string conversions are actually broken and MUST NOT be used, ever. return mpt::transcode(mpt::logical_encoding::locale, src.string()); #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) } else if constexpr (std::is_same::value) { return mpt::transcode(src.wstring()); #endif // !MPT_COMPILER_QUIRK_NO_WCHAR } else if constexpr (std::is_same::value) { return mpt::transcode(src.u32string()); } else if constexpr (std::is_same::value) { return mpt::transcode(src.u16string()); #if MPT_CXX_AT_LEAST(20) } else if constexpr (std::is_same::value) { return mpt::transcode(src.u8string()); #endif } else { #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) return mpt::transcode(src.wstring()); #elif MPT_OS_WINDOWS return mpt::transcode(mpt::logical_encoding::locale, src.string()); #else // completely unknown implementation, assume it can sanely convert to/from UTF16/UTF32 if constexpr (sizeof(mpt::widechar) == sizeof(char32_t)) { return mpt::transcode(src.u32string()); } else if constexpr (sizeof(mpt::widechar) == sizeof(char16_t)) { return mpt::transcode(src.u16string()); } else { return mpt::transcode(src.u32string()); } #endif } } static inline string_type encode(const mpt::widestring & src, std::filesystem::path::format fmt) { if constexpr (std::is_same::value) { // In contrast to standard recommendation and cppreference, // native encoding on unix-like systems with libstdc++ or libc++ is actually *NOT* UTF8, // but instead the conventional std::locale::locale("") encoding (which happens to be UTF8 on all modern systems, but this is not guaranteed). // Note: libstdc++ and libc++ however assume that their internal representation is UTF8, // which implies that wstring/u32string/u16string/u8string conversions are actually broken and MUST NOT be used, ever. return std::filesystem::path{mpt::transcode(mpt::logical_encoding::locale, src), fmt}; #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) } else if constexpr (std::is_same::value) { return std::filesystem::path{mpt::transcode(src), fmt}; #endif // !MPT_COMPILER_QUIRK_NO_WCHAR } else if constexpr (std::is_same::value) { return std::filesystem::path{mpt::transcode(src), fmt}; } else if constexpr (std::is_same::value) { return std::filesystem::path{mpt::transcode(src), fmt}; #if MPT_CXX_AT_LEAST(20) } else if constexpr (std::is_same::value) { return std::filesystem::path{mpt::transcode(src), fmt}; #endif } else { #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) return std::filesystem::path{mpt::transcode(src), fmt}; #elif MPT_OS_WINDOWS return std::filesystem::path{mpt::transcode(mpt::logical_encoding::locale, src), fmt}; #else // completely unknown implementation, assume it can sanely convert to/from UTF16/UTF32 if constexpr (sizeof(mpt::widechar) == sizeof(char32_t)) { return std::filesystem::path{mpt::transcode(src), fmt}; } else if constexpr (sizeof(mpt::widechar) == sizeof(char16_t)) { return std::filesystem::path{mpt::transcode(src), fmt}; } else { return std::filesystem::path{mpt::transcode(src), fmt}; } #endif } } static inline string_type encode(const mpt::widestring & src) { return encode(src, std::filesystem::path::auto_format); } }; // Best heuristics we can come up with to define std::filesystem::path literals that do not involve (or at least only non-lossy) runtime conversion. #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) #define MPT_STDPATH_CHAR(x) L##x #define MPT_STDPATH_LITERAL(x) L##x #define MPT_STDPATH(x) \ std::filesystem::path { \ L##x \ } #elif MPT_OS_WINDOWS #define MPT_STDPATH_CHAR(x) x #define MPT_STDPATH_LITERAL(x) x #define MPT_STDPATH(x) \ std::filesystem::path { \ x \ } #elif MPT_CXX_AT_LEAST(20) #define MPT_STDPATH_CHAR(x) u8##x #define MPT_STDPATH_LITERAL(x) u8##x #define MPT_STDPATH(x) \ std::filesystem::path { \ u8##x \ } #else #define MPT_STDPATH_CHAR(x) U##x #define MPT_STDPATH_LITERAL(x) U##x #define MPT_STDPATH(x) \ std::filesystem::path { \ U##x \ } #endif // std::filesystem::path offers implicit conversions to/from types of which it is confused about their encodings. // The only way to work around this problem is to implement our own mpt::path that does not do such broken nonsense. // We offer no implicit conversions and only explicit conversions from std::filesystem::path and mpt::os_path. class path { public: using format = std::filesystem::path::format; using std_value_type = std::filesystem::path::value_type; using std_string_type = std::filesystem::path; static constexpr inline std_value_type std_preferred_separator = std::filesystem::path::preferred_separator; using os_value_type = os_path::value_type; using os_string_type = os_path; static constexpr inline os_value_type os_preferred_separator = static_cast(std::filesystem::path::preferred_separator); private: std::filesystem::path m_path; private: template ::value, bool> = true> explicit path(const path_type & p) : m_path(p) { return; } template ::value, bool> = true> explicit path(path_type && p) : m_path(std::forward(p)) { return; } public: struct internal { static inline path make_path(std::filesystem::path && p) { return path{std::move(p)}; } }; public: template ::value, bool> = true> static path from_stdpath(const path_type & p) { return path{p}; } static std::filesystem::path to_stdpath(const path & p) { return p.m_path; } static os_path to_ospath(const path & p) { return mpt::transcode(p.m_path); } static std::filesystem::path from_ospath(const os_path & s, std::filesystem::path::format fmt = std::filesystem::path::auto_format) { return string_transcoder{}.encode(mpt::transcode(s), fmt); } public: path() noexcept = default; path(const path & p) : m_path(p.m_path) { return; } path(path && p) : m_path(std::move(p.m_path)) { return; } explicit path(const os_path & s, std::filesystem::path::format fmt = std::filesystem::path::auto_format) : m_path(from_ospath(s, fmt)) { return; } path & operator=(const path & p) { m_path = p.m_path; return *this; } path & operator=(path && p) { m_path = std::move(p.m_path); return *this; } path & assign(const path & p) { m_path = p.m_path; return *this; } path & assign(path && p) { m_path = std::move(p.m_path); return *this; } path & operator/=(const path & p) { m_path /= p.m_path; return *this; } path & operator/=(path && p) { m_path /= std::move(p.m_path); return *this; } // concatenation path & append(const path & p) { m_path /= p.m_path; return *this; } path & append(path && p) { m_path /= std::move(p.m_path); return *this; } path & operator+=(const path & p) { m_path += p.m_path; return *this; } path & operator+=(path && p) { m_path += std::move(p.m_path); return *this; } path & concat(const path & p) { m_path += p.m_path; return *this; } path & concat(path && p) { m_path += std::move(p.m_path); return *this; } // modifiers void clear() noexcept { m_path.clear(); } path & make_preferred() { m_path.make_preferred(); return *this; } path & remove_filename() { m_path.remove_filename(); return *this; } path & replace_filename(const path & replacement) { m_path.replace_filename(replacement.m_path); return *this; } path & replace_extension(const path & replacement = path()) { m_path.replace_extension(replacement.m_path); return *this; } void swap(path & other) { m_path.swap(other.m_path); } // format observers std::filesystem::path stdpath() const { return m_path; } os_path ospath() const { return to_ospath(*this); } // compare int compare(const path & p) const noexcept { return m_path.compare(p.m_path); } // generation path lexically_normal() const { return path{m_path.lexically_normal()}; } path lexically_relative(const path & base) const { return path{m_path.lexically_relative(base.m_path)}; } path lexically_proximate(const path & base) const { return path{m_path.lexically_proximate(base.m_path)}; } // decomposition path root_name() const { return path{m_path.root_name()}; } path root_directory() const { return path{m_path.root_directory()}; } path root_path() const { return path{m_path.root_path()}; } path relative_path() const { return path{m_path.relative_path()}; } path parent_path() const { return path{m_path.parent_path()}; } path filename() const { return path{m_path.filename()}; } path stem() const { return path{m_path.stem()}; } path extension() const { return path{m_path.extension()}; } // queries [[nodiscard]] bool empty() const noexcept { return m_path.empty(); } bool has_root_path() const { return m_path.has_root_path(); } bool has_root_name() const { return m_path.has_root_name(); } bool has_root_directory() const { return m_path.has_root_directory(); } bool has_relative_path() const { return m_path.has_relative_path(); } bool has_parent_path() const { return m_path.has_parent_path(); } bool has_filename() const { return m_path.has_filename(); } bool has_stem() const { return m_path.has_stem(); } bool has_extension() const { return m_path.has_extension(); } bool is_absolute() const { return m_path.is_absolute(); } bool is_relative() const { return m_path.is_relative(); } // comparison operators friend bool operator==(const path & lhs, const path & rhs) noexcept { return lhs.m_path == rhs.m_path; } friend bool operator!=(const path & lhs, const path & rhs) noexcept { return lhs.m_path != rhs.m_path; } friend bool operator<(const path & lhs, const path & rhs) noexcept { return lhs.m_path < rhs.m_path; } friend bool operator<=(const path & lhs, const path & rhs) noexcept { return lhs.m_path <= rhs.m_path; } friend bool operator>(const path & lhs, const path & rhs) noexcept { return lhs.m_path > rhs.m_path; } friend bool operator>=(const path & lhs, const path & rhs) noexcept { return lhs.m_path >= rhs.m_path; } // copncatenation operator friend path operator/(const path & lhs, const path & rhs) { return path{lhs.m_path / rhs.m_path}; } }; // Best heuristics we can come up with to define mpt::path literals that do not involve (or at least only non-lossy) runtime conversion. #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) #define MPT_PATH_CHAR(x) L##x #define MPT_PATH_LITERAL(x) L##x #define MPT_PATH(x) mpt::path::internal::make_path(L##x) #elif MPT_OS_WINDOWS #define MPT_PATH_CHAR(x) x #define MPT_PATH_LITERAL(x) x #define MPT_PATH(x) mpt::path::internal::make_path(x) #elif MPT_CXX_AT_LEAST(20) #define MPT_PATH_CHAR(x) u8##x #define MPT_PATH_LITERAL(x) u8##x #define MPT_PATH(x) mpt::path::internal::make_path(u8##x) #else #define MPT_PATH_CHAR(x) U##x #define MPT_PATH_LITERAL(x) U##x #define MPT_PATH(x) mpt::path::internal::make_path(U##x) #endif template <> struct make_string_type { using type = mpt::path; }; template <> struct is_string_type : public std::true_type { }; template <> struct string_transcoder { using string_type = mpt::path; static inline mpt::widestring decode(const string_type & src) { return mpt::transcode(src.ospath()); } static inline string_type encode(const mpt::widestring & src) { return mpt::path{mpt::transcode(src)}; } }; #endif // MPT_COMPILER_QUIRK_NO_FILESYSTEM } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_PATH_PATH_HPP libopenmpt-0.8.1+release.autotools/src/mpt/path/os_path.hpp0000644000175000017500000000257314253061630020756 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_PATH_OS_PATH_HPP #define MPT_PATH_OS_PATH_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { // mpt::os_path is an alias to a string type that represents native operating system path encoding. // Note that this differs from std::filesystem::path::string_type on both Windows and Posix. // On Windows, we actually honor UNICODE and thus allow os_path.c_str() to be usable with WinAPI functions. // On Posix, we use a type-safe string type in locale encoding, in contrast to the encoding-confused supposedly UTF8 std::string in std::filesystem::path. #if MPT_OS_WINDOWS using os_path = mpt::winstring; #else // !MPT_OS_WINDOWS using os_path = mpt::lstring; #endif // MPT_OS_WINDOWS // mpt::os_path literals that do not involve runtime conversion. #if MPT_OS_WINDOWS #define MPT_OS_PATH_CHAR(x) TEXT(x) #define MPT_OS_PATH_LITERAL(x) TEXT(x) #define MPT_OS_PATH(x) \ mpt::winstring { \ TEXT(x) \ } #else // !MPT_OS_WINDOWS #define MPT_OS_PATH_CHAR(x) x #define MPT_OS_PATH_LITERAL(x) x #define MPT_OS_PATH(x) \ mpt::lstring { \ x \ } #endif // MPT_OS_WINDOWS } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_PATH_OS_PATH_HPP libopenmpt-0.8.1+release.autotools/src/mpt/path/basic_path.hpp0000644000175000017500000007434614463360707021437 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_PATH_BASIC_PATH_HPP #define MPT_PATH_BASIC_PATH_HPP #include "mpt/base/detect.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/detect/mfc.hpp" #include "mpt/string_transcode/transcode.hpp" #include #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace path_literals { template struct literals; template MPT_CONSTEVAL Tchar L(char x) { return path_literals::literals::L(x); } template MPT_CONSTEVAL const Tchar * L(const char (&x)[N]) { return path_literals::literals::L(x); } template <> struct literals { using char_type = char; static MPT_CONSTEVAL char_type L(char c) { if (c == '\0') return '\0'; if (c == '\\') return '\\'; if (c == '/') return '/'; if (c == '.') return '.'; if (c == ':') return ':'; if (c == '?') return '?'; if (c == '*') return '*'; if (c == '|') return '|'; if (c == '<') return '<'; if (c == '>') return '>'; if (c == '\"') return '\"'; if (c == '_') return '_'; #if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) else return false ? 0 : throw std::domain_error("invalid path literal"); #else throw std::domain_error("invalid path literal"); #endif } template static MPT_CONSTEVAL const char_type * L(const char (&s)[N]) { if (std::string_view(s) == std::string_view("")) return ""; if (std::string_view(s) == std::string_view("/")) return "/"; if (std::string_view(s) == std::string_view(".")) return "."; if (std::string_view(s) == std::string_view("\\")) return "\\"; if (std::string_view(s) == std::string_view("..")) return ".."; if (std::string_view(s) == std::string_view("//")) return "//"; if (std::string_view(s) == std::string_view("./")) return "./"; if (std::string_view(s) == std::string_view(".\\")) return ".\\"; if (std::string_view(s) == std::string_view("\\/")) return "\\/"; if (std::string_view(s) == std::string_view("/\\")) return "/\\"; if (std::string_view(s) == std::string_view("\\\\")) return "\\\\"; if (std::string_view(s) == std::string_view("\\\\?\\")) return "\\\\?\\"; if (std::string_view(s) == std::string_view("\\\\?\\UNC")) return "\\\\?\\UNC"; if (std::string_view(s) == std::string_view("\\\\?\\UNC\\")) return "\\\\?\\UNC\\"; #if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) else return false ? nullptr : throw std::domain_error("invalid path literal"); #else throw std::domain_error("invalid path literal"); #endif } }; #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> struct literals { using char_type = wchar_t; static MPT_CONSTEVAL char_type L(char c) { if (c == '\0') return L'\0'; if (c == '\\') return L'\\'; if (c == '/') return L'/'; if (c == '.') return L'.'; if (c == ':') return L':'; if (c == '?') return L'?'; if (c == '*') return L'*'; if (c == '|') return L'|'; if (c == '<') return L'<'; if (c == '>') return L'>'; if (c == '\"') return L'\"'; if (c == '_') return L'_'; #if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) else return false ? 0 : throw std::domain_error("invalid path literal"); #else throw std::domain_error("invalid path literal"); #endif } template static MPT_CONSTEVAL const char_type * L(const char (&s)[N]) { if (std::string_view(s) == std::string_view("")) return L""; if (std::string_view(s) == std::string_view("/")) return L"/"; if (std::string_view(s) == std::string_view(".")) return L"."; if (std::string_view(s) == std::string_view("\\")) return L"\\"; if (std::string_view(s) == std::string_view("..")) return L".."; if (std::string_view(s) == std::string_view("//")) return L"//"; if (std::string_view(s) == std::string_view("./")) return L"./"; if (std::string_view(s) == std::string_view(".\\")) return L".\\"; if (std::string_view(s) == std::string_view("\\/")) return L"\\/"; if (std::string_view(s) == std::string_view("/\\")) return L"/\\"; if (std::string_view(s) == std::string_view("\\\\")) return L"\\\\"; if (std::string_view(s) == std::string_view("\\\\?\\")) return L"\\\\?\\"; if (std::string_view(s) == std::string_view("\\\\?\\UNC")) return L"\\\\?\\UNC"; if (std::string_view(s) == std::string_view("\\\\?\\UNC\\")) return L"\\\\?\\UNC\\"; #if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) else return false ? nullptr : throw std::domain_error("invalid path literal"); #else throw std::domain_error("invalid path literal"); #endif } }; #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_CXX_AT_LEAST(20) template <> struct literals { using char_type = char8_t; static MPT_CONSTEVAL char_type L(char c) { if (c == '\0') return u8'\0'; if (c == '\\') return u8'\\'; if (c == '/') return u8'/'; if (c == '.') return u8'.'; if (c == ':') return u8':'; if (c == '?') return u8'?'; if (c == '*') return u8'*'; if (c == '|') return u8'|'; if (c == '<') return u8'<'; if (c == '>') return u8'>'; if (c == '\"') return u8'\"'; if (c == '_') return u8'_'; #if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) else return false ? 0 : throw std::domain_error("invalid path literal"); #else throw std::domain_error("invalid path literal"); #endif } template static MPT_CONSTEVAL const char_type * L(const char (&s)[N]) { if (std::string_view(s) == std::string_view("")) return u8""; if (std::string_view(s) == std::string_view("/")) return u8"/"; if (std::string_view(s) == std::string_view(".")) return u8"."; if (std::string_view(s) == std::string_view("\\")) return u8"\\"; if (std::string_view(s) == std::string_view("..")) return u8".."; if (std::string_view(s) == std::string_view("//")) return u8"//"; if (std::string_view(s) == std::string_view("./")) return u8"./"; if (std::string_view(s) == std::string_view(".\\")) return u8".\\"; if (std::string_view(s) == std::string_view("\\/")) return u8"\\/"; if (std::string_view(s) == std::string_view("/\\")) return u8"/\\"; if (std::string_view(s) == std::string_view("\\\\")) return u8"\\\\"; if (std::string_view(s) == std::string_view("\\\\?\\")) return u8"\\\\?\\"; if (std::string_view(s) == std::string_view("\\\\?\\UNC")) return u8"\\\\?\\UNC"; if (std::string_view(s) == std::string_view("\\\\?\\UNC\\")) return u8"\\\\?\\UNC\\"; #if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) else return false ? nullptr : throw std::domain_error("invalid path literal"); #else throw std::domain_error("invalid path literal"); #endif } }; #endif // C++20 template <> struct literals { using char_type = char16_t; static MPT_CONSTEVAL char_type L(char c) { if (c == '\0') return u'\0'; if (c == '\\') return u'\\'; if (c == '/') return u'/'; if (c == '.') return u'.'; if (c == ':') return u':'; if (c == '?') return u'?'; if (c == '*') return u'*'; if (c == '|') return u'|'; if (c == '<') return u'<'; if (c == '>') return u'>'; if (c == '\"') return u'\"'; if (c == '_') return u'_'; #if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) else return false ? 0 : throw std::domain_error("invalid path literal"); #else throw std::domain_error("invalid path literal"); #endif } template static MPT_CONSTEVAL const char_type * L(const char (&s)[N]) { if (std::string_view(s) == std::string_view("")) return u""; if (std::string_view(s) == std::string_view("/")) return u"/"; if (std::string_view(s) == std::string_view(".")) return u"."; if (std::string_view(s) == std::string_view("\\")) return u"\\"; if (std::string_view(s) == std::string_view("..")) return u".."; if (std::string_view(s) == std::string_view("//")) return u"//"; if (std::string_view(s) == std::string_view("./")) return u"./"; if (std::string_view(s) == std::string_view(".\\")) return u".\\"; if (std::string_view(s) == std::string_view("\\/")) return u"\\/"; if (std::string_view(s) == std::string_view("/\\")) return u"/\\"; if (std::string_view(s) == std::string_view("\\\\")) return u"\\\\"; if (std::string_view(s) == std::string_view("\\\\?\\")) return u"\\\\?\\"; if (std::string_view(s) == std::string_view("\\\\?\\UNC")) return u"\\\\?\\UNC"; if (std::string_view(s) == std::string_view("\\\\?\\UNC\\")) return u"\\\\?\\UNC\\"; #if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) else return false ? nullptr : throw std::domain_error("invalid path literal"); #else throw std::domain_error("invalid path literal"); #endif } }; template <> struct literals { using char_type = char32_t; static MPT_CONSTEVAL char_type L(char c) { if (c == '\0') return U'\0'; if (c == '\\') return U'\\'; if (c == '/') return U'/'; if (c == '.') return U'.'; if (c == ':') return U':'; if (c == '?') return U'?'; if (c == '*') return U'*'; if (c == '|') return U'|'; if (c == '<') return U'<'; if (c == '>') return U'>'; if (c == '\"') return U'\"'; if (c == '_') return U'_'; #if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) else return false ? 0 : throw std::domain_error("invalid path literal"); #else throw std::domain_error("invalid path literal"); #endif } template static MPT_CONSTEVAL const char_type * L(const char (&s)[N]) { if (std::string_view(s) == std::string_view("")) return U""; if (std::string_view(s) == std::string_view("/")) return U"/"; if (std::string_view(s) == std::string_view(".")) return U"."; if (std::string_view(s) == std::string_view("\\")) return U"\\"; if (std::string_view(s) == std::string_view("..")) return U".."; if (std::string_view(s) == std::string_view("//")) return U"//"; if (std::string_view(s) == std::string_view("./")) return U"./"; if (std::string_view(s) == std::string_view(".\\")) return U".\\"; if (std::string_view(s) == std::string_view("\\/")) return U"\\/"; if (std::string_view(s) == std::string_view("/\\")) return U"/\\"; if (std::string_view(s) == std::string_view("\\\\")) return U"\\\\"; if (std::string_view(s) == std::string_view("\\\\?\\")) return U"\\\\?\\"; if (std::string_view(s) == std::string_view("\\\\?\\UNC")) return U"\\\\?\\UNC"; if (std::string_view(s) == std::string_view("\\\\?\\UNC\\")) return U"\\\\?\\UNC\\"; #if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) else return false ? nullptr : throw std::domain_error("invalid path literal"); #else throw std::domain_error("invalid path literal"); #endif } }; } // namespace path_literals enum class PathStyle { Posix, DOS_DJGPP, Windows9x, WindowsNT, }; template struct PathStyleTag { static inline constexpr PathStyle path_style = EStyle; }; template struct PathTraits { static inline constexpr PathStyle path_style = PathStyleTag::path_style; using raw_path_type = TRawPath; using char_type = typename raw_path_type::value_type; static bool IsPathSeparator(char_type c) { using namespace path_literals; bool result{}; if constexpr ((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x) || (path_style == PathStyle::DOS_DJGPP)) { result = (c == L('\\')) || (c == L('/')); } else if constexpr (path_style == PathStyle::Posix) { result = (c == L('/')); } else { //static_assert(false); } return result; } static char_type GetDefaultPathSeparator() { using namespace path_literals; char_type result{}; if constexpr ((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x) || (path_style == PathStyle::DOS_DJGPP)) { result = L('\\'); } else if constexpr (path_style == PathStyle::Posix) { result = L('/'); } else { //static_assert(false); } return result; } static bool IsValidComponentChar(char_type c) { using namespace path_literals; bool result = true; if constexpr ((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x) || (path_style == PathStyle::DOS_DJGPP)) { if (c == L('\\') || c == L('\"') || c == L('/') || c == L(':') || c == L('?') || c == L('<') || c == L('>') || c == L('|') || c == L('*')) { result = false; } else { result = true; } } else if constexpr (path_style == PathStyle::Posix) { result = (c != L('/')); } else { // nothing } return result; } static char_type InvalidComponentCharReplacement() { using namespace path_literals; return L('_'); } #if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) // Work-around / // . #pragma GCC push_options #if defined(__OPTIMIZE__) #pragma GCC optimize("O1") #endif // Work-around brain-damaged GCC warning 'void operator delete(void*, std::size_t)' called on a pointer to an unallocated object '"\\\000\\\000\000"'. // Probably a duplicate of one of the many incarnations of . #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfree-nonheap-object" #endif static void SplitPath(raw_path_type p, raw_path_type * prefix, raw_path_type * drive, raw_path_type * dir, raw_path_type * fbase, raw_path_type * fext) { using namespace path_literals; if (prefix) { *prefix = raw_path_type(); } if (drive) { *drive = raw_path_type(); } if (dir) { *dir = raw_path_type(); } if (fbase) { *fbase = raw_path_type(); } if (fext) { *fext = raw_path_type(); } if constexpr ((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x) || (path_style == PathStyle::DOS_DJGPP)) { // We cannot use CRT splitpath here, because: // * limited to _MAX_PATH or similar // * no support for UNC paths // * no support for \\?\ prefixed paths if constexpr (path_style == PathStyle::WindowsNT) { // remove \\?\\ prefix if (p.substr(0, 8) == L("\\\\?\\UNC\\")) { if (prefix) { *prefix = L("\\\\?\\UNC"); } p = L("\\\\") + p.substr(8); } else if (p.substr(0, 4) == L("\\\\?\\")) { if (prefix) { *prefix = L("\\\\?\\"); } p = p.substr(4); } } MPT_MAYBE_CONSTANT_IF (((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x)) && (p.length() >= 2) && (p.substr(0, 2) == L("\\\\") || p.substr(0, 2) == L("\\/") || p.substr(0, 2) == L("/\\") || p.substr(0, 2) == L("//"))) { // UNC typename raw_path_type::size_type first_slash = p.substr(2).find_first_of(L("\\/")); if (first_slash != raw_path_type::npos) { typename raw_path_type::size_type second_slash = p.substr(2 + first_slash + 1).find_first_of(L("\\/")); if (second_slash != raw_path_type::npos) { if (drive) { *drive = p.substr(0, 2 + first_slash + 1 + second_slash); } p = p.substr(2 + first_slash + 1 + second_slash); } else { if (drive) { *drive = p; } p = raw_path_type(); } } else { if (drive) { *drive = p; } p = raw_path_type(); } } else { // local if (p.length() >= 2 && (p[1] == L(':'))) { if (drive) { *drive = p.substr(0, 2); } p = p.substr(2); } else { if (drive) { *drive = raw_path_type(); } } } typename raw_path_type::size_type last_slash = p.find_last_of(L("\\/")); if (last_slash != raw_path_type::npos) { if (dir) { *dir = p.substr(0, last_slash + 1); } p = p.substr(last_slash + 1); } else { if (dir) { *dir = raw_path_type(); } } typename raw_path_type::size_type last_dot = p.find_last_of(L(".")); if (last_dot == raw_path_type::npos) { if (fbase) { *fbase = p; } if (fext) { *fext = raw_path_type(); } } else if (last_dot == 0) { if (fbase) { *fbase = p; } if (fext) { *fext = raw_path_type(); } } else if (p == L(".") || p == L("..")) { if (fbase) { *fbase = p; } if (fext) { *fext = raw_path_type(); } } else { if (fbase) { *fbase = p.substr(0, last_dot); } if (fext) { *fext = p.substr(last_dot); } } } else if constexpr (path_style == PathStyle::Posix) { typename raw_path_type::size_type last_slash = p.find_last_of(L("/")); if (last_slash != raw_path_type::npos) { if (dir) { *dir = p.substr(0, last_slash + 1); } p = p.substr(last_slash + 1); } else { if (dir) { *dir = raw_path_type(); } } typename raw_path_type::size_type last_dot = p.find_last_of(L(".")); if (last_dot == raw_path_type::npos) { if (fbase) { *fbase = p; } if (fext) { *fext = raw_path_type(); } } else if (last_dot == 0) { if (fbase) { *fbase = p; } if (fext) { *fext = raw_path_type(); } } else if (p == L(".") || p == L("..")) { if (fbase) { *fbase = p; } if (fext) { *fext = raw_path_type(); } } else { if (fbase) { *fbase = p.substr(0, last_dot); } if (fext) { *fext = p.substr(last_dot); } } } else { //static_assert(false); } } #if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) #pragma GCC diagnostic pop #pragma GCC pop_options #endif #if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) // Work-around / // . #pragma GCC push_options #if defined(__OPTIMIZE__) #pragma GCC optimize("O1") #endif #endif // Convert a path to its simplified form, i.e. remove ".\" and "..\" entries // Note: We use our own implementation as PathCanonicalize is limited to MAX_PATH // and unlimited versions are only available on Windows 8 and later. // Furthermore, we also convert forward-slashes to backslashes and always remove trailing slashes. static raw_path_type Simplify(const raw_path_type & path) { using namespace path_literals; raw_path_type result{}; if (path.empty()) { return result; } std::vector components; if constexpr ((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x) || (path_style == PathStyle::DOS_DJGPP)) { raw_path_type root; typename raw_path_type::size_type startPos = 0; if (path.size() >= 2 && path[1] == L(':')) { // Drive letter root = path.substr(0, 2) + L('\\'); startPos = 2; } else MPT_MAYBE_CONSTANT_IF (((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x)) && (path.substr(0, 2) == L("\\\\"))) { // Network share root = L("\\\\"); startPos = 2; } else if (path.substr(0, 2) == L(".\\") || path.substr(0, 2) == L("./")) { // Special case for relative paths root = L(".\\"); startPos = 2; } else if (path.size() >= 1 && (path[0] == L('\\') || path[0] == L('/'))) { // Special case for relative paths root = L("\\"); startPos = 1; } while (startPos < path.size()) { auto pos = path.find_first_of(L("\\/"), startPos); if (pos == raw_path_type::npos) { pos = path.size(); } raw_path_type dir = path.substr(startPos, pos - startPos); if (dir == L("..")) { // Go back one directory if (!components.empty()) { components.pop_back(); } } else if (dir == L(".")) { // nop } else if (!dir.empty()) { components.push_back(std::move(dir)); } startPos = pos + 1; } result = root; result.reserve(path.size()); for (const auto & component : components) { result += component + L("\\"); } if (!components.empty()) { result.pop_back(); } } else if constexpr (path_style == PathStyle::Posix) { raw_path_type root; typename raw_path_type::size_type startPos = 0; if (path.substr(0, 2) == L("./")) { // Special case for relative paths root = L("./"); startPos = 2; } else if (path.size() >= 1 && (path[0] == L('/'))) { // Special case for relative paths root = L("/"); startPos = 1; } while (startPos < path.size()) { auto pos = path.find_first_of(L("/"), startPos); if (pos == raw_path_type::npos) { pos = path.size(); } raw_path_type dir = path.substr(startPos, pos - startPos); if (dir == L("..")) { // Go back one directory if (!components.empty()) { components.pop_back(); } } else if (dir == L(".")) { // nop } else if (!dir.empty()) { components.push_back(std::move(dir)); } startPos = pos + 1; } result = root; result.reserve(path.size()); for (const auto & component : components) { result += component + L("/"); } if (!components.empty()) { result.pop_back(); } } else { //static_assert(false); } return result; } #if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) #pragma GCC pop_options #endif #if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) // Work-around / // . #pragma GCC push_options #if defined(__OPTIMIZE__) #pragma GCC optimize("O1") #endif #endif static bool IsAbsolute(const raw_path_type & path) { using namespace path_literals; bool result{}; if constexpr (path_style == PathStyle::WindowsNT) { if (path.substr(0, 8) == L("\\\\?\\UNC\\")) { return true; } if (path.substr(0, 4) == L("\\\\?\\")) { return true; } if (path.substr(0, 2) == L("\\\\")) { return true; // UNC } if (path.substr(0, 2) == L("//")) { return true; // UNC } result = (path.length()) >= 3 && (path[1] == L(':')) && IsPathSeparator(path[2]); } else if constexpr (path_style == PathStyle::Windows9x) { if (path.substr(0, 2) == L("\\\\")) { return true; // UNC } if (path.substr(0, 2) == L("//")) { return true; // UNC } result = (path.length()) >= 3 && (path[1] == L(':')) && IsPathSeparator(path[2]); } else if constexpr (path_style == PathStyle::DOS_DJGPP) { result = (path.length()) >= 3 && (path[1] == L(':')) && IsPathSeparator(path[2]); } else if constexpr (path_style == PathStyle::Posix) { result = (path.length() >= 1) && IsPathSeparator(path[0]); } else { //static_assert(false); } return result; } #if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) #pragma GCC pop_options #endif }; template class BasicPathString { public: using path_traits = Traits; using raw_path_type = typename path_traits::raw_path_type; using char_type = typename raw_path_type::value_type; private: raw_path_type path; public: template ::value, bool>::type = true> BasicPathString(const Tpath & path_) : path(path_) { return; } template ::value, bool>::type = true> operator Tpath() const { return path; } public: BasicPathString() = default; BasicPathString(const BasicPathString &) = default; BasicPathString(BasicPathString &&) noexcept = default; BasicPathString & assign(const BasicPathString & other) { path = other.path; return *this; } BasicPathString & assign(BasicPathString && other) noexcept { path = std::move(other.path); return *this; } BasicPathString & operator=(const BasicPathString & other) { return assign(other); } BasicPathString & operator=(BasicPathString && other) noexcept { return assign(std::move(other)); } BasicPathString & append(const BasicPathString & other) { path.append(other.path); return *this; } BasicPathString & operator+=(const BasicPathString & other) { return append(other); } friend BasicPathString operator+(const BasicPathString & a, const BasicPathString & b) { return BasicPathString(a).append(b); } friend bool operator<(const BasicPathString & a, const BasicPathString & b) { return a.AsNative() < b.AsNative(); } friend bool operator==(const BasicPathString & a, const BasicPathString & b) { return a.AsNative() == b.AsNative(); } friend bool operator!=(const BasicPathString & a, const BasicPathString & b) { return a.AsNative() != b.AsNative(); } bool empty() const { return path.empty(); } std::size_t length() const { return path.size(); } std::size_t Length() const { return path.size(); } public: raw_path_type AsNative() const { return path; } static BasicPathString FromNative(const raw_path_type & path) { return BasicPathString(path); } mpt::ustring ToUnicode() const { return mpt::transcode(path); } static BasicPathString FromUnicode(const mpt::ustring & path) { return BasicPathString(mpt::transcode(path)); } std::string ToUTF8() const { return mpt::transcode(mpt::common_encoding::utf8, path); } static BasicPathString FromUTF8(const std::string & path) { return BasicPathString(mpt::transcode(mpt::common_encoding::utf8, path)); } #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) std::wstring ToWide() const { return mpt::transcode(path); } static BasicPathString FromWide(const std::wstring & path) { return BasicPathString(mpt::transcode(path)); } #endif // !MPT_COMPILER_QUIRK_NO_WCHAR template ::type = true> std::string ToLocale() const { return mpt::transcode(mpt::logical_encoding::locale, path); } template ::type = true> static BasicPathString FromLocale(const std::string & path) { return BasicPathString(mpt::transcode(mpt::logical_encoding::locale, path)); } #if MPT_DETECTED_MFC CString ToCString() const { return mpt::transcode(path); } static BasicPathString FromCString(const CString & path) { return BasicPathString(mpt::transcode(path)); } #endif // MPT_DETECTED_MFC public: static bool IsPathSeparator(char_type c) { return path_traits::IsPathSeparator(c); } static char_type GetDefaultPathSeparator() { return path_traits::GetDefaultPathSeparator(); } bool HasTrailingSlash() const { if (path.empty()) { return false; } char_type c = path[path.length() - 1]; return IsPathSeparator(c); } BasicPathString AsSanitizedComponent() const { BasicPathString result = *this; for (auto & c : result.path) { if (!path_traits::IsValidComponentChar(c)) { c = path_traits::InvalidComponentCharReplacement(); } } return result; } BasicPathString WithoutTrailingSlash() const { BasicPathString result = *this; while (result.HasTrailingSlash()) { if (result.Length() == 1) { return result; } result = BasicPathString(result.AsNative().substr(0, result.AsNative().length() - 1)); } return result; } BasicPathString WithTrailingSlash() const { BasicPathString result = *this; if (!result.empty() && !result.HasTrailingSlash()) { result.path += GetDefaultPathSeparator(); } return result; } void SplitPath(BasicPathString * prefix, BasicPathString * drive, BasicPathString * dir, BasicPathString * fbase, BasicPathString * fext) const { path_traits::SplitPath(path, prefix ? &prefix->path : nullptr, drive ? &drive->path : nullptr, dir ? &dir->path : nullptr, fbase ? &fbase->path : nullptr, fext ? &fext->path : nullptr); } // \\?\ or \\?\\UNC or empty BasicPathString GetPrefix() const { BasicPathString prefix; SplitPath(&prefix, nullptr, nullptr, nullptr, nullptr); return prefix; } // Drive letter + colon, e.g. "C:" or \\server\share BasicPathString GetDrive() const { BasicPathString drive; SplitPath(nullptr, &drive, nullptr, nullptr, nullptr); return drive; } // Directory, e.g. "\OpenMPT\" BasicPathString GetDirectory() const { BasicPathString dir; SplitPath(nullptr, nullptr, &dir, nullptr, nullptr); return dir; } // Drive + Dir, e.g. "C:\OpenMPT\" BasicPathString GetDirectoryWithDrive() const { BasicPathString drive, dir; SplitPath(nullptr, &drive, &dir, nullptr, nullptr); return drive + dir; } // File name without extension, e.g. "OpenMPT" BasicPathString GetFilenameBase() const { BasicPathString fname; SplitPath(nullptr, nullptr, nullptr, &fname, nullptr); return fname; } // Extension including dot, e.g. ".exe" BasicPathString GetFilenameExtension() const { BasicPathString ext; SplitPath(nullptr, nullptr, nullptr, nullptr, &ext); return ext; } // File name + extension, e.g. "OpenMPT.exe" BasicPathString GetFilename() const { BasicPathString name, ext; SplitPath(nullptr, nullptr, nullptr, &name, &ext); return name + ext; } // Return the same path string with a different (or appended) extension (including "."), e.g. "foo.bar",".txt" -> "foo.txt" or "C:\OpenMPT\foo",".txt" -> "C:\OpenMPT\foo.txt" BasicPathString ReplaceExtension(const BasicPathString & newExt) const { return GetDirectoryWithDrive() + GetFilenameBase() + newExt; } // Convert a path to its simplified form, i.e. remove ".\" and "..\" entries, similar to std::fs::path::lexically_normal BasicPathString Simplify() const { return BasicPathString::FromNative(path_traits::Simplify(path)); } bool IsAbsolute() const { return path_traits::IsAbsolute(path); } bool is_absolute() const { return path_traits::IsAbsolute(path); } bool is_relative() const { return !path_traits::IsAbsolute(path); } }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_PATH_BASIC_PATH_HPP libopenmpt-0.8.1+release.autotools/src/mpt/path/os_path_long.hpp0000644000175000017500000000361414354032307021773 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_PATH_OS_PATH_LONG_HPP #define MPT_PATH_OS_PATH_LONG_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/path/os_path.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { inline mpt::os_path support_long_path(const mpt::os_path & path) { #if MPT_OS_WINDOWS #if !MPT_OS_WINDOWS_WINRT #define MPT_PATH_OS_PATH_USE_WINDOWS_LONG_PATH_PREFIX #else // MPT_OS_WINDOWS_WINRT // For WinRT on Windows 8, there is no official wy to determine an absolute path. #if MPT_WINRT_AT_LEAST(MPT_WIN_10) #define MPT_PATH_OS_PATH_USE_WINDOWS_LONG_PATH_PREFIX #endif // Windows >= 10 #endif // !MPT_OS_WINDOWS_WINRT #endif // MPT_OS_WINDOWS #if defined(MPT_PATH_OS_PATH_USE_WINDOWS_LONG_PATH_PREFIX) if (path.length() < MAX_PATH) { // path is short enough return path; } if (path.substr(0, 4) == MPT_OS_PATH_LITERAL("\\\\?\\")) { // path is already in prefixed form return path; } mpt::os_path absolute_path = path; DWORD size = GetFullPathName(path.c_str(), 0, nullptr, nullptr); if (size != 0) { std::vector fullPathName(size, TEXT('\0')); if (GetFullPathName(path.c_str(), size, fullPathName.data(), nullptr) != 0) { absolute_path = fullPathName.data(); } } if (absolute_path.substr(0, 2) == MPT_OS_PATH_LITERAL("\\\\")) { // Path is a network share: \\server\foo.bar -> \\?\UNC\server\foo.bar return MPT_OS_PATH_LITERAL("\\\\?\\UNC") + absolute_path.substr(1); } else { // Regular file: C:\foo.bar -> \\?\C:\foo.bar return MPT_OS_PATH_LITERAL("\\\\?\\") + absolute_path; } #else return path; #endif } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_PATH_OS_PATH_LONG_HPP libopenmpt-0.8.1+release.autotools/src/mpt/system_error/0000755000175000017500000000000015023302361020455 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/system_error/system_error.hpp0000644000175000017500000000713514107230757023664 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_SYSTEM_ERROR_SYSTEM_ERROR_HPP #define MPT_SYSTEM_ERROR_SYSTEM_ERROR_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/format/message.hpp" #include "mpt/format/message_macros.hpp" #include "mpt/format/simple.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include "mpt/out_of_memory/out_of_memory.hpp" #if MPT_OS_WINDOWS #include #if MPT_OS_WINDOWS_WINRT #include #endif // MPT_OS_WINDOWS_WINRT #endif // MPT_OS_WINDOWS #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_OS_WINDOWS namespace windows { inline mpt::ustring GetErrorMessage(DWORD errorCode, HANDLE hModule = NULL) { #if MPT_OS_WINDOWS_WINRT std::vector msgbuf(65536); if (FormatMessage( (hModule ? FORMAT_MESSAGE_FROM_HMODULE : 0) | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, hModule, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), msgbuf.data(), mpt::saturate_cast(msgbuf.size()), NULL) == 0) { DWORD e = GetLastError(); if ((e == ERROR_NOT_ENOUGH_MEMORY) || (e == ERROR_OUTOFMEMORY)) { mpt::throw_out_of_memory(); } return {}; } return mpt::transcode(mpt::winstring{msgbuf.data()}); #else mpt::ustring message; void * lpMsgBuf = nullptr; if (FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | (hModule ? FORMAT_MESSAGE_FROM_HMODULE : 0) | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, hModule, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL) == 0) { DWORD e = GetLastError(); if (lpMsgBuf) { LocalFree(lpMsgBuf); } if ((e == ERROR_NOT_ENOUGH_MEMORY) || (e == ERROR_OUTOFMEMORY)) { mpt::throw_out_of_memory(); } return {}; } if (!lpMsgBuf) { return {}; } try { message = mpt::transcode(mpt::winstring{static_cast(lpMsgBuf)}); } catch (mpt::out_of_memory e) { LocalFree(lpMsgBuf); mpt::rethrow_out_of_memory(e); } LocalFree(lpMsgBuf); return message; #endif } class error : public std::runtime_error { public: error(DWORD errorCode, HANDLE hModule = NULL) : std::runtime_error(mpt::transcode(mpt::exception_encoding, MPT_UFORMAT_MESSAGE("Windows Error: 0x{}: {}")(mpt::format::hex0<8>(errorCode), GetErrorMessage(errorCode, hModule)))) { return; } }; inline HANDLE CheckFileHANDLE(HANDLE handle) { if (handle == INVALID_HANDLE_VALUE) { DWORD err = ::GetLastError(); if ((err == ERROR_NOT_ENOUGH_MEMORY) || (err == ERROR_OUTOFMEMORY)) { mpt::throw_out_of_memory(); } throw windows::error(err); } return handle; } inline HANDLE CheckHANDLE(HANDLE handle) { if (handle == NULL) { DWORD err = ::GetLastError(); if ((err == ERROR_NOT_ENOUGH_MEMORY) || (err == ERROR_OUTOFMEMORY)) { mpt::throw_out_of_memory(); } throw windows::error(err); } return handle; } inline void CheckBOOL(BOOL result) { if (result == FALSE) { DWORD err = ::GetLastError(); if ((err == ERROR_NOT_ENOUGH_MEMORY) || (err == ERROR_OUTOFMEMORY)) { mpt::throw_out_of_memory(); } throw windows::error(err); } } inline void ExpectError(DWORD expected) { DWORD err = ::GetLastError(); if (err != expected) { if ((err == ERROR_NOT_ENOUGH_MEMORY) || (err == ERROR_OUTOFMEMORY)) { mpt::throw_out_of_memory(); } throw windows::error(err); } } } // namespace windows #endif // MPT_OS_WINDOWS } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_SYSTEM_ERROR_SYSTEM_ERROR_HPP libopenmpt-0.8.1+release.autotools/src/mpt/LICENSE.BSD-3-Clause.txt0000644000175000017500000000307414734741400021461 00000000000000Copyright (c) 2004-2025, OpenMPT Project Developers and Contributors Copyright (c) 1997-2003, Olivier Lapicque All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the OpenMPT project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. libopenmpt-0.8.1+release.autotools/src/mpt/test/0000755000175000017500000000000015023302361016677 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/test/test.hpp0000644000175000017500000004544414336355151020335 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_TEST_TEST_HPP #define MPT_TEST_TEST_HPP #include "mpt/base/namespace.hpp" #include "mpt/base/source_location.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace test { template struct is_to_stream_writable : std::false_type { }; template struct is_to_stream_writable() << std::declval())>> : std::true_type { }; template inline auto format(const T & x) -> typename std::enable_if::value, std::string>::type { std::ostringstream s; s << x; return std::move(s).str(); } template inline auto format(const T & x) -> typename std::enable_if::value, std::string>::type { return typeid(x).name(); } inline std::string get_exception_text() { std::string result; try { // cppcheck false-positive // cppcheck-suppress rethrowNoCurrentException throw; } catch (const std::exception & e) { result = e.what(); } catch (...) { result = "unknown exception"; } return result; } struct result_success { }; struct result_failure { std::string text{}; }; struct result_unexpected_exception { std::string text{}; }; struct result { std::variant info{std::monostate{}}; }; struct statistics_counters { std::size_t total{0}; std::size_t run{0}; std::size_t successes{0}; std::size_t failures{0}; std::size_t unexpected_exceptions{0}; std::size_t completed{0}; constexpr statistics_counters & operator+=(const statistics_counters & other) noexcept { total += other.total; run += other.run; successes += other.successes; failures += other.failures; unexpected_exceptions += other.unexpected_exceptions; completed += other.completed; return *this; } }; struct group_statistics { statistics_counters tests{}; statistics_counters cases{}; statistics_counters local_cases{}; }; struct global_statistics { statistics_counters groups{}; statistics_counters tests{}; statistics_counters cases{}; std::map individual_group_statistics{}; explicit constexpr operator bool() noexcept { return succeeded(); } constexpr bool operator!() noexcept { return failed(); } constexpr bool succeeded() noexcept { return groups.successes == groups.run; } constexpr bool failed() noexcept { return groups.failures > 0 || groups.unexpected_exceptions > 0; } }; class reporter_interface { protected: virtual ~reporter_interface() = default; public: virtual void run_begin(const mpt::source_location & loc) = 0; virtual void group_begin(const mpt::source_location & loc, const char * name) = 0; virtual void test_begin(const mpt::source_location & loc, const char * name) = 0; virtual void case_run(const mpt::source_location & loc) = 0; virtual void case_run(const mpt::source_location & loc, const char * text_e) = 0; virtual void case_run(const mpt::source_location & loc, const char * text_ex, const char * text_e) = 0; virtual void case_run(const mpt::source_location & loc, const char * text_a, const char * text_cmp, const char * text_b) = 0; virtual void case_result(const mpt::source_location & loc, const mpt::test::result & result) = 0; virtual void test_end(const mpt::source_location & loc, const char * name, const statistics_counters & counters) = 0; virtual void group_end(const mpt::source_location & loc, const char * name, const group_statistics & statistics) = 0; virtual void run_end(const mpt::source_location & loc, const global_statistics & statistics) = 0; virtual void immediate_breakpoint() = 0; }; class silent_reporter : public reporter_interface { public: silent_reporter() = default; ~silent_reporter() override = default; public: virtual void run_begin(const mpt::source_location &) override { } virtual void group_begin(const mpt::source_location &, const char *) override { } virtual void test_begin(const mpt::source_location &, const char *) override { } virtual void case_run(const mpt::source_location &) override { } virtual void case_run(const mpt::source_location &, const char *) override { } virtual void case_run(const mpt::source_location &, const char *, const char *) override { } virtual void case_run(const mpt::source_location &, const char *, const char *, const char *) override { } virtual void case_result(const mpt::source_location &, const mpt::test::result &) override { } virtual void test_end(const mpt::source_location &, const char *, const statistics_counters &) override { } virtual void group_end(const mpt::source_location &, const char *, const group_statistics &) override { } virtual void run_end(const mpt::source_location &, const global_statistics &) override { } virtual void immediate_breakpoint() override { } }; class simple_reporter : public reporter_interface { private: std::ostream & s; public: simple_reporter(std::ostream & s_) : s(s_) { s.flush(); } ~simple_reporter() override { s.flush(); } public: void run_begin(const mpt::source_location & loc) override { static_cast(loc); s << "Running test suite ..." << std::endl; } void group_begin(const mpt::source_location & loc, const char * name) override { static_cast(loc); s << "Running group '" << name << "' ..." << std::endl; } void test_begin(const mpt::source_location & loc, const char * name) override { static_cast(loc); s << " Running test '" << name << "' ..." << std::endl; } void case_run(const mpt::source_location & loc) override { static_cast(loc); s << " Checking ..." << std::endl; } void case_run(const mpt::source_location & loc, const char * text_e) override { static_cast(loc); s << " Checking '" << text_e << "' ..." << std::endl; } void case_run(const mpt::source_location & loc, const char * text_ex, const char * text_e) override { static_cast(loc); if (text_ex) { s << " Checking '" << text_e << " throws " << text_ex << "' ..." << std::endl; } else { s << " Checking '" << text_e << " throws' ..." << std::endl; } } void case_run(const mpt::source_location & loc, const char * text_a, const char * text_cmp, const char * text_b) override { static_cast(loc); s << " Checking '" << text_a << " " << text_cmp << " " << text_b << "' ..." << std::endl; } void case_result(const mpt::source_location & loc, const mpt::test::result & result) override { static_cast(loc); s << " Checking done: "; if (std::holds_alternative(result.info)) { s << "Success."; } else if (std::holds_alternative(result.info)) { s << "FAILURE: " << std::get(result.info).text; } else if (std::holds_alternative(result.info)) { s << "UNEXPECTED EXCEPTION: " << std::get(result.info).text; } s << std::endl; } void test_end(const mpt::source_location & loc, const char * name, const statistics_counters & counters) override { static_cast(loc); static_cast(counters); s << " Running test '" << name << "' done." << std::endl; } void group_end(const mpt::source_location & loc, const char * name, const group_statistics & statistics) override { static_cast(loc); static_cast(statistics); s << "Running group '" << name << "' done." << std::endl; } void run_end(const mpt::source_location & loc, const global_statistics & statistics) override { static_cast(loc); s << "Running test suite done." << std::endl; s << "groups: " << statistics.groups.total << " | " << statistics.groups.successes << " passed"; if (statistics.groups.failures || statistics.groups.unexpected_exceptions) { s << " | " << statistics.groups.failures << " FAILED"; if (statistics.groups.unexpected_exceptions) { s << " | " << statistics.groups.unexpected_exceptions << " UNEXPECTED EXCEPTIONS"; } } s << std::endl; s << "tests: " << statistics.tests.total << " | " << statistics.tests.successes << " passed"; if (statistics.tests.failures || statistics.tests.unexpected_exceptions) { s << " | " << statistics.tests.failures << " FAILED"; if (statistics.tests.unexpected_exceptions) { s << " | " << statistics.tests.unexpected_exceptions << " UNEXPECTED EXCEPTIONS"; } } s << std::endl; s << "checks: " << statistics.cases.total << " | " << statistics.cases.successes << " passed"; if (statistics.cases.failures || statistics.cases.unexpected_exceptions) { s << " | " << statistics.cases.failures << " FAILED"; if (statistics.cases.unexpected_exceptions) { s << " | " << statistics.cases.unexpected_exceptions << " UNEXPECTED EXCEPTIONS"; } } s << std::endl; } void immediate_breakpoint() override { return; } }; struct group; struct context { mpt::test::group & group; mpt::test::reporter_interface & reporter; mpt::test::group_statistics statistics{}; }; using void_context_function = void (*)(mpt::test::context &); struct group { group * next{nullptr}; const char * name{""}; void_context_function func{nullptr}; inline group(const char * name_, void_context_function f) : name(name_) , func(f) { next = group_list(); group_list() = this; } group_statistics run(mpt::test::reporter_interface & reporter, const mpt::source_location & loc = mpt::source_location::current()) { mpt::test::context context{*this, reporter}; context.reporter.group_begin(loc, name); if (func) { func(context); } context.reporter.group_end(loc, name, context.statistics); return context.statistics; } public: [[nodiscard]] static inline group *& group_list() noexcept { static group * group_list = nullptr; return group_list; } }; inline global_statistics run_all(mpt::test::reporter_interface & reporter, const mpt::source_location & loc = mpt::source_location::current()) { global_statistics statistics{}; reporter.run_begin(loc); for (group * g = group::group_list(); g; g = g->next) { statistics.groups.total++; statistics.groups.run++; group_statistics s = g->run(reporter, loc); if (s.tests.unexpected_exceptions) { statistics.groups.unexpected_exceptions++; } else if (s.tests.failures) { statistics.groups.failures++; } else { statistics.groups.successes++; } statistics.tests += s.tests; statistics.cases += s.cases; statistics.groups.completed++; statistics.individual_group_statistics[g->name] = s; } reporter.run_end(loc, statistics); return statistics; } struct test { mpt::test::context & context; const char * name{""}; mpt::source_location source_location{mpt::source_location::current()}; void (*breakpoint)(void){nullptr}; test(const test &) = delete; test & operator=(const test &) = delete; inline test(mpt::test::context & context_, void (*breakpoint_)(void) = nullptr, const mpt::source_location & source_location_ = mpt::source_location::current()) : context(context_) , source_location(source_location_) , breakpoint(breakpoint_) { report_test_begin(); } inline test(mpt::test::context & context_, const char * name_, void (*breakpoint_)(void) = nullptr, const mpt::source_location & source_location_ = mpt::source_location::current()) : context(context_) , name(name_) , source_location(source_location_) , breakpoint(breakpoint_) { report_test_begin(); } inline ~test() { report_test_end(); } inline void immediate_breakpoint() { if (breakpoint) { breakpoint(); } else { context.reporter.immediate_breakpoint(); } } void report_test_begin() { context.statistics.tests.total++; context.statistics.tests.run++; context.statistics.local_cases = statistics_counters{}; context.reporter.test_begin(source_location, name); } void report_run() { context.statistics.local_cases.total++; context.statistics.local_cases.run++; context.reporter.case_run(source_location); } void report_run(const char * text_e) { context.statistics.local_cases.total++; context.statistics.local_cases.run++; context.reporter.case_run(source_location, text_e); } void report_run(const char * text_ex, const char * text_e) { context.statistics.local_cases.total++; context.statistics.local_cases.run++; context.reporter.case_run(source_location, text_ex, text_e); } void report_run(const char * text_a, const char * text_cmp, const char * text_b) { context.statistics.local_cases.total++; context.statistics.local_cases.run++; context.reporter.case_run(source_location, text_a, text_cmp, text_b); } void report_result(mpt::test::result result) { if (std::holds_alternative(result.info)) { context.statistics.local_cases.successes++; } else if (std::holds_alternative(result.info)) { context.statistics.local_cases.failures++; } else if (std::holds_alternative(result.info)) { context.statistics.local_cases.unexpected_exceptions++; } context.statistics.local_cases.completed++; context.reporter.case_result(source_location, result); } void report_test_end() { context.statistics.cases += context.statistics.local_cases; if (context.statistics.local_cases.unexpected_exceptions) { context.statistics.tests.unexpected_exceptions++; } else if (context.statistics.local_cases.failures) { context.statistics.tests.failures++; } else { context.statistics.tests.successes++; } context.statistics.tests.completed++; context.reporter.test_end(source_location, name, context.statistics.local_cases); } template ::value, bool>::type = true> inline test & expect_throws(Tcallable c, const char * text_ex = nullptr, const char * text_e = nullptr) { const std::type_info & tiexception = typeid(Texception); const std::type_info & tic = typeid(decltype(c())); report_run(text_ex ? text_ex : tiexception.name(), text_e ? text_e : tic.name()); mpt::test::result result; try { c(); immediate_breakpoint(); result.info = mpt::test::result_failure{}; } catch (const Texception &) { result.info = mpt::test::result_success{}; } catch (...) { immediate_breakpoint(); result.info = mpt::test::result_unexpected_exception{mpt::test::get_exception_text()}; } report_result(result); return *this; } template ::value, bool>::type = true> inline test & expect_throws_any(Tcallable c, const char * text_e = nullptr) { const std::type_info & tic = typeid(decltype(c())); report_run(nullptr, text_e ? text_e : tic.name()); mpt::test::result result; try { c(); immediate_breakpoint(); result.info = mpt::test::result_failure{}; } catch (...) { result.info = mpt::test::result_success{}; } report_result(result); return *this; } template ::value, bool>::type = true> inline test & expect(Texpr e, const char * text_e = nullptr) { const std::type_info & tie = typeid(decltype(std::invoke(e))); report_run(text_e ? text_e : tie.name()); mpt::test::result result; try { const auto ve = std::invoke(e); if (!ve) { immediate_breakpoint(); result.info = mpt::test::result_failure{/*mpt::test::format(ve)*/}; } else { result.info = mpt::test::result_success{}; } } catch (...) { immediate_breakpoint(); result.info = mpt::test::result_unexpected_exception{mpt::test::get_exception_text()}; } report_result(result); return *this; } template ::value, bool>::type = true, typename std::enable_if::value, bool>::type = true> inline test & expect(Ta && a, Tcmp cmp, Tb && b, const char * text_a = nullptr, const char * text_cmp = nullptr, const char * text_b = nullptr) { const std::type_info & tia = typeid(decltype(std::invoke(a))); const std::type_info & ticmp = typeid(decltype(cmp)); const std::type_info & tib = typeid(decltype(std::invoke(b))); report_run(text_a ? text_a : tia.name(), text_cmp ? text_cmp : ticmp.name(), text_b ? text_b : tib.name()); mpt::test::result result; try { const auto va = std::invoke(a); const auto vb = std::invoke(b); if (!cmp(va, vb)) { immediate_breakpoint(); result.info = mpt::test::result_failure{mpt::test::format(va) + " " + mpt::test::format(cmp) + " " + mpt::test::format(vb)}; } else { result.info = mpt::test::result_success{}; } } catch (...) { immediate_breakpoint(); result.info = mpt::test::result_unexpected_exception{mpt::test::get_exception_text()}; } report_result(result); return *this; } template ::value, bool>::type = true> inline test & expect(Texpr && e, const char * text_e = nullptr) { const std::type_info & tie = typeid(decltype(std::forward(e))); report_run(text_e ? text_e : tie.name()); mpt::test::result result; try { const auto ve = std::forward(e); if (!ve) { immediate_breakpoint(); result.info = mpt::test::result_failure{/*mpt::test::format(ve)*/}; } else { result.info = mpt::test::result_success{}; } } catch (...) { immediate_breakpoint(); result.info = mpt::test::result_unexpected_exception{mpt::test::get_exception_text()}; } report_result(result); return *this; } template ::value, bool>::type = true, typename std::enable_if::value, bool>::type = true> inline test & expect(Ta && a, Tcmp cmp, Tb && b, const char * text_a = nullptr, const char * text_cmp = nullptr, const char * text_b = nullptr) { const std::type_info & tia = typeid(decltype(std::forward(a))); const std::type_info & ticmp = typeid(decltype(cmp)); const std::type_info & tib = typeid(decltype(std::forward(b))); report_run(text_a ? text_a : tia.name(), text_cmp ? text_cmp : ticmp.name(), text_b ? text_b : tib.name()); mpt::test::result result; try { const auto va = std::forward(a); const auto vb = std::forward(b); if (!cmp(va, vb)) { immediate_breakpoint(); result.info = mpt::test::result_failure{mpt::test::format(va) + " " + mpt::test::format(cmp) + " " + mpt::test::format(vb)}; } else { result.info = mpt::test::result_success{}; } } catch (...) { immediate_breakpoint(); result.info = mpt::test::result_unexpected_exception{mpt::test::get_exception_text()}; } report_result(result); return *this; } }; } // namespace test } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_TEST_TEST_HPP libopenmpt-0.8.1+release.autotools/src/mpt/test/test_macros.hpp0000644000175000017500000000544314044173557021700 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_TEST_TEST_MACROS_HPP #define MPT_TEST_TEST_MACROS_HPP #include "mpt/base/namespace.hpp" #include "mpt/base/preprocessor.hpp" #include "mpt/test/test.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace test { #define MPT_TEST_GROUP_BEGIN(name) \ inline mpt::test::group MPT_PP_UNIQUE_IDENTIFIER(mpt_test_group_name) { \ name, [](mpt::test::context & mpt_test_context) { #define MPT_TEST_GROUP_END() \ } \ } \ ; #define MPT_TEST_GROUP_INLINE_IDENTIFIER(identifier, name) \ inline void MPT_PP_JOIN(mpt_test_group_func_, identifier)(mpt::test::context & mpt_test_context); \ inline mpt::test::group MPT_PP_JOIN(mpt_test_group_name_, identifier){ \ name, [](mpt::test::context & mpt_test_context) { \ MPT_PP_JOIN(mpt_test_group_func_, identifier) \ (mpt_test_context); \ }}; \ inline void MPT_PP_UNIQUE_IDENTIFIER(mpt_test_group_func)(mpt::test::context & mpt_test_context) #define MPT_TEST_GROUP_INLINE(name) \ inline void MPT_PP_UNIQUE_IDENTIFIER(mpt_test_group_func)(mpt::test::context & mpt_test_context); \ inline mpt::test::group MPT_PP_UNIQUE_IDENTIFIER(mpt_test_group_name){ \ name, [](mpt::test::context & mpt_test_context) { \ MPT_PP_UNIQUE_IDENTIFIER(mpt_test_group_func) \ (mpt_test_context); \ }}; \ inline void MPT_PP_UNIQUE_IDENTIFIER(mpt_test_group_func)(mpt::test::context & mpt_test_context) #define MPT_TEST_GROUP_STATIC(name) \ static void MPT_PP_UNIQUE_IDENTIFIER(mpt_test_group_func)(mpt::test::context & mpt_test_context); \ static mpt::test::group MPT_PP_UNIQUE_IDENTIFIER(mpt_test_group_name){ \ name, [](mpt::test::context & mpt_test_context) { \ MPT_PP_UNIQUE_IDENTIFIER(mpt_test_group_func) \ (mpt_test_context); \ }}; \ static void MPT_PP_UNIQUE_IDENTIFIER(mpt_test_group_func)(mpt::test::context & mpt_test_context) #define MPT_TEST_DELAYED(x) [&] { \ return x; \ } #define MPT_TEST_EXPECT mpt::test::test{context}.expect #define MPT_TEST_EXPECT_EXPR(e) mpt::test::test{mpt_test_context}.expect([&] { return e; }, #e) #define MPT_TEST_EXPECT_CMP(a, cmp, b) mpt::test::test{mpt_test_context}.expect([&] { return a; }, [](const auto & a_, const auto & b_) { return a_ cmp b_; }, [&] { return b; }, #a, #cmp, #b) #define MPT_TEST_EXPECT_THROWS_ANY(expr) mpt::test::test{mpt_test_context}.expect_throws_any([&] { expr; }, #expr) #define MPT_TEST_EXPECT_THROWS(exception, expr) mpt::test::test{mpt_test_context}.expect_throws([&] { expr; }, #exception, #expr) #define MPT_TEST_EXPECT_EQUAL(a, b) mpt::test::test{mpt_test_context}.expect([&] { return a; }, std::equal_to<>{}, [&] { return b; }, #a, "==", #b) } // namespace test } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_TEST_TEST_MACROS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/uuid/0000755000175000017500000000000015023302361016666 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/uuid/uuid.hpp0000644000175000017500000002750314460001065020275 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_UUID_UUID_HPP #define MPT_UUID_UUID_HPP #include "mpt/base/constexpr_throw.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/endian/integer.hpp" #include "mpt/format/default_formatter.hpp" #include "mpt/format/simple.hpp" #include "mpt/parse/parse.hpp" #include "mpt/random/random.hpp" #include "mpt/string/types.hpp" #include "mpt/string/utility.hpp" #if MPT_OS_WINDOWS #if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) #include #endif // MPT_WIN_VISTA #include #include #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { // Microsoft on-disk layout struct GUIDms { uint32le Data1; uint16le Data2; uint16le Data3; uint64be Data4; // yes, big endian here }; constexpr bool declare_binary_safe(const GUIDms &) { return true; } static_assert(mpt::check_binary_size(16)); // RFC binary format struct UUIDbin { uint32be Data1; uint16be Data2; uint16be Data3; uint64be Data4; }; constexpr bool declare_binary_safe(const UUIDbin &) { return true; } static_assert(mpt::check_binary_size(16)); struct UUID { private: uint32 Data1; uint16 Data2; uint16 Data3; uint64 Data4; public: MPT_CONSTEXPRINLINE uint32 GetData1() const noexcept { return Data1; } MPT_CONSTEXPRINLINE uint16 GetData2() const noexcept { return Data2; } MPT_CONSTEXPRINLINE uint16 GetData3() const noexcept { return Data3; } MPT_CONSTEXPRINLINE uint64 GetData4() const noexcept { return Data4; } public: MPT_CONSTEXPRINLINE uint64 GetData64_1() const noexcept { return (static_cast(Data1) << 32) | (static_cast(Data2) << 16) | (static_cast(Data3) << 0); } MPT_CONSTEXPRINLINE uint64 GetData64_2() const noexcept { return Data4; } public: // xxxxxxxx-xxxx-Mmxx-Nnxx-xxxxxxxxxxxx // <--32-->-<16>-<16>-<-------64------> MPT_CONSTEXPRINLINE bool IsNil() const noexcept { return (Data1 == 0) && (Data2 == 0) && (Data3 == 0) && (Data4 == 0); } MPT_CONSTEXPRINLINE bool IsValid() const noexcept { return (Data1 != 0) || (Data2 != 0) || (Data3 != 0) || (Data4 != 0); } MPT_CONSTEXPRINLINE uint8 Variant() const noexcept { return Nn() >> 4u; } MPT_CONSTEXPRINLINE uint8 Version() const noexcept { return Mm() >> 4u; } MPT_CONSTEXPRINLINE bool IsRFC4122() const noexcept { return (Variant() & 0xcu) == 0x8u; } private: MPT_CONSTEXPRINLINE uint8 Mm() const noexcept { return static_cast((Data3 >> 8) & 0xffu); } MPT_CONSTEXPRINLINE uint8 Nn() const noexcept { return static_cast((Data4 >> 56) & 0xffu); } #if MPT_COMPILER_GCC #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #endif // MPT_COMPILER_GCC void MakeRFC4122(uint8 version) noexcept { // variant uint8 Nn = static_cast((Data4 >> 56) & 0xffu); Data4 &= 0x00ffffffffffffffull; Nn &= ~(0xc0u); Nn |= 0x80u; Data4 |= static_cast(Nn) << 56; // version version &= 0x0fu; uint8 Mm = static_cast((Data3 >> 8) & 0xffu); Data3 &= 0x00ffu; Mm &= ~(0xf0u); Mm |= (version << 4u); Data3 |= static_cast(Mm) << 8; } #if MPT_COMPILER_GCC #pragma GCC diagnostic pop #endif // MPT_COMPILER_GCC #if MPT_OS_WINDOWS private: static mpt::UUID UUIDFromWin32(::UUID uuid) { return mpt::UUID(uuid.Data1, uuid.Data2, uuid.Data3, (static_cast(0) | (static_cast(uuid.Data4[0]) << 56) | (static_cast(uuid.Data4[1]) << 48) | (static_cast(uuid.Data4[2]) << 40) | (static_cast(uuid.Data4[3]) << 32) | (static_cast(uuid.Data4[4]) << 24) | (static_cast(uuid.Data4[5]) << 16) | (static_cast(uuid.Data4[6]) << 8) | (static_cast(uuid.Data4[7]) << 0))); } static ::UUID UUIDToWin32(mpt::UUID uuid) { ::UUID result = ::UUID(); result.Data1 = uuid.GetData1(); result.Data2 = uuid.GetData2(); result.Data3 = uuid.GetData3(); result.Data4[0] = static_cast(uuid.GetData4() >> 56); result.Data4[1] = static_cast(uuid.GetData4() >> 48); result.Data4[2] = static_cast(uuid.GetData4() >> 40); result.Data4[3] = static_cast(uuid.GetData4() >> 32); result.Data4[4] = static_cast(uuid.GetData4() >> 24); result.Data4[5] = static_cast(uuid.GetData4() >> 16); result.Data4[6] = static_cast(uuid.GetData4() >> 8); result.Data4[7] = static_cast(uuid.GetData4() >> 0); return result; } public: explicit UUID(::UUID uuid) { *this = UUIDFromWin32(uuid); } operator ::UUID() const { return UUIDToWin32(*this); } #endif // MPT_OS_WINDOWS private: static MPT_CONSTEXPRINLINE uint8 NibbleFromChar(char x) { return ('0' <= x && x <= '9') ? static_cast(x - '0' + 0) : ('a' <= x && x <= 'z') ? static_cast(x - 'a' + 10) : ('A' <= x && x <= 'Z') ? static_cast(x - 'A' + 10) : mpt::constexpr_throw(std::domain_error("")); } static MPT_CONSTEXPRINLINE uint8 ByteFromHex(char x, char y) { return static_cast(uint8(0) | (NibbleFromChar(x) << 4) | (NibbleFromChar(y) << 0)); } static MPT_CONSTEXPRINLINE uint16 ParseHex16(const char * str) { return static_cast(uint16(0) | (static_cast(ByteFromHex(str[0], str[1])) << 8) | (static_cast(ByteFromHex(str[2], str[3])) << 0)); } static MPT_CONSTEXPRINLINE uint32 ParseHex32(const char * str) { return static_cast(uint32(0) | (static_cast(ByteFromHex(str[0], str[1])) << 24) | (static_cast(ByteFromHex(str[2], str[3])) << 16) | (static_cast(ByteFromHex(str[4], str[5])) << 8) | (static_cast(ByteFromHex(str[6], str[7])) << 0)); } public: static MPT_CONSTEXPRINLINE UUID ParseLiteral(const char * str, std::size_t len) { return (len == 36 && str[8] == '-' && str[13] == '-' && str[18] == '-' && str[23] == '-') ? mpt::UUID( ParseHex32(str + 0), ParseHex16(str + 9), ParseHex16(str + 14), uint64(0) | (static_cast(ParseHex16(str + 19)) << 48) | (static_cast(ParseHex16(str + 24)) << 32) | (static_cast(ParseHex32(str + 28)) << 0)) : mpt::constexpr_throw(std::domain_error("")); } public: MPT_CONSTEXPRINLINE UUID() noexcept : Data1(0) , Data2(0) , Data3(0) , Data4(0) { return; } MPT_CONSTEXPRINLINE explicit UUID(uint32 Data1, uint16 Data2, uint16 Data3, uint64 Data4) noexcept : Data1(Data1) , Data2(Data2) , Data3(Data3) , Data4(Data4) { return; } explicit UUID(UUIDbin uuid) { Data1 = uuid.Data1.get(); Data2 = uuid.Data2.get(); Data3 = uuid.Data3.get(); Data4 = uuid.Data4.get(); } explicit UUID(GUIDms guid) { Data1 = guid.Data1.get(); Data2 = guid.Data2.get(); Data3 = guid.Data3.get(); Data4 = guid.Data4.get(); } operator UUIDbin() const { UUIDbin result{}; result.Data1 = GetData1(); result.Data2 = GetData2(); result.Data3 = GetData3(); result.Data4 = GetData4(); return result; } operator GUIDms() const { GUIDms result{}; result.Data1 = GetData1(); result.Data2 = GetData2(); result.Data3 = GetData3(); result.Data4 = GetData4(); return result; } public: // Create a UUID template static UUID Generate(Trng & rng) { #if MPT_WINRT_AT_LEAST(MPT_WIN_8) ::GUID guid = ::GUID(); HRESULT result = CoCreateGuid(&guid); if (result != S_OK) { return mpt::UUID::RFC4122Random(rng); } return mpt::UUID::UUIDFromWin32(guid); #elif MPT_WINRT_BEFORE(MPT_WIN_8) return mpt::UUID::RFC4122Random(rng); #elif MPT_OS_WINDOWS ::UUID uuid = ::UUID(); RPC_STATUS status = ::UuidCreate(&uuid); if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) { return mpt::UUID::RFC4122Random(rng); } status = RPC_S_OK; if (UuidIsNil(&uuid, &status) != FALSE) { return mpt::UUID::RFC4122Random(rng); } if (status != RPC_S_OK) { return mpt::UUID::RFC4122Random(rng); } return mpt::UUID::UUIDFromWin32(uuid); #else return mpt::UUID::RFC4122Random(rng); #endif } // Create a UUID that contains local, traceable information. // Safe for local use. May be faster. template static UUID GenerateLocalUseOnly(Trng & rng) { #if MPT_WINRT_AT_LEAST(MPT_WIN_8) ::GUID guid = ::GUID(); HRESULT result = CoCreateGuid(&guid); if (result != S_OK) { return mpt::UUID::RFC4122Random(rng); } return mpt::UUID::UUIDFromWin32(guid); #elif MPT_WINRT_BEFORE(MPT_WIN_8) return mpt::UUID::RFC4122Random(rng); #elif MPT_WINNT_AT_LEAST(MPT_WIN_XP) // Available since Win2000, but we check for WinXP in order to not use this // function in Win32old builds. It is not available on some non-fully // patched Win98SE installs in the wild. ::UUID uuid = ::UUID(); RPC_STATUS status = ::UuidCreateSequential(&uuid); if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) { return Generate(rng); } status = RPC_S_OK; if (UuidIsNil(&uuid, &status) != FALSE) { return mpt::UUID::RFC4122Random(rng); } if (status != RPC_S_OK) { return mpt::UUID::RFC4122Random(rng); } return mpt::UUID::UUIDFromWin32(uuid); #elif MPT_OS_WINDOWS // Fallback to ::UuidCreate is safe as ::UuidCreateSequential is only a // tiny performance optimization. return Generate(rng); #else return RFC4122Random(rng); #endif } // Create a RFC4122 Random UUID. template static UUID RFC4122Random(Trng & prng) { UUID result; result.Data1 = mpt::random(prng); result.Data2 = mpt::random(prng); result.Data3 = mpt::random(prng); result.Data4 = mpt::random(prng); result.MakeRFC4122(4); return result; } friend UUID UUIDRFC4122NamespaceV3(const UUID & ns, const mpt::ustring & name); friend UUID UUIDRFC4122NamespaceV5(const UUID & ns, const mpt::ustring & name); public: // General UUID<->string conversion. // The string must/will be in standard UUID format: 4f9a455d-e7ef-4367-b2f0-0c83a38a5c72 static UUID FromString(const mpt::ustring & str) { std::vector segments = mpt::split(str, MPT_ULITERAL("-")); if (segments.size() != 5) { return UUID(); } if (segments[0].length() != 8) { return UUID(); } if (segments[1].length() != 4) { return UUID(); } if (segments[2].length() != 4) { return UUID(); } if (segments[3].length() != 4) { return UUID(); } if (segments[4].length() != 12) { return UUID(); } UUID result; result.Data1 = mpt::parse_hex(segments[0]); result.Data2 = mpt::parse_hex(segments[1]); result.Data3 = mpt::parse_hex(segments[2]); result.Data4 = mpt::parse_hex(segments[3] + segments[4]); return result; } mpt::ustring ToUString() const { return mpt::ustring() + mpt::format::hex0<8>(GetData1()) + MPT_USTRING("-") + mpt::format::hex0<4>(GetData2()) + MPT_USTRING("-") + mpt::format::hex0<4>(GetData3()) + MPT_USTRING("-") + mpt::format::hex0<4>(static_cast(GetData4() >> 48)) + MPT_USTRING("-") + mpt::format::hex0<4>(static_cast(GetData4() >> 32)) + mpt::format::hex0<8>(static_cast(GetData4() >> 0)); } }; MPT_CONSTEXPRINLINE bool operator==(const mpt::UUID & a, const mpt::UUID & b) noexcept { return (a.GetData1() == b.GetData1()) && (a.GetData2() == b.GetData2()) && (a.GetData3() == b.GetData3()) && (a.GetData4() == b.GetData4()); } MPT_CONSTEXPRINLINE bool operator!=(const mpt::UUID & a, const mpt::UUID & b) noexcept { return (a.GetData1() != b.GetData1()) || (a.GetData2() != b.GetData2()) || (a.GetData3() != b.GetData3()) || (a.GetData4() != b.GetData4()); } namespace uuid_literals { MPT_CONSTEVAL mpt::UUID operator""_uuid(const char * str, std::size_t len) { return mpt::UUID::ParseLiteral(str, len); } } // namespace uuid_literals } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_UUID_UUID_HPP libopenmpt-0.8.1+release.autotools/src/mpt/uuid/guid.hpp0000644000175000017500000001424514354032307020263 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_UUID_GUID_HPP #define MPT_UUID_GUID_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/out_of_memory/out_of_memory.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include "mpt/uuid/uuid.hpp" #include #include #if MPT_OS_WINDOWS #if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) #include #endif // MPT_WIN_VISTA #include #include #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) // COM CLSID<->string conversion // A CLSID string is not necessarily a standard UUID string, // it might also be a symbolic name for the interface. // (see CLSIDFromString ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms680589%28v=vs.85%29.aspx )) inline mpt::winstring CLSIDToString(CLSID clsid) { std::wstring str; LPOLESTR tmp = nullptr; switch (::StringFromCLSID(clsid, &tmp)) { case S_OK: break; case E_OUTOFMEMORY: if (tmp) { ::CoTaskMemFree(tmp); tmp = nullptr; } mpt::throw_out_of_memory(); break; default: if (tmp) { ::CoTaskMemFree(tmp); tmp = nullptr; } throw std::logic_error("StringFromCLSID() failed."); break; } if (!tmp) { throw std::logic_error("StringFromCLSID() failed."); } try { str = tmp; } catch (mpt::out_of_memory e) { ::CoTaskMemFree(tmp); tmp = nullptr; mpt::rethrow_out_of_memory(e); } ::CoTaskMemFree(tmp); tmp = nullptr; return mpt::transcode(str); } inline CLSID StringToCLSID(const mpt::winstring & str_) { const std::wstring str = mpt::transcode(str_); CLSID clsid = CLSID(); std::vector tmp(str.c_str(), str.c_str() + str.length() + 1); switch (::CLSIDFromString(tmp.data(), &clsid)) { case NOERROR: // nothing break; case E_INVALIDARG: clsid = CLSID(); break; case CO_E_CLASSSTRING: clsid = CLSID(); break; case REGDB_E_CLASSNOTREG: clsid = CLSID(); break; case REGDB_E_READREGDB: clsid = CLSID(); throw std::runtime_error("CLSIDFromString() failed: REGDB_E_READREGDB."); break; default: clsid = CLSID(); throw std::logic_error("CLSIDFromString() failed."); break; } return clsid; } inline bool VerifyStringToCLSID(const mpt::winstring & str_, CLSID & clsid) { const std::wstring str = mpt::transcode(str_); bool result = false; clsid = CLSID(); std::vector tmp(str.c_str(), str.c_str() + str.length() + 1); switch (::CLSIDFromString(tmp.data(), &clsid)) { case NOERROR: result = true; break; case E_INVALIDARG: result = false; break; case CO_E_CLASSSTRING: result = false; break; case REGDB_E_CLASSNOTREG: result = false; break; case REGDB_E_READREGDB: throw std::runtime_error("CLSIDFromString() failed: REGDB_E_READREGDB."); break; default: throw std::logic_error("CLSIDFromString() failed."); break; } return result; } inline bool IsCLSID(const mpt::winstring & str_) { const std::wstring str = mpt::transcode(str_); bool result = false; CLSID clsid = CLSID(); std::vector tmp(str.c_str(), str.c_str() + str.length() + 1); switch (::CLSIDFromString(tmp.data(), &clsid)) { case NOERROR: result = true; break; case E_INVALIDARG: result = false; break; case CO_E_CLASSSTRING: result = false; break; case REGDB_E_CLASSNOTREG: result = false; break; case REGDB_E_READREGDB: result = false; throw std::runtime_error("CLSIDFromString() failed: REGDB_E_READREGDB."); break; default: result = false; throw std::logic_error("CLSIDFromString() failed."); break; } return result; } // COM IID<->string conversion inline IID StringToIID(const mpt::winstring & str_) { const std::wstring str = mpt::transcode(str_); IID iid = IID(); std::vector tmp(str.c_str(), str.c_str() + str.length() + 1); switch (::IIDFromString(tmp.data(), &iid)) { case S_OK: // nothing break; case E_OUTOFMEMORY: iid = IID(); mpt::throw_out_of_memory(); break; case E_INVALIDARG: iid = IID(); break; default: iid = IID(); throw std::logic_error("IIDFromString() failed."); break; } return iid; } inline mpt::winstring IIDToString(IID iid) { std::wstring str; LPOLESTR tmp = nullptr; switch (::StringFromIID(iid, &tmp)) { case S_OK: break; case E_OUTOFMEMORY: if (tmp) { ::CoTaskMemFree(tmp); tmp = nullptr; } mpt::throw_out_of_memory(); break; default: if (tmp) { ::CoTaskMemFree(tmp); tmp = nullptr; } throw std::logic_error("StringFromIID() failed."); break; } if (!tmp) { throw std::logic_error("StringFromIID() failed."); } try { str = tmp; } catch (mpt::out_of_memory e) { ::CoTaskMemFree(tmp); tmp = nullptr; mpt::rethrow_out_of_memory(e); } return mpt::transcode(str); } // General GUID<->string conversion. // The string must/will be in standard GUID format: {4F9A455D-E7EF-4367-B2F0-0C83A38A5C72} inline GUID StringToGUID(const mpt::winstring & str) { return StringToIID(str); } inline mpt::winstring GUIDToString(GUID guid) { std::vector tmp(256); if (::StringFromGUID2(guid, tmp.data(), static_cast(tmp.size())) <= 0) { throw std::logic_error("StringFromGUID2() failed."); } return mpt::transcode(tmp.data()); } // Create a COM GUID inline GUID CreateGUID() { GUID guid = GUID(); switch (::CoCreateGuid(&guid)) { case S_OK: // nothing break; default: guid = GUID(); throw std::runtime_error("CoCreateGuid() failed."); } return guid; } // Checks the UUID against the NULL UUID. Returns false if it is NULL, true otherwise. inline bool IsValid(::UUID uuid) { return false || uuid.Data1 != 0 || uuid.Data2 != 0 || uuid.Data3 != 0 || uuid.Data4[0] != 0 || uuid.Data4[1] != 0 || uuid.Data4[2] != 0 || uuid.Data4[3] != 0 || uuid.Data4[4] != 0 || uuid.Data4[5] != 0 || uuid.Data4[6] != 0 || uuid.Data4[7] != 0; } #endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_UUID_GUID_HPP libopenmpt-0.8.1+release.autotools/src/mpt/uuid/tests/0000755000175000017500000000000015023302361020030 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/uuid/tests/tests_uuid.hpp0000644000175000017500000001036314664604252022672 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TESTS_UUID_HPP #define MPT_BASE_TESTS_UUID_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/random/default_engines.hpp" #include "mpt/random/device.hpp" #include "mpt/random/seed.hpp" #include "mpt/string/types.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include "mpt/uuid/guid.hpp" #include "mpt/uuid/uuid.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace uuid { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/uuid") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { using namespace mpt::uuid_literals; MPT_TEST_EXPECT_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull).ToUString(), MPT_USTRING("2ed6593a-dfe6-4cf8-b2e5-75ad7f600c32")); #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) constexpr mpt::UUID uuid_tmp = "2ed6593a-dfe6-4cf8-b2e5-75ad7f600c32"_uuid; MPT_TEST_EXPECT_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull), uuid_tmp); MPT_TEST_EXPECT_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull), mpt::UUID(mpt::StringToGUID(TEXT("{2ed6593a-dfe6-4cf8-b2e5-75ad7f600c32}")))); MPT_TEST_EXPECT_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull), mpt::UUID(mpt::StringToCLSID(TEXT("{2ed6593a-dfe6-4cf8-b2e5-75ad7f600c32}")))); MPT_TEST_EXPECT_EQUAL(mpt::UUID(0x00112233u, 0x4455, 0x6677, 0x8899AABBCCDDEEFFull), mpt::UUID(mpt::StringToGUID(TEXT("{00112233-4455-6677-8899-AABBCCDDEEFF}")))); MPT_TEST_EXPECT_EQUAL(mpt::UUID(0x00112233u, 0x4455, 0x6677, 0xC899AABBCCDDEEFFull), mpt::UUID(mpt::StringToGUID(TEXT("{00112233-4455-6677-C899-AABBCCDDEEFF}")))); MPT_TEST_EXPECT_EQUAL(mpt::GUIDToString(mpt::UUID(0x00112233u, 0x4455, 0x6677, 0x8899AABBCCDDEEFFull)), TEXT("{00112233-4455-6677-8899-AABBCCDDEEFF}")); MPT_TEST_EXPECT_EQUAL(mpt::GUIDToString(mpt::UUID(0x00112233u, 0x4455, 0x6677, 0xC899AABBCCDDEEFFull)), TEXT("{00112233-4455-6677-C899-AABBCCDDEEFF}")); #endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR mpt::sane_random_device rd; mpt::good_engine prng = mpt::make_prng(rd); #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) MPT_TEST_EXPECT_EQUAL(mpt::IsValid(mpt::CreateGUID()), true); { mpt::UUID uuid = mpt::UUID::Generate(prng); MPT_TEST_EXPECT_EQUAL(uuid, mpt::UUID::FromString(mpt::UUID(uuid).ToUString())); MPT_TEST_EXPECT_EQUAL(uuid, mpt::UUID(mpt::StringToGUID(mpt::GUIDToString(uuid)))); MPT_TEST_EXPECT_EQUAL(uuid, mpt::UUID(mpt::StringToIID(mpt::IIDToString(uuid)))); MPT_TEST_EXPECT_EQUAL(uuid, mpt::UUID(mpt::StringToCLSID(mpt::CLSIDToString(uuid)))); } { GUID guid = mpt::UUID::Generate(prng); MPT_TEST_EXPECT_EQUAL(IsEqualGUID(guid, static_cast(mpt::UUID::FromString(mpt::UUID(guid).ToUString()))), TRUE); MPT_TEST_EXPECT_EQUAL(IsEqualGUID(guid, mpt::StringToGUID(mpt::GUIDToString(guid))), TRUE); MPT_TEST_EXPECT_EQUAL(IsEqualGUID(guid, mpt::StringToIID(mpt::IIDToString(guid))), TRUE); MPT_TEST_EXPECT_EQUAL(IsEqualGUID(guid, mpt::StringToCLSID(mpt::CLSIDToString(guid))), TRUE); } #endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR MPT_TEST_EXPECT_EQUAL(mpt::UUID::Generate(prng).IsValid(), true); MPT_TEST_EXPECT_EQUAL(mpt::UUID::GenerateLocalUseOnly(prng).IsValid(), true); MPT_TEST_EXPECT_EQUAL(mpt::UUID::Generate(prng) != mpt::UUID::Generate(prng), true); mpt::UUID a = mpt::UUID::Generate(prng); MPT_TEST_EXPECT_EQUAL(a, mpt::UUID::FromString(a.ToUString())); std::byte uuiddata[16]{}; for (std::size_t i = 0; i < 16; ++i) { uuiddata[i] = mpt::byte_cast(static_cast(i)); } static_assert(sizeof(mpt::UUID) == 16); mpt::UUIDbin uuid2; std::memcpy(&uuid2, uuiddata, 16); MPT_TEST_EXPECT_EQUAL(mpt::UUID(uuid2).ToUString(), MPT_USTRING("00010203-0405-0607-0809-0a0b0c0d0e0f")); constexpr mpt::UUID uuid3 = "2ed6593a-dfe6-4cf8-b2e5-75ad7f600c32"_uuid; MPT_TEST_EXPECT_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull), uuid3); } } // namespace uuid } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TESTS_UUID_HPP libopenmpt-0.8.1+release.autotools/src/mpt/out_of_memory/0000755000175000017500000000000015023302361020603 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/out_of_memory/out_of_memory.hpp0000644000175000017500000000315314075537720024140 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_OUT_OF_MEMORY_OUT_OF_MEMORY_HPP #define MPT_OUT_OF_MEMORY_OUT_OF_MEMORY_HPP #include "mpt/base/detect.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/detect/mfc.hpp" #include #if !MPT_DETECTED_MFC #include #endif // !MPT_DETECTED_MFC #if MPT_DETECTED_MFC // cppcheck-suppress missingInclude #include #endif // MPT_DETECTED_MFC namespace mpt { inline namespace MPT_INLINE_NS { // Exception handling helpers, because MFC requires explicit deletion of the exception object, // Thus, always call exactly one of mpt::rethrow_out_of_memory(e) or mpt::delete_out_of_memory(e). #if MPT_DETECTED_MFC using out_of_memory = CMemoryException *; [[noreturn]] inline void throw_out_of_memory() { AfxThrowMemoryException(); } [[noreturn]] inline void rethrow_out_of_memory(out_of_memory e) { MPT_UNUSED(e); // cppcheck false-positive // cppcheck-suppress rethrowNoCurrentException throw; } inline void delete_out_of_memory(out_of_memory & e) { if (e) { e->Delete(); e = nullptr; } } #else // !MPT_DETECTED_MFC using out_of_memory = const std::bad_alloc &; [[noreturn]] inline void throw_out_of_memory() { throw std::bad_alloc(); } [[noreturn]] inline void rethrow_out_of_memory(out_of_memory e) { MPT_UNUSED(e); // cppcheck false-positive // cppcheck-suppress rethrowNoCurrentException throw; } inline void delete_out_of_memory(out_of_memory e) { MPT_UNUSED(e); } #endif // MPT_DETECTED_MFC } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_OUT_OF_MEMORY_OUT_OF_MEMORY_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/0000755000175000017500000000000015023302361016632 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/base/aligned_array.hpp0000644000175000017500000000642314123355754022107 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_ALIGNED_ARRAY_HPP #define MPT_BASE_ALIGNED_ARRAY_HPP #include "mpt/base/bit.hpp" #include "mpt/base/namespace.hpp" #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { template struct alignas(static_cast(alignment)) aligned_array : std::array { static_assert(static_cast(alignment) >= alignof(T)); static_assert(((count * sizeof(T)) % static_cast(alignment)) == 0); static_assert(sizeof(std::array) == (sizeof(T) * count)); }; static_assert(sizeof(mpt::aligned_array) == sizeof(std::array)); template T * align_elements(std::array & a) { static_assert(mpt::has_single_bit(alignof(T))); static_assert(mpt::has_single_bit(sizeof(T))); static_assert(mpt::has_single_bit(alignment_elements)); static_assert((expected_elements + alignment_elements - 1) <= N); void * buf = a.data(); std::size_t size = N * sizeof(T); void * result = std::align(alignment_elements * sizeof(T), expected_elements * sizeof(T), buf, size); assert(result); return reinterpret_cast(result); } template T * align_elements(T (&a)[N]) { static_assert(mpt::has_single_bit(alignof(T))); static_assert(mpt::has_single_bit(sizeof(T))); static_assert(mpt::has_single_bit(alignment_elements)); static_assert((expected_elements + alignment_elements - 1) <= N); void * buf = a; std::size_t size = N * sizeof(T); void * result = std::align(alignment_elements * sizeof(T), expected_elements * sizeof(T), buf, size); assert(result); return reinterpret_cast(result); } template T * align_bytes(std::array & a) { static_assert(mpt::has_single_bit(alignof(T))); static_assert(mpt::has_single_bit(sizeof(T))); static_assert(mpt::has_single_bit(alignment_bytes)); static_assert((alignment_bytes % alignof(T)) == 0); static_assert(((expected_elements * sizeof(T)) + alignment_bytes - 1) <= (N * sizeof(T))); void * buf = a.data(); std::size_t size = N * sizeof(T); void * result = std::align(alignment_bytes, expected_elements * sizeof(T), buf, size); assert(result); return reinterpret_cast(result); } template T * align_bytes(T (&a)[N]) { static_assert(mpt::has_single_bit(alignof(T))); static_assert(mpt::has_single_bit(sizeof(T))); static_assert(mpt::has_single_bit(alignment_bytes)); static_assert((alignment_bytes % alignof(T)) == 0); static_assert(((expected_elements * sizeof(T)) + alignment_bytes - 1) <= (N * sizeof(T))); void * buf = a; std::size_t size = N * sizeof(T); void * result = std::align(alignment_bytes, expected_elements * sizeof(T), buf, size); assert(result); return reinterpret_cast(result); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_ALIGNED_ARRAY_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/arithmetic_shift.hpp0000644000175000017500000000744114730241435022627 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_ARITHMETIC_SHIFT_HPP #define MPT_BASE_ARITHMETIC_SHIFT_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" namespace mpt { inline namespace MPT_INLINE_NS { // mpt::rshift_signed // mpt::lshift_signed // Shift a signed integer value in a well-defined manner. // Does the same thing as MSVC would do. This is verified by the test suite. template constexpr auto rshift_signed_portable(T x, int y) noexcept -> decltype(x >> y) { static_assert(std::numeric_limits::is_integer); static_assert(std::numeric_limits::is_signed); using result_type = decltype(x >> y); using unsigned_result_type = typename std::make_unsigned::type; const unsigned_result_type roffset = static_cast(1) << ((sizeof(result_type) * 8) - 1); result_type rx = x; unsigned_result_type urx = static_cast(rx); urx += roffset; urx >>= y; urx -= roffset >> y; return static_cast(urx); } template constexpr auto lshift_signed_portable(T x, int y) noexcept -> decltype(x << y) { static_assert(std::numeric_limits::is_integer); static_assert(std::numeric_limits::is_signed); using result_type = decltype(x << y); using unsigned_result_type = typename std::make_unsigned::type; const unsigned_result_type roffset = static_cast(1) << ((sizeof(result_type) * 8) - 1); result_type rx = x; unsigned_result_type urx = static_cast(rx); urx += roffset; urx <<= y; urx -= roffset << y; return static_cast(urx); } #if MPT_CXX_AT_LEAST(20) || MPT_COMPILER_SHIFT_SIGNED template constexpr auto rshift_signed_cxx20(T x, int y) noexcept -> decltype(x >> y) { static_assert(std::numeric_limits::is_integer); static_assert(std::numeric_limits::is_signed); #if MPT_COMPILER_GCC // #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshift-negative-value" #endif // MPT_COMPILER_GCC return x >> y; #if MPT_COMPILER_GCC #pragma GCC diagnostic pop #endif // MPT_COMPILER_GCC } template constexpr auto lshift_signed_cxx20(T x, int y) noexcept -> decltype(x << y) { static_assert(std::numeric_limits::is_integer); static_assert(std::numeric_limits::is_signed); #if MPT_COMPILER_GCC // #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshift-negative-value" #endif // MPT_COMPILER_GCC return x << y; #if MPT_COMPILER_GCC #pragma GCC diagnostic pop #endif // MPT_COMPILER_GCC } template constexpr auto rshift_signed(T x, int y) noexcept -> decltype(x >> y) { return mpt::rshift_signed_cxx20(x, y); } template constexpr auto lshift_signed(T x, int y) noexcept -> decltype(x << y) { return mpt::lshift_signed_cxx20(x, y); } #else template constexpr auto rshift_signed(T x, int y) noexcept -> decltype(x >> y) { return mpt::rshift_signed_portable(x, y); } template constexpr auto lshift_signed(T x, int y) noexcept -> decltype(x << y) { return mpt::lshift_signed_portable(x, y); } #endif template constexpr auto arithmetic_shift_right(T x, int y) noexcept -> decltype(x >> y) { return mpt::rshift_signed(x, y); } template constexpr auto arithmetic_shift_right(T x, int y) noexcept -> decltype(x << y) { return mpt::lshift_signed(x, y); } template constexpr auto sar(T x, int y) noexcept -> decltype(x >> y) { return mpt::rshift_signed(x, y); } template constexpr auto sal(T x, int y) noexcept -> decltype(x << y) { return mpt::lshift_signed(x, y); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_ARITHMETIC_SHIFT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/source_location.hpp0000644000175000017500000000665314733325453022503 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_SOURCE_LOCATION_HPP #define MPT_BASE_SOURCE_LOCATION_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #if MPT_CXX_AT_LEAST(20) && !MPT_MSVC_BEFORE(2022, 0) && !MPT_COMPILER_CLANG #include #endif // C++20 namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_CXX_AT_LEAST(20) && !MPT_MSVC_BEFORE(2022, 0) && !MPT_COMPILER_CLANG using std::source_location; #define MPT_SOURCE_LOCATION_CURRENT() std::source_location::current() #else // !C++20 #if MPT_COMPILER_MSVC && MPT_MSVC_AT_LEAST(2019, 6) #define MPT_SOURCE_LOCATION_FILE __builtin_FILE() #define MPT_SOURCE_LOCATION_FUNCTION __builtin_FUNCTION() #define MPT_SOURCE_LOCATION_LINE __builtin_LINE() #define MPT_SOURCE_LOCATION_COLUMN __builtin_COLUMN() #elif MPT_COMPILER_GCC #define MPT_SOURCE_LOCATION_FILE __builtin_FILE() #define MPT_SOURCE_LOCATION_FUNCTION __builtin_FUNCTION() #define MPT_SOURCE_LOCATION_LINE __builtin_LINE() #define MPT_SOURCE_LOCATION_COLUMN 0 #elif MPT_COMPILER_CLANG && ((!MPT_OS_MACOSX_OR_IOS && MPT_CLANG_AT_LEAST(9, 0, 0)) || (MPT_OS_MACOSX_OR_IOS && MPT_CLANG_AT_LEAST(12, 0, 0))) // We do not know which Apple Clang version introduced __builtin_FILE(). // It fails with 10.x (see ), // and IRC dicussion decided on 12.x as a somewhat safe choice. #define MPT_SOURCE_LOCATION_FILE __builtin_FILE() #define MPT_SOURCE_LOCATION_FUNCTION __builtin_FUNCTION() #define MPT_SOURCE_LOCATION_LINE __builtin_LINE() #define MPT_SOURCE_LOCATION_COLUMN __builtin_COLUMN() #else #define MPT_SOURCE_LOCATION_FILE __FILE__ #define MPT_SOURCE_LOCATION_FUNCTION "" #define MPT_SOURCE_LOCATION_LINE __LINE__ #define MPT_SOURCE_LOCATION_COLUMN 0 #endif // compatible with C++20 std::source_location struct source_location { private: const char * m_file_name; const char * m_function_name; uint32 m_line; uint32 m_column; public: constexpr source_location() noexcept : m_file_name("") , m_function_name("") , m_line(0) , m_column(0) { } constexpr source_location(const char * file, const char * function, uint32 line, uint32 column) noexcept : m_file_name(file) , m_function_name(function) , m_line(line) , m_column(column) { } source_location(const source_location &) = default; source_location(source_location &&) = default; static constexpr source_location current(const char * file = MPT_SOURCE_LOCATION_FILE, const char * function = MPT_SOURCE_LOCATION_FUNCTION, uint32 line = MPT_SOURCE_LOCATION_LINE, uint32 column = MPT_SOURCE_LOCATION_COLUMN) noexcept { return source_location(file, function, line, column); } constexpr uint32 line() const noexcept { return m_line; } constexpr uint32 column() const noexcept { return m_column; } constexpr const char * file_name() const noexcept { return m_file_name; } constexpr const char * function_name() const noexcept { return m_function_name; } }; #if (MPT_COMPILER_MSVC && MPT_MSVC_AT_LEAST(2019, 6)) || MPT_COMPILER_GCC || (MPT_COMPILER_CLANG && MPT_CLANG_AT_LEAST(9, 0, 0)) #define MPT_SOURCE_LOCATION_CURRENT() mpt::source_location::current() #else #define MPT_SOURCE_LOCATION_CURRENT() mpt::source_location::current(__FILE__, __func__, __LINE__, 0) #endif #endif // C++20 } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_SOURCE_LOCATION_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/span.hpp0000644000175000017500000000733614723102535020244 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_SPAN_HPP #define MPT_BASE_SPAN_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include #if MPT_CXX_AT_LEAST(20) #include #else // !C++20 #include #include #include #endif // C++20 #if MPT_CXX_BEFORE(20) #include #endif // !C++20 namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_CXX_AT_LEAST(20) using std::dynamic_extent; using std::span; #else // !C++20 // Simplified version of gsl::span. // Non-owning read-only or read-write view into a contiguous block of T // objects, i.e. equivalent to a (beg,end) or (data,size) tuple. // Can eventually be replaced without further modifications with a full C++20 // std::span. inline constexpr std::size_t dynamic_extent = std::numeric_limits::max(); template class span { public: using element_type = T; using value_type = typename std::remove_cv::type; using index_type = std::size_t; using pointer = T *; using const_pointer = const T *; using reference = T &; using const_reference = const T &; using iterator = pointer; using difference_type = typename std::iterator_traits::difference_type; private: T * m_data; std::size_t m_size; public: span() noexcept : m_data(nullptr) , m_size(0) { } span(pointer beg, pointer end) : m_data(beg) , m_size(end - beg) { } span(pointer data, index_type size) : m_data(data) , m_size(size) { } template span(element_type (&arr)[N]) : m_data(arr) , m_size(N) { } template span(std::array & arr) : m_data(arr.data()) , m_size(arr.size()) { } template span(const std::array & arr) : m_data(arr.data()) , m_size(arr.size()) { } span(const span & other) noexcept = default; template span(const span & other) : m_data(other.data()) , m_size(other.size()) { } span & operator=(const span & other) noexcept = default; iterator begin() const { return iterator(m_data); } iterator end() const { return iterator(m_data + m_size); } reference operator[](index_type index) { return m_data[index]; } const_reference operator[](index_type index) const { return m_data[index]; } pointer data() const noexcept { return m_data; } bool empty() const noexcept { return size() == 0; } index_type size() const noexcept { return m_size; } index_type length() const noexcept { return size(); } span subspan(std::size_t offset, std::size_t count = mpt::dynamic_extent) const { return span(data() + offset, (count == mpt::dynamic_extent) ? (size() - offset) : count); } span first(std::size_t count) const { return span(data(), count); } span last(std::size_t count) const { return span(data() + (size() - count), count); } }; // class span #endif // C++20 template inline span as_span(T * beg, T * end) { return span(beg, end); } template inline span as_span(T * data, std::size_t size) { return span(data, size); } template inline span as_span(T (&arr)[N]) { return span(std::begin(arr), std::end(arr)); } template inline span as_span(std::array & cont) { return span(cont); } template inline span as_span(const std::array & cont) { return span(cont); } template bool span_elements_equal(const Ca & a, const Cb & b) { return a.size() == b.size() && (a.data() == b.data() || std::equal(a.begin(), a.end(), b.begin())); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_SPAN_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/detect_compiler.hpp0000644000175000017500000002151015014575572022444 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_DETECT_COMPILER_HPP #define MPT_BASE_DETECT_COMPILER_HPP #define MPT_COMPILER_MAKE_VERSION2(version, sp) ((version)*100 + (sp)) #define MPT_COMPILER_MAKE_VERSION3(major, minor, patch) ((major)*10000 + (minor)*100 + (patch)) #if defined(MPT_COMPILER_GENERIC) #undef MPT_COMPILER_GENERIC #define MPT_COMPILER_GENERIC 1 #elif defined(__clang__) && defined(_MSC_VER) && defined(__c2__) #error "Clang/C2 is not supported. Please use Clang/LLVM for Windows instead." #elif defined(__clang__) #define MPT_COMPILER_CLANG 1 #define MPT_COMPILER_CLANG_VERSION MPT_COMPILER_MAKE_VERSION3(__clang_major__, __clang_minor__, __clang_patchlevel__) #define MPT_CLANG_AT_LEAST(major, minor, patch) (MPT_COMPILER_CLANG_VERSION >= MPT_COMPILER_MAKE_VERSION3((major), (minor), (patch))) #define MPT_CLANG_BEFORE(major, minor, patch) (MPT_COMPILER_CLANG_VERSION < MPT_COMPILER_MAKE_VERSION3((major), (minor), (patch))) #if MPT_CLANG_BEFORE(6, 0, 0) #error "clang version 6 required" #endif #if defined(__clang_analyzer__) #ifndef MPT_BUILD_ANALYZED #define MPT_BUILD_ANALYZED #endif #endif #elif defined(__GNUC__) #define MPT_COMPILER_GCC 1 #define MPT_COMPILER_GCC_VERSION MPT_COMPILER_MAKE_VERSION3(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #define MPT_GCC_AT_LEAST(major, minor, patch) (MPT_COMPILER_GCC_VERSION >= MPT_COMPILER_MAKE_VERSION3((major), (minor), (patch))) #define MPT_GCC_BEFORE(major, minor, patch) (MPT_COMPILER_GCC_VERSION < MPT_COMPILER_MAKE_VERSION3((major), (minor), (patch))) #if MPT_GCC_BEFORE(7, 1, 0) #error "GCC version 7.1 required" #endif #elif defined(_MSC_VER) #define MPT_COMPILER_MSVC 1 #if (_MSC_VER >= 1944) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 14) #elif (_MSC_VER >= 1943) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 13) #elif (_MSC_VER >= 1942) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 12) #elif (_MSC_VER >= 1941) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 11) #elif (_MSC_VER >= 1940) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 10) #elif (_MSC_VER >= 1939) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 9) #elif (_MSC_VER >= 1938) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 8) #elif (_MSC_VER >= 1937) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 7) #elif (_MSC_VER >= 1936) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 6) #elif (_MSC_VER >= 1935) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 5) #elif (_MSC_VER >= 1934) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 4) #elif (_MSC_VER >= 1933) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 3) #elif (_MSC_VER >= 1932) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 2) #elif (_MSC_VER >= 1931) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 1) #elif (_MSC_VER >= 1930) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 0) #elif (_MSC_VER >= 1929) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019, 10) #elif (_MSC_VER >= 1928) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019, 8) #elif (_MSC_VER >= 1927) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019, 7) #elif (_MSC_VER >= 1926) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019, 6) #elif (_MSC_VER >= 1925) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019, 5) #elif (_MSC_VER >= 1924) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019, 4) #elif (_MSC_VER >= 1923) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019, 3) #elif (_MSC_VER >= 1922) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019, 2) #elif (_MSC_VER >= 1921) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019, 1) #elif (_MSC_VER >= 1920) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019, 0) #elif (_MSC_VER >= 1916) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017, 9) #elif (_MSC_VER >= 1915) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017, 8) #elif (_MSC_VER >= 1914) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017, 7) #elif (_MSC_VER >= 1913) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017, 6) #elif (_MSC_VER >= 1912) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017, 5) #elif (_MSC_VER >= 1911) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017, 3) #elif (_MSC_VER >= 1910) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017, 0) #elif (_MSC_VER >= 1900) && defined(_MSVC_LANG) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2015, 3) #elif (_MSC_VER >= 1900) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2015, 0) #elif (_MSC_VER >= 1800) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2013, 0) #elif (_MSC_VER >= 1700) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2012, 0) #elif (_MSC_VER >= 1600) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2010, 0) #elif (_MSC_VER >= 1500) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2008, 0) #else #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2005, 0) #endif #define MPT_MSVC_AT_LEAST(version, sp) (MPT_COMPILER_MSVC_VERSION >= MPT_COMPILER_MAKE_VERSION2((version), (sp))) #define MPT_MSVC_BEFORE(version, sp) (MPT_COMPILER_MSVC_VERSION < MPT_COMPILER_MAKE_VERSION2((version), (sp))) #if MPT_MSVC_BEFORE(2017, 9) #error "MSVC version 2017 15.9 required" #endif #if defined(_PREFAST_) #ifndef MPT_BUILD_ANALYZED #define MPT_BUILD_ANALYZED #endif #endif #else #define MPT_COMPILER_GENERIC 1 #endif #ifndef MPT_COMPILER_GENERIC #define MPT_COMPILER_GENERIC 0 #endif #ifndef MPT_COMPILER_CLANG #define MPT_COMPILER_CLANG 0 #define MPT_CLANG_AT_LEAST(major, minor, patch) 0 #define MPT_CLANG_BEFORE(major, minor, patch) 0 #endif #ifndef MPT_COMPILER_GCC #define MPT_COMPILER_GCC 0 #define MPT_GCC_AT_LEAST(major, minor, patch) 0 #define MPT_GCC_BEFORE(major, minor, patch) 0 #endif #ifndef MPT_COMPILER_MSVC #define MPT_COMPILER_MSVC 0 #define MPT_MSVC_AT_LEAST(version, sp) 0 #define MPT_MSVC_BEFORE(version, sp) 0 #endif #if MPT_COMPILER_GENERIC #if (__cplusplus >= 202302) #define MPT_CXX 23 #elif (__cplusplus >= 202002) #define MPT_CXX 20 #elif (__cplusplus >= 201703) #define MPT_CXX 17 #endif #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG #if (__cplusplus >= 202302) #define MPT_CXX 23 #elif (__cplusplus >= 202002) #if defined(__APPLE__) && MPT_CLANG_BEFORE(13, 0, 0) // XCode 12.5 has a really weird mix of Clang and libc++. Just black-list C++20 support for XCode <= 12. #define MPT_CXX 17 #else #define MPT_CXX 20 #endif #elif (__cplusplus >= 201703) #define MPT_CXX 17 #endif #elif MPT_COMPILER_MSVC #if MPT_MSVC_AT_LEAST(2015, 3) #if (_MSVC_LANG >= 202302) #define MPT_CXX 23 #elif (_MSVC_LANG >= 202002) #define MPT_CXX 20 #elif (_MSVC_LANG >= 201703) #define MPT_CXX 17 #endif #endif #endif // default to C++17 #ifndef MPT_CXX #define MPT_CXX 17 #endif // MPT_CXX is stricter than just using __cplusplus directly. // We will only claim a language version as supported IFF all core language and // library fatures that we need are actually supported AND working correctly // (to our needs). #define MPT_CXX_AT_LEAST(version) (MPT_CXX >= (version)) #define MPT_CXX_BEFORE(version) (MPT_CXX < (version)) // detect compiler quirks #if MPT_COMPILER_CLANG #if defined(__APPLE__) #define MPT_COMPILER_QUIRK_APPLE_CLANG #endif #endif // detect compiler setting quirks #if MPT_COMPILER_GCC #if (MPT_GCC_AT_LEAST(14, 0, 0) && MPT_GCC_BEFORE(14, 2, 0)) || (MPT_GCC_AT_LEAST(13, 0, 0) && MPT_GCC_BEFORE(13, 4, 0)) || (MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(12, 5, 0)) || MPT_GCC_BEFORE(12, 0, 0) // GCC 14 causes severe miscompilation of inline functions on MinGW. // See . // Current investigation suggests a general problem with -fipa-ra on non-ELF // platforms. // As far as we understand the issue, it could possibly also manifest with // other inter-procedure-optimizations and with older GCC versions. // Fixed in GCC 15 // (), // GCC 14.2 // (). // GCC 13.4 // (). // and GCC 12.5 // (). #if !defined(__ELF__) #define MPT_COMPILER_SETTING_QUIRK_GCC_BROKEN_IPA #endif #endif #endif #endif // MPT_BASE_DETECT_COMPILER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/compiletime_warning.hpp0000644000175000017500000000224014044173026023323 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_COMPILETIME_WARNING_HPP #define MPT_BASE_COMPILETIME_WARNING_HPP #include "mpt/base/detect.hpp" #include "mpt/base/preprocessor.hpp" #if MPT_COMPILER_MSVC #define MPT_WARNING(text) __pragma(message(__FILE__ "(" MPT_PP_DEFER(MPT_PP_STRINGIFY, __LINE__) "): Warning: " text)) #define MPT_WARNING_STATEMENT(text) __pragma(message(__FILE__ "(" MPT_PP_DEFER(MPT_PP_STRINGIFY, __LINE__) "): Warning: " text)) #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG #define MPT_WARNING(text) _Pragma(MPT_PP_STRINGIFY(GCC warning text)) #define MPT_WARNING_STATEMENT(text) _Pragma(MPT_PP_STRINGIFY(GCC warning text)) #else // portable #pragma message or #warning replacement #define MPT_WARNING(text) \ static inline int MPT_PP_UNIQUE_IDENTIFIER(MPT_WARNING_NAME)() noexcept { \ int warning [[deprecated("Warning: " text)]] = 0; \ return warning; \ } \ /**/ #define MPT_WARNING_STATEMENT(text) \ int MPT_PP_UNIQUE_IDENTIFIER(MPT_WARNING_NAME) = []() { \ int warning [[deprecated("Warning: " text)]] = 0; \ return warning; \ }() /**/ #endif #endif // MPT_BASE_COMPILETIME_WARNING_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/debugging.hpp0000644000175000017500000001057414657354306021247 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_DEBUGGING_HPP #define MPT_BASE_DEBUGGING_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/macros.hpp" #if MPT_CXX_AT_LEAST(26) #include #endif // C++26 #if MPT_CXX_BEFORE(26) #if MPT_OS_LINUX #include #include #endif #endif // !C++26 #if MPT_CXX_BEFORE(26) #if MPT_OS_LINUX #include #include #include #endif #endif // !C++26 #if MPT_CXX_BEFORE(26) #if MPT_OS_WINDOWS #include #endif #endif // !C++26 #if MPT_CXX_BEFORE(26) #if MPT_COMPILER_MSVC #include #endif #endif // !C++26 namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_CXX_AT_LEAST(26) using std::breakpoint; using std::breakpoint_if_debugging; using std::is_debugger_present; #else // !C++26 #if MPT_OS_WINDOWS inline bool is_debugger_present() noexcept { return (IsDebuggerPresent() != FALSE); } MPT_FORCEINLINE void breakpoint() noexcept { #if MPT_COMPILER_MSVC __debugbreak(); #elif MPT_COMPILER_CLANG __builtin_debugtrap(); #elif MPT_COMPILER_GCC && (MPT_ARCH_X86 || MPT_ARCH_AMD64) __asm__ __volatile__("int 3"); #else DebugBreak(); #endif } #elif MPT_OS_LINUX namespace detail { namespace debugging { inline bool parse_proc_status_line(char * buf, std::size_t size) noexcept { if (std::strncmp(buf, "TracerPid:\t", 11) != 0) { return false; } unsigned long long pid = 0; std::size_t pos = 11; while (pos < size) { unsigned char byte = static_cast(buf[pos]); if (!(static_cast('0') <= byte && byte <= static_cast('9'))) { return false; } uint8 digit = static_cast(byte - static_cast('0')); pid = (pid * 10) + digit; pos++; } return (pid != 0); } inline bool parse_proc_status() noexcept { int olderrno = errno; bool detected_debugger = false; int error = 0; int fd = -1; bool open_done = false; while (!open_done) { int res = open("/proc/self/status", O_RDONLY); if (res >= 0) { fd = res; open_done = true; } else if (errno != EINTR) { error = errno; open_done = true; } } if (error != 0) { errno = olderrno; return false; } if (fd < 0) { errno = olderrno; return false; } bool eof = false; uint8 iobuf[1024]; std::size_t iobuf_size = 0; char linebuf[128]; std::size_t linebuf_size = 0; while (!eof) { ssize_t bytes_read = read(fd, iobuf, 1024); if (bytes_read == -1) { if (errno == EINTR) { continue; } } else if (bytes_read == 0) { eof = true; } iobuf_size = static_cast(bytes_read); for (std::size_t i = 0; i < iobuf_size; ++i) { if (static_cast(iobuf[i]) == static_cast('\n')) { if (parse_proc_status_line(linebuf, linebuf_size)) { detected_debugger = true; } linebuf_size = 0; } else { if (linebuf_size < 128) { linebuf[linebuf_size] = static_cast(static_cast(iobuf[i])); linebuf_size++; } } } if (linebuf_size > 0) { if (parse_proc_status_line(linebuf, linebuf_size)) { detected_debugger = true; } linebuf_size = 0; } } bool close_done = false; while (!close_done) { int res = close(fd); if (res == 0) { fd = -1; close_done = true; } else if (errno != EINTR) { error = errno; close_done = true; } } if (error != 0) { errno = olderrno; return false; } errno = olderrno; return detected_debugger; } } // namespace debugging } // namespace detail inline MPT_NOINLINE bool is_debugger_present() noexcept { return mpt::detail::debugging::parse_proc_status(); } MPT_FORCEINLINE void breakpoint() noexcept { #if MPT_COMPILER_CLANG __builtin_debugtrap(); #elif MPT_COMPILER_GCC && (MPT_ARCH_X86 || MPT_ARCH_AMD64) __asm__ __volatile__("int 3"); #else kill(getpid(), SIGTRAP); #endif } #else inline bool is_debugger_present() noexcept { return false; } MPT_FORCEINLINE void breakpoint() noexcept { #if MPT_COMPILER_MSVC __debugbreak(); #elif MPT_COMPILER_CLANG __builtin_debugtrap(); #elif MPT_COMPILER_GCC && (MPT_ARCH_X86 || MPT_ARCH_AMD64) __asm__ __volatile__("int 3"); #endif } #endif MPT_FORCEINLINE void breakpoint_if_debugging() noexcept { if (mpt::is_debugger_present()) { mpt::breakpoint(); } } #endif // C++26 } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_DEBUGGING_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/secure.hpp0000644000175000017500000001136614303710624020565 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_SECURE_HPP #define MPT_BASE_SECURE_HPP #include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { // C23 memset_explicit inline MPT_NOINLINE void * memset_explicit(void * const dst, int const value, std::size_t const len) noexcept { std::atomic_thread_fence(std::memory_order_seq_cst); volatile unsigned char * volatile p = static_cast(dst); std::atomic_thread_fence(std::memory_order_seq_cst); for (volatile std::size_t i = 0; i < len; ++i) { p[i] = static_cast(value); } std::atomic_thread_fence(std::memory_order_seq_cst); return dst; } namespace secure { inline MPT_NOINLINE void memzero(std::byte * const dst, std::size_t const len) noexcept { std::atomic_thread_fence(std::memory_order_seq_cst); volatile std::byte * volatile p = static_cast(dst); std::atomic_thread_fence(std::memory_order_seq_cst); for (volatile std::size_t i = 0; i < len; ++i) { p[i] = std::byte{0}; } std::atomic_thread_fence(std::memory_order_seq_cst); } inline MPT_NOINLINE void memzero(void * const dst, std::size_t const len) noexcept { std::atomic_thread_fence(std::memory_order_seq_cst); volatile std::byte * volatile p = static_cast(dst); std::atomic_thread_fence(std::memory_order_seq_cst); for (volatile std::size_t i = 0; i < len; ++i) { p[i] = std::byte{0}; } std::atomic_thread_fence(std::memory_order_seq_cst); } inline MPT_NOINLINE void memzero(char * const dst, std::size_t const len) noexcept { std::atomic_thread_fence(std::memory_order_seq_cst); volatile std::byte * volatile p = reinterpret_cast(dst); std::atomic_thread_fence(std::memory_order_seq_cst); for (volatile std::size_t i = 0; i < len; ++i) { p[i] = std::byte{0}; } std::atomic_thread_fence(std::memory_order_seq_cst); } inline MPT_NOINLINE void memzero(uint8 * const dst, std::size_t const len) noexcept { std::atomic_thread_fence(std::memory_order_seq_cst); volatile std::byte * volatile p = reinterpret_cast(dst); std::atomic_thread_fence(std::memory_order_seq_cst); for (volatile std::size_t i = 0; i < len; ++i) { p[i] = std::byte{0}; } std::atomic_thread_fence(std::memory_order_seq_cst); } template inline MPT_NOINLINE void clear(T & val) { std::atomic_signal_fence(std::memory_order_seq_cst); volatile T * volatile v = &val; std::atomic_thread_fence(std::memory_order_seq_cst); *v = T{}; std::atomic_signal_fence(std::memory_order_seq_cst); } class byte { private: std::byte value; public: byte() noexcept : value(std::byte{0}) { return; } explicit byte(std::byte value) noexcept : value(value) { return; } byte(const byte & other) noexcept : value(other.value) { return; } byte(byte && other) noexcept : value(std::move(other.value)) { mpt::secure::clear(other.value); } byte & operator=(const byte & other) noexcept { if (&other == this) { return *this; } value = other.value; return *this; } byte & operator==(byte && other) noexcept { if (&other == this) { return *this; } value = std::move(other.value); mpt::secure::clear(other.value); return *this; } explicit operator std::byte() const noexcept { return value; } ~byte() { mpt::secure::clear(value); } }; class buffer { private: std::vector m_data; public: buffer() : m_data(0) { return; } explicit buffer(const std::vector & data) : m_data(data) { return; } explicit buffer(const std::byte * beg, const std::byte * end) : m_data(beg, end) { return; } buffer(const buffer & other) : m_data(other.m_data) { return; } buffer(buffer && other) noexcept : m_data(std::move(other.m_data)) { mpt::secure::memzero(other.m_data.data(), other.m_data.size()); } buffer & operator=(const buffer & other) { if (&other == this) { return *this; } m_data = other.m_data; return *this; } buffer & operator=(buffer && other) noexcept { if (&other == this) { return *this; } m_data = std::move(other.m_data); mpt::secure::memzero(other.m_data.data(), other.m_data.size()); return *this; } ~buffer() { mpt::secure::memzero(m_data.data(), m_data.size()); m_data.resize(0); m_data.shrink_to_fit(); } explicit operator std::vector() const { return m_data; } const std::byte * data() const { return m_data.data(); } std::byte * data() { return m_data.data(); } std::size_t size() const { return m_data.size(); } }; } // namespace secure } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_SECURE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/alloc.hpp0000644000175000017500000001234614722343424020375 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_ALLOC_HPP #define MPT_BASE_ALLOC_HPP #include "mpt/base/namespace.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/span.hpp" #include #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { template inline mpt::span as_span(std::vector & cont) { return mpt::span(cont.data(), cont.data() + cont.size()); } template inline mpt::span as_span(const std::vector & cont) { return mpt::span(cont.data(), cont.data() + cont.size()); } template inline span as_span(std::basic_string & str) { return span(str.data(), str.size()); } template inline span as_span(const std::basic_string & str) { return span(str.data(), str.size()); } template inline std::vector::type> make_vector(T * beg, T * end) { return std::vector::type>(beg, end); } template inline std::vector::type> make_vector(T * data, std::size_t size) { return std::vector::type>(data, data + size); } template inline std::vector::type> make_vector(mpt::span data) { return std::vector::type>(data.data(), data.data() + data.size()); } template inline std::vector::type> make_vector(T (&arr)[N]) { return std::vector::type>(std::begin(arr), std::end(arr)); } template inline std::vector::type> make_vector(const std::basic_string & str) { return std::vector::type>(str.begin(), str.end()); } template inline std::basic_string::type> make_basic_string(T * beg, T * end) { return std::basic_string::type>(beg, end); } template inline std::basic_string::type> make_basic_string(T * data, std::size_t size) { return std::basic_string::type>(data, data + size); } template inline std::basic_string::type> make_basic_string(mpt::span data) { return std::basic_string::type>(data.data(), data.data() + data.size()); } template inline std::basic_string::type> make_basic_string(T (&arr)[N]) { return std::basic_string::type>(std::begin(arr), std::end(arr)); } template inline std::basic_string::type> make_basic_string(const std::vector & str) { return std::vector::type>(str.begin(), str.end()); } template inline Tcont1 & append(Tcont1 & cont1, const Tcont2 & cont2) { cont1.insert(cont1.end(), cont2.begin(), cont2.end()); return cont1; } template inline Tcont1 & append(Tcont1 & cont1, Tit2 beg, Tit2 end) { cont1.insert(cont1.end(), beg, end); return cont1; } template struct buffer_cast_impl { inline Tdst operator()(const Tsrc & src) const { return Tdst(mpt::byte_cast(src.data()), mpt::byte_cast(src.data()) + src.size()); } }; // casts between vector<->string of byte-castable types template inline Tdst buffer_cast(const Tsrc & src) { return buffer_cast_impl()(src); } template struct as_raw_memory_impl> { inline mpt::const_byte_span operator()(const std::vector & v) const { static_assert(mpt::is_binary_safe::type>::value); return mpt::as_span(reinterpret_cast(v.data()), v.size() * sizeof(T)); } inline mpt::byte_span operator()(std::vector & v) const { static_assert(mpt::is_binary_safe::type>::value); return mpt::as_span(reinterpret_cast(v.data()), v.size() * sizeof(T)); } }; template struct as_raw_memory_impl> { inline mpt::const_byte_span operator()(const std::vector & v) const { static_assert(mpt::is_binary_safe::type>::value); return mpt::as_span(reinterpret_cast(v.data()), v.size() * sizeof(T)); } }; template class heap_value { private: std::unique_ptr m_value{}; public: template heap_value(Targs &&... args) : m_value(std::make_unique(std::forward(args)...)) { return; } const T & operator*() const { return *m_value; } T & operator*() { return *m_value; } const T * operator->() const { return m_value.get(); } T * operator->() { return m_value.get(); } const T * get() const { return m_value.get(); } T * get() { return m_value.get(); } }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_ALLOC_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/semantic_version.hpp0000644000175000017500000000554414275170614022657 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_SEMANTIC_VERSION_HPP #define MPT_BASE_SEMANTIC_VERSION_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/version.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { struct semantic_version { unsigned long long major = 0; unsigned long long minor = 0; unsigned long long patch = 0; constexpr std::tuple as_tuple() const noexcept { return std::make_tuple(major, minor, patch); } }; constexpr bool operator==(const semantic_version a, const semantic_version b) noexcept { return a.as_tuple() == b.as_tuple(); } constexpr bool operator!=(const semantic_version a, const semantic_version b) noexcept { return a.as_tuple() != b.as_tuple(); } constexpr bool operator<(const semantic_version a, const semantic_version b) noexcept { return a.as_tuple() < b.as_tuple(); } constexpr bool operator>(const semantic_version a, const semantic_version b) noexcept { return a.as_tuple() > b.as_tuple(); } constexpr bool operator<=(const semantic_version a, const semantic_version b) noexcept { return a.as_tuple() <= b.as_tuple(); } constexpr bool operator>=(const semantic_version a, const semantic_version b) noexcept { return a.as_tuple() >= b.as_tuple(); } struct version_info { semantic_version semver{}; unsigned long long build = 0; constexpr std::tuple, unsigned long long> as_tuple() const noexcept { return std::make_tuple(semver.as_tuple(), build); } template friend Tostream & operator<<(Tostream & os, const version_info vi) { if (vi.build > 0) { os << vi.semver.major << "." << vi.semver.minor << "." << vi.semver.patch << "+build." << vi.build; } else { os << vi.semver.major << "." << vi.semver.minor << "." << vi.semver.patch; } return os; } }; constexpr bool operator==(const version_info a, const version_info b) noexcept { return a.as_tuple() == b.as_tuple(); } constexpr bool operator!=(const version_info a, const version_info b) noexcept { return a.as_tuple() != b.as_tuple(); } constexpr bool operator<(const version_info a, const version_info b) noexcept { return a.as_tuple() < b.as_tuple(); } constexpr bool operator>(const version_info a, const version_info b) noexcept { return a.as_tuple() > b.as_tuple(); } constexpr bool operator<=(const version_info a, const version_info b) noexcept { return a.as_tuple() <= b.as_tuple(); } constexpr bool operator>=(const version_info a, const version_info b) noexcept { return a.as_tuple() >= b.as_tuple(); } constexpr inline version_info Version = { {MPT_VERSION_MAJOR, MPT_VERSION_MINOR, MPT_VERSION_PATCH}, MPT_VERSION_BUILD }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_SEMANTIC_VERSION_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/namespace.hpp0000644000175000017500000000650214710657531021240 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_NAMESPACE_HPP #define MPT_BASE_NAMESPACE_HPP #include "mpt/base/detect.hpp" #include "mpt/base/version.hpp" #include "mpt/base/compiletime_warning.hpp" #if !defined(MPT_INLINE_NS) #define MPT_BUILD_VERSION_NAMESPACE_IMPL(a, b, c, d) v##a##_##b##_##c##_##d #define MPT_BUILD_VERSION_NAMESPACE(a, b, c, d) MPT_BUILD_VERSION_NAMESPACE_IMPL(a, b, c, d) #define MPT_VERSION_NAMESPACE MPT_BUILD_VERSION_NAMESPACE(MPT_VERSION_MAJOR, MPT_VERSION_MINOR, MPT_VERSION_PATCH, MPT_VERSION_BUILD) #if MPT_OS_WINDOWS #ifdef UNICODE #define MPT_VERSION_ABI_OS u #else #define MPT_VERSION_ABI_OS 8 #endif #else #define MPT_VERSION_ABI_OS _ #endif #if MPT_LIBC_GENERIC #define MPT_VERSION_ABI_LIBC _ #elif MPT_LIBC_MS #if MPT_LIBC_MS_UCRT #if MPT_LIBC_MS_SHARED #ifdef MPT_LIBC_MS_DEBUG #define MPT_VERSION_ABI_LIBC UMDd #else #define MPT_VERSION_ABI_LIBC UMDr #endif #elif MPT_LIBC_MS_STATIC #ifdef MPT_LIBC_MS_DEBUG #define MPT_VERSION_ABI_LIBC UMTd #else #define MPT_VERSION_ABI_LIBC UMTr #endif #else #ifdef MPT_LIBC_MS_DEBUG #define MPT_VERSION_ABI_LIBC UMd #else #define MPT_VERSION_ABI_LIBC UMr #endif #endif #elif MPT_LIBC_MS_MSVCRT #if MPT_LIBC_MS_SHARED #ifdef MPT_LIBC_MS_DEBUG #define MPT_VERSION_ABI_LIBC MMDd #else #define MPT_VERSION_ABI_LIBC MMDr #endif #elif MPT_LIBC_MS_STATIC #ifdef MPT_LIBC_MS_DEBUG #define MPT_VERSION_ABI_LIBC MMTd #else #define MPT_VERSION_ABI_LIBC MMTr #endif #else #ifdef MPT_LIBC_MS_DEBUG #define MPT_VERSION_ABI_LIBC MMd #else #define MPT_VERSION_ABI_LIBC MMr #endif #endif #else #if MPT_LIBC_MS_SHARED #ifdef MPT_LIBC_MS_DEBUG #define MPT_VERSION_ABI_LIBC MDd #else #define MPT_VERSION_ABI_LIBC MDr #endif #elif MPT_LIBC_MS_STATIC #ifdef MPT_LIBC_MS_DEBUG #define MPT_VERSION_ABI_LIBC MTd #else #define MPT_VERSION_ABI_LIBC MTr #endif #else #ifdef MPT_LIBC_MS_DEBUG #define MPT_VERSION_ABI_LIBC Md #else #define MPT_VERSION_ABI_LIBC Mr #endif #endif #endif #elif MPT_LIBC_GLIBC #define MPT_VERSION_ABI_LIBC G #elif MPT_LIBC_MINGW #if MPT_LIBC_MINGW_UCRT #define MPT_VERSION_ABI_LIBC MWU #elif MPT_LIBC_MINGW_MSVCRT #define MPT_VERSION_ABI_LIBC MWM #elif MPT_LIBC_MINGW_CRTDLL #define MPT_VERSION_ABI_LIBC MWC #else #define MPT_VERSION_ABI_LIBC MW #endif #elif MPT_LIBC_BIONIC #define MPT_VERSION_ABI_LIBC B #elif MPT_LIBC_APPLE #define MPT_VERSION_ABI_LIBC A #else #define MPT_VERSION_ABI_LIBC _ #endif #ifdef NDEBUG #define MPT_VERSION_ABI_LIBC_DEBUG _ #else #define MPT_VERSION_ABI_LIBC_DEBUG D #endif #define MPT_BUILD_ABI_NAMESPACE_IMPL(a, b, c) ABI_##a##_##b #define MPT_BUILD_ABI_NAMESPACE(a, b, c) MPT_BUILD_ABI_NAMESPACE_IMPL(a, b, c) #define MPT_ABI_NAMESPACE MPT_BUILD_ABI_NAMESPACE(MPT_VERSION_ABI_OS, MPT_VERSION_ABI_LIBC, MPT_VERSION_ABI_LIBC_DEBUG) #if !defined(MPT_PROJECT_NAMESPACE) MPT_WARNING("Please #define MPT_PROJECT_NAMESPACE or #define MPT_INLINE_NS in build configuration.") #define MPT_PROJECT_NAMESPACE x #endif // !MPT_PROJECT_NAMESPACE #define MPT_BUILD_INLINE_NS_IMPL(a, b, c) a##_##b##_##c #define MPT_BUILD_INLINE_NS(a, b, c) MPT_BUILD_INLINE_NS_IMPL(a, b, c) #define MPT_INLINE_NS MPT_BUILD_INLINE_NS(MPT_VERSION_NAMESPACE, MPT_ABI_NAMESPACE, MPT_PROJECT_NAMESPACE) #endif // !MPT_INLINE_NS namespace mpt { inline namespace MPT_INLINE_NS { } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_NAMESPACE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/saturate_cast.hpp0000644000175000017500000000445214730244445022146 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_SATURATE_CAST_HPP #define MPT_BASE_SATURATE_CAST_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include #include #if MPT_CXX_AT_LEAST(26) #include #endif namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_CXX_AT_LEAST(26) using std::saturate_cast; #else // Saturate the value of src to the domain of Tdst template constexpr Tdst saturate_cast(Tsrc src) noexcept { // This code tries not only to obviously avoid overflows but also to avoid signed/unsigned comparison warnings and type truncation warnings (which in fact would be safe here) by explicit casting. static_assert(std::numeric_limits::is_integer); static_assert(std::numeric_limits::is_integer); if constexpr (std::numeric_limits::is_signed && std::numeric_limits::is_signed) { if constexpr (sizeof(Tdst) >= sizeof(Tsrc)) { return static_cast(src); } else { return static_cast(std::max(static_cast(std::numeric_limits::min()), std::min(src, static_cast(std::numeric_limits::max())))); } } else if constexpr (!std::numeric_limits::is_signed && !std::numeric_limits::is_signed) { if constexpr (sizeof(Tdst) >= sizeof(Tsrc)) { return static_cast(src); } else { return static_cast(std::min(src, static_cast(std::numeric_limits::max()))); } } else if constexpr (std::numeric_limits::is_signed && !std::numeric_limits::is_signed) { if constexpr (sizeof(Tdst) > sizeof(Tsrc)) { return static_cast(src); } else if constexpr (sizeof(Tdst) == sizeof(Tsrc)) { return static_cast(std::min(src, static_cast(std::numeric_limits::max()))); } else { return static_cast(std::min(src, static_cast(std::numeric_limits::max()))); } } else { // Tdst unsigned, Tsrc signed if constexpr (sizeof(Tdst) >= sizeof(Tsrc)) { return static_cast(std::max(static_cast(0), src)); } else { return static_cast(std::max(static_cast(0), std::min(src, static_cast(std::numeric_limits::max())))); } } } #endif } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_SATURATE_CAST_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/math.hpp0000644000175000017500000000321014730562501020220 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_MATH_HPP #define MPT_BASE_MATH_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_OS_DJGPP inline long double log2(const long double val) { return static_cast(::log2(static_cast(val))); } inline double log2(const double val) { return ::log2(val); } inline float log2(const float val) { return ::log2f(val); } #else // !MPT_OS_DJGPP // C++11 std::log2 using std::log2; #endif // MPT_OS_DJGPP #if MPT_OS_DJGPP inline long double round(const long double val) { return ::roundl(val); } inline double round(const double val) { return ::round(val); } inline float round(const float val) { return ::roundf(val); } #else // !MPT_OS_DJGPP // C++11 std::round using std::round; #endif // MPT_OS_DJGPP #if MPT_OS_DJGPP inline long double trunc(const long double val) { return ::truncl(val); } inline double trunc(const double val) { return ::trunc(val); } inline float trunc(const float val) { return ::truncf(val); } #else // !MPT_OS_DJGPP // C++11 std::trunc using std::trunc; #endif // MPT_OS_DJGPP template inline T sanitize_nan(T val) { static_assert(std::is_floating_point::value); if (std::isnan(val)) { return T(0.0); } return val; } template inline T safe_clamp(T v, T lo, T hi) { static_assert(std::is_floating_point::value); return std::clamp(mpt::sanitize_nan(v), lo, hi); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_MATH_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/saturate_round.hpp0000644000175000017500000000320214730567171022337 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_SATURATE_ROUND_HPP #define MPT_BASE_SATURATE_ROUND_HPP #include "mpt/base/namespace.hpp" #include "mpt/base/math.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { template constexpr Tdst saturate_trunc(Tsrc src) { static_assert(std::is_floating_point::value); if (src >= static_cast(std::numeric_limits::max())) { return std::numeric_limits::max(); } if (src <= static_cast(std::numeric_limits::min())) { return std::numeric_limits::min(); } return static_cast(src); } // Rounds given double value to nearest integer value of type T. // Out-of-range values are saturated to the specified integer type's limits. template inline Tdst saturate_round(Tsrc val) { static_assert(std::is_floating_point::value); static_assert(std::numeric_limits::is_integer); return mpt::saturate_trunc(mpt::round(val)); } template inline Tdst saturate_ceil(Tsrc val) { static_assert(std::is_floating_point::value); static_assert(std::numeric_limits::is_integer); return mpt::saturate_trunc(std::ceil(val)); } template inline Tdst saturate_floor(Tsrc val) { static_assert(std::is_floating_point::value); static_assert(std::numeric_limits::is_integer); return mpt::saturate_trunc(std::floor(val)); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_SATURATE_ROUND_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/detect.hpp0000644000175000017500000000056214220065541020542 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_DETECT_HPP #define MPT_BASE_DETECT_HPP #include "mpt/base/detect_arch.hpp" #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_libc.hpp" #include "mpt/base/detect_libcxx.hpp" #include "mpt/base/detect_os.hpp" #include "mpt/base/detect_quirks.hpp" #endif // MPT_BASE_DETECT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/detect_arch.hpp0000644000175000017500000002653314767255435021570 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_DETECT_ARCH_HPP #define MPT_BASE_DETECT_ARCH_HPP #include "mpt/base/detect_compiler.hpp" // The order of the checks matters! #if MPT_COMPILER_GENERIC #define MPT_ARCH_GENERIC 1 #elif MPT_COMPILER_MSVC #if defined(_M_ARM64) || defined(_M_ARM64EC) #define MPT_ARCH_AARCH64 1 #elif defined(_M_ARM) #define MPT_ARCH_ARM 1 #elif defined(_M_AMD64) || defined(_M_X64) #define MPT_ARCH_AMD64 1 #elif defined(_M_IX86) #define MPT_ARCH_X86 1 #endif #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG #if defined(__wasm64__) || defined(__wasm64) #define MPT_ARCH_WASM64 1 #elif defined(__wasm32__) || defined(__wasm32) #define MPT_ARCH_WASM32 1 #elif defined(__aarch64__) #define MPT_ARCH_AARCH64 1 #elif defined(__arm__) #define MPT_ARCH_ARM 1 #elif defined(__amd64__) || defined(__x86_64__) #define MPT_ARCH_AMD64 1 #elif defined(__i386__) || defined(_X86_) #define MPT_ARCH_X86 1 #endif #else // MPT_COMPILER #if defined(__wasm64__) || defined(__wasm64) #define MPT_ARCH_WASM64 1 #elif defined(__wasm32__) || defined(__wasm32) #define MPT_ARCH_WASM32 1 #elif defined(__aarch64__) || defined(_M_ARM64) #define MPT_ARCH_AARCH64 1 #elif defined(__arm__) || defined(_M_ARM) #define MPT_ARCH_ARM 1 #elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64) || defined(__amd64) || defined(__x86_64) #define MPT_ARCH_AMD64 1 #elif defined(__i386__) || defined(_X86_) || defined(_M_IX86) || defined(__i386) || defined(__X86__) #define MPT_ARCH_X86 1 #endif #endif // MPT_COMPILER #ifndef MPT_ARCH_GENERIC #define MPT_ARCH_GENERIC 0 #endif #ifndef MPT_ARCH_WASM64 #define MPT_ARCH_WASM64 0 #endif #ifndef MPT_ARCH_WASM32 #define MPT_ARCH_WASM32 0 #endif #ifndef MPT_ARCH_AARCH64 #define MPT_ARCH_AARCH64 0 #endif #ifndef MPT_ARCH_ARM #define MPT_ARCH_ARM 0 #endif #ifndef MPT_ARCH_AMD64 #define MPT_ARCH_AMD64 0 #endif #ifndef MPT_ARCH_X86 #define MPT_ARCH_X86 0 #endif #if !MPT_COMPILER_GENERIC #if MPT_COMPILER_MSVC #define MPT_ARCH_LITTLE_ENDIAN #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define MPT_ARCH_BIG_ENDIAN #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define MPT_ARCH_LITTLE_ENDIAN #endif #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && defined(__ORDER_LITTLE_ENDIAN__) #if __ORDER_BIG_ENDIAN__ != __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define MPT_ARCH_BIG_ENDIAN #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define MPT_ARCH_LITTLE_ENDIAN #endif #endif #endif // fallback: #if !defined(MPT_ARCH_BIG_ENDIAN) && !defined(MPT_ARCH_LITTLE_ENDIAN) #if (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) \ || (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) \ || (defined(_STLP_BIG_ENDIAN) && !defined(_STLP_LITTLE_ENDIAN)) #define MPT_ARCH_BIG_ENDIAN #elif (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) \ || (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) \ || (defined(_STLP_LITTLE_ENDIAN) && !defined(_STLP_BIG_ENDIAN)) #define MPT_ARCH_LITTLE_ENDIAN #elif defined(__hpux) || defined(__hppa) \ || defined(_MIPSEB) \ || defined(__s390__) #define MPT_ARCH_BIG_ENDIAN #elif defined(__i386__) || defined(_M_IX86) \ || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \ || defined(__bfin__) #define MPT_ARCH_LITTLE_ENDIAN #endif #endif #endif // !MPT_COMPILER_GENERIC // compiler assumed instruction set support // clang-format off #if MPT_ARCH_X86 || MPT_ARCH_AMD64 #if MPT_COMPILER_MSVC #if defined(_M_X64) #define MPT_ARCH_X86_I386 #define MPT_ARCH_X86_FPU #define MPT_ARCH_X86_FSIN #define MPT_ARCH_X86_I486 #define MPT_ARCH_X86_CPUID #define MPT_ARCH_X86_TSC #define MPT_ARCH_X86_CX8 #define MPT_ARCH_X86_CMOV #define MPT_ARCH_X86_MMX #define MPT_ARCH_X86_MMXEXT #define MPT_ARCH_X86_FXSR #define MPT_ARCH_X86_SSE #define MPT_ARCH_X86_SSE2 #elif defined(_M_IX86) && defined(_M_IX86_FP) #if (_M_IX86_FP >= 2) #define MPT_ARCH_X86_I386 #define MPT_ARCH_X86_FPU #define MPT_ARCH_X86_FSIN #define MPT_ARCH_X86_I486 #define MPT_ARCH_X86_CPUID #define MPT_ARCH_X86_TSC #define MPT_ARCH_X86_CX8 #define MPT_ARCH_X86_CMOV #define MPT_ARCH_X86_MMX #define MPT_ARCH_X86_MMXEXT #define MPT_ARCH_X86_FXSR #define MPT_ARCH_X86_SSE #define MPT_ARCH_X86_SSE2 #elif (_M_IX86_FP == 1) #define MPT_ARCH_X86_I386 #define MPT_ARCH_X86_FPU #define MPT_ARCH_X86_FSIN #define MPT_ARCH_X86_I486 #define MPT_ARCH_X86_CPUID #define MPT_ARCH_X86_TSC #define MPT_ARCH_X86_CX8 #define MPT_ARCH_X86_CMOV #define MPT_ARCH_X86_MMX #define MPT_ARCH_X86_MMXEXT #define MPT_ARCH_X86_FXSR #define MPT_ARCH_X86_SSE #elif MPT_MSVC_AT_LEAST(2008, 0) #define MPT_ARCH_X86_I386 #define MPT_ARCH_X86_FPU #define MPT_ARCH_X86_FSIN #define MPT_ARCH_X86_I486 #define MPT_ARCH_X86_CPUID #define MPT_ARCH_X86_TSC #define MPT_ARCH_X86_CX8 #elif MPT_MSVC_AT_LEAST(2005, 0) #define MPT_ARCH_X86_I386 #define MPT_ARCH_X86_FPU #define MPT_ARCH_X86_FSIN #define MPT_ARCH_X86_I486 #elif MPT_MSVC_AT_LEAST(1998, 0) #define MPT_ARCH_X86_I386 #define MPT_ARCH_X86_FPU #define MPT_ARCH_X86_FSIN #else #define MPT_ARCH_X86_I386 #endif #endif #if defined(__AVX__) #define MPT_ARCH_X86_3DNOWPREFETCH #ifndef MPT_ARCH_X86_XSAVE #define MPT_ARCH_X86_XSAVE #endif #define MPT_ARCH_X86_AVX #endif #if defined(__AVX2__) #ifndef MPT_ARCH_X86_XSAVE #define MPT_ARCH_X86_XSAVE #endif #define MPT_ARCH_X86_AVX2 #define MPT_ARCH_X86_FMA #define MPT_ARCH_X86_BMI1 #endif #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG #define MPT_ARCH_X86_I386 #if !defined(_SOFT_FLOAT) #define MPT_ARCH_X86_FPU // GCC does not provide a macro for FSIN. Deduce it from 486 later. #endif #if defined(__i486__) // GCC does not consistently provide i486, deduce it later from cpuid. #define MPT_ARCH_X86_I486 #endif #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 // GCC does not provide TSC or CPUID. // Imply it by CX8. #define MPT_ARCH_X86_CX8 #define MPT_ARCH_X86_TSC #define MPT_ARCH_X86_CPUID #endif #if defined(__i686__) || defined(__athlon__) // GCC is broken here and does not set __i686__ for various non-Intel and even modern Intel CPUs // Imply __i686__ by __SSE__ as a work-around. #define MPT_ARCH_X86_CMOV #endif #if defined(MPT_ARCH_X86_CPUID) #ifndef MPT_ARCH_X86_I486 #define MPT_ARCH_X86_I486 #endif #endif #if defined(MPT_ARCH_X86_I486) && defined(MPT_ARCH_X86_FPU) #define MPT_ARCH_X86_FSIN #endif #ifdef __MMX__ #define MPT_ARCH_X86_MMX #endif #ifdef __3dNOW__ #define MPT_ARCH_X86_3DNOW #endif #ifdef __3dNOW_A__ #define MPT_ARCH_X86_MMXEXT #define MPT_ARCH_X86_3DNOWEXT #endif #ifdef __PRFCHW__ #define MPT_ARCH_X86_3DNOWPREFETCH #endif #ifdef __FXSR__ #define MPT_ARCH_X86_FXSR #endif #ifdef __SSE__ #ifndef MPT_ARCH_X86_MMXEXT #define MPT_ARCH_X86_MMXEXT #endif #define MPT_ARCH_X86_SSE #ifndef MPT_ARCH_X86_CMOV #define MPT_ARCH_X86_CMOV #endif #endif #ifdef __SSE2__ #define MPT_ARCH_X86_SSE2 #endif #ifdef __SSE3__ #define MPT_ARCH_X86_SSE3 #endif #ifdef __SSSE3__ #define MPT_ARCH_X86_SSSE3 #endif #ifdef __SSE4_1__ #define MPT_ARCH_X86_SSE4_1 #endif #ifdef __SSE4_2__ #define MPT_ARCH_X86_SSE4_2 #endif #ifdef __XSAVE__ #define MPT_ARCH_X86_XSAVE #endif #ifdef __AVX__ #define MPT_ARCH_X86_AVX #endif #ifdef __AVX2__ #define MPT_ARCH_X86_AVX2 #endif #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 #define MPT_ARCH_X86_CX16 #endif #ifdef __LAHF_SAHF__ #define MPT_ARCH_X86_LAHF #endif #ifdef __POPCNT__ #define MPT_ARCH_X86_POPCNT #endif #ifdef __BMI__ #define MPT_ARCH_X86_BMI1 #endif #ifdef __BMI2__ #define MPT_ARCH_X86_BMI2 #endif #ifdef __F16C__ #define MPT_ARCH_X86_F16C #endif #ifdef __FMA__ #define MPT_ARCH_X86_FMA #endif #ifdef __LZCNT__ #define MPT_ARCH_X86_LZCNT #endif #ifdef __MOVBE__ #define MPT_ARCH_X86_MOVBE #endif #endif // MPT_COMPILER #endif // MPT_ARCH // clang-format on // compiler supported instrinsics // clang-format off #if MPT_ARCH_X86 || MPT_ARCH_AMD64 #if MPT_COMPILER_MSVC #define MPT_ARCH_INTRINSICS_X86_I386 #define MPT_ARCH_INTRINSICS_X86_FPU #define MPT_ARCH_INTRINSICS_X86_FSIN #define MPT_ARCH_INTRINSICS_X86_CPUID #define MPT_ARCH_INTRINSICS_X86_TSC #define MPT_ARCH_INTRINSICS_X86_CX8 #define MPT_ARCH_INTRINSICS_X86_CMOV #define MPT_ARCH_INTRINSICS_X86_MMX #define MPT_ARCH_INTRINSICS_X86_MMXEXT #define MPT_ARCH_INTRINSICS_X86_3DNOW #define MPT_ARCH_INTRINSICS_X86_3DNOWEXT #define MPT_ARCH_INTRINSICS_X86_3DNOWPREFETCH #if MPT_MSVC_AT_LEAST(2003, 0) #define MPT_ARCH_INTRINSICS_X86_FXSR #define MPT_ARCH_INTRINSICS_X86_SSE #define MPT_ARCH_INTRINSICS_X86_SSE2 #endif #if MPT_MSVC_AT_LEAST(2008, 0) #define MPT_ARCH_INTRINSICS_X86_SSE3 #define MPT_ARCH_INTRINSICS_X86_SSSE3 #define MPT_ARCH_INTRINSICS_X86_SSE4_1 #define MPT_ARCH_INTRINSICS_X86_SSE4_2 #endif #if MPT_MSVC_AT_LEAST(2010, 1) #define MPT_ARCH_INTRINSICS_X86_XSAVE #define MPT_ARCH_INTRINSICS_X86_AVX #endif #if MPT_MSVC_AT_LEAST(2012, 0) #define MPT_ARCH_INTRINSICS_X86_AVX2 #define MPT_ARCH_INTRINSICS_X86_FMA #define MPT_ARCH_INTRINSICS_X86_BMI1 #endif #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG #ifdef MPT_ARCH_X86_I386 #define MPT_ARCH_INTRINSICS_X86_I386 #endif #ifdef MPT_ARCH_X86_FPU #define MPT_ARCH_INTRINSICS_X86_FPU #endif #ifdef MPT_ARCH_X86_FSIN #define MPT_ARCH_INTRINSICS_X86_FSIN #endif #ifdef MPT_ARCH_X86_I486 #define MPT_ARCH_INTRINSICS_X86_I486 #endif #ifdef MPT_ARCH_X86_CPUID #define MPT_ARCH_INTRINSICS_X86_CPUID #endif #ifdef MPT_ARCH_X86_TSC #define MPT_ARCH_INTRINSICS_X86_TSC #endif #ifdef MPT_ARCH_X86_CX8 #define MPT_ARCH_INTRINSICS_X86_CX8 #endif #ifdef MPT_ARCH_X86_CMOV #define MPT_ARCH_INTRINSICS_X86_CMOV #endif #ifdef MPT_ARCH_X86_MMX #define MPT_ARCH_INTRINSICS_X86_MMX #endif #ifdef MPT_ARCH_X86_MMXEXT #define MPT_ARCH_INTRINSICS_X86_MMXEXT #endif #ifdef MPT_ARCH_X86_3DNOW #define MPT_ARCH_INTRINSICS_X86_3DNOW #endif #ifdef MPT_ARCH_X86_3DNOWEXT #define MPT_ARCH_INTRINSICS_X86_3DNOWEXT #endif #ifdef MPT_ARCH_X86_3DNOWPREFETCH #define MPT_ARCH_INTRINSICS_X86_3DNOWPREFETCH #endif #ifdef MPT_ARCH_X86_FXSR #define MPT_ARCH_INTRINSICS_X86_FXSR #endif #ifdef MPT_ARCH_X86_SSE #define MPT_ARCH_INTRINSICS_X86_SSE #endif #ifdef MPT_ARCH_X86_SSE2 #define MPT_ARCH_INTRINSICS_X86_SSE2 #endif #ifdef MPT_ARCH_X86_SSE3 #define MPT_ARCH_INTRINSICS_X86_SSE3 #endif #ifdef MPT_ARCH_X86_SSSE3 #define MPT_ARCH_INTRINSICS_X86_SSSE3 #endif #ifdef MPT_ARCH_X86_SSE4_1 #define MPT_ARCH_INTRINSICS_X86_SSE4_1 #endif #ifdef MPT_ARCH_X86_SSE4_2 #define MPT_ARCH_INTRINSICS_X86_SSE4_2 #endif #ifdef MPT_ARCH_X86_XSAVE #define MPT_ARCH_INTRINSICS_X86_XSAVE #endif #ifdef MPT_ARCH_X86_AVX #define MPT_ARCH_INTRINSICS_X86_AVX #endif #ifdef MPT_ARCH_X86_AVX2 #define MPT_ARCH_INTRINSICS_X86_AVX2 #endif #ifdef MPT_ARCH_X86_CX16 #define MPT_ARCH_INTRINSICS_X86_CX16 #endif #ifdef MPT_ARCH_X86_LAHF #define MPT_ARCH_INTRINSICS_X86_LAHF #endif #ifdef MPT_ARCH_X86_POPCNT #define MPT_ARCH_INTRINSICS_X86_POPCNT #endif #ifdef MPT_ARCH_X86_BMI1 #define MPT_ARCH_INTRINSICS_X86_BMI1 #endif #ifdef MPT_ARCH_X86_BMI2 #define MPT_ARCH_INTRINSICS_X86_BMI2 #endif #ifdef MPT_ARCH_X86_F16C #define MPT_ARCH_INTRINSICS_X86_F16C #endif #ifdef MPT_ARCH_X86_FMA #define MPT_ARCH_INTRINSICS_X86_FMA #endif #ifdef MPT_ARCH_X86_LZCNT #define MPT_ARCH_INTRINSICS_X86_LZCNT #endif #ifdef MPT_ARCH_X86_MOVBE #define MPT_ARCH_INTRINSICS_X86_MOVBE #endif #endif // MPT_COMPILER #endif // MPT_ARCH // clang-format on #endif // MPT_BASE_DETECT_ARCH_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/macros.hpp0000644000175000017500000001236014734546535020576 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_MACROS_HPP #define MPT_BASE_MACROS_HPP #include "mpt/base/detect.hpp" #include #if MPT_COMPILER_MSVC && MPT_OS_WINDOWS #include #endif // MPT_COMPILER_MSVC && MPT_OS_WINDOWS // Advanced inline attributes #if MPT_COMPILER_MSVC #define MPT_FORCEINLINE __forceinline #define MPT_NOINLINE __declspec(noinline) #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG #define MPT_FORCEINLINE __attribute__((always_inline)) inline #define MPT_NOINLINE __attribute__((noinline)) #else #define MPT_FORCEINLINE inline #define MPT_NOINLINE #endif // constexpr #define MPT_CONSTEXPRINLINE constexpr MPT_FORCEINLINE #if MPT_CXX_AT_LEAST(23) #define MPT_CONSTEXPR20_FUN constexpr MPT_FORCEINLINE #define MPT_CONSTEXPR20_VAR constexpr #define MPT_CONSTEXPR23_FUN constexpr MPT_FORCEINLINE #define MPT_CONSTEXPR23_VAR constexpr #elif MPT_CXX_AT_LEAST(20) #define MPT_CONSTEXPR20_FUN constexpr MPT_FORCEINLINE #define MPT_CONSTEXPR20_VAR constexpr #define MPT_CONSTEXPR23_FUN MPT_FORCEINLINE #define MPT_CONSTEXPR23_VAR const #else // C++ #define MPT_CONSTEXPR20_FUN MPT_FORCEINLINE #define MPT_CONSTEXPR20_VAR const #define MPT_CONSTEXPR23_FUN MPT_FORCEINLINE #define MPT_CONSTEXPR23_VAR const #endif // C++ #if !defined(MPT_LIBCXX_QUIRK_NO_CXX20_CONSTEXPR_ALGORITHM) #define MPT_CONSTEXPR20_ALGORITHM_FUN MPT_CONSTEXPR20_FUN #define MPT_CONSTEXPR20_ALGORITHM_VAR MPT_CONSTEXPR20_VAR #else #define MPT_CONSTEXPR20_ALGORITHM_FUN MPT_CONSTEXPR23_FUN #define MPT_CONSTEXPR20_ALGORITHM_VAR MPT_CONSTEXPR23_VAR #endif #if !defined(MPT_LIBCXX_QUIRK_NO_CXX20_CONSTEXPR_CONTAINER) #define MPT_CONSTEXPR20_CONTAINER_FUN MPT_CONSTEXPR20_FUN #define MPT_CONSTEXPR20_CONTAINER_VAR MPT_CONSTEXPR20_VAR #else #define MPT_CONSTEXPR20_CONTAINER_FUN MPT_CONSTEXPR23_FUN #define MPT_CONSTEXPR20_CONTAINER_VAR MPT_CONSTEXPR23_VAR #endif #if MPT_CXX_AT_LEAST(20) #define MPT_CONSTEVAL consteval #else // !C++20 // fallback to constexpr #define MPT_CONSTEVAL MPT_CONSTEXPRINLINE #endif // C++20 #if MPT_CXX_AT_LEAST(20) #define MPT_CONSTEVAL_NOEXCEPT noexcept #else // !C++20 #define MPT_CONSTEVAL_NOEXCEPT #endif // C++20 #define MPT_FORCE_CONSTEXPR_EXPRESSION(expr) [&]() { \ constexpr auto x = (expr); \ return x; \ }() #define MPT_FORCE_CONSTEXPR_VALUE(val) []() { \ constexpr auto x = (val); \ return x; \ }() #if MPT_CXX_AT_LEAST(20) // this assumes that for C++20, a consteval function will be used #define MPT_FORCE_CONSTEVAL_EXPRESSION(expr) (expr) #define MPT_FORCE_CONSTEVAL_VALUE(val) (val) #else // !C++20 #define MPT_FORCE_CONSTEVAL_EXPRESSION(expr) [&]() { \ constexpr auto x = (expr); \ return x; \ }() #define MPT_FORCE_CONSTEVAL_VALUE(val) []() { \ constexpr auto x = (val); \ return x; \ }() #endif // C++20 #if MPT_CXX_AT_LEAST(20) #define MPT_CONSTINIT constinit #else // !C++20 // fallback to nothing #define MPT_CONSTINIT #endif // C++20 #if MPT_CXX_AT_LEAST(20) #define MPT_IS_CONSTANT_EVALUATED20() std::is_constant_evaluated() #define MPT_IS_CONSTANT_EVALUATED() std::is_constant_evaluated() #else // !C++20 #define MPT_IS_CONSTANT_EVALUATED20() false // this pessimizes the case for C++17 by always assuming constexpr context, which implies always running constexpr-friendly code #define MPT_IS_CONSTANT_EVALUATED() true #endif // C++20 #if MPT_COMPILER_MSVC #define MPT_MAYBE_CONSTANT_IF(x) \ __pragma(warning(push)) \ __pragma(warning(disable : 4127)) \ if (x) \ __pragma(warning(pop)) \ /**/ #endif #if MPT_COMPILER_GCC #define MPT_MAYBE_CONSTANT_IF(x) \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \ if (x) \ _Pragma("GCC diagnostic pop") \ /**/ #endif #if MPT_COMPILER_CLANG #define MPT_MAYBE_CONSTANT_IF(x) \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") \ _Pragma("clang diagnostic ignored \"-Wtype-limits\"") \ _Pragma("clang diagnostic ignored \"-Wtautological-constant-out-of-range-compare\"") \ if (x) \ _Pragma("clang diagnostic pop") \ /**/ #endif #if !defined(MPT_MAYBE_CONSTANT_IF) // MPT_MAYBE_CONSTANT_IF disables compiler warnings for conditions that may in some case be either always false or always true (this may turn out to be useful in ASSERTions in some cases). #define MPT_MAYBE_CONSTANT_IF(x) if (x) #endif #if MPT_COMPILER_MSVC && MPT_OS_WINDOWS #define MPT_UNUSED(x) UNREFERENCED_PARAMETER(x) #else #define MPT_UNUSED(x) static_cast(x) #endif #define MPT_DISCARD(expr) static_cast(expr) // Use MPT_RESTRICT to indicate that a pointer is guaranteed to not be aliased. #if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG #define MPT_RESTRICT __restrict #else #define MPT_RESTRICT #endif #if MPT_CXX_AT_LEAST(23) && !MPT_GCC_BEFORE(13, 0, 0) && !MPT_CLANG_BEFORE(19, 0, 0) && !MPT_COMPILER_MSVC #define MPT_ASSUME(expr) [[assume(expr)]] #else // !C++23 #if MPT_COMPILER_CLANG #define MPT_ASSUME(expr) __builtin_assume(expr) #endif #if MPT_COMPILER_MSVC #define MPT_ASSUME(expr) __assume(expr) #endif #if MPT_COMPILER_GCC #define MPT_ASSUME(expr) \ do { \ if (!expr) { \ __builtin_unreachable(); \ } \ } while (0) #endif #if !defined(MPT_ASSUME) #define MPT_ASSUME(expr) MPT_DISCARD(expr) #endif #endif // C++23 #endif // MPT_BASE_MACROS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/bit.hpp0000644000175000017500000003310014650435437020056 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_BIT_HPP #define MPT_BASE_BIT_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/macros.hpp" #if MPT_CXX_BEFORE(20) #include #endif // !C++20 #if defined(MPT_COMPILER_QUIRK_BROKEN_BITCAST) #include #endif #if MPT_CXX_AT_LEAST(20) #include #endif // C++20 #if MPT_CXX_BEFORE(23) || MPT_COMPILER_MSVC || MPT_LIBCXX_GNU_BEFORE(12) || MPT_LIBCXX_LLVM_BEFORE(14000) #include #endif // !C++23 #include #if MPT_CXX_BEFORE(20) || MPT_LIBCXX_GNU_BEFORE(11) || MPT_LIBCXX_LLVM_BEFORE(14000) || defined(MPT_COMPILER_QUIRK_BROKEN_BITCAST) #include #endif // !C++20 #if MPT_CXX_BEFORE(23) && MPT_COMPILER_MSVC #include #endif // !C++23 namespace mpt { inline namespace MPT_INLINE_NS { #if defined(MPT_COMPILER_QUIRK_BROKEN_BITCAST) // VS2022 17.6.0 ARM64 gets confused about alignment in std::bit_cast (or equivalent code), // causing an ICE with LTCG turned on. // We try to work-around this problem by placing signal fences as an optimization barrier around the (presumably) confused operation. template MPT_FORCEINLINE typename std::enable_if<(sizeof(Tdst) == sizeof(Tsrc)) && std::is_trivially_copyable::value && std::is_trivially_copyable::value, Tdst>::type bit_cast(const Tsrc & src) noexcept { Tdst dst{}; std::atomic_signal_fence(std::memory_order_seq_cst); std::memcpy(&dst, &src, sizeof(Tdst)); std::atomic_signal_fence(std::memory_order_seq_cst); return dst; } #elif MPT_CXX_AT_LEAST(20) && !MPT_LIBCXX_GNU_BEFORE(11) && !MPT_LIBCXX_LLVM_BEFORE(14000) using std::bit_cast; #else // !C++20 // C++2a compatible bit_cast. // Not implementing constexpr because this is not easily possible pre C++20. template MPT_FORCEINLINE typename std::enable_if<(sizeof(Tdst) == sizeof(Tsrc)) && std::is_trivially_copyable::value && std::is_trivially_copyable::value, Tdst>::type bit_cast(const Tsrc & src) noexcept { Tdst dst{}; std::memcpy(&dst, &src, sizeof(Tdst)); return dst; } #endif // C++20 #if MPT_CXX_AT_LEAST(20) using std::endian; static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported"); constexpr mpt::endian get_endian() noexcept { return mpt::endian::native; } constexpr bool endian_is_little() noexcept { return get_endian() == mpt::endian::little; } constexpr bool endian_is_big() noexcept { return get_endian() == mpt::endian::big; } constexpr bool endian_is_weird() noexcept { return !endian_is_little() && !endian_is_big(); } #else // !C++20 #if MPT_COMPILER_MSVC // same definition as VS2022 C++20 in order to be compatible with debugvis enum class endian { little = 0, big = 1, weird = -1, native = little, }; #else // !MPT_COMPILER_MSVC enum class endian { little = 0x78563412u, big = 0x12345678u, weird = 1u, #if MPT_COMPILER_GENERIC native = 0u, #elif defined(MPT_ARCH_LITTLE_ENDIAN) native = little, #elif defined(MPT_ARCH_BIG_ENDIAN) native = big, #else native = 0u, #endif }; #endif // MPT_COMPILER_MSVC static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported"); MPT_FORCEINLINE mpt::endian endian_probe() noexcept { using endian_probe_type = uint32; static_assert(sizeof(endian_probe_type) == 4); constexpr endian_probe_type endian_probe_big = 0x12345678u; constexpr endian_probe_type endian_probe_little = 0x78563412u; const std::array probe{ {std::byte{0x12}, std::byte{0x34}, std::byte{0x56}, std::byte{0x78}} }; const endian_probe_type test = mpt::bit_cast(probe); mpt::endian result = mpt::endian::native; switch (test) { case endian_probe_big: result = mpt::endian::big; break; case endian_probe_little: result = mpt::endian::little; break; default: result = mpt::endian::weird; break; } return result; } MPT_FORCEINLINE mpt::endian get_endian() noexcept { #if MPT_COMPILER_MSVC #pragma warning(push) #pragma warning(disable : 6285) // false-positive: ( || ) is always a non-zero constant. #endif // MPT_COMPILER_MSVC if constexpr ((mpt::endian::native == mpt::endian::little) || (mpt::endian::native == mpt::endian::big)) { return mpt::endian::native; } else { return mpt::endian_probe(); } #if MPT_COMPILER_MSVC #pragma warning(pop) #endif // MPT_COMPILER_MSVC } MPT_FORCEINLINE bool endian_is_little() noexcept { return get_endian() == mpt::endian::little; } MPT_FORCEINLINE bool endian_is_big() noexcept { return get_endian() == mpt::endian::big; } MPT_FORCEINLINE bool endian_is_weird() noexcept { return !endian_is_little() && !endian_is_big(); } #endif // C++20 #if MPT_CXX_AT_LEAST(20) && MPT_MSVC_AT_LEAST(2022, 1) && !MPT_LIBCXX_GNU_BEFORE(10) && !MPT_LIBCXX_LLVM_BEFORE(12000) // Disabled for VS2022.0 because of // // / with fix already queued // (). using std::bit_ceil; using std::bit_floor; using std::bit_width; using std::countl_one; using std::countl_zero; using std::countr_one; using std::countr_zero; using std::has_single_bit; using std::popcount; using std::rotl; using std::rotr; #else // !C++20 // C++20 header. // Note that we do not use SFINAE here but instead rely on static_assert. template constexpr int popcount(T val) noexcept { static_assert(std::numeric_limits::is_integer); static_assert(std::is_unsigned::value); int result = 0; while (val > 0) { if (val & 0x1) { result++; } val >>= 1; } return result; } template constexpr bool has_single_bit(T x) noexcept { static_assert(std::numeric_limits::is_integer); static_assert(std::is_unsigned::value); return mpt::popcount(x) == 1; } template constexpr T bit_ceil(T x) noexcept { static_assert(std::numeric_limits::is_integer); static_assert(std::is_unsigned::value); T result = 1; while (result < x) { T newresult = result << 1; if (newresult < result) { return 0; } result = newresult; } return result; } template constexpr T bit_floor(T x) noexcept { static_assert(std::numeric_limits::is_integer); static_assert(std::is_unsigned::value); if (x == 0) { return 0; } T result = 1; do { T newresult = result << 1; if (newresult < result) { return result; } result = newresult; } while (result <= x); return result >> 1; } template constexpr int bit_width(T x) noexcept { static_assert(std::numeric_limits::is_integer); static_assert(std::is_unsigned::value); int result = 0; while (x > 0) { x >>= 1; result += 1; } return result; } template constexpr int countl_zero(T x) noexcept { static_assert(std::numeric_limits::is_integer); static_assert(std::is_unsigned::value); int count = 0; for (int bit = std::numeric_limits::digits - 1; bit >= 0; --bit) { if ((x & (1u << bit)) == 0u) { count++; } else { break; } } return count; } template constexpr int countl_one(T x) noexcept { static_assert(std::numeric_limits::is_integer); static_assert(std::is_unsigned::value); int count = 0; for (int bit = std::numeric_limits::digits - 1; bit >= 0; --bit) { if ((x & (1u << bit)) != 0u) { count++; } else { break; } } return count; } template constexpr int countr_zero(T x) noexcept { static_assert(std::numeric_limits::is_integer); static_assert(std::is_unsigned::value); int count = 0; for (int bit = 0; bit < std::numeric_limits::digits; ++bit) { if ((x & (1u << bit)) == 0u) { count++; } else { break; } } return count; } template constexpr int countr_one(T x) noexcept { static_assert(std::numeric_limits::is_integer); static_assert(std::is_unsigned::value); int count = 0; for (int bit = 0; bit < std::numeric_limits::digits; ++bit) { if ((x & (1u << bit)) != 0u) { count++; } else { break; } } return count; } template constexpr T rotl_impl(T x, int r) noexcept { auto N = std::numeric_limits::digits; return (x >> (N - r)) | (x << r); } template constexpr T rotr_impl(T x, int r) noexcept { auto N = std::numeric_limits::digits; return (x << (N - r)) | (x >> r); } template constexpr T rotl(T x, int s) noexcept { static_assert(std::numeric_limits::is_integer); static_assert(std::is_unsigned::value); auto N = std::numeric_limits::digits; auto r = s % N; return (s < 0) ? mpt::rotr_impl(x, -s) : ((x >> (N - r)) | (x << r)); } template constexpr T rotr(T x, int s) noexcept { static_assert(std::numeric_limits::is_integer); static_assert(std::is_unsigned::value); auto N = std::numeric_limits::digits; auto r = s % N; return (s < 0) ? mpt::rotl_impl(x, -s) : ((x << (N - r)) | (x >> r)); } #endif // C++20 #if MPT_CXX_AT_LEAST(23) && !MPT_LIBCXX_GNU_BEFORE(12) && !MPT_LIBCXX_LLVM_BEFORE(14000) && !MPT_MSVC_BEFORE(2022, 1) using std::byteswap; #else // !C++23 constexpr inline uint16 byteswap_impl_constexpr16(uint16 x) noexcept { #if MPT_COMPILER_GCC #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #endif // MPT_COMPILER_GCC return uint16(0) | ((x >> 8) & 0x00FFu) | ((x << 8) & 0xFF00u); #if MPT_COMPILER_GCC #pragma GCC diagnostic pop #endif // MPT_COMPILER_GCC } constexpr inline uint32 byteswap_impl_constexpr32(uint32 x) noexcept { return uint32(0) | ((x & 0x000000FFu) << 24) | ((x & 0x0000FF00u) << 8) | ((x & 0x00FF0000u) >> 8) | ((x & 0xFF000000u) >> 24); } constexpr inline uint64 byteswap_impl_constexpr64(uint64 x) noexcept { return uint64(0) | (((x >> 0) & 0xffull) << 56) | (((x >> 8) & 0xffull) << 48) | (((x >> 16) & 0xffull) << 40) | (((x >> 24) & 0xffull) << 32) | (((x >> 32) & 0xffull) << 24) | (((x >> 40) & 0xffull) << 16) | (((x >> 48) & 0xffull) << 8) | (((x >> 56) & 0xffull) << 0); } #if MPT_COMPILER_GCC // Clang also supports these, // however . #define MPT_byteswap_impl16 __builtin_bswap16 #define MPT_byteswap_impl32 __builtin_bswap32 #define MPT_byteswap_impl64 __builtin_bswap64 #elif MPT_COMPILER_MSVC #define MPT_byteswap_impl16 _byteswap_ushort #define MPT_byteswap_impl32 _byteswap_ulong #define MPT_byteswap_impl64 _byteswap_uint64 #endif // No intrinsics available #ifndef MPT_byteswap_impl16 #define MPT_byteswap_impl16(x) byteswap_impl_constexpr16(x) #endif #ifndef MPT_byteswap_impl32 #define MPT_byteswap_impl32(x) byteswap_impl_constexpr32(x) #endif #ifndef MPT_byteswap_impl64 #define MPT_byteswap_impl64(x) byteswap_impl_constexpr64(x) #endif MPT_CONSTEXPR20_FUN uint64 byteswap_impl(uint64 value) noexcept { MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { return byteswap_impl_constexpr64(value); } else { return MPT_byteswap_impl64(value); } } MPT_CONSTEXPR20_FUN uint32 byteswap_impl(uint32 value) noexcept { MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { return byteswap_impl_constexpr32(value); } else { return MPT_byteswap_impl32(value); } } MPT_CONSTEXPR20_FUN uint16 byteswap_impl(uint16 value) noexcept { MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { return byteswap_impl_constexpr16(value); } else { return MPT_byteswap_impl16(value); } } MPT_CONSTEXPR20_FUN int64 byteswap_impl(int64 value) noexcept { MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { return byteswap_impl_constexpr64(value); } else { return MPT_byteswap_impl64(value); } } MPT_CONSTEXPR20_FUN int32 byteswap_impl(int32 value) noexcept { MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { return byteswap_impl_constexpr32(value); } else { return MPT_byteswap_impl32(value); } } MPT_CONSTEXPR20_FUN int16 byteswap_impl(int16 value) noexcept { MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { return byteswap_impl_constexpr16(value); } else { return MPT_byteswap_impl16(value); } } // Do NOT remove these overloads, even if they seem useless. // We do not want risking to extend 8bit integers to int and then // endian-converting and casting back to int. // Thus these overloads. constexpr inline uint8 byteswap_impl(uint8 value) noexcept { return value; } constexpr inline int8 byteswap_impl(int8 value) noexcept { return value; } constexpr inline char byteswap_impl(char value) noexcept { return value; } #undef MPT_byteswap_impl16 #undef MPT_byteswap_impl32 #undef MPT_byteswap_impl64 template constexpr T byteswap(T x) noexcept { static_assert(std::numeric_limits::is_integer); return byteswap_impl(x); } #endif // C++23 template constexpr int lower_bound_entropy_bits(T x_) { typename std::make_unsigned::type x = static_cast::type>(x_); return (static_cast(mpt::bit_width(x)) == static_cast::type>(mpt::popcount(x))) ? mpt::bit_width(x) : mpt::bit_width(x) - 1; } template constexpr bool is_mask(T x) { static_assert(std::is_integral::value); typedef typename std::make_unsigned::type unsigned_T; unsigned_T ux = static_cast(x); unsigned_T mask = 0; for (std::size_t bits = 0; bits <= (sizeof(unsigned_T) * 8); ++bits) { mask = (mask << 1) | 1u; if (ux == mask) { return true; } } return false; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_BIT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/pointer.hpp0000644000175000017500000000274214351531562020762 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_POINTER_HPP #define MPT_BASE_POINTER_HPP #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { inline constexpr int arch_bits = sizeof(void *) * 8; inline constexpr std::size_t pointer_size = sizeof(void *); template struct pointer_cast_helper { static constexpr Tdst cast(const Tsrc & src) noexcept { return src; } }; template struct pointer_cast_helper { static constexpr Tdst cast(const Tptr * const & src) noexcept { return reinterpret_cast(src); } }; template struct pointer_cast_helper { static constexpr Tdst cast(const Tptr * const & src) noexcept { return reinterpret_cast(src); } }; template constexpr Tdst pointer_cast(const Tsrc & src) noexcept { return pointer_cast_helper::cast(src); } template class void_ptr { private: T * m_ptr = nullptr; public: MPT_FORCEINLINE explicit void_ptr(void * ptr) : m_ptr(reinterpret_cast(ptr)) { return; } MPT_FORCEINLINE T & operator*() { return *m_ptr; } MPT_FORCEINLINE T * operator->() { return m_ptr; } MPT_FORCEINLINE operator void *() { return m_ptr; } }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_POINTER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/algorithm.hpp0000644000175000017500000000767414674326761021314 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_ALGORITHM_HPP #define MPT_BASE_ALGORITHM_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { // Grows x with an exponential factor suitable for increasing buffer sizes. // Clamps the result at limit. // And avoids integer overflows while doing its business. // The growth factor is 1.5, rounding down, execpt for the initial x==1 case. template inline T exponential_grow(const T & x, const Tlimit & limit) { if (x <= 1) { return 2; } T add = std::min(x >> 1, std::numeric_limits::max() - x); return std::min(x + add, mpt::saturate_cast(limit)); } template inline T exponential_grow(const T & x) { return mpt::exponential_grow(x, std::numeric_limits::max()); } // Check if val is in [lo,hi] without causing compiler warnings // if theses checks are always true due to the domain of T. // GCC does not warn if the type is templated. template constexpr bool is_in_range(const T & val, const C & lo, const C & hi) { return lo <= val && val <= hi; } namespace detail { namespace contains { template struct has_find : std::false_type { }; template struct has_find { private: template static constexpr inline auto check(T *) -> typename std::is_same().find(std::declval()...)), Ret>::type { return {}; } template static constexpr inline std::false_type check(...) { return {}; } public: typedef decltype(check(nullptr)) type; static constexpr inline bool value = type::value; }; template MPT_CONSTEXPR20_FUN bool contains_class_find_impl(const Tcontainer & container, const Tval & value, std::true_type) noexcept(noexcept(container.find(value) != container.end())) { return container.find(value) != container.end(); } template MPT_CONSTEXPR20_FUN bool contains_class_find_impl(const Tcontainer & container, const Tval & value, std::false_type) noexcept(noexcept(std::find(std::begin(container), std::end(container), value))) { return std::find(std::begin(container), std::end(container), value) != std::end(container); } template MPT_CONSTEXPR20_FUN bool contains_class_impl(const Tcontainer & container, const Tval & value, std::true_type) noexcept(noexcept(mpt::detail::contains::contains_class_find_impl(container, value, typename mpt::detail::contains::has_find::type{}))) { return mpt::detail::contains::contains_class_find_impl(container, value, typename mpt::detail::contains::has_find::type{}); } template MPT_CONSTEXPR20_FUN bool contains_class_impl(const Tcontainer & container, const Tval & value, std::false_type) noexcept(noexcept(std::find(std::begin(container), std::end(container), value))) { return std::find(std::begin(container), std::end(container), value) != std::end(container); } } // namespace contains } // namespace detail template MPT_CONSTEXPR20_FUN bool contains(const Tcontainer & container, const Tval & value) noexcept(noexcept(mpt::detail::contains::contains_class_impl(container, value, typename std::is_class::type{}))) { return mpt::detail::contains::contains_class_impl(container, value, typename std::is_class::type{}); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_ALGORITHM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/wrapping_divide.hpp0000644000175000017500000000154614044173026022452 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_WRAPPING_DIVIDE_HPP #define MPT_BASE_WRAPPING_DIVIDE_HPP #include "mpt/base/namespace.hpp" namespace mpt { inline namespace MPT_INLINE_NS { // Modulo with more intuitive behaviour for some contexts: // Instead of being symmetrical around 0, the pattern for positive numbers is repeated in the negative range. // For example, wrapping_modulo(-1, m) == (m - 1). // Behaviour is undefined if m<=0. template constexpr auto wrapping_modulo(T x, M m) -> decltype(x % m) { return (x >= 0) ? (x % m) : (m - 1 - ((-1 - x) % m)); } template constexpr auto wrapping_divide(T x, D d) -> decltype(x / d) { return (x >= 0) ? (x / d) : (((x + 1) / d) - 1); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_WRAPPING_DIVIDE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/detect_os.hpp0000644000175000017500000003500114736004356021250 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_DETECT_OS_HPP #define MPT_BASE_DETECT_OS_HPP #define MPT_WIN_MAKE_VERSION(major, minor, sp, build) ((major << 24) + (minor << 16) + (sp << 8) + (build << 0)) // clang-format off #define MPT_WIN_WIN32S MPT_WIN_MAKE_VERSION(0x03, 0x00, 0x00, 0x00) #define MPT_WIN_WIN95 MPT_WIN_MAKE_VERSION(0x04, 0x00, 0x00, 0x00) #define MPT_WIN_WIN98 MPT_WIN_MAKE_VERSION(0x04, 0x10, 0x00, 0x00) #define MPT_WIN_WINME MPT_WIN_MAKE_VERSION(0x04, 0x90, 0x00, 0x00) #define MPT_WIN_NT3 MPT_WIN_MAKE_VERSION(0x03, 0x00, 0x00, 0x00) #define MPT_WIN_NT4 MPT_WIN_MAKE_VERSION(0x04, 0x00, 0x00, 0x00) #define MPT_WIN_2000 MPT_WIN_MAKE_VERSION(0x05, 0x00, 0x00, 0x00) #define MPT_WIN_2000SP1 MPT_WIN_MAKE_VERSION(0x05, 0x00, 0x01, 0x00) #define MPT_WIN_2000SP2 MPT_WIN_MAKE_VERSION(0x05, 0x00, 0x02, 0x00) #define MPT_WIN_2000SP3 MPT_WIN_MAKE_VERSION(0x05, 0x00, 0x03, 0x00) #define MPT_WIN_2000SP4 MPT_WIN_MAKE_VERSION(0x05, 0x00, 0x04, 0x00) #define MPT_WIN_XP MPT_WIN_MAKE_VERSION(0x05, 0x01, 0x00, 0x00) #define MPT_WIN_XPSP1 MPT_WIN_MAKE_VERSION(0x05, 0x01, 0x01, 0x00) #define MPT_WIN_XPSP2 MPT_WIN_MAKE_VERSION(0x05, 0x01, 0x02, 0x00) #define MPT_WIN_XPSP3 MPT_WIN_MAKE_VERSION(0x05, 0x01, 0x03, 0x00) #define MPT_WIN_XPSP4 MPT_WIN_MAKE_VERSION(0x05, 0x01, 0x04, 0x00) // unused #define MPT_WIN_XP64 MPT_WIN_MAKE_VERSION(0x05, 0x02, 0x00, 0x00) // unused #define MPT_WIN_XP64SP1 MPT_WIN_MAKE_VERSION(0x05, 0x02, 0x01, 0x00) #define MPT_WIN_XP64SP2 MPT_WIN_MAKE_VERSION(0x05, 0x02, 0x02, 0x00) #define MPT_WIN_XP64SP3 MPT_WIN_MAKE_VERSION(0x05, 0x02, 0x03, 0x00) // unused #define MPT_WIN_XP64SP4 MPT_WIN_MAKE_VERSION(0x05, 0x02, 0x04, 0x00) // unused #define MPT_WIN_VISTA MPT_WIN_MAKE_VERSION(0x06, 0x00, 0x00, 0x00) #define MPT_WIN_VISTASP1 MPT_WIN_MAKE_VERSION(0x06, 0x00, 0x01, 0x00) #define MPT_WIN_VISTASP2 MPT_WIN_MAKE_VERSION(0x06, 0x00, 0x02, 0x00) #define MPT_WIN_VISTASP3 MPT_WIN_MAKE_VERSION(0x06, 0x00, 0x03, 0x00) // unused #define MPT_WIN_VISTASP4 MPT_WIN_MAKE_VERSION(0x06, 0x00, 0x04, 0x00) // unused #define MPT_WIN_7 MPT_WIN_MAKE_VERSION(0x06, 0x01, 0x00, 0x00) #define MPT_WIN_8 MPT_WIN_MAKE_VERSION(0x06, 0x02, 0x00, 0x00) #define MPT_WIN_81 MPT_WIN_MAKE_VERSION(0x06, 0x03, 0x00, 0x00) #define MPT_WIN_10_PRE MPT_WIN_MAKE_VERSION(0x06, 0x04, 0x00, 0x00) #define MPT_WIN_10 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x00) // NTDDI_WIN10 1507 #define MPT_WIN_10_1511 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x01) // NTDDI_WIN10_TH2 1511 #define MPT_WIN_10_1607 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x02) // NTDDI_WIN10_RS1 1607 #define MPT_WIN_10_1703 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x03) // NTDDI_WIN10_RS2 1703 #define MPT_WIN_10_1709 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x04) // NTDDI_WIN10_RS3 1709 #define MPT_WIN_10_1803 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x05) // NTDDI_WIN10_RS4 1803 #define MPT_WIN_10_1809 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x06) // NTDDI_WIN10_RS5 1809 #define MPT_WIN_10_1903 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x07) // NTDDI_WIN10_19H1 1903/19H1 #define MPT_WIN_10_1909 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x08) // NTDDI_WIN10_VB 1909/19H2 #define MPT_WIN_10_2004 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x09) // NTDDI_WIN10_MN 2004/20H1 #define MPT_WIN_10_20H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0a) // NTDDI_WIN10_FE 20H2 #define MPT_WIN_10_21H1 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0b) // NTDDI_WIN10_CO 21H1 #define MPT_WIN_10_21H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0c) // NTDDI_WIN10_NI 21H2 #define MPT_WIN_10_22H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0d) // NTDDI_WIN10_CU 22H2 #define MPT_WIN_11 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0e) // NTDDI_WIN11_ZN 21H2 #define MPT_WIN_11_22H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0f) // NTDDI_WIN11_GA 22H2 #define MPT_WIN_11_23H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x10) // NTDDI_WIN11_GE 23H2 // MPT_WIN_API_DESKTOP : Windows 8/10 Desktop Application (Win32) // MPT_WIN_API_UNIVERSAL : Windows 10 Store App / Universal App // MPT_WIN_API_STORE_PC : Windows 8 Store Desktop App // MPT_WIN_API_STORE_PHONE : Windows 8 Store Phone App // clang-format on // The order of the checks matters! #if defined(__DJGPP__) #define MPT_OS_DJGPP 1 #elif defined(__EMSCRIPTEN__) #define MPT_OS_EMSCRIPTEN 1 #if !defined(__EMSCRIPTEN_major__) || !defined(__EMSCRIPTEN_minor__) || !defined(__EMSCRIPTEN_tiny__) #include #endif #if defined(__EMSCRIPTEN_major__) && defined(__EMSCRIPTEN_minor__) #if (__EMSCRIPTEN_major__ > 3) // ok #elif (__EMSCRIPTEN_major__ == 3) && (__EMSCRIPTEN_minor__ > 1) // ok #elif (__EMSCRIPTEN_major__ == 3) && (__EMSCRIPTEN_minor__ == 1) && (__EMSCRIPTEN_tiny__ >= 51) // ok #else #error "Emscripten >= 3.1.51 is required." #endif #endif #elif defined(__CYGWIN__) #define MPT_OS_CYGWIN 1 #elif defined(_WIN32) #define MPT_OS_WINDOWS 1 #if !defined(_WIN32_WINDOWS) && !defined(WINVER) // include modern SDK version header if not targeting Win9x #include #ifdef _WIN32_WINNT_NT4 static_assert((_WIN32_WINNT_NT4 << 16) == MPT_WIN_NT4); #endif #ifdef _WIN32_WINNT_WIN2K static_assert((_WIN32_WINNT_WIN2K << 16) == MPT_WIN_2000); #endif #ifdef _WIN32_WINNT_WINXP static_assert((_WIN32_WINNT_WINXP << 16) == MPT_WIN_XP); #endif #ifdef _WIN32_WINNT_WS03 static_assert((_WIN32_WINNT_WS03 << 16) == MPT_WIN_XP64); #endif #ifdef _WIN32_WINNT_VISTA static_assert((_WIN32_WINNT_VISTA << 16) == MPT_WIN_VISTA); #endif #ifdef _WIN32_WINNT_WIN7 static_assert((_WIN32_WINNT_WIN7 << 16) == MPT_WIN_7); #endif #ifdef _WIN32_WINNT_WIN8 static_assert((_WIN32_WINNT_WIN8 << 16) == MPT_WIN_8); #endif #ifdef _WIN32_WINNT_WINBLUE static_assert((_WIN32_WINNT_WINBLUE << 16) == MPT_WIN_81); #endif #ifdef _WIN32_WINNT_WIN10 static_assert((_WIN32_WINNT_WIN10 << 16) == MPT_WIN_10); #endif #ifdef NTDDI_WIN4 static_assert(NTDDI_WIN4 == MPT_WIN_NT4); #endif #ifdef NTDDI_WIN2K static_assert(NTDDI_WIN2K == MPT_WIN_2000); #endif #ifdef NTDDI_WIN2KSP1 static_assert(NTDDI_WIN2KSP1 == MPT_WIN_2000SP1); #endif #ifdef NTDDI_WIN2KSP2 static_assert(NTDDI_WIN2KSP2 == MPT_WIN_2000SP2); #endif #ifdef NTDDI_WIN2KSP3 static_assert(NTDDI_WIN2KSP3 == MPT_WIN_2000SP3); #endif #ifdef NTDDI_WIN2KSP4 static_assert(NTDDI_WIN2KSP4 == MPT_WIN_2000SP4); #endif #ifdef NTDDI_WINXP static_assert(NTDDI_WINXP == MPT_WIN_XP); #endif #ifdef NTDDI_WINXPSP1 static_assert(NTDDI_WINXPSP1 == MPT_WIN_XPSP1); #endif #ifdef NTDDI_WINXPSP2 static_assert(NTDDI_WINXPSP2 == MPT_WIN_XPSP2); #endif #ifdef NTDDI_WINXPSP3 static_assert(NTDDI_WINXPSP3 == MPT_WIN_XPSP3); #endif #ifdef NTDDI_WINXPSP4 static_assert(NTDDI_WINXPSP4 == MPT_WIN_XPSP4); #endif #ifdef NTDDI_WS03 static_assert(NTDDI_WS03 == MPT_WIN_XP64); #endif #ifdef NTDDI_WS03SP1 static_assert(NTDDI_WS03SP1 == MPT_WIN_XP64SP1); #endif #ifdef NTDDI_WS03SP2 static_assert(NTDDI_WS03SP2 == MPT_WIN_XP64SP2); #endif #ifdef NTDDI_WS03SP3 static_assert(NTDDI_WS03SP3 == MPT_WIN_XP64SP3); #endif #ifdef NTDDI_WS03SP4 static_assert(NTDDI_WS03SP4 == MPT_WIN_XP64SP4); #endif #ifdef NTDDI_VISTA static_assert(NTDDI_VISTA == MPT_WIN_VISTA); #endif #ifdef NTDDI_VISTASP1 static_assert(NTDDI_VISTASP1 == MPT_WIN_VISTASP1); #endif #ifdef NTDDI_VISTASP2 static_assert(NTDDI_VISTASP2 == MPT_WIN_VISTASP2); #endif #ifdef NTDDI_VISTASP3 static_assert(NTDDI_VISTASP3 == MPT_WIN_VISTASP3); #endif #ifdef NTDDI_VISTASP4 static_assert(NTDDI_VISTASP4 == MPT_WIN_VISTASP4); #endif #ifdef NTDDI_WIN7 static_assert(NTDDI_WIN7 == MPT_WIN_7); #endif #ifdef NTDDI_WIN8 static_assert(NTDDI_WIN8 == MPT_WIN_8); #endif #ifdef NTDDI_WINBLUE static_assert(NTDDI_WINBLUE == MPT_WIN_81); #endif #ifdef NTDDI_WIN10 static_assert(NTDDI_WIN10 == MPT_WIN_10); #endif #ifdef NTDDI_WIN10_TH2 static_assert(NTDDI_WIN10_TH2 == MPT_WIN_10_1511); #endif #ifdef NTDDI_WIN10_RS1 static_assert(NTDDI_WIN10_RS1 == MPT_WIN_10_1607); #endif #ifdef NTDDI_WIN10_RS2 static_assert(NTDDI_WIN10_RS2 == MPT_WIN_10_1703); #endif #ifdef NTDDI_WIN10_RS3 static_assert(NTDDI_WIN10_RS3 == MPT_WIN_10_1709); #endif #ifdef NTDDI_WIN10_RS4 static_assert(NTDDI_WIN10_RS4 == MPT_WIN_10_1803); #endif #ifdef NTDDI_WIN10_RS5 static_assert(NTDDI_WIN10_RS5 == MPT_WIN_10_1809); #endif #ifdef NTDDI_WIN10_19H1 static_assert(NTDDI_WIN10_19H1 == MPT_WIN_10_1903); #endif #ifdef NTDDI_WIN10_VB static_assert(NTDDI_WIN10_VB == MPT_WIN_10_1909); #endif #ifdef NTDDI_WIN10_MN static_assert(NTDDI_WIN10_MN == MPT_WIN_10_2004); #endif #ifdef NTDDI_WIN10_FE static_assert(NTDDI_WIN10_FE == MPT_WIN_10_20H2); #endif #ifdef NTDDI_WIN10_CO static_assert(NTDDI_WIN10_CO == MPT_WIN_10_21H1); #endif #ifdef NTDDI_WIN10_NI static_assert(NTDDI_WIN10_NI == MPT_WIN_10_21H2); #endif #ifdef NTDDI_WIN10_CU static_assert(NTDDI_WIN10_CU == MPT_WIN_10_22H2); #endif #ifdef NTDDI_WIN11_ZN static_assert(NTDDI_WIN11_ZN == MPT_WIN_11); #endif #ifdef NTDDI_WIN11_GA static_assert(NTDDI_WIN11_GA == MPT_WIN_11_22H2); #endif #ifdef NTDDI_WIN11_GE static_assert(NTDDI_WIN11_GE == MPT_WIN_11_23H2); #endif #endif #if defined(WINAPI_FAMILY) #include #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define MPT_OS_WINDOWS_WINRT 0 #else #define MPT_OS_WINDOWS_WINRT 1 #endif #define MPT_WIN_API_DESKTOP WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define MPT_WIN_API_UNIVERSAL WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PC_APP) #define MPT_WIN_API_STORE_PC WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) #define MPT_WIN_API_STORE_PHONE WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) #else // !WINAPI_FAMILY #define MPT_OS_WINDOWS_WINRT 0 #define MPT_WIN_API_DESKTOP 1 #define MPT_WIN_API_UNIVERSAL 0 #define MPT_WIN_API_STORE_PC 0 #define MPT_WIN_API_STORE_PHONE 0 #endif // WINAPI_FAMILY #if defined(NTDDI_VERSION) || defined(_WIN32_WINNT) #define MPT_OS_WINDOWS_WINNT 1 #define MPT_OS_WINDOWS_WIN9X 0 #define MPT_OS_WINDOWS_WIN32 0 #if defined(NTDDI_VERSION) #define MPT_WIN_VERSION NTDDI_VERSION #else #define MPT_WIN_VERSION (_WIN32_WINNT << 16) #endif #elif defined(_WIN32_WINDOWS) #define MPT_OS_WINDOWS_WINNT 0 #define MPT_OS_WINDOWS_WIN9X 1 #define MPT_OS_WINDOWS_WIN32 0 #define MPT_WIN_VERSION (_WIN32_WINDOWS << 16) #elif defined(WINVER) #define MPT_OS_WINDOWS_WINNT 0 #define MPT_OS_WINDOWS_WIN9X 0 #define MPT_OS_WINDOWS_WIN32 1 #define MPT_WIN_VERSION (WINVER << 16) #else // assume modern #define MPT_OS_WINDOWS_WINNT 1 #define MPT_OS_WINDOWS_WIN9X 0 #define MPT_OS_WINDOWS_WIN32 0 #define MPT_WIN_VERSION MPT_WIN_NT4 #endif #define MPT_WINRT_AT_LEAST(v) (MPT_OS_WINDOWS_WINRT && MPT_OS_WINDOWS_WINNT && (MPT_WIN_VERSION >= (v))) #define MPT_WINRT_BEFORE(v) (MPT_OS_WINDOWS_WINRT && MPT_OS_WINDOWS_WINNT && (MPT_WIN_VERSION < (v))) #define MPT_WINNT_AT_LEAST(v) (MPT_OS_WINDOWS_WINNT && (MPT_WIN_VERSION >= (v))) #define MPT_WINNT_BEFORE(v) (MPT_OS_WINDOWS_WINNT && (MPT_WIN_VERSION < (v))) #define MPT_WIN9X_AT_LEAST(v) ((MPT_OS_WINDOWS_WINNT || MPT_OS_WINDOWS_WIN9X) && (MPT_WIN_VERSION >= (v))) #define MPT_WIN9X_BEFORE(v) ((MPT_OS_WINDOWS_WINNT || MPT_OS_WINDOWS_WIN9X) && (MPT_WIN_VERSION < (v))) #define MPT_WIN32_AT_LEAST(v) ((MPT_OS_WINDOWS_WINNT || MPT_OS_WINDOWS_WIN9X || MPT_OS_WINDOWS_WIN32) && (MPT_WIN_VERSION >= (v))) #define MPT_WIN32_BEFORE(v) ((MPT_OS_WINDOWS_WINNT || MPT_OS_WINDOWS_WIN9X || MPT_OS_WINDOWS_WIN32) && (MPT_WIN_VERSION < (v))) #if MPT_OS_WINDOWS_WINRT #define MPT_WIN_AT_LEAST(v) MPT_WINRT_AT_LEAST(v) #define MPT_WIN_BEFORE(v) MPT_WINRT_BEFORE(v) #elif MPT_OS_WINDOWS_WINNT #define MPT_WIN_AT_LEAST(v) MPT_WINNT_AT_LEAST(v) #define MPT_WIN_BEFORE(v) MPT_WINNT_BEFORE(v) #elif MPT_OS_WINDOWS_WIN9X #define MPT_WIN_AT_LEAST(v) MPT_WIN9X_AT_LEAST(v) #define MPT_WIN_BEFORE(v) MPT_WIN9X_BEFORE(v) #elif MPT_OS_WINDOWS_WIN32 #define MPT_WIN_AT_LEAST(v) MPT_WIN32_AT_LEAST(v) #define MPT_WIN_BEFORE(v) MPT_WIN32_BEFORE(v) #else #define MPT_WIN_AT_LEAST(v) 0 #define MPT_WIN_BEFORE(v) 1 #endif #elif defined(__APPLE__) #define MPT_OS_MACOSX_OR_IOS 1 #include #if defined(TARGET_OS_OSX) #if (TARGET_OS_OSX != 0) #include #endif #endif //#if TARGET_IPHONE_SIMULATOR //#elif TARGET_OS_IPHONE //#elif TARGET_OS_MAC //#else //#endif #elif defined(__HAIKU__) #define MPT_OS_HAIKU 1 #elif defined(__ANDROID__) || defined(ANDROID) #define MPT_OS_ANDROID 1 #elif defined(__linux__) #define MPT_OS_LINUX 1 #elif defined(__DragonFly__) #define MPT_OS_DRAGONFLYBSD 1 #elif defined(__FreeBSD__) #define MPT_OS_FREEBSD 1 #elif defined(__OpenBSD__) #define MPT_OS_OPENBSD 1 #elif defined(__NetBSD__) #define MPT_OS_NETBSD 1 #elif defined(__unix__) #define MPT_OS_GENERIC_UNIX 1 #else #define MPT_OS_UNKNOWN 1 #endif #ifndef MPT_OS_DJGPP #define MPT_OS_DJGPP 0 #endif #ifndef MPT_OS_EMSCRIPTEN #define MPT_OS_EMSCRIPTEN 0 #endif #ifndef MPT_OS_CYGWIN #define MPT_OS_CYGWIN 0 #endif #ifndef MPT_OS_WINDOWS #define MPT_OS_WINDOWS 0 #endif #ifndef MPT_OS_WINDOWS_WINRT #define MPT_OS_WINDOWS_WINRT 0 #endif #ifndef MPT_OS_WINDOWS_WINNT #define MPT_OS_WINDOWS_WINNT 0 #endif #ifndef MPT_OS_WINDOWS_WIN9X #define MPT_OS_WINDOWS_WIN9X 0 #endif #ifndef MPT_OS_WINDOWS_WIN32 #define MPT_OS_WINDOWS_WIN32 0 #endif #ifndef MPT_WINRT_AT_LEAST #define MPT_WINRT_AT_LEAST(v) 0 #endif #ifndef MPT_WINRT_BEFORE #define MPT_WINRT_BEFORE(v) 0 #endif #ifndef MPT_WINNT_AT_LEAST #define MPT_WINNT_AT_LEAST(v) 0 #endif #ifndef MPT_WINNT_BEFORE #define MPT_WINNT_BEFORE(v) 0 #endif #ifndef MPT_WIN9X_AT_LEAST #define MPT_WIN9X_AT_LEAST(v) 0 #endif #ifndef MPT_WIN9X_BEFORE #define MPT_WIN9X_BEFORE(v) 0 #endif #ifndef MPT_WIN32_AT_LEAST #define MPT_WIN32_AT_LEAST(v) 0 #endif #ifndef MPT_WIN32_BEFORE #define MPT_WIN32_BEFORE(v) 0 #endif #ifndef MPT_WIN_AT_LEAST #define MPT_WIN_AT_LEAST(v) 0 #endif #ifndef MPT_WIN_BEFORE #define MPT_WIN_BEFORE(v) 0 #endif #ifndef MPT_WIN_API_DESKTOP #define MPT_WIN_API_DESKTOP 0 #endif #ifndef MPT_WIN_API_UNIVERSAL #define MPT_WIN_API_UNIVERSAL 0 #endif #ifndef MPT_WIN_API_STORE_PC #define MPT_WIN_API_STORE_PC 0 #endif #ifndef MPT_WIN_API_STORE_PHONE #define MPT_WIN_API_STORE_PHONE 0 #endif #ifndef MPT_OS_MACOSX_OR_IOS #define MPT_OS_MACOSX_OR_IOS 0 #endif #ifndef MPT_OS_HAIKU #define MPT_OS_HAIKU 0 #endif #ifndef MPT_OS_ANDROID #define MPT_OS_ANDROID 0 #endif #ifndef MPT_OS_LINUX #define MPT_OS_LINUX 0 #endif #ifndef MPT_OS_DRAGONFLYBSD #define MPT_OS_DRAGONFLYBSD 0 #endif #ifndef MPT_OS_FREEBSD #define MPT_OS_FREEBSD 0 #endif #ifndef MPT_OS_OPENBSD #define MPT_OS_OPENBSD 0 #endif #ifndef MPT_OS_NETBSD #define MPT_OS_NETBSD 0 #endif #ifndef MPT_OS_GENERIC_UNIX #define MPT_OS_GENERIC_UNIX 0 #endif #ifndef MPT_OS_UNKNOWN #define MPT_OS_UNKNOWN 0 #endif #define MPT_MODE_KERNEL 0 #endif // MPT_BASE_DETECT_OS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/constexpr_throw.hpp0000644000175000017500000000245314250644555022556 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_CONSTEXPR_THROW_HPP #define MPT_BASE_CONSTEXPR_THROW_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { // Work-around for the requirement of at least 1 non-throwing function argument combination in C++ (17,2a). template constexpr bool constexpr_throw_helper(Exception && e, bool really = true) { //return !really ? really : throw std::forward(e); if (really) { throw std::forward(e); } // cppcheck-suppress identicalConditionAfterEarlyExit return really; } template constexpr bool constexpr_throw(Exception && e) { return mpt::constexpr_throw_helper(std::forward(e)); } template constexpr T constexpr_throw_helper(Exception && e, bool really = true) { //return !really ? really : throw std::forward(e); if (really) { throw std::forward(e); } return T{}; } template constexpr T constexpr_throw(Exception && e) { return mpt::constexpr_throw_helper(std::forward(e)); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_CONSTEXPR_THROW_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/size.hpp0000644000175000017500000000257514463723277020272 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_SIZE_HPP #define MPT_BASE_SIZE_HPP #include "mpt/base/detect.hpp" #if MPT_CXX_AT_LEAST(20) #include "mpt/base/constexpr_throw.hpp" #endif // C++20 #include "mpt/base/namespace.hpp" #if MPT_CXX_AT_LEAST(20) #include "mpt/base/utility.hpp" #endif // C++20 #if MPT_CXX_AT_LEAST(20) #include #endif // C++20 #include namespace mpt { inline namespace MPT_INLINE_NS { using usize = std::size_t; using ssize = std::ptrdiff_t; namespace size_literals { #if MPT_CXX_AT_LEAST(20) consteval usize operator""_uz(unsigned long long val) noexcept { if (!mpt::in_range(val)) { mpt::constexpr_throw(std::domain_error("")); } return static_cast(val); } #else // !C++20 constexpr usize operator""_uz(unsigned long long val) noexcept { return static_cast(val); } #endif // C++20 } // namespace size_literals namespace size_literals { #if MPT_CXX_AT_LEAST(20) consteval ssize operator""_z(unsigned long long val) noexcept { if (!mpt::in_range(val)) { mpt::constexpr_throw(std::domain_error("")); } return static_cast(val); } #else // !C++20 constexpr ssize operator""_z(unsigned long long val) noexcept { return static_cast(val); } #endif // C++20 } // namespace size_literals } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_SIZE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/utility.hpp0000644000175000017500000001506714764347444021025 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_UTILITY_HPP #define MPT_BASE_UTILITY_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #if MPT_CXX_BEFORE(20) || MPT_LIBCXX_LLVM_BEFORE(13000) #include "mpt/base/saturate_cast.hpp" #include "mpt/base/saturate_round.hpp" #endif #if MPT_CXX_BEFORE(23) && !MPT_COMPILER_MSVC && !MPT_COMPILER_GCC && !MPT_COMPILER_CLANG #include #endif #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { template MPT_CONSTEXPRINLINE Tdst c_cast(Tsrc && x) { return (Tdst)std::forward(x); } template MPT_CONSTEXPRINLINE Tdst function_pointer_cast(Tsrc f) { #if !defined(MPT_LIBCXX_QUIRK_INCOMPLETE_IS_FUNCTION) // MinGW64 std::is_function is always false for non __cdecl functions. // Issue is similar to . static_assert(std::is_pointer::type>::value); static_assert(std::is_pointer::type>::value); static_assert(std::is_function::type>::type>::value); static_assert(std::is_function::type>::type>::value); #endif #if (MPT_CLANG_AT_LEAST(19, 0, 0) && !MPT_OS_ANDROID) || MPT_CLANG_AT_LEAST(20, 0, 0) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wcast-function-type-mismatch" #endif return reinterpret_cast(f); #if (MPT_CLANG_AT_LEAST(19, 0, 0) && !MPT_OS_ANDROID) || MPT_CLANG_AT_LEAST(20, 0, 0) #pragma clang diagnostic pop #endif } #if MPT_CXX_AT_LEAST(20) && !MPT_LIBCXX_LLVM_BEFORE(13000) using std::in_range; #else namespace detail { template constexpr Tdst saturate_cast(Tsrc src) noexcept { return mpt::saturate_cast(src); } template constexpr Tdst saturate_cast(double src) { return mpt::saturate_trunc(src); } template constexpr Tdst saturate_cast(float src) { return mpt::saturate_trunc(src); } } // namespace detail // Returns true iff Tdst can represent the value val. // Use as if(mpt::in_range(-1)). template constexpr bool in_range(Tsrc val) { return (static_cast(mpt::detail::saturate_cast(val)) == val); } #endif #if MPT_CXX_AT_LEAST(23) using std::to_underlying; #else // !C++23 template constexpr std::underlying_type_t to_underlying(T value) noexcept { return static_cast::type>(value); } #endif // C++23 template struct value_initializer { inline void operator()(T & x) { x = T{}; } }; template struct value_initializer { inline void operator()(T (&a)[N]) { for (auto & e : a) { value_initializer{}(e); } } }; template inline void reset(T & x) { value_initializer{}(x); } template void reset(T & x, Targs &&... args) { x = T{std::forward(args)...}; } template void reconstruct(T & x, Targs &&... args) { x.~T(); new (&x) T{std::forward(args)...}; } #if MPT_CXX_AT_LEAST(20) && !MPT_LIBCXX_LLVM_BEFORE(13000) using std::cmp_equal; using std::cmp_greater; using std::cmp_greater_equal; using std::cmp_less; using std::cmp_less_equal; using std::cmp_not_equal; #else template constexpr bool cmp_equal(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a == b; } else if constexpr (std::is_signed::value) { return (a < 0) ? false : static_cast(a) == b; } else { return (b < 0) ? false : a == static_cast(b); } } template constexpr bool cmp_not_equal(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a != b; } else if constexpr (std::is_signed::value) { return (a < 0) ? true : static_cast(a) != b; } else { return (b < 0) ? true : a != static_cast(b); } } template constexpr bool cmp_less(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a < b; } else if constexpr (std::is_signed::value) { return (a < 0) ? true : static_cast(a) < b; } else { return (b < 0) ? false : a < static_cast(b); } } template constexpr bool cmp_greater(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a > b; } else if constexpr (std::is_signed::value) { return (a < 0) ? false : static_cast(a) > b; } else { return (b < 0) ? true : a > static_cast(b); } } template constexpr bool cmp_less_equal(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a <= b; } else if constexpr (std::is_signed::value) { return (a < 0) ? true : static_cast(a) <= b; } else { return (b < 0) ? false : a <= static_cast(b); } } template constexpr bool cmp_greater_equal(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a >= b; } else if constexpr (std::is_signed::value) { return (a < 0) ? false : static_cast(a) >= b; } else { return (b < 0) ? true : a >= static_cast(b); } } #endif #if MPT_CXX_AT_LEAST(23) && !MPT_LIBCXX_GNU_BEFORE(12) using std::unreachable; #else // !C++23 [[noreturn]] inline void unreachable() { #if MPT_COMPILER_MSVC __assume(false); #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG __builtin_unreachable(); #else std::terminate(); #endif } #endif // C++23 } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_UTILITY_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/array.hpp0000644000175000017500000000412314731261753020417 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_ARRAY_HPP #define MPT_BASE_ARRAY_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { template struct stdarray_extent : std::integral_constant { }; template struct stdarray_extent> : std::integral_constant { }; template struct is_stdarray : std::false_type { }; template struct is_stdarray> : std::true_type { }; // mpt::extent is the same as std::extent, // but also works for std::array, // and asserts that the given type is actually an array type instead of returning 0. // use as: // mpt::extent() // mpt::extent() // mpt::extent() // mpt::extent() template constexpr std::size_t extent() noexcept { using Tarray = typename std::remove_cv::type>::type; static_assert(std::is_array::value || mpt::is_stdarray::value); if constexpr (mpt::is_stdarray::value) { return mpt::stdarray_extent(); } else { return std::extent(); } } template struct array_size; template struct array_size> { static constexpr std::size_t size = N; }; template struct array_size { static constexpr std::size_t size = N; }; template constexpr std::array init_array(const Tx & x) { std::array result{}; for (std::size_t i = 0; i < N; ++i) { result[i] = x; } return result; } template constexpr std::array generate_array(Fgen generator) { std::array result{}; for (std::size_t i = 0; i < N; ++i) { result[i] = generator(i); } return result; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_ARRAY_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/preprocessor.hpp0000644000175000017500000000063314044173026022021 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_PREPROCESSOR_HPP #define MPT_BASE_PREPROCESSOR_HPP #define MPT_PP_DEFER(m, ...) m(__VA_ARGS__) #define MPT_PP_STRINGIFY(x) #x #define MPT_PP_JOIN_HELPER(a, b) a##b #define MPT_PP_JOIN(a, b) MPT_PP_JOIN_HELPER(a, b) #define MPT_PP_UNIQUE_IDENTIFIER(prefix) MPT_PP_JOIN(prefix, __LINE__) #endif // MPT_BASE_PREPROCESSOR_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/detect_quirks.hpp0000644000175000017500000002422215017330707022143 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_DETECT_QUIRKS_HPP #define MPT_BASE_DETECT_QUIRKS_HPP #include "mpt/base/detect_arch.hpp" #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_libc.hpp" #include "mpt/base/detect_libcxx.hpp" #include "mpt/base/detect_os.hpp" #if MPT_CXX_AT_LEAST(20) #include #else // !C++20 #include #endif // C++20 #if MPT_LIBCXX_MS // for _ITERATOR_DEBUG_LEVEL #include #endif // MPT_LIBCXX_MS #if MPT_OS_DJGPP #define MPT_ARCH_QUIRK_NO_SIMD256 #endif #if MPT_COMPILER_MSVC #if !defined(_MSVC_TRADITIONAL) #define MPT_COMPILER_QUIRK_MSVC_OLD_PREPROCESSOR #else #if _MSVC_TRADITIONAL #define MPT_COMPILER_QUIRK_MSVC_OLD_PREPROCESSOR #endif #endif #endif #if MPT_GCC_BEFORE(9, 1, 0) #define MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW #endif #if MPT_COMPILER_MSVC && MPT_MSVC_AT_LEAST(2022, 6) && MPT_MSVC_BEFORE(2022, 8) && MPT_ARCH_AARCH64 // VS2022 17.6.0 ARM64 gets confused about alignment in std::bit_cast (or equivalent code), // causing an ICE. // See . #define MPT_COMPILER_QUIRK_BROKEN_BITCAST #endif #if MPT_CXX_BEFORE(20) && MPT_COMPILER_MSVC // Compiler has multiplication/division semantics when shifting signed integers. // In C++20, this behaviour is required by the standard. #define MPT_COMPILER_SHIFT_SIGNED 1 #endif #ifndef MPT_COMPILER_SHIFT_SIGNED #define MPT_COMPILER_SHIFT_SIGNED 0 #endif // This should really be based on __STDCPP_THREADS__, // but that is not defined consistently by GCC or clang. Stupid. // Just assume multithreaded and disable for platforms we know are // singlethreaded later on. #define MPT_PLATFORM_MULTITHREADED 1 #if MPT_OS_DJGPP #undef MPT_PLATFORM_MULTITHREADED #define MPT_PLATFORM_MULTITHREADED 0 #endif #if (MPT_OS_EMSCRIPTEN && !defined(__EMSCRIPTEN_PTHREADS__)) #undef MPT_PLATFORM_MULTITHREADED #define MPT_PLATFORM_MULTITHREADED 0 #endif #if MPT_MSVC_BEFORE(2019, 0) || MPT_GCC_BEFORE(8, 1, 0) #define MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT #endif #if MPT_GCC_BEFORE(11, 1, 0) #define MPT_COMPILER_QUIRK_NO_STDCPP_THREADS #elif MPT_CLANG_BEFORE(12, 0, 0) #define MPT_COMPILER_QUIRK_NO_STDCPP_THREADS #elif (defined(__MINGW32__) || defined(__MINGW64__)) && MPT_LIBCXX_GNU && defined(_GLIBCXX_HAS_GTHREADS) && !defined(__STDCPP_THREADS__) #define MPT_COMPILER_QUIRK_NO_STDCPP_THREADS #endif #if MPT_OS_WINDOWS && MPT_COMPILER_MSVC #if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) #define MPT_COMPILER_QUIRK_COMPLEX_STD_MUTEX #endif #endif #if MPT_OS_EMSCRIPTEN && defined(MPT_BUILD_AUDIOWORKLETPROCESSOR) #define MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK #endif #if MPT_OS_EMSCRIPTEN && defined(MPT_BUILD_AUDIOWORKLETPROCESSOR) #define MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE #endif #if MPT_LIBCXX_GNU #if !defined(_GLIBCXX_USE_WCHAR_T) #ifndef MPT_COMPILER_QUIRK_NO_WCHAR #define MPT_COMPILER_QUIRK_NO_WCHAR #endif #endif #endif #if defined(__MINGW32__) && !defined(__MINGW64__) && (MPT_OS_WINDOWS_WIN9X || MPT_OS_WINDOWS_WIN32) #ifndef MPT_COMPILER_QUIRK_NO_WCHAR #define MPT_COMPILER_QUIRK_NO_WCHAR #endif #endif #if MPT_LIBCXX_LLVM_BEFORE(14000) #define MPT_COMPILER_QUIRK_NO_STRING_VIEW_ITERATOR_CTOR #endif #if MPT_LIBCXX_GNU_BEFORE(9) #define MPT_COMPILER_QUIRK_NO_FILESYSTEM #endif #if MPT_OS_WINDOWS && MPT_GCC_BEFORE(9, 1, 0) // GCC C++ library has no wchar_t overloads #define MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR #endif #if MPT_COMPILER_GCC || MPT_COMPILER_CLANG #if defined(__FAST_MATH__) #define MPT_COMPILER_QUIRK_FASTMATH 1 #endif #if defined(__FINITE_MATH_ONLY__) #if (__FINITE_MATH_ONLY__ >= 1) #define MPT_COMPILER_QUIRK_FINITEMATH 1 #endif #endif #elif MPT_COMPILER_MSVC #if defined(_M_FP_FAST) #define MPT_COMPILER_QUIRK_FASTMATH 1 #define MPT_COMPILER_QUIRK_FINITEMATH 1 #endif #endif #ifndef MPT_COMPILER_QUIRK_FASTMATH #define MPT_COMPILER_QUIRK_FASTMATH 0 #endif #ifndef MPT_COMPILER_QUIRK_FINITEMATH #define MPT_COMPILER_QUIRK_FINITEMATH 0 #endif #if MPT_COMPILER_GCC && !defined(__arm__) #if defined(_SOFT_FLOAT) #define MPT_COMPILER_QUIRK_FLOAT_EMULATED 1 #endif #endif #if defined(__arm__) #if defined(__SOFTFP__) #define MPT_COMPILER_QUIRK_FLOAT_EMULATED 1 #else #define MPT_COMPILER_QUIRK_FLOAT_EMULATED 0 #endif #if defined(__VFP_FP__) // native-endian IEEE754 #define MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN 0 #define MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754 0 #elif defined(__MAVERICK__) // little-endian IEEE754, we assume native-endian though #define MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN 1 #define MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754 0 #else // not IEEE754 #define MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN 1 #define MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754 1 #endif #elif defined(__mips__) #if defined(__mips_soft_float) #define MPT_COMPILER_QUIRK_FLOAT_EMULATED 1 #else #define MPT_COMPILER_QUIRK_FLOAT_EMULATED 0 #endif #endif #if MPT_OS_EMSCRIPTEN #define MPT_COMPILER_QUIRK_FLOAT_PREFER64 1 #endif #ifndef MPT_COMPILER_QUIRK_FLOAT_PREFER32 #define MPT_COMPILER_QUIRK_FLOAT_PREFER32 0 #endif #ifndef MPT_COMPILER_QUIRK_FLOAT_PREFER64 #define MPT_COMPILER_QUIRK_FLOAT_PREFER64 0 #endif #ifndef MPT_COMPILER_QUIRK_FLOAT_EMULATED #define MPT_COMPILER_QUIRK_FLOAT_EMULATED 0 #endif #ifndef MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN #define MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN 0 #endif #ifndef MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754 #define MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754 0 #endif #if MPT_LIBC_MINGW // MinGW32 runtime headers require __off64_t when including some C and/or C++ stdlib headers. // This is declared in , which howeger is not included in some header chains. #if (defined(__MINGW32__) && !defined(__MINGW64__)) #define MPT_LIBC_QUIRK_REQUIRES_SYS_TYPES_H #endif #endif #if MPT_LIBC_DJGPP #define MPT_LIBC_QUIRK_NO_FENV #endif #if MPT_OS_CYGWIN #define MPT_LIBCXX_QUIRK_BROKEN_USER_LOCALE // #define MPT_LIBCXX_QUIRK_ASSUME_USER_LOCALE_UTF8 #elif MPT_OS_HAIKU #define MPT_LIBCXX_QUIRK_BROKEN_USER_LOCALE #define MPT_LIBCXX_QUIRK_ASSUME_USER_LOCALE_UTF8 #endif // #define MPT_LIBCXX_QUIRK_BROKEN_ACTIVE_LOCALE #if MPT_OS_WINDOWS && MPT_LIBCXX_GNU #define MPT_LIBCXX_QUIRK_INCOMPLETE_IS_FUNCTION #endif #if MPT_CXX_AT_LEAST(20) #if MPT_LIBCXX_GNU_BEFORE(10) || MPT_LIBCXX_LLVM_BEFORE(13000) || (MPT_LIBCXX_MS && MPT_MSVC_BEFORE(2022, 0)) || (MPT_LIBCXX_MS && !MPT_COMPILER_MSVC) #define MPT_LIBCXX_QUIRK_NO_CXX20_CONSTEXPR_ALGORITHM #endif #endif #if MPT_CXX_AT_LEAST(20) #if MPT_LIBCXX_GNU_BEFORE(12) || MPT_LIBCXX_LLVM_BEFORE(15000) || (MPT_LIBCXX_MS && MPT_MSVC_BEFORE(2022, 0)) || (MPT_LIBCXX_MS && !MPT_COMPILER_MSVC) #ifndef MPT_LIBCXX_QUIRK_NO_CXX20_CONSTEXPR_CONTAINER #define MPT_LIBCXX_QUIRK_NO_CXX20_CONSTEXPR_CONTAINER #endif #endif #if MPT_LIBCXX_MS // So, in 2025, Microsoft still ships a STL that by default is not standard-compliant with its own default Debug options. // constexpr auto foo = std::vector{}; does not compile with iterator debugging enabled (i.e. in Debug builds). // See . #if defined(_ITERATOR_DEBUG_LEVEL) #if (_ITERATOR_DEBUG_LEVEL >= 1) #ifndef MPT_LIBCXX_QUIRK_NO_CXX20_CONSTEXPR_CONTAINER #define MPT_LIBCXX_QUIRK_NO_CXX20_CONSTEXPR_CONTAINER #endif #endif #endif #endif #endif #if MPT_CXX_AT_LEAST(20) // Clang 14 is incompatible with libstdc++ 13 in C++20 mode #if MPT_CLANG_BEFORE(15, 0, 0) && MPT_LIBCXX_GNU_AT_LEAST(13) #define MPT_LIBCXX_QUIRK_NO_CHRONO #endif #endif #if MPT_CXX_AT_LEAST(20) #if MPT_LIBCXX_MS && MPT_OS_WINDOWS #if MPT_WIN_BEFORE(MPT_WIN_10_1903) // std::chrono timezones require Windows 10 1903 with VS2022 as of 2022-01-22. // See and // . #define MPT_LIBCXX_QUIRK_NO_CHRONO_DATE #endif #endif #if MPT_LIBCXX_GNU_BEFORE(11) #define MPT_LIBCXX_QUIRK_NO_CHRONO_DATE #elif MPT_LIBCXX_LLVM_BEFORE(7000) #define MPT_LIBCXX_QUIRK_NO_CHRONO_DATE #endif #if MPT_LIBCXX_MS && (MPT_MSVC_BEFORE(2022, 2) || !MPT_COMPILER_MSVC) #elif MPT_LIBCXX_GNU #define MPT_LIBCXX_QUIRK_NO_CHRONO_DATE_PARSE #endif #if MPT_LIBCXX_MS && (MPT_MSVC_BEFORE(2022, 15) || !MPT_COMPILER_MSVC) // Causes massive memory leaks. // See // // / . #define MPT_LIBCXX_QUIRK_CHRONO_TZ_MEMLEAK #endif #endif #if MPT_LIBCXX_GNU_BEFORE(13) #define MPT_LIBCXX_QUIRK_CHRONO_DATE_NO_ZONED_TIME #endif #if MPT_MSVC_AT_LEAST(2022, 6) && MPT_MSVC_BEFORE(2022, 7) // std::chrono triggers ICE in VS2022 17.6.0, see . #define MPT_LIBCXX_QUIRK_CHRONO_DATE_BROKEN_ZONED_TIME #endif #if MPT_LIBCXX_GNU_BEFORE(8) #define MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT #elif MPT_LIBCXX_LLVM_BEFORE(7000) #define MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT #elif MPT_OS_ANDROID && MPT_LIBCXX_LLVM_BEFORE(8000) #define MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT #elif MPT_OS_MACOSX_OR_IOS #if defined(TARGET_OS_OSX) #if TARGET_OS_OSX #if !defined(MAC_OS_X_VERSION_10_15) #define MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT #else #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_15) #define MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT #endif #endif #endif #endif #endif #if (MPT_LIBCXX_MS && (MPT_MSVC_BEFORE(2019, 4) || !MPT_COMPILER_MSVC)) || MPT_LIBCXX_GNU_BEFORE(11) || MPT_LIBCXX_LLVM || MPT_LIBCXX_GENERIC #define MPT_LIBCXX_QUIRK_NO_TO_CHARS_FLOAT #endif #if MPT_OS_ANDROID && MPT_LIBCXX_LLVM_BEFORE(7000) #define MPT_LIBCXX_QUIRK_NO_HAS_UNIQUE_OBJECT_REPRESENTATIONS #endif #if MPT_OS_ANDROID && MPT_LIBCXX_LLVM_BEFORE(17000) #define MPT_LIBCXX_QUIRK_NO_NUMBERS #endif #if MPT_LIBCXX_GNU_BEFORE(13) || (MPT_LIBCXX_MS && !MPT_MSVC_AT_LEAST(2022, 7)) || MPT_LIBCXX_LLVM #define MPT_LIBCXX_QUIRK_NO_STDFLOAT #endif #if MPT_OS_MACOSX_OR_IOS #if defined(TARGET_OS_OSX) #if TARGET_OS_OSX #if !defined(MAC_OS_X_VERSION_10_14) #define MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE #else #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_14) #define MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE #endif #endif #endif #endif #endif #endif // MPT_BASE_DETECT_QUIRKS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/version.hpp0000644000175000017500000000040714044173026020757 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_VERSION_HPP #define MPT_BASE_VERSION_HPP #define MPT_VERSION_MAJOR 0 #define MPT_VERSION_MINOR 0 #define MPT_VERSION_PATCH 0 #define MPT_VERSION_BUILD 0 #endif // MPT_BASE_VERSION_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/memory.hpp0000644000175000017500000002423714356527671020630 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_MEMORY_HPP #define MPT_BASE_MEMORY_HPP #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/span.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { using byte_span = mpt::span; using const_byte_span = mpt::span; // Tell which types are safe for mpt::byte_cast. // signed char is actually not allowed to alias into an object representation, // which means that, if the actual type is not itself signed char but char or // unsigned char instead, dereferencing the signed char pointer is undefined // behaviour. template struct is_byte_castable : public std::false_type { }; template <> struct is_byte_castable : public std::true_type { }; template <> struct is_byte_castable : public std::true_type { }; template <> struct is_byte_castable : public std::true_type { }; template <> struct is_byte_castable : public std::true_type { }; template <> struct is_byte_castable : public std::true_type { }; template <> struct is_byte_castable : public std::true_type { }; template struct is_byte : public std::false_type { }; template <> struct is_byte : public std::true_type { }; template <> struct is_byte : public std::true_type { }; template constexpr bool declare_binary_safe(const T &) noexcept { return false; } constexpr bool declare_binary_safe(const char &) noexcept { return true; } constexpr bool declare_binary_safe(const uint8 &) noexcept { return true; } constexpr bool declare_binary_safe(const int8 &) noexcept { return true; } constexpr bool declare_binary_safe(const std::byte &) noexcept { return true; } // Tell which types are safe to binary write into files. // By default, no types are safe. // When a safe type gets defined, // also specialize this template so that IO functions will work. template struct is_binary_safe : public std::conditional::type { }; // Generic Specialization for arrays. template struct is_binary_safe : public is_binary_safe::type> { }; template struct is_binary_safe : public is_binary_safe::type> { }; template struct is_binary_safe> : public is_binary_safe::type> { }; template struct is_binary_safe> : public is_binary_safe::type> { }; template struct is_binary_safe> : public is_binary_safe::type> { }; template struct is_binary_safe> : public is_binary_safe::type> { }; template constexpr bool check_binary_size(std::size_t size) noexcept { return true && (sizeof(T) == size) && (alignof(T) == 1) && std::is_standard_layout::value #if !defined(MPT_LIBCXX_QUIRK_NO_HAS_UNIQUE_OBJECT_REPRESENTATIONS) && std::has_unique_object_representations::value #endif && mpt::is_binary_safe::value; } template struct byte_cast_impl { inline Tdst operator()(Tsrc src) const noexcept { static_assert(sizeof(Tsrc) == sizeof(std::byte)); static_assert(sizeof(Tdst) == sizeof(std::byte)); // not checking is_byte_castable here because we are actually // doing a static_cast and converting the value static_assert(std::is_integral::value || mpt::is_byte::value); static_assert(std::is_integral::value || mpt::is_byte::value); return static_cast(src); } }; template struct byte_cast_impl, mpt::span> { inline mpt::span operator()(mpt::span src) const noexcept { static_assert(sizeof(Tsrc) == sizeof(std::byte)); static_assert(sizeof(Tdst) == sizeof(std::byte)); static_assert(mpt::is_byte_castable::value); static_assert(mpt::is_byte_castable::value); static_assert(std::is_integral::value || mpt::is_byte::value); static_assert(std::is_integral::value || mpt::is_byte::value); return mpt::as_span(mpt::byte_cast_impl()(src.data()), mpt::byte_cast_impl()(src.data() + src.size())); } }; template struct byte_cast_impl { inline Tdst * operator()(Tsrc * src) const noexcept { static_assert(sizeof(Tsrc) == sizeof(std::byte)); static_assert(sizeof(Tdst) == sizeof(std::byte)); static_assert(mpt::is_byte_castable::value); static_assert(mpt::is_byte_castable::value); static_assert(std::is_integral::value || mpt::is_byte::value); static_assert(std::is_integral::value || mpt::is_byte::value); return reinterpret_cast(src); } }; template struct void_cast_impl; template struct void_cast_impl { inline Tdst * operator()(void * src) const noexcept { static_assert(sizeof(Tdst) == sizeof(std::byte)); static_assert(mpt::is_byte_castable::value); static_assert(std::is_integral::value || mpt::is_byte::value); return reinterpret_cast(src); } }; template struct void_cast_impl { inline Tdst * operator()(const void * src) const noexcept { static_assert(sizeof(Tdst) == sizeof(std::byte)); static_assert(mpt::is_byte_castable::value); static_assert(std::is_integral::value || mpt::is_byte::value); return reinterpret_cast(src); } }; template struct void_cast_impl { inline void * operator()(Tsrc * src) const noexcept { static_assert(sizeof(Tsrc) == sizeof(std::byte)); static_assert(mpt::is_byte_castable::value); static_assert(std::is_integral::value || mpt::is_byte::value); return reinterpret_cast(src); } }; template struct void_cast_impl { inline const void * operator()(Tsrc * src) const noexcept { static_assert(sizeof(Tsrc) == sizeof(std::byte)); static_assert(mpt::is_byte_castable::value); static_assert(std::is_integral::value || mpt::is_byte::value); return reinterpret_cast(src); } }; // casts between different byte (char) types or pointers to these types template inline Tdst byte_cast(Tsrc src) noexcept { return byte_cast_impl()(src); } // casts between pointers to void and pointers to byte template inline Tdst void_cast(Tsrc src) noexcept { return void_cast_impl()(src); } template MPT_CONSTEXPRINLINE std::byte as_byte(T src) noexcept { static_assert(std::is_integral::value); return static_cast(static_cast(src)); } template struct as_raw_memory_impl { inline mpt::const_byte_span operator()(const T & v) const { static_assert(mpt::is_binary_safe::type>::value); return mpt::as_span(reinterpret_cast(&v), sizeof(T)); } inline mpt::byte_span operator()(T & v) const { static_assert(mpt::is_binary_safe::type>::value); return mpt::as_span(reinterpret_cast(&v), sizeof(T)); } }; template struct as_raw_memory_impl { inline mpt::const_byte_span operator()(const T (&v)[N]) const { static_assert(mpt::is_binary_safe::type>::value); return mpt::as_span(reinterpret_cast(v), N * sizeof(T)); } inline mpt::byte_span operator()(T (&v)[N]) const { static_assert(mpt::is_binary_safe::type>::value); return mpt::as_span(reinterpret_cast(v), N * sizeof(T)); } }; template struct as_raw_memory_impl { inline mpt::const_byte_span operator()(const T (&v)[N]) const { static_assert(mpt::is_binary_safe::type>::value); return mpt::as_span(reinterpret_cast(v), N * sizeof(T)); } }; template struct as_raw_memory_impl> { inline mpt::const_byte_span operator()(const mpt::span & v) const { static_assert(mpt::is_binary_safe::type>::value); return mpt::as_span(reinterpret_cast(v.data()), v.size() * sizeof(T)); } inline mpt::byte_span operator()(const mpt::span & v) const { static_assert(mpt::is_binary_safe::type>::value); return mpt::as_span(reinterpret_cast(v.data()), v.size() * sizeof(T)); } }; template struct as_raw_memory_impl> { inline mpt::const_byte_span operator()(const mpt::span & v) const { static_assert(mpt::is_binary_safe::type>::value); return mpt::as_span(reinterpret_cast(v.data()), v.size() * sizeof(T)); } }; // In order to be able to partially specialize it, // as_raw_memory is implemented via a class template. // Do not overload or specialize as_raw_memory directly. // Using a wrapper (by default just around a cast to const std::byte *), // allows for implementing raw memory access // via on-demand generating a cached serialized representation. template inline mpt::const_byte_span as_raw_memory(const T & v) { return mpt::as_raw_memory_impl()(v); } template inline mpt::byte_span as_raw_memory(T & v) { return mpt::as_raw_memory_impl()(v); } template inline void memclear(T & x) { static_assert(std::is_standard_layout::value); static_assert((std::is_trivially_default_constructible::value && std::is_trivially_copyable::value) || mpt::is_binary_safe::value); std::memset(&x, 0, sizeof(T)); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_MEMORY_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/detect_libcxx.hpp0000644000175000017500000000314114172246622022116 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_DETECT_LIBCXX_HPP #define MPT_BASE_DETECT_LIBCXX_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_os.hpp" #if MPT_CXX_AT_LEAST(20) #include #else // !C++20 #include #endif // C++20 // order of checks is important! #if MPT_COMPILER_GENERIC #define MPT_LIBCXX_GENERIC 1 #elif defined(_LIBCPP_VERSION) #define MPT_LIBCXX_LLVM 1 #define MPT_LIBCXX_LLVM_VERSION _LIBCPP_VERSION #define MPT_LIBCXX_LLVM_AT_LEAST(ver) (MPT_LIBCXX_LLVM_VERSION >= (ver)) #define MPT_LIBCXX_LLVM_BEFORE(ver) (MPT_LIBCXX_LLVM_VERSION < (ver)) #elif defined(__GLIBCXX__) || defined(__GLIBCPP__) #define MPT_LIBCXX_GNU 1 #define MPT_LIBCXX_GNU_VERSION _GLIBCXX_RELEASE #define MPT_LIBCXX_GNU_AT_LEAST(ver) (MPT_LIBCXX_GNU_VERSION >= (ver)) #define MPT_LIBCXX_GNU_BEFORE(ver) (MPT_LIBCXX_GNU_VERSION < (ver)) #elif MPT_COMPILER_MSVC #define MPT_LIBCXX_MS 1 #elif MPT_COMPILER_CLANG && MPT_OS_WINDOWS #define MPT_LIBCXX_MS 1 #else #define MPT_LIBCXX_GENERIC 1 #endif #ifndef MPT_LIBCXX_GENERIC #define MPT_LIBCXX_GENERIC 0 #endif #ifndef MPT_LIBCXX_LLVM #define MPT_LIBCXX_LLVM 0 #define MPT_LIBCXX_LLVM_VERSION 0 #define MPT_LIBCXX_LLVM_AT_LEAST(ver) 0 #define MPT_LIBCXX_LLVM_BEFORE(ver) 0 #endif #ifndef MPT_LIBCXX_GNU #define MPT_LIBCXX_GNU 0 #define MPT_LIBCXX_GNU_VERSION 0 #define MPT_LIBCXX_GNU_AT_LEAST(ver) 0 #define MPT_LIBCXX_GNU_BEFORE(ver) 0 #endif #ifndef MPT_LIBCXX_MS #define MPT_LIBCXX_MS 0 #endif #endif // MPT_BASE_DETECT_LIBCXX_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/check_platform.hpp0000644000175000017500000000473214216574123022264 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_CHECK_PLATFORM_HPP #define MPT_BASE_CHECK_PLATFORM_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/pointer.hpp" #include #include #include #include #if MPT_LIBC_DJGPP #include #endif // MPT_LIBC_DJGPP namespace mpt { inline namespace MPT_INLINE_NS { static_assert(sizeof(std::uintptr_t) == sizeof(void *)); static_assert(std::numeric_limits::digits == 8); static_assert(sizeof(char) == 1); static_assert(sizeof(std::byte) == 1); static_assert(alignof(std::byte) == 1); static_assert(mpt::arch_bits == static_cast(mpt::pointer_size) * 8); #if MPT_LIBC_DJGPP namespace platform { namespace detail { struct libc_checker { private: bool m_libc_check_failure = false; bool m_libc_has_implicit_code_locking = false; public: [[nodiscard]] inline libc_checker() { assert(((_crt0_startup_flags & _CRT0_FLAG_NONMOVE_SBRK) == _CRT0_FLAG_NONMOVE_SBRK) && ((_crt0_startup_flags & _CRT0_FLAG_UNIX_SBRK) == 0)); if (((_crt0_startup_flags & _CRT0_FLAG_NONMOVE_SBRK) == _CRT0_FLAG_NONMOVE_SBRK) && ((_crt0_startup_flags & _CRT0_FLAG_UNIX_SBRK) != 0)) { m_libc_check_failure = true; } assert((_crt0_startup_flags & _CRT0_DISABLE_SBRK_ADDRESS_WRAP) == _CRT0_DISABLE_SBRK_ADDRESS_WRAP); if ((_crt0_startup_flags & _CRT0_DISABLE_SBRK_ADDRESS_WRAP) != _CRT0_DISABLE_SBRK_ADDRESS_WRAP) { m_libc_check_failure = true; } if ((_crt0_startup_flags & _CRT0_FLAG_LOCK_MEMORY) == _CRT0_FLAG_LOCK_MEMORY) { m_libc_has_implicit_code_locking = true; } } libc_checker(const libc_checker &) = delete; libc_checker & operator=(const libc_checker &) = delete; [[nodiscard]] inline bool is_ok() const noexcept { return !m_libc_check_failure; } [[nodiscard]] inline bool has_implicit_code_locking() const noexcept { return m_libc_has_implicit_code_locking; } }; #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif // MPT_COMPILER_CLANG inline const libc_checker g_libc_checker; #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG } // namespace detail [[nodiscard]] inline const mpt::platform::detail::libc_checker & libc() noexcept { return mpt::platform::detail::g_libc_checker; } } // namespace platform #endif // MPT_LIBC_DJGPP } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_CHECK_PLATFORM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/detect_libc.hpp0000644000175000017500000001770614734730734021560 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_DETECT_LIBC_HPP #define MPT_BASE_DETECT_LIBC_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_os.hpp" #include // Version numbers try to follow MinGW32 // , // and MinGW-w64 version numbers are adjusted for // , #define MPT_LIBC_MS_VER_CRTDLL 0x0000 #define MPT_LIBC_MS_VER_MSVCR10 0x0100 #define MPT_LIBC_MS_VER_MSVCR20 0x0200 #define MPT_LIBC_MS_VER_MSVCR40 0x0400 #define MPT_LIBC_MS_VER_MSVCRT40 0x0400 #define MPT_LIBC_MS_VER_MSVCRT 0x0600 #define MPT_LIBC_MS_VER_MSVCR60 0x0600 #define MPT_LIBC_MS_VER_MSVCR61 0x0601 #define MPT_LIBC_MS_VER_MSVCR70 0x0700 #define MPT_LIBC_MS_VER_MSVCR71 0x0701 #define MPT_LIBC_MS_VER_MSVCR80 0x0800 #define MPT_LIBC_MS_VER_MSVCR90 0x0900 #define MPT_LIBC_MS_VER_MSVCR100 0x1000 #define MPT_LIBC_MS_VER_MSVCR110 0x1100 #define MPT_LIBC_MS_VER_MSVCR120 0x1200 #define MPT_LIBC_MS_VER_UCRT 0x1400 // order of checks is important! #if MPT_COMPILER_GENERIC #define MPT_LIBC_GENERIC 1 #elif (defined(__MINGW32__) || defined(__MINGW64__)) #define MPT_LIBC_MINGW 1 #if defined(__MINGW64_VERSION_MAJOR) && defined(__MINGW64_VERSION_MINOR) #define MPT_LIBC_MINGW_MINGWW64 1 #define MPT_LIBC_MINGW_MINGWW64_AT_LEAST(major, minor) (((major) > __MINGW64_VERSION_MAJOR) || (((major) == __MINGW64_VERSION_MAJOR) && ((minor) >= __MINGW64_VERSION_MINOR))) #define MPT_LIBC_MINGW_MINGWW64_BEFORE(major, minor) (((major) < __MINGW64_VERSION_MAJOR) || (((major) == __MINGW64_VERSION_MAJOR) && ((minor) < __MINGW64_VERSION_MINOR))) #elif defined(__MINGW64_VERSION_MAJOR) #define MPT_LIBC_MINGW_MINGWW64 1 #define MPT_LIBC_MINGW_MINGWW64_AT_LEAST(major, minor) ((major) >= __MINGW64_VERSION_MAJOR) #define MPT_LIBC_MINGW_MINGWW64_BEFORE(major, minor) ((major) < __MINGW64_VERSION_MAJOR) #elif defined(__MINGW64_VERSION_MINOR) #define MPT_LIBC_MINGW_MINGWW64 1 #define MPT_LIBC_MINGW_MINGWW64_AT_LEAST(major, minor) 0 #define MPT_LIBC_MINGW_MINGWW64_BEFORE(major, minor) 1 #elif defined(__MINGW32_VERSION_MAJOR) && defined(__MINGW32_VERSION_MINOR) #define MPT_LIBC_MINGW_MINGW32 1 #define MPT_LIBC_MINGW_MINGW32_AT_LEAST(major, minor) (((major) > __MINGW32_VERSION_MAJOR) || (((major) == __MINGW32_VERSION_MAJOR) && ((minor) >= __MINGW32_VERSION_MINOR))) #define MPT_LIBC_MINGW_MINGW32_BEFORE(major, minor) (((major) < __MINGW32_VERSION_MAJOR) || (((major) == __MINGW32_VERSION_MAJOR) && ((minor) < __MINGW32_VERSION_MINOR))) #elif defined(__MINGW32_VERSION_MAJOR) #define MPT_LIBC_MINGW_MINGW32 1 #define MPT_LIBC_MINGW_MINGW32_AT_LEAST(major, minor) ((major) >= __MINGW32_VERSION_MAJOR) #define MPT_LIBC_MINGW_MINGW32_BEFORE(major, minor) ((major) < __MINGW32_VERSION_MAJOR) #elif defined(__MINGW32_VERSION_MINOR) #define MPT_LIBC_MINGW_MINGW32 1 #define MPT_LIBC_MINGW_MINGW32_AT_LEAST(major, minor) 0 #define MPT_LIBC_MINGW_MINGW32_BEFORE(major, minor) 1 #endif #if defined(MPT_LIBC_MINGW_MINGW32) #ifdef __MSVCR60_DLL static_assert(__MSVCR60_DLL == MPT_LIBC_MS_VER_MSVCR60); #endif #ifdef __MSVCR61_DLL static_assert(__MSVCR61_DLL == MPT_LIBC_MS_VER_MSVCR61); #endif #ifdef __MSVCR70_DLL static_assert(__MSVCR70_DLL == MPT_LIBC_MS_VER_MSVCR70); #endif #ifdef __MSVCR71_DLL static_assert(__MSVCR71_DLL == MPT_LIBC_MS_VER_MSVCR71); #endif #ifdef __MSVCR80_DLL static_assert(__MSVCR80_DLL == MPT_LIBC_MS_VER_MSVCR80); #endif #ifdef __MSVCR90_DLL static_assert(__MSVCR90_DLL == MPT_LIBC_MS_VER_MSVCR90); #endif #ifdef __MSVCR100_DLL static_assert(__MSVCR100_DLL == MPT_LIBC_MS_VER_MSVCR100); #endif #ifdef __MSVCR110_DLL static_assert(__MSVCR110_DLL == MPT_LIBC_MS_VER_MSVCR110); #endif #ifdef __MSVCR120_DLL static_assert(__MSVCR120_DLL == MPT_LIBC_MS_VER_MSVCR120); #endif #endif #if defined(_UCRT) #define MPT_LIBC_MS_UCRT 1 #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_UCRT #elif defined(__MSVCRT__) #define MPT_LIBC_MS_MSVCRT 1 #if defined(__MSVCRT_VERSION__) #if defined(MPT_LIBC_MINGW_MINGWW64) #if (__MSVCRT_VERSION__ > 0x09ff) // MinGW-w64 completely fucked up version numbers in // , // so we need to compensate for that mother of brainfarts. #define MPT_LIBC_MS_VERSION (__MSVCRT_VERSION__ + (0x1000 - 0x0A00)) #else #define MPT_LIBC_MS_VERSION __MSVCRT_VERSION__ #endif #define MPT_LIBC_MS_VERSION __MSVCRT_VERSION__ #elif defined(MPT_LIBC_MINGW_MINGW32) #define MPT_LIBC_MS_VERSION __MSVCRT_VERSION__ #else #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_MSVCRT #endif #endif #elif defined(__CRTDLL__) #define MPT_LIBC_MS_CRTDLL 1 #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_CRTDLL #endif #elif (defined(__GLIBC__) || defined(__GNU_LIBRARY__)) #define MPT_LIBC_GLIBC 1 #elif defined(_UCRT) #define MPT_LIBC_MS 1 #define MPT_LIBC_MS_UCRT 1 #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_UCRT #elif MPT_COMPILER_MSVC #define MPT_LIBC_MS 1 #define MPT_LIBC_MS_MSVCRT 1 #if MPT_MSVC_AT_LEAST(2015, 0) #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_UCRT #elif MPT_MSVC_AT_LEAST(2013, 0) #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_MSVCR120 #elif MPT_MSVC_AT_LEAST(2012, 0) #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_MSVCR110 #elif MPT_MSVC_AT_LEAST(2010, 0) #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_MSVCR100 #elif MPT_MSVC_AT_LEAST(2008, 0) #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_MSVCR90 #elif MPT_MSVC_AT_LEAST(2005, 0) #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_MSVCR80 #elif MPT_MSVC_AT_LEAST(2003, 0) #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_MSVCR71 #elif MPT_MSVC_AT_LEAST(2002, 0) #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_MSVCR70 #else #define MPT_LIBC_MS_VERSION MPT_LIBC_MS_VER_MSVCRT #endif #elif MPT_COMPILER_CLANG && MPT_OS_WINDOWS #define MPT_LIBC_MS 1 #elif defined(__BIONIC__) #define MPT_LIBC_BIONIC 1 #elif defined(__APPLE__) #define MPT_LIBC_APPLE 1 #elif defined(__DJGPP__) #define MPT_LIBC_DJGPP 1 #else #define MPT_LIBC_GENERIC 1 #endif #if defined(MPT_LIBC_MS_VERSION) #define MPT_LIBC_MS_AT_LEAST(v) (MPT_LIBC_MS_VERSION >= (v)) #define MPT_LIBC_MS_BEFORE(v) (MPT_LIBC_MS_VERSION < (v)) #endif #ifndef MPT_LIBC_GENERIC #define MPT_LIBC_GENERIC 0 #endif #ifndef MPT_LIBC_GLIBC #define MPT_LIBC_GLIBC 0 #endif #ifndef MPT_LIBC_MINGW #define MPT_LIBC_MINGW 0 #endif #ifndef MPT_LIBC_MINGW_MINGWW64 #define MPT_LIBC_MINGW_MINGWW64 0 #endif #ifndef MPT_LIBC_MINGW_MINGW32 #define MPT_LIBC_MINGW_MINGW32 0 #endif #ifndef MPT_LIBC_MINGW_MINGWW64_AT_LEAST #define MPT_LIBC_MINGW_MINGWW64_AT_LEAST(major, minor) 0 #endif #ifndef MPT_LIBC_MINGW_MINGWW64_BEFORE #define MPT_LIBC_MINGW_MINGWW64_BEFORE(major, minor) 0 #endif #ifndef MPT_LIBC_MINGW_MINGW32_AT_LEAST #define MPT_LIBC_MINGW_MINGW32_AT_LEAST(major, minor) 0 #endif #ifndef MPT_LIBC_MINGW_MINGW32_BEFORE #define MPT_LIBC_MINGW_MINGW32_BEFORE(major, minor) 0 #endif #ifndef MPT_LIBC_MS #define MPT_LIBC_MS 0 #endif #ifndef MPT_LIBC_MS_UCRT #define MPT_LIBC_MS_UCRT 0 #endif #ifndef MPT_LIBC_MS_MSVCRT #define MPT_LIBC_MS_MSVCRT 0 #endif #ifndef MPT_LIBC_MS_CRTDLL #define MPT_LIBC_MS_CRTDLL 0 #endif #ifndef MPT_LIBC_MS_AT_LEAST #define MPT_LIBC_MS_AT_LEAST(v) 0 #endif #ifndef MPT_LIBC_MS_BEFORE #define MPT_LIBC_MS_BEFORE(v) 0 #endif #ifndef MPT_LIBC_BIONIC #define MPT_LIBC_BIONIC 0 #endif #ifndef MPT_LIBC_APPLE #define MPT_LIBC_APPLE 0 #endif #ifndef MPT_LIBC_DJGPP #define MPT_LIBC_DJGPP 0 #endif #if MPT_LIBC_MS #if defined(_DEBUG) #define MPT_LIBC_MS_DEBUG 1 #endif #if defined(_DLL) #define MPT_LIBC_MS_SHARED 1 #define MPT_LIBC_MS_STATIC 0 #else #define MPT_LIBC_MS_SHARED 0 #define MPT_LIBC_MS_STATIC 1 #endif #endif #ifndef MPT_LIBC_MS_DEBUG #define MPT_LIBC_MS_DEBUG 0 #endif #ifndef MPT_LIBC_MS_SHARED #define MPT_LIBC_MS_SHARED 0 #endif #ifndef MPT_LIBC_MS_STATIC #define MPT_LIBC_MS_STATIC 0 #endif #endif // MPT_BASE_DETECT_LIBC_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/float.hpp0000644000175000017500000001513414657611604020413 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_FLOAT_HPP #define MPT_BASE_FLOAT_HPP #include "mpt/base/detect.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include #if MPT_CXX_AT_LEAST(23) && !defined(MPT_LIBCXX_QUIRK_NO_STDFLOAT) #include #endif // C++23 #include namespace mpt { inline namespace MPT_INLINE_NS { // fp half // n/a // fp single using single_float = float; namespace float_literals { MPT_CONSTEVAL single_float operator""_fs(long double lit) noexcept { return static_cast(lit); } } // namespace float_literals // fp double using double_float = float; namespace float_literals { MPT_CONSTEVAL double_float operator""_fd(long double lit) noexcept { return static_cast(lit); } } // namespace float_literals // fp extended using extended_float = long double; namespace float_literals { MPT_CONSTEVAL extended_float operator""_fe(long double lit) noexcept { return static_cast(lit); } } // namespace float_literals // fp quad // n/a #if MPT_CXX_AT_LEAST(23) && !defined(MPT_LIBCXX_QUIRK_NO_STDFLOAT) #if defined(__STDCPP_FLOAT16_T__) #if (__STDCPP_FLOAT16_T__ == 1) #define MPT_BASE_STDFLOAT_FLOAT16 #endif #endif #endif #if MPT_CXX_AT_LEAST(23) && !defined(MPT_LIBCXX_QUIRK_NO_STDFLOAT) #if defined(__STDCPP_FLOAT32_T__) #if (__STDCPP_FLOAT32_T__ == 1) #define MPT_BASE_STDFLOAT_FLOAT32 #endif #endif #endif #if MPT_CXX_AT_LEAST(23) && !defined(MPT_LIBCXX_QUIRK_NO_STDFLOAT) #if defined(__STDCPP_FLOAT64_T__) #if (__STDCPP_FLOAT64_T__ == 1) #define MPT_BASE_STDFLOAT_FLOAT64 #endif #endif #endif #if MPT_CXX_AT_LEAST(23) && !defined(MPT_LIBCXX_QUIRK_NO_STDFLOAT) #if defined(__STDCPP_FLOAT128_T__) #if (__STDCPP_FLOAT128_T__ == 1) #define MPT_BASE_STDFLOAT_FLOAT128 #endif #endif #endif #if defined(MPT_BASE_STDFLOAT_FLOAT16) using stdfloat16 = std::float16_t; #else using stdfloat16 = std::conditional::type>::type>::type; #endif #if defined(MPT_BASE_STDFLOAT_FLOAT32) using stdfloat32 = std::float32_t; #else using stdfloat32 = std::conditional::type>::type>::type; #endif #if defined(MPT_BASE_STDFLOAT_FLOAT64) using stdfloat64 = std::float64_t; #else using stdfloat64 = std::conditional::type>::type>::type; #endif #if defined(MPT_BASE_STDFLOAT_FLOAT128) using stdfloat128 = std::float128_t; #else using stdfloat128 = std::conditional::type>::type>::type; #endif #undef MPT_BASE_STDFLOAT_FLOAT16 #undef MPT_BASE_STDFLOAT_FLOAT32 #undef MPT_BASE_STDFLOAT_FLOAT64 #undef MPT_BASE_STDFLOAT_FLOAT128 namespace float_literals { MPT_CONSTEVAL stdfloat16 operator""_stdf16(long double lit) noexcept { return static_cast(lit); } MPT_CONSTEVAL stdfloat32 operator""_stdf32(long double lit) noexcept { return static_cast(lit); } MPT_CONSTEVAL stdfloat64 operator""_stdf64(long double lit) noexcept { return static_cast(lit); } MPT_CONSTEVAL stdfloat128 operator""_stdf128(long double lit) noexcept { return static_cast(lit); } } // namespace float_literals // fast floating point types of roughly requested size using fastfloat32 = std::conditional::type>::type>::type; namespace float_literals { MPT_CONSTEVAL fastfloat32 operator""_ff32(long double lit) noexcept { return static_cast(lit); } } // namespace float_literals using fastfloat64 = std::conditional::type>::type>::type; namespace float_literals { MPT_CONSTEVAL fastfloat64 operator""_ff64(long double lit) noexcept { return static_cast(lit); } } // namespace float_literals // floating point type of roughly requested size using somefloat32 = std::conditional::type>::type; namespace float_literals { MPT_CONSTEVAL somefloat32 operator""_sf32(long double lit) noexcept { return static_cast(lit); } } // namespace float_literals using somefloat64 = std::conditional::type>::type; namespace float_literals { MPT_CONSTEVAL somefloat64 operator""_sf64(long double lit) noexcept { return static_cast(lit); } } // namespace float_literals template struct float_traits { static constexpr bool is_float = !std::numeric_limits::is_integer; static constexpr bool is_hard = is_float && !MPT_COMPILER_QUIRK_FLOAT_EMULATED; static constexpr bool is_soft = is_float && MPT_COMPILER_QUIRK_FLOAT_EMULATED; static constexpr bool is_float16 = is_float && (sizeof(T) == 2); static constexpr bool is_float32 = is_float && (sizeof(T) == 4); static constexpr bool is_float64 = is_float && (sizeof(T) == 8); static constexpr bool is_float128 = is_float && (sizeof(T) == 16); static constexpr bool is_native_endian = is_float && !MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN; static constexpr bool is_ieee754_binary = is_float && std::numeric_limits::is_iec559 && !MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754; static constexpr bool is_preferred = is_float && ((is_float32 && MPT_COMPILER_QUIRK_FLOAT_PREFER32) || (is_float64 && MPT_COMPILER_QUIRK_FLOAT_PREFER64)); }; // prefer smaller floats, but try to use IEEE754 floats using nativefloat = std::conditional::is_preferred, somefloat32, std::conditional::is_preferred, somefloat64, std::conditional::is_iec559, float, std::conditional::is_iec559, double, std::conditional::is_iec559, long double, float>::type>::type>::type>::type>::type; namespace float_literals { MPT_CONSTEVAL nativefloat operator""_nf(long double lit) noexcept { return static_cast(lit); } } // namespace float_literals } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_FLOAT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/type_traits.hpp0000644000175000017500000000077714657636600021667 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TYPE_TRAITS_HPP #define MPT_BASE_TYPE_TRAITS_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_CXX_AT_LEAST(20) using std::type_identity; #else // ! C++20 template struct type_identity { using type = T; }; #endif // C++20 } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TYPE_TRAITS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/integer.hpp0000644000175000017500000000103114044173026020721 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_INTEGER_HPP #define MPT_BASE_INTEGER_HPP #include "mpt/base/namespace.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { using int8 = std::int8_t; using int16 = std::int16_t; using int32 = std::int32_t; using int64 = std::int64_t; using uint8 = std::uint8_t; using uint16 = std::uint16_t; using uint32 = std::uint32_t; using uint64 = std::uint64_t; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_INTEGER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/numbers.hpp0000644000175000017500000001477314647521620020766 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_NUMBRES_HPP #define MPT_BASE_NUMBRES_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_quirks.hpp" #include "mpt/base/namespace.hpp" #if MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_NUMBERS) #include #else #include #include #include #endif namespace mpt { inline namespace MPT_INLINE_NS { namespace numbers { #if MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_NUMBERS) template inline constexpr T e_v = std::numbers::e_v; template inline constexpr T log2e_v = std::numbers::log2e_v; template inline constexpr T log10e_v = std::numbers::log10e_v; template inline constexpr T pi_v = std::numbers::pi_v; template inline constexpr T inv_pi_v = std::numbers::inv_pi_v; template inline constexpr T inv_sqrtpi_v = std::numbers::inv_sqrtpi_v; template inline constexpr T ln2_v = std::numbers::ln2_v; template inline constexpr T ln10_v = std::numbers::ln10_v; template inline constexpr T sqrt2_v = std::numbers::sqrt2_v; template inline constexpr T sqrt3_v = std::numbers::sqrt3_v; template inline constexpr T inv_sqrt3_v = std::numbers::inv_sqrt3_v; template inline constexpr T egamma_v = std::numbers::egamma_v; template inline constexpr T phi_v = std::numbers::phi_v; inline constexpr double e = e_v; inline constexpr double log2e = log2e_v; inline constexpr double log10e = log10e_v; inline constexpr double pi = pi_v; inline constexpr double inv_pi = inv_pi_v; inline constexpr double inv_sqrtpi = inv_sqrtpi_v; inline constexpr double ln2 = ln2_v; inline constexpr double ln10 = ln10_v; inline constexpr double sqrt2 = sqrt2_v; inline constexpr double sqrt3 = sqrt3_v; inline constexpr double inv_sqrt3 = inv_sqrt3_v; inline constexpr double egamma = egamma_v; inline constexpr double phi = phi_v; #else #ifdef M_E template ::value, bool>::type = true> inline constexpr T e_v = static_cast(M_E); #else template ::value, bool>::type = true> inline constexpr T e_v = static_cast(2.71828182845904523536); #endif #ifdef M_LOG2E template ::value, bool>::type = true> inline constexpr T log2e_v = static_cast(M_LOG2E); #else template ::value, bool>::type = true> inline constexpr T log2e_v = static_cast(1.44269504088896340736); #endif #ifdef M_LOG10E template ::value, bool>::type = true> inline constexpr T log10e_v = static_cast(M_LOG10E); #else template ::value, bool>::type = true> inline constexpr T log10e_v = static_cast(0.434294481903251827651); #endif #ifdef M_PI template ::value, bool>::type = true> inline constexpr T pi_v = static_cast(M_PI); #else template ::value, bool>::type = true> inline constexpr T pi_v = static_cast(3.14159265358979323846); #endif #ifdef M_1_PI template ::value, bool>::type = true> inline constexpr T inv_pi_v = static_cast(M_1_PI); #else template ::value, bool>::type = true> inline constexpr T inv_pi_v = static_cast(0.318309886183790671538); #endif template ::value, bool>::type = true> inline constexpr T inv_sqrtpi_v = static_cast(0.564189583547756286948079451560772586); #ifdef M_LN2 template ::value, bool>::type = true> inline constexpr T ln2_v = static_cast(M_LN2); #else template ::value, bool>::type = true> inline constexpr T ln2_v = static_cast(0.693147180559945309417); #endif #ifdef M_LN10 template ::value, bool>::type = true> inline constexpr T ln10_v = static_cast(M_LN10); #else template ::value, bool>::type = true> inline constexpr T ln10_v = static_cast(2.30258509299404568402); #endif #ifdef M_SQRT2 template ::value, bool>::type = true> inline constexpr T sqrt2_v = static_cast(M_SQRT2); #else template ::value, bool>::type = true> inline constexpr T sqrt2_v = static_cast(1.41421356237309504880); #endif template ::value, bool>::type = true> inline constexpr T sqrt3_v = static_cast(1.732050807568877293527446341505872367); template ::value, bool>::type = true> inline constexpr T inv_sqrt3_v = static_cast(0.577350269189625764509148780501957456); template ::value, bool>::type = true> inline constexpr T egamma_v = static_cast(0.577215664901532860606512090082402431); template ::value, bool>::type = true> inline constexpr T phi_v = static_cast(1.618033988749894848204586834365638118); inline constexpr double e = e_v; inline constexpr double log2e = log2e_v; inline constexpr double log10e = log10e_v; inline constexpr double pi = pi_v; inline constexpr double inv_pi = inv_pi_v; inline constexpr double inv_sqrtpi = inv_sqrtpi_v; inline constexpr double ln2 = ln2_v; inline constexpr double ln10 = ln10_v; inline constexpr double sqrt2 = sqrt2_v; inline constexpr double sqrt3 = sqrt3_v; inline constexpr double inv_sqrt3 = inv_sqrt3_v; inline constexpr double egamma = egamma_v; inline constexpr double phi = phi_v; #endif } // namespace numbers } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_NUMBRES_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/numeric.hpp0000644000175000017500000000446614575042614020754 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_NUMERIC_HPP #define MPT_BASE_NUMERIC_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/bit.hpp" #include "mpt/base/saturate_cast.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { template struct ModIfNotZeroImpl { template constexpr Tval mod(Tval x) { static_assert(std::numeric_limits::is_integer); static_assert(!std::numeric_limits::is_signed); static_assert(std::numeric_limits::is_integer); static_assert(!std::numeric_limits::is_signed); return static_cast(x % m); } }; template <> struct ModIfNotZeroImpl { template constexpr Tval mod(Tval x) { return x; } }; template <> struct ModIfNotZeroImpl { template constexpr Tval mod(Tval x) { return x; } }; template <> struct ModIfNotZeroImpl { template constexpr Tval mod(Tval x) { return x; } }; template <> struct ModIfNotZeroImpl { template constexpr Tval mod(Tval x) { return x; } }; // Returns x % m if m != 0, x otherwise. // i.e. "return (m == 0) ? x : (x % m);", but without causing a warning with stupid older compilers template constexpr Tval modulo_if_not_zero(Tval x) { return ModIfNotZeroImpl().mod(x); } // rounds x up to multiples of target template constexpr T align_up(T x, T target) { return ((x + (target - 1)) / target) * target; } // rounds x down to multiples of target template constexpr T align_down(T x, T target) { return (x / target) * target; } // rounds x up to multiples of target or saturation of T template constexpr T saturate_align_up(T x, T target) { if (x > (std::numeric_limits::max() - (target - 1))) { return std::numeric_limits::max(); } return ((x + (target - 1)) / target) * target; } // Returns sign of a number (-1 for negative numbers, 1 for positive numbers, 0 for 0) template constexpr int signum(T value) { return (value > T(0)) - (value < T(0)); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_ALGORITHM_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/tests/0000755000175000017500000000000015023302361017774 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/base/tests/tests_base_wrapping_divide.hpp0000644000175000017500000002232014044173026026021 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TESTS_WRAPPING_DIVIDE_HPP #define MPT_BASE_TESTS_WRAPPING_DIVIDE_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/wrapping_divide.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace base { namespace wrapping_divide { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/base/wrapping_divide") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(-25, 12), 11); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(-24, 12), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(-23, 12), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(-8, 7), 6); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(-7, 7), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(-6, 7), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(-5, 7), 2); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(-4, 7), 3); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(-3, 7), 4); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(-2, 7), 5); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(-1, 7), 6); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(0, 12), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(0, 7), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(1, 7), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(2, 7), 2); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(3, 7), 3); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(4, 7), 4); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(5, 7), 5); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(6, 7), 6); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(7, 7), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(8, 7), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(23, 12), 11); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(24, 12), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(25, 12), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(uint32(0x7fffffff), uint32(0x80000000)), uint32(0x7fffffff)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(0x7ffffffe), int32(0x7fffffff)), int32(0x7ffffffe)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), int32(1)), int32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), int32(2)), int32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), int32(1)), int32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), int32(2)), int32(1)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), int32(1)), int32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), int32(2)), int32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), int32(0x7fffffff)), int32(0x7ffffffe)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), int32(0x7fffffff)), int32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), int32(0x7fffffff)), int32(1)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), int32(0x7ffffffe)), int32(0x7ffffffc)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), int32(0x7ffffffe)), int32(0x7ffffffd)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), int32(0x7ffffffe)), int32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), int32(0x7ffffffd)), int32(0x7ffffffa)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), int32(0x7ffffffd)), int32(0x7ffffffb)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), int32(0x7ffffffd)), int32(0x7ffffffc)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(0), int32(0x7fffffff)), int32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-1), int32(0x7fffffff)), int32(0x7ffffffe)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-2), int32(0x7fffffff)), int32(0x7ffffffd)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(0), int32(0x7ffffffe)), int32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-1), int32(0x7ffffffe)), int32(0x7ffffffd)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-2), int32(0x7ffffffe)), int32(0x7ffffffc)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(1)), uint32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(2)), uint32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), uint32(1)), uint32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), uint32(2)), uint32(1)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), uint32(1)), uint32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), uint32(2)), uint32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x40000001), uint32(0xffffffff)), uint32(0xbffffffe)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x40000000), uint32(0xffffffff)), uint32(0xbfffffff)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x3fffffff), uint32(0xffffffff)), uint32(0xc0000000)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x80000000)), uint32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), uint32(0x80000000)), uint32(1)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), uint32(0x80000000)), uint32(2)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x80000001)), uint32(1)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), uint32(0x80000001)), uint32(2)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), uint32(0x80000001)), uint32(3)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x80000000)), uint32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), uint32(0x80000000)), uint32(1)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), uint32(0x80000000)), uint32(2)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x7fffffff)), uint32(0x7ffffffe)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), uint32(0x7fffffff)), uint32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), uint32(0x7fffffff)), uint32(1)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x7ffffffe)), uint32(0x7ffffffc)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), uint32(0x7ffffffe)), uint32(0x7ffffffd)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), uint32(0x7ffffffe)), uint32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x7ffffffd)), uint32(0x7ffffffa)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), uint32(0x7ffffffd)), uint32(0x7ffffffb)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), uint32(0x7ffffffd)), uint32(0x7ffffffc)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(0), uint32(0x7fffffff)), uint32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-1), uint32(0x7fffffff)), uint32(0x7ffffffe)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-2), uint32(0x7fffffff)), uint32(0x7ffffffd)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(0), uint32(0x7ffffffe)), uint32(0)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-1), uint32(0x7ffffffe)), uint32(0x7ffffffd)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_modulo(int32(-2), uint32(0x7ffffffe)), uint32(0x7ffffffc)); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-15, 7), -3); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-14, 7), -2); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-13, 7), -2); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-12, 7), -2); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-11, 7), -2); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-10, 7), -2); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-9, 7), -2); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-8, 7), -2); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-7, 7), -1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-6, 7), -1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-5, 7), -1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-4, 7), -1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-3, 7), -1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-2, 7), -1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(-1, 7), -1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(0, 7), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(1, 7), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(2, 7), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(3, 7), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(4, 7), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(5, 7), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(6, 7), 0); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(7, 7), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(8, 7), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(9, 7), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(10, 7), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(11, 7), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(12, 7), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(13, 7), 1); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(14, 7), 2); MPT_TEST_EXPECT_EQUAL(mpt::wrapping_divide(15, 7), 2); } } // namespace wrapping_divide } // namespace base } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TESTS_WRAPPING_DIVIDE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/tests/tests_base_arithmetic_shift.hpp0000644000175000017500000006625714161604104026211 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TESTS_ARITHMETIC_SHIFT_HPP #define MPT_BASE_TESTS_ARITHMETIC_SHIFT_HPP #include "mpt/base/arithmetic_shift.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace base { namespace arithmetic_shift { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/base/arithmetic_shift") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 1), mpt::rshift_signed_portable(-32768, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 1), mpt::rshift_signed_portable(-32767, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 1), mpt::rshift_signed_portable(-32766, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 1), mpt::rshift_signed_portable(-2, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 1), mpt::rshift_signed_portable(-1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 1), mpt::rshift_signed_portable(0, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 1), mpt::rshift_signed_portable(1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 1), mpt::rshift_signed_portable(2, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 1), mpt::rshift_signed_portable(32766, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 1), mpt::rshift_signed_portable(32767, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 14), mpt::rshift_signed_portable(-32768, 14)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 14), mpt::rshift_signed_portable(-32767, 14)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 14), mpt::rshift_signed_portable(-32766, 14)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 14), mpt::rshift_signed_portable(-2, 14)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 14), mpt::rshift_signed_portable(-1, 14)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 14), mpt::rshift_signed_portable(0, 14)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 14), mpt::rshift_signed_portable(1, 14)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 14), mpt::rshift_signed_portable(2, 14)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 14), mpt::rshift_signed_portable(32766, 14)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 14), mpt::rshift_signed_portable(32767, 14)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 15), mpt::rshift_signed_portable(-32768, 15)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 15), mpt::rshift_signed_portable(-32767, 15)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 15), mpt::rshift_signed_portable(-32766, 15)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 15), mpt::rshift_signed_portable(-2, 15)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 15), mpt::rshift_signed_portable(-1, 15)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 15), mpt::rshift_signed_portable(0, 15)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 15), mpt::rshift_signed_portable(1, 15)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 15), mpt::rshift_signed_portable(2, 15)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 15), mpt::rshift_signed_portable(32766, 15)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 15), mpt::rshift_signed_portable(32767, 15)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 1), mpt::lshift_signed_portable(-32768, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 1), mpt::lshift_signed_portable(-32767, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 1), mpt::lshift_signed_portable(-32766, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 1), mpt::lshift_signed_portable(-2, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 1), mpt::lshift_signed_portable(-1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 1), mpt::lshift_signed_portable(0, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 1), mpt::lshift_signed_portable(1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 1), mpt::lshift_signed_portable(2, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 1), mpt::lshift_signed_portable(32766, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 1), mpt::lshift_signed_portable(32767, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 14), mpt::lshift_signed_portable(-32768, 14)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 14), mpt::lshift_signed_portable(-32767, 14)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 14), mpt::lshift_signed_portable(-32766, 14)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 14), mpt::lshift_signed_portable(-2, 14)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 14), mpt::lshift_signed_portable(-1, 14)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 14), mpt::lshift_signed_portable(0, 14)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 14), mpt::lshift_signed_portable(1, 14)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 14), mpt::lshift_signed_portable(2, 14)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 14), mpt::lshift_signed_portable(32766, 14)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 14), mpt::lshift_signed_portable(32767, 14)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 15), mpt::lshift_signed_portable(-32768, 15)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 15), mpt::lshift_signed_portable(-32767, 15)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 15), mpt::lshift_signed_portable(-32766, 15)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 15), mpt::lshift_signed_portable(-2, 15)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 15), mpt::lshift_signed_portable(-1, 15)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 15), mpt::lshift_signed_portable(0, 15)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 15), mpt::lshift_signed_portable(1, 15)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 15), mpt::lshift_signed_portable(2, 15)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 15), mpt::lshift_signed_portable(32766, 15)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 15), mpt::lshift_signed_portable(32767, 15)); #if MPT_CXX_AT_LEAST(20) || MPT_COMPILER_SHIFT_SIGNED #if MPT_COMPILER_GCC // #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshift-negative-value" #endif // MPT_COMPILER_GCC MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 1), (-32768) >> 1); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 1), (-32767) >> 1); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 1), (-32766) >> 1); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 1), (-2) >> 1); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 1), (-1) >> 1); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 1), (0) >> 1); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 1), (1) >> 1); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 1), (2) >> 1); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 1), (32766) >> 1); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 1), (32767) >> 1); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 14), (-32768) >> 14); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 14), (-32767) >> 14); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 14), (-32766) >> 14); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 14), (-2) >> 14); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 14), (-1) >> 14); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 14), (0) >> 14); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 14), (1) >> 14); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 14), (2) >> 14); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 14), (32766) >> 14); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 14), (32767) >> 14); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 15), (-32768) >> 15); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 15), (-32767) >> 15); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 15), (-32766) >> 15); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 15), (-2) >> 15); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 15), (-1) >> 15); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 15), (0) >> 15); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 15), (1) >> 15); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 15), (2) >> 15); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 15), (32766) >> 15); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 15), (32767) >> 15); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 1), (-32768) << 1); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 1), (-32767) << 1); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 1), (-32766) << 1); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 1), (-2) << 1); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 1), (-1) << 1); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 1), (0) << 1); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 1), (1) << 1); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 1), (2) << 1); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 1), (32766) << 1); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 1), (32767) << 1); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 14), (-32768) << 14); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 14), (-32767) << 14); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 14), (-32766) << 14); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 14), (-2) << 14); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 14), (-1) << 14); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 14), (0) << 14); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 14), (1) << 14); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 14), (2) << 14); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 14), (32766) << 14); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 14), (32767) << 14); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 15), (-32768) << 15); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 15), (-32767) << 15); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 15), (-32766) << 15); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 15), (-2) << 15); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 15), (-1) << 15); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 15), (0) << 15); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 15), (1) << 15); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 15), (2) << 15); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 15), (32766) << 15); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 15), (32767) << 15); #if MPT_COMPILER_GCC #pragma GCC diagnostic pop #endif // MPT_COMPILER_GCC #endif MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 1), mpt::rshift_signed_portable(0 - 0x80000000, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 1), mpt::rshift_signed_portable(-0x7fffffff, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 1), mpt::rshift_signed_portable(-0x7ffffffe, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 1), mpt::rshift_signed_portable(-1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 1), mpt::rshift_signed_portable(0, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 1), mpt::rshift_signed_portable(1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 1), mpt::rshift_signed_portable(0x7ffffffe, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 1), mpt::rshift_signed_portable(0x7fffffff, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 31), mpt::rshift_signed_portable(0 - 0x80000000, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 31), mpt::rshift_signed_portable(-0x7fffffff, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 31), mpt::rshift_signed_portable(-0x7ffffffe, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 31), mpt::rshift_signed_portable(-1, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 31), mpt::rshift_signed_portable(0, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 31), mpt::rshift_signed_portable(1, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 31), mpt::rshift_signed_portable(0x7ffffffe, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 31), mpt::rshift_signed_portable(0x7fffffff, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 1), mpt::lshift_signed_portable(0 - 0x80000000, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 1), mpt::lshift_signed_portable(-0x7fffffff, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 1), mpt::lshift_signed_portable(-0x7ffffffe, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 1), mpt::lshift_signed_portable(-1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 1), mpt::lshift_signed_portable(0, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 1), mpt::lshift_signed_portable(1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 1), mpt::lshift_signed_portable(0x7ffffffe, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 1), mpt::lshift_signed_portable(0x7fffffff, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 31), mpt::lshift_signed_portable(0 - 0x80000000, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 31), mpt::lshift_signed_portable(-0x7fffffff, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 31), mpt::lshift_signed_portable(-0x7ffffffe, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 31), mpt::lshift_signed_portable(-1, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 31), mpt::lshift_signed_portable(0, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 31), mpt::lshift_signed_portable(1, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 31), mpt::lshift_signed_portable(0x7ffffffe, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 31), mpt::lshift_signed_portable(0x7fffffff, 31)); #if MPT_CXX_AT_LEAST(20) || MPT_COMPILER_SHIFT_SIGNED #if MPT_COMPILER_GCC // #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshift-negative-value" #endif // MPT_COMPILER_GCC MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 1), mpt::rshift_signed_cxx20(0 - 0x80000000, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 1), mpt::rshift_signed_cxx20(-0x7fffffff, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 1), mpt::rshift_signed_cxx20(-0x7ffffffe, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 1), mpt::rshift_signed_cxx20(-1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 1), mpt::rshift_signed_cxx20(0, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 1), mpt::rshift_signed_cxx20(1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 1), mpt::rshift_signed_cxx20(0x7ffffffe, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 1), mpt::rshift_signed_cxx20(0x7fffffff, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 31), mpt::rshift_signed_cxx20(0 - 0x80000000, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 31), mpt::rshift_signed_cxx20(-0x7fffffff, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 31), mpt::rshift_signed_cxx20(-0x7ffffffe, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 31), mpt::rshift_signed_cxx20(-1, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 31), mpt::rshift_signed_cxx20(0, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 31), mpt::rshift_signed_cxx20(1, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 31), mpt::rshift_signed_cxx20(0x7ffffffe, 31)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 31), mpt::rshift_signed_cxx20(0x7fffffff, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 1), mpt::lshift_signed_cxx20(0 - 0x80000000, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 1), mpt::lshift_signed_cxx20(-0x7fffffff, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 1), mpt::lshift_signed_cxx20(-0x7ffffffe, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 1), mpt::lshift_signed_cxx20(-1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 1), mpt::lshift_signed_cxx20(0, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 1), mpt::lshift_signed_cxx20(1, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 1), mpt::lshift_signed_cxx20(0x7ffffffe, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 1), mpt::lshift_signed_cxx20(0x7fffffff, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 31), mpt::lshift_signed_cxx20(0 - 0x80000000, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 31), mpt::lshift_signed_cxx20(-0x7fffffff, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 31), mpt::lshift_signed_cxx20(-0x7ffffffe, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 31), mpt::lshift_signed_cxx20(-1, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 31), mpt::lshift_signed_cxx20(0, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 31), mpt::lshift_signed_cxx20(1, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 31), mpt::lshift_signed_cxx20(0x7ffffffe, 31)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 31), mpt::lshift_signed_cxx20(0x7fffffff, 31)); #if MPT_COMPILER_GCC #pragma GCC diagnostic pop #endif // MPT_COMPILER_GCC #endif MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 1), mpt::rshift_signed_portable(0ull - 0x8000000000000000ull, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 1), mpt::rshift_signed_portable(-0x7fffffffffffffffll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 1), mpt::rshift_signed_portable(-0x7ffffffffffffffell, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 1), mpt::rshift_signed_portable(-1ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 1), mpt::rshift_signed_portable(0ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 1), mpt::rshift_signed_portable(1ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 1), mpt::rshift_signed_portable(0x7ffffffffffffffell, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 1), mpt::rshift_signed_portable(0x7fffffffffffffffll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 63), mpt::rshift_signed_portable(0ull - 0x8000000000000000ull, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 63), mpt::rshift_signed_portable(-0x7fffffffffffffffll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 63), mpt::rshift_signed_portable(-0x7ffffffffffffffell, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 63), mpt::rshift_signed_portable(-1ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 63), mpt::rshift_signed_portable(0ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 63), mpt::rshift_signed_portable(1ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 63), mpt::rshift_signed_portable(0x7ffffffffffffffell, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 63), mpt::rshift_signed_portable(0x7fffffffffffffffll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 1), mpt::lshift_signed_portable(0ull - 0x8000000000000000ull, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 1), mpt::lshift_signed_portable(-0x7fffffffffffffffll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 1), mpt::lshift_signed_portable(-0x7ffffffffffffffell, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 1), mpt::lshift_signed_portable(-1ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 1), mpt::lshift_signed_portable(0ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 1), mpt::lshift_signed_portable(1ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 1), mpt::lshift_signed_portable(0x7ffffffffffffffell, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 1), mpt::lshift_signed_portable(0x7fffffffffffffffll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 63), mpt::lshift_signed_portable(0ull - 0x8000000000000000ull, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 63), mpt::lshift_signed_portable(-0x7fffffffffffffffll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 63), mpt::lshift_signed_portable(-0x7ffffffffffffffell, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 63), mpt::lshift_signed_portable(-1ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 63), mpt::lshift_signed_portable(0ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 63), mpt::lshift_signed_portable(1ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 63), mpt::lshift_signed_portable(0x7ffffffffffffffell, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 63), mpt::lshift_signed_portable(0x7fffffffffffffffll, 63)); #if MPT_CXX_AT_LEAST(20) || MPT_COMPILER_SHIFT_SIGNED #if MPT_COMPILER_GCC // #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshift-negative-value" #endif // MPT_COMPILER_GCC MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 1), mpt::rshift_signed_cxx20(0ull - 0x8000000000000000ull, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 1), mpt::rshift_signed_cxx20(-0x7fffffffffffffffll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 1), mpt::rshift_signed_cxx20(-0x7ffffffffffffffell, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 1), mpt::rshift_signed_cxx20(-1ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 1), mpt::rshift_signed_cxx20(0ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 1), mpt::rshift_signed_cxx20(1ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 1), mpt::rshift_signed_cxx20(0x7ffffffffffffffell, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 1), mpt::rshift_signed_cxx20(0x7fffffffffffffffll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 63), mpt::rshift_signed_cxx20(0ull - 0x8000000000000000ull, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 63), mpt::rshift_signed_cxx20(-0x7fffffffffffffffll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 63), mpt::rshift_signed_cxx20(-0x7ffffffffffffffell, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 63), mpt::rshift_signed_cxx20(-1ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 63), mpt::rshift_signed_cxx20(0ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 63), mpt::rshift_signed_cxx20(1ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 63), mpt::rshift_signed_cxx20(0x7ffffffffffffffell, 63)); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 63), mpt::rshift_signed_cxx20(0x7fffffffffffffffll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 1), mpt::lshift_signed_cxx20(0ull - 0x8000000000000000ull, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 1), mpt::lshift_signed_cxx20(-0x7fffffffffffffffll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 1), mpt::lshift_signed_cxx20(-0x7ffffffffffffffell, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 1), mpt::lshift_signed_cxx20(-1ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 1), mpt::lshift_signed_cxx20(0ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 1), mpt::lshift_signed_cxx20(1ll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 1), mpt::lshift_signed_cxx20(0x7ffffffffffffffell, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 1), mpt::lshift_signed_cxx20(0x7fffffffffffffffll, 1)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 63), mpt::lshift_signed_cxx20(0ull - 0x8000000000000000ull, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 63), mpt::lshift_signed_cxx20(-0x7fffffffffffffffll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 63), mpt::lshift_signed_cxx20(-0x7ffffffffffffffell, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 63), mpt::lshift_signed_cxx20(-1ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 63), mpt::lshift_signed_cxx20(0ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 63), mpt::lshift_signed_cxx20(1ll, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 63), mpt::lshift_signed_cxx20(0x7ffffffffffffffell, 63)); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 63), mpt::lshift_signed_cxx20(0x7fffffffffffffffll, 63)); #if MPT_COMPILER_GCC #pragma GCC diagnostic pop #endif // MPT_COMPILER_GCC #endif } } // namespace arithmetic_shift } // namespace base } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TESTS_ARITHMETIC_SHIFT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/tests/tests_base_math.hpp0000644000175000017500000001245414730562501023610 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TESTS_MATH_HPP #define MPT_BASE_TESTS_MATH_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/math.hpp" #include "mpt/base/namespace.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace base { namespace math { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/base/math") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { MPT_TEST_EXPECT_EQUAL(mpt::round(1.99f), 2.0f); MPT_TEST_EXPECT_EQUAL(mpt::round(1.5f), 2.0f); MPT_TEST_EXPECT_EQUAL(mpt::round(1.1f), 1.0f); MPT_TEST_EXPECT_EQUAL(mpt::round(-0.1f), 0.0f); MPT_TEST_EXPECT_EQUAL(mpt::round(-0.5f), -1.0f); MPT_TEST_EXPECT_EQUAL(mpt::round(-0.9f), -1.0f); MPT_TEST_EXPECT_EQUAL(mpt::round(-1.4f), -1.0f); MPT_TEST_EXPECT_EQUAL(mpt::round(-1.7f), -2.0f); MPT_TEST_EXPECT_EQUAL(mpt::round(1.99), 2.0); MPT_TEST_EXPECT_EQUAL(mpt::round(1.5), 2.0); MPT_TEST_EXPECT_EQUAL(mpt::round(1.1), 1.0); MPT_TEST_EXPECT_EQUAL(mpt::round(-0.1), 0.0); MPT_TEST_EXPECT_EQUAL(mpt::round(-0.5), -1.0); MPT_TEST_EXPECT_EQUAL(mpt::round(-0.9), -1.0); MPT_TEST_EXPECT_EQUAL(mpt::round(-1.4), -1.0); MPT_TEST_EXPECT_EQUAL(mpt::round(-1.7), -2.0); MPT_TEST_EXPECT_EQUAL(mpt::round(1.99l), 2.0l); MPT_TEST_EXPECT_EQUAL(mpt::round(1.5l), 2.0l); MPT_TEST_EXPECT_EQUAL(mpt::round(1.1l), 1.0l); MPT_TEST_EXPECT_EQUAL(mpt::round(-0.1l), 0.0l); MPT_TEST_EXPECT_EQUAL(mpt::round(-0.5l), -1.0l); MPT_TEST_EXPECT_EQUAL(mpt::round(-0.9l), -1.0l); MPT_TEST_EXPECT_EQUAL(mpt::round(-1.4l), -1.0l); MPT_TEST_EXPECT_EQUAL(mpt::round(-1.7l), -2.0l); MPT_TEST_EXPECT_EQUAL(std::ceil(1.99f), 2.0f); MPT_TEST_EXPECT_EQUAL(std::ceil(1.5f), 2.0f); MPT_TEST_EXPECT_EQUAL(std::ceil(1.1f), 2.0f); MPT_TEST_EXPECT_EQUAL(std::ceil(-0.1f), 0.0f); MPT_TEST_EXPECT_EQUAL(std::ceil(-0.5f), 0.0f); MPT_TEST_EXPECT_EQUAL(std::ceil(-0.9f), 0.0f); MPT_TEST_EXPECT_EQUAL(std::ceil(-1.4f), -1.0f); MPT_TEST_EXPECT_EQUAL(std::ceil(-1.7f), -1.0f); MPT_TEST_EXPECT_EQUAL(std::ceil(1.99), 2.0); MPT_TEST_EXPECT_EQUAL(std::ceil(1.5), 2.0); MPT_TEST_EXPECT_EQUAL(std::ceil(1.1), 2.0); MPT_TEST_EXPECT_EQUAL(std::ceil(-0.1), 0.0); MPT_TEST_EXPECT_EQUAL(std::ceil(-0.5), 0.0); MPT_TEST_EXPECT_EQUAL(std::ceil(-0.9), 0.0); MPT_TEST_EXPECT_EQUAL(std::ceil(-1.4), -1.0); MPT_TEST_EXPECT_EQUAL(std::ceil(-1.7), -1.0); MPT_TEST_EXPECT_EQUAL(std::ceil(1.99l), 2.0l); MPT_TEST_EXPECT_EQUAL(std::ceil(1.5l), 2.0l); MPT_TEST_EXPECT_EQUAL(std::ceil(1.1l), 2.0l); MPT_TEST_EXPECT_EQUAL(std::ceil(-0.1l), 0.0l); MPT_TEST_EXPECT_EQUAL(std::ceil(-0.5l), 0.0l); MPT_TEST_EXPECT_EQUAL(std::ceil(-0.9l), 0.0l); MPT_TEST_EXPECT_EQUAL(std::ceil(-1.4l), -1.0l); MPT_TEST_EXPECT_EQUAL(std::ceil(-1.7l), -1.0l); MPT_TEST_EXPECT_EQUAL(std::floor(1.99f), 1.0f); MPT_TEST_EXPECT_EQUAL(std::floor(1.5f), 1.0f); MPT_TEST_EXPECT_EQUAL(std::floor(1.1f), 1.0f); MPT_TEST_EXPECT_EQUAL(std::floor(-0.1f), -1.0f); MPT_TEST_EXPECT_EQUAL(std::floor(-0.5f), -1.0f); MPT_TEST_EXPECT_EQUAL(std::floor(-0.9f), -1.0f); MPT_TEST_EXPECT_EQUAL(std::floor(-1.4f), -2.0f); MPT_TEST_EXPECT_EQUAL(std::floor(-1.7f), -2.0f); MPT_TEST_EXPECT_EQUAL(std::floor(1.99), 1.0); MPT_TEST_EXPECT_EQUAL(std::floor(1.5), 1.0); MPT_TEST_EXPECT_EQUAL(std::floor(1.1), 1.0); MPT_TEST_EXPECT_EQUAL(std::floor(-0.1), -1.0); MPT_TEST_EXPECT_EQUAL(std::floor(-0.5), -1.0); MPT_TEST_EXPECT_EQUAL(std::floor(-0.9), -1.0); MPT_TEST_EXPECT_EQUAL(std::floor(-1.4), -2.0); MPT_TEST_EXPECT_EQUAL(std::floor(-1.7), -2.0); MPT_TEST_EXPECT_EQUAL(std::floor(1.99l), 1.0l); MPT_TEST_EXPECT_EQUAL(std::floor(1.5l), 1.0l); MPT_TEST_EXPECT_EQUAL(std::floor(1.1l), 1.0l); MPT_TEST_EXPECT_EQUAL(std::floor(-0.1l), -1.0l); MPT_TEST_EXPECT_EQUAL(std::floor(-0.5l), -1.0l); MPT_TEST_EXPECT_EQUAL(std::floor(-0.9l), -1.0l); MPT_TEST_EXPECT_EQUAL(std::floor(-1.4l), -2.0l); MPT_TEST_EXPECT_EQUAL(std::floor(-1.7l), -2.0l); MPT_TEST_EXPECT_EQUAL(mpt::trunc(1.99f), 1.0f); MPT_TEST_EXPECT_EQUAL(mpt::trunc(1.5f), 1.0f); MPT_TEST_EXPECT_EQUAL(mpt::trunc(1.1f), 1.0f); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-0.1f), 0.0f); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-0.5f), 0.0f); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-0.9f), 0.0f); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-1.4f), -1.0f); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-1.7f), -1.0f); MPT_TEST_EXPECT_EQUAL(mpt::trunc(1.99), 1.0); MPT_TEST_EXPECT_EQUAL(mpt::trunc(1.5), 1.0); MPT_TEST_EXPECT_EQUAL(mpt::trunc(1.1), 1.0); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-0.1), 0.0); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-0.5), 0.0); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-0.9), 0.0); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-1.4), -1.0); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-1.7), -1.0); MPT_TEST_EXPECT_EQUAL(mpt::trunc(1.99l), 1.0l); MPT_TEST_EXPECT_EQUAL(mpt::trunc(1.5l), 1.0l); MPT_TEST_EXPECT_EQUAL(mpt::trunc(1.1l), 1.0l); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-0.1l), 0.0l); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-0.5l), 0.0l); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-0.9l), 0.0l); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-1.4l), -1.0l); MPT_TEST_EXPECT_EQUAL(mpt::trunc(-1.7l), -1.0l); } } // namespace math } // namespace base } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TESTS_MATH_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/tests/tests_base_saturate_round.hpp0000644000175000017500000000664414730567171025732 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TESTS_SATURATE_ROUND_HPP #define MPT_BASE_TESTS_SATURATE_ROUND_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_round.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace base { namespace saturate_round { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/base/saturate_round") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { MPT_TEST_EXPECT_EQUAL(mpt::saturate_trunc(static_cast(std::numeric_limits::max())), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(std::numeric_limits::max() + 0.1), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(std::numeric_limits::max() - 0.4), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(std::numeric_limits::min() + 0.1), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(std::numeric_limits::min() - 0.1), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(std::numeric_limits::max() + 0.499), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(110.1), 110); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(-110.1), -110); MPT_TEST_EXPECT_EQUAL(mpt::saturate_trunc(-0.6), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_trunc(-0.5), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_trunc(-0.4), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_trunc(0.4), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_trunc(0.5), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_trunc(0.6), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(-0.6), -1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(-0.5), -1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(-0.4), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(0.4), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(0.5), 1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(0.6), 1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_ceil(-0.6), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_ceil(-0.5), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_ceil(-0.4), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_ceil(0.4), 1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_ceil(0.5), 1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_ceil(0.6), 1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_floor(-0.6), -1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_floor(-0.5), -1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_floor(-0.4), -1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_floor(0.4), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_floor(0.5), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_floor(0.6), 0); // These should fail to compile //mpt::saturate_round(1.0); //mpt::saturate_round(1.0); //mpt::saturate_round(1.0); // This should trigger assert in Round. //MPT_TEST_EXPECT_EQUAL(mpt::saturate_round(-129), 0); } } // namespace saturate_round } // namespace base } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TESTS_SATURATE_ROUND_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/tests/tests_base_saturate_cast.hpp0000644000175000017500000001336314730245406025523 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TESTS_SATURATE_CAST_HPP #define MPT_BASE_TESTS_SATURATE_CAST_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace base { namespace saturate_cast { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/base/saturate_cast") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { // trivials MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(-1), -1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(0), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(1), 1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::min()), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max()), std::numeric_limits::max()); // signed / unsigned MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::min()), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max()), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::min()), (int32)std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max()), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::min()), (int64)std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max()), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::min()), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max()), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::min()), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max()), (uint32)std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::min()), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max()), (uint64)std::numeric_limits::max()); // overflow MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::min() - 1), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max() + 1), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::min() - int64(1)), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max() + int64(1)), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::min() - 1), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max() + 1), (uint16)std::numeric_limits::max() + 1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::min() - int64(1)), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max() + int64(1)), (uint32)std::numeric_limits::max() + 1); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(32000)), 127); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(-32000)), -128); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(32000)), 127); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(64000)), 127); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(32000)), 255); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(-32000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(32000)), 255); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(64000)), 255); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(32000)), 32000); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(-32000)), -32000); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(32000)), 32000); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(64000)), 32767); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(32000)), 32000); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(-32000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(32000)), 32000); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(64000)), 64000); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(32000)), 32000); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(-32000)), -32000); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(32000)), 32000); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(64000)), 64000); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(32000)), 32000u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(int16(-32000)), 0u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(32000)), 32000u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(uint16(64000)), 64000u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max() - 1), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast(std::numeric_limits::max() - 1), std::numeric_limits::max()); } } // namespace saturate_cast } // namespace base } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TESTS_SATURATE_CAST_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/tests/tests_base_bit.hpp0000644000175000017500000002604014333116164023430 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TESTS_BASE_BIT_HPP #define MPT_BASE_TESTS_BASE_BIT_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace base { namespace bit { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/base/bit") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { #if MPT_CXX_BEFORE(20) MPT_TEST_EXPECT_EQUAL(mpt::get_endian(), mpt::endian_probe()); #endif MPT_MAYBE_CONSTANT_IF (mpt::endian_is_little()) { MPT_TEST_EXPECT_EQUAL(mpt::get_endian(), mpt::endian::little); MPT_MAYBE_CONSTANT_IF ((mpt::endian::native == mpt::endian::little) || (mpt::endian::native == mpt::endian::big)) { MPT_TEST_EXPECT_EQUAL(mpt::endian::native, mpt::endian::little); } #if MPT_CXX_BEFORE(20) MPT_TEST_EXPECT_EQUAL(mpt::endian_probe(), mpt::endian::little); #endif } MPT_MAYBE_CONSTANT_IF (mpt::endian_is_big()) { MPT_TEST_EXPECT_EQUAL(mpt::get_endian(), mpt::endian::big); MPT_MAYBE_CONSTANT_IF ((mpt::endian::native == mpt::endian::little) || (mpt::endian::native == mpt::endian::big)) { MPT_TEST_EXPECT_EQUAL(mpt::endian::native, mpt::endian::big); } #if MPT_CXX_BEFORE(20) MPT_TEST_EXPECT_EQUAL(mpt::endian_probe(), mpt::endian::big); #endif } MPT_TEST_EXPECT_EQUAL(mpt::popcount(static_cast(int32(-1))), 32); MPT_TEST_EXPECT_EQUAL(mpt::popcount(0u), 0); MPT_TEST_EXPECT_EQUAL(mpt::popcount(1u), 1); MPT_TEST_EXPECT_EQUAL(mpt::popcount(2u), 1); MPT_TEST_EXPECT_EQUAL(mpt::popcount(3u), 2); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(0u), false); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(1u), true); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(2u), true); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(3u), false); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(4u), true); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(5u), false); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(6u), false); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(7u), false); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(8u), true); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(9u), false); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(uint32(0x7fffffffu)), false); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(uint32(0x80000000u)), true); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(uint32(0x80000001u)), false); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(uint32(0xfffffffeu)), false); MPT_TEST_EXPECT_EQUAL(mpt::has_single_bit(uint32(0xffffffffu)), false); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(0u), 1u); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(1u), 1u); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(2u), 2u); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(3u), 4u); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(4u), 4u); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(5u), 8u); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(6u), 8u); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(7u), 8u); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(8u), 8u); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(9u), 16u); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(uint32(0x7fffffffu)), 0x80000000u); MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(uint32(0x80000000u)), 0x80000000u); //MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(uint32(0x80000001u)), 0u); //MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(uint32(0xfffffffeu)), 0u); //MPT_TEST_EXPECT_EQUAL(mpt::bit_ceil(uint32(0xffffffffu)), 0u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(0u), 0u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(1u), 1u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(2u), 2u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(3u), 2u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(4u), 4u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(5u), 4u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(6u), 4u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(7u), 4u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(8u), 8u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(9u), 8u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(uint32(0x7fffffffu)), 0x40000000u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(uint32(0x80000000u)), 0x80000000u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(uint32(0x80000001u)), 0x80000000u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(uint32(0xfffffffeu)), 0x80000000u); MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(uint32(0xffffffffu)), 0x80000000u); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(0u), 0); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(1u), 1); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(2u), 2); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(3u), 2); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(4u), 3); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(5u), 3); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(6u), 3); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(7u), 3); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(8u), 4); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(9u), 4); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0x7fffffffu)), 31); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0x80000000u)), 32); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0x80000001u)), 32); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0xfffffffeu)), 32); MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0xffffffffu)), 32); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b00000000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b00000001)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b00000011)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b00000111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b00001111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b00011111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b00111111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b01111111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b11111111)), 8); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b11111110)), 7); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b11111100)), 6); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b11111000)), 5); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b11110000)), 4); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b11100000)), 3); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b11000000)), 2); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b10000000)), 1); MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b00000000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b00000000)), 8); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b00000001)), 7); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b00000011)), 6); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b00000111)), 5); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b00001111)), 4); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b00011111)), 3); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b00111111)), 2); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b01111111)), 1); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b11111111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b11111110)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b11111100)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b11111000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b11110000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b11100000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b11000000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b10000000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countl_zero(uint8(0b00000000)), 8); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b00000000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b00000001)), 1); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b00000011)), 2); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b00000111)), 3); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b00001111)), 4); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b00011111)), 5); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b00111111)), 6); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b01111111)), 7); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b11111111)), 8); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b11111110)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b11111100)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b11111000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b11110000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b11100000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b11000000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b10000000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_one(uint8(0b00000000)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b00000000)), 8); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b00000001)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b00000011)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b00000111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b00001111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b00011111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b00111111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b01111111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b11111111)), 0); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b11111110)), 1); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b11111100)), 2); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b11111000)), 3); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b11110000)), 4); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b11100000)), 5); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b11000000)), 6); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b10000000)), 7); MPT_TEST_EXPECT_EQUAL(mpt::countr_zero(uint8(0b00000000)), 8); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0xffffffffu), 32); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0xfffffffeu), 31); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x80000000u), 31); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x7fffffffu), 31); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x7ffffffeu), 30); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x00000007u), 3); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x00000006u), 2); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x00000005u), 2); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x00000004u), 2); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x00000003u), 2); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x00000002u), 1); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x00000001u), 1); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x00000000u), 0); MPT_TEST_EXPECT_EQUAL(mpt::byteswap(uint8(0x12)), 0x12); MPT_TEST_EXPECT_EQUAL(mpt::byteswap(uint16(0x1234)), 0x3412); MPT_TEST_EXPECT_EQUAL(mpt::byteswap(uint32(0x12345678u)), 0x78563412u); MPT_TEST_EXPECT_EQUAL(mpt::byteswap(uint64(0x123456789abcdef0ull)), 0xf0debc9a78563412ull); MPT_TEST_EXPECT_EQUAL(mpt::byteswap(int8(std::numeric_limits::min())), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::byteswap(int16(std::numeric_limits::min())), int16(0x80)); MPT_TEST_EXPECT_EQUAL(mpt::byteswap(int32(std::numeric_limits::min())), int32(0x80)); MPT_TEST_EXPECT_EQUAL(mpt::byteswap(int64(std::numeric_limits::min())), int64(0x80)); } } // namespace bit } // namespace base } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TESTS_BASE_BIT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/base/tests/tests_base_numeric.hpp0000644000175000017500000000631514575023246024325 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TESTS_NUMERIC_HPP #define MPT_BASE_TESTS_NUMERIC_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/numeric.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace base { namespace numeric { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/base/numeric") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(0u, 4u), 0u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(1u, 4u), 4u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(2u, 4u), 4u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(3u, 4u), 4u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(4u, 4u), 4u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(5u, 4u), 8u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 5u, 4u), std::numeric_limits::max() - 3u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 4u, 4u), std::numeric_limits::max() - 3u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 3u, 4u), std::numeric_limits::max() - 3u); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 2u, 4u), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 1u, 4u), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 0u, 4u), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(0, 4), 0); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(1, 4), 4); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(2, 4), 4); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(3, 4), 4); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(4, 4), 4); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(5, 4), 8); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 5, 4), std::numeric_limits::max() - 3); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 4, 4), std::numeric_limits::max() - 3); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 3, 4), std::numeric_limits::max() - 3); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 2, 4), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 1, 4), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::saturate_align_up(std::numeric_limits::max() - 0, 4), std::numeric_limits::max()); } } // namespace numeric } // namespace base } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TESTS_NUMERIC_HPP libopenmpt-0.8.1+release.autotools/src/mpt/string_transcode/0000755000175000017500000000000015023302361021270 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/string_transcode/macros.hpp0000644000175000017500000000130414107230757023216 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_STRING_TRANSCODE_MACROS_HPP #define MPT_STRING_TRANSCODE_MACROS_HPP #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include // The MPT_UTF8_STRING allows specifying UTF8 char arrays. // The resulting type is mpt::ustring and the construction might require runtime translation, // i.e. it is NOT generally available at compile time. // Use explicit UTF8 encoding, // i.e. U+00FC (LATIN SMALL LETTER U WITH DIAERESIS) would be written as "\xC3\xBC". #define MPT_UTF8_STRING(x) mpt::transcode(mpt::common_encoding::utf8, std::string{x}) #endif // MPT_STRING_TRANSCODE_MACROS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/string_transcode/transcode.hpp0000644000175000017500000031032115017332722023712 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_STRING_TRANSCODE_TRANSCODE_HPP #define MPT_STRING_TRANSCODE_TRANSCODE_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/detect/mfc.hpp" #include "mpt/out_of_memory/out_of_memory.hpp" #include "mpt/string/types.hpp" #include "mpt/string/utility.hpp" #include #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) #include #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #include #include #include #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) #include #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #include #include #include #if MPT_OS_DJGPP #include #endif // MPT_OS_DJGPP #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS #if MPT_OS_DJGPP #include #endif // MPT_OS_DJGPP namespace mpt { inline namespace MPT_INLINE_NS { inline constexpr char32_t UCS4ud = 0xffffffffu; // default 1:1 mapping inline constexpr char32_t CharsetTableISO8859_1[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff}; inline constexpr char32_t CharsetTableISO8859_15[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20ac, 0x00a5, 0x0160, 0x00a7, 0x0161, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x017d, 0x00b5, 0x00b6, 0x00b7, 0x017e, 0x00b9, 0x00ba, 0x00bb, 0x0152, 0x0153, 0x0178, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff}; inline constexpr char32_t CharsetTableWindows1252[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f, 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff}; // cat CP437.TXT | grep -v '^#' | head -n 256 | awk '{print $2;}' | ./tablerize.py > cp437.h /* #!/usr/bin/env python3 import fileinput i = 0 for line in fileinput.input(): if i % 16 == 0: print("\t", end='') print(line.strip(), end='') i = i + 1 if i % 256 != 0: print(",", end='') if i % 16 != 0: print(" ", end='') if i % 16 == 0: if i % 256 == 0: print("};\n", end='') else: print("\n", end='') */ inline constexpr char32_t CharsetTableCP437[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP737[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03c9, 0x03ac, 0x03ad, 0x03ae, 0x03ca, 0x03af, 0x03cc, 0x03cd, 0x03cb, 0x03ce, 0x0386, 0x0388, 0x0389, 0x038a, 0x038c, 0x038e, 0x038f, 0x00b1, 0x2265, 0x2264, 0x03aa, 0x03ab, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP775[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x0106, 0x00fc, 0x00e9, 0x0101, 0x00e4, 0x0123, 0x00e5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012b, 0x0179, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x014d, 0x00f6, 0x0122, 0x00a2, 0x015a, 0x015b, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x00a4, 0x0100, 0x012a, 0x00f3, 0x017b, 0x017c, 0x017a, 0x201d, 0x00a6, 0x00a9, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x0141, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010c, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255d, 0x012e, 0x0160, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x0172, 0x016a, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x017d, 0x0105, 0x010d, 0x0119, 0x0117, 0x012f, 0x0161, 0x0173, 0x016b, 0x017e, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x00d3, 0x00df, 0x014c, 0x0143, 0x00f5, 0x00d5, 0x00b5, 0x0144, 0x0136, 0x0137, 0x013b, 0x013c, 0x0146, 0x0112, 0x0145, 0x2019, 0x00ad, 0x00b1, 0x201c, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x201e, 0x00b0, 0x2219, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP850[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x00c0, 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, 0x00f0, 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x0131, 0x00cd, 0x00ce, 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, 0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe, 0x00de, 0x00da, 0x00db, 0x00d9, 0x00fd, 0x00dd, 0x00af, 0x00b4, 0x00ad, 0x00b1, 0x2017, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP852[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x016f, 0x0107, 0x00e7, 0x0142, 0x00eb, 0x0150, 0x0151, 0x00ee, 0x0179, 0x00c4, 0x0106, 0x00c9, 0x0139, 0x013a, 0x00f4, 0x00f6, 0x013d, 0x013e, 0x015a, 0x015b, 0x00d6, 0x00dc, 0x0164, 0x0165, 0x0141, 0x00d7, 0x010d, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x0104, 0x0105, 0x017d, 0x017e, 0x0118, 0x0119, 0x00ac, 0x017a, 0x010c, 0x015f, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x011a, 0x015e, 0x2563, 0x2551, 0x2557, 0x255d, 0x017b, 0x017c, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x0102, 0x0103, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, 0x0111, 0x0110, 0x010e, 0x00cb, 0x010f, 0x0147, 0x00cd, 0x00ce, 0x011b, 0x2518, 0x250c, 0x2588, 0x2584, 0x0162, 0x016e, 0x2580, 0x00d3, 0x00df, 0x00d4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00da, 0x0155, 0x0170, 0x00fd, 0x00dd, 0x0163, 0x00b4, 0x00ad, 0x02dd, 0x02db, 0x02c7, 0x02d8, 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x02d9, 0x0171, 0x0158, 0x0159, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP855[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0459, 0x0409, 0x045a, 0x040a, 0x045b, 0x040b, 0x045c, 0x040c, 0x045e, 0x040e, 0x045f, 0x040f, 0x044e, 0x042e, 0x044a, 0x042a, 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255d, 0x0439, 0x0419, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x043a, 0x041a, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, 0x043b, 0x041b, 0x043c, 0x041c, 0x043d, 0x041d, 0x043e, 0x041e, 0x043f, 0x2518, 0x250c, 0x2588, 0x2584, 0x041f, 0x044f, 0x2580, 0x042f, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044c, 0x042c, 0x2116, 0x00ad, 0x044b, 0x042b, 0x0437, 0x0417, 0x0448, 0x0428, 0x044d, 0x042d, 0x0449, 0x0429, 0x0447, 0x0427, 0x00a7, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP857[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x0131, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x0130, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x015e, 0x015f, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x011e, 0x011f, 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x00c0, 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, 0x00ba, 0x00aa, 0x00ca, 0x00cb, 0x00c8, UCS4ud, 0x00cd, 0x00ce, 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, 0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, UCS4ud, 0x00d7, 0x00da, 0x00db, 0x00d9, 0x00ec, 0x00ff, 0x00af, 0x00b4, 0x00ad, 0x00b1, UCS4ud, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP860[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e3, 0x00e0, 0x00c1, 0x00e7, 0x00ea, 0x00ca, 0x00e8, 0x00cd, 0x00d4, 0x00ec, 0x00c3, 0x00c2, 0x00c9, 0x00c0, 0x00c8, 0x00f4, 0x00f5, 0x00f2, 0x00da, 0x00f9, 0x00cc, 0x00d5, 0x00dc, 0x00a2, 0x00a3, 0x00d9, 0x20a7, 0x00d3, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x00d2, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP861[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00d0, 0x00f0, 0x00de, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00fe, 0x00fb, 0x00dd, 0x00fd, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00c1, 0x00cd, 0x00d3, 0x00da, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP862[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP863[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00c2, 0x00e0, 0x00b6, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x2017, 0x00c0, 0x00a7, 0x00c9, 0x00c8, 0x00ca, 0x00f4, 0x00cb, 0x00cf, 0x00fb, 0x00f9, 0x00a4, 0x00d4, 0x00dc, 0x00a2, 0x00a3, 0x00d9, 0x00db, 0x0192, 0x00a6, 0x00b4, 0x00f3, 0x00fa, 0x00a8, 0x00b8, 0x00b3, 0x00af, 0x00ce, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00be, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP864[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x066a, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00b0, 0x00b7, 0x2219, 0x221a, 0x2592, 0x2500, 0x2502, 0x253c, 0x2524, 0x252c, 0x251c, 0x2534, 0x2510, 0x250c, 0x2514, 0x2518, 0x03b2, 0x221e, 0x03c6, 0x00b1, 0x00bd, 0x00bc, 0x2248, 0x00ab, 0x00bb, 0xfef7, 0xfef8, UCS4ud, UCS4ud, 0xfefb, 0xfefc, UCS4ud, 0x00a0, 0x00ad, 0xfe82, 0x00a3, 0x00a4, 0xfe84, UCS4ud, UCS4ud, 0xfe8e, 0xfe8f, 0xfe95, 0xfe99, 0x060c, 0xfe9d, 0xfea1, 0xfea5, 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xfed1, 0x061b, 0xfeb1, 0xfeb5, 0xfeb9, 0x061f, 0x00a2, 0xfe80, 0xfe81, 0xfe83, 0xfe85, 0xfeca, 0xfe8b, 0xfe8d, 0xfe91, 0xfe93, 0xfe97, 0xfe9b, 0xfe9f, 0xfea3, 0xfea7, 0xfea9, 0xfeab, 0xfead, 0xfeaf, 0xfeb3, 0xfeb7, 0xfebb, 0xfebf, 0xfec1, 0xfec5, 0xfecb, 0xfecf, 0x00a6, 0x00ac, 0x00f7, 0x00d7, 0xfec9, 0x0640, 0xfed3, 0xfed7, 0xfedb, 0xfedf, 0xfee3, 0xfee7, 0xfeeb, 0xfeed, 0xfeef, 0xfef3, 0xfebd, 0xfecc, 0xfece, 0xfecd, 0xfee1, 0xfe7d, 0x0651, 0xfee5, 0xfee9, 0xfeec, 0xfef0, 0xfef2, 0xfed0, 0xfed5, 0xfef5, 0xfef6, 0xfedd, 0xfed9, 0xfef1, 0x25a0, UCS4ud}; inline constexpr char32_t CharsetTableCP865[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00a4, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP866[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040e, 0x045e, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x2116, 0x00a4, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP869[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, 0x0386, UCS4ud, 0x00b7, 0x00ac, 0x00a6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, 0x038a, 0x03aa, 0x038c, UCS4ud, UCS4ud, 0x038e, 0x03ab, 0x00a9, 0x038f, 0x00b2, 0x00b3, 0x03ac, 0x00a3, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, 0x03cd, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00bd, 0x0398, 0x0399, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039a, 0x039b, 0x039c, 0x039d, 0x2563, 0x2551, 0x2557, 0x255d, 0x039e, 0x039f, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x03a0, 0x03a1, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03b1, 0x03b2, 0x03b3, 0x2518, 0x250c, 0x2588, 0x2584, 0x03b4, 0x03b5, 0x2580, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x0384, 0x00ad, 0x00b1, 0x03c5, 0x03c6, 0x03c7, 0x00a7, 0x03c8, 0x0385, 0x00b0, 0x00a8, 0x03c9, 0x03cb, 0x03b0, 0x03ce, 0x25a0, 0x00a0}; inline constexpr char32_t CharsetTableCP874[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x20AC, UCS4ud, UCS4ud, UCS4ud, UCS4ud, 0x2026, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, 0x0E38, 0x0E39, 0x0E3A, UCS4ud, UCS4ud, UCS4ud, UCS4ud, 0x0E3F, 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, UCS4ud, UCS4ud, UCS4ud, UCS4ud}; // inline constexpr char32_t CharsetTableAmiga[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2592, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x2013, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff}; // Based on RISCOSI.TXT from , // with gaps filled in from standard set at . inline constexpr char32_t CharsetTableRISC_OS[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x20AC, 0x0174, 0x0175, 0x25f0, 0x1fbc0, 0x0176, 0x0177, 0xfffd, 0x21e6, 0x21e8, 0x21e9, 0x21e7, 0x2026, 0x2122, 0x2030, 0x2022, 0x2018, 0x2019, 0x2039, 0x203A, 0x201C, 0x201D, 0x201E, 0x2013, 0x2014, 0x2212, 0x0152, 0x0153, 0x2020, 0x2021, 0xFB01, 0xFB02, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff}; // inline constexpr char32_t CharsetTableAtariST[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x00DF, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x00E3, 0x00F5, 0x00D8, 0x00F8, 0x0153, 0x0152, 0x00C0, 0x00C3, 0x00D5, 0x00A8, 0x00B4, 0x2020, 0x00B6, 0x00A9, 0x00AE, 0x2122, 0x0133, 0x0132, 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DB, 0x05DC, 0x05DE, 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05DF, 0x05DA, 0x05DD, 0x05E3, 0x05E5, 0x00A7, 0x2227, 0x221E, 0x03B1, 0x03B2, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x222E, 0x03C6, 0x2208, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x00B3, 0x00AF}; template inline void encode_single_utf16(Tdststring & out, char32_t ucs4) { static_assert(sizeof(typename Tdststring::value_type) == 2); if (ucs4 <= 0xffff) { out.push_back(static_cast(static_cast(static_cast(ucs4)))); } else { uint32 surrogate = static_cast(ucs4) - 0x10000; uint16 hi_sur = static_cast((0x36 << 10) | ((surrogate >> 10) & ((1 << 10) - 1))); uint16 lo_sur = static_cast((0x37 << 10) | ((surrogate >> 0) & ((1 << 10) - 1))); out.push_back(static_cast(hi_sur)); out.push_back(static_cast(lo_sur)); } } template inline char32_t decode_single_utf16(std::size_t & i, const Tsrcstring & in) { static_assert(sizeof(typename Tsrcstring::value_type) == 2); char32_t ucs4 = 0; typename Tsrcstring::value_type wc = in[i]; uint16 c = static_cast(wc); if (i + 1 < in.length()) { // check for surrogate pair uint16 hi_sur = in[i + 0]; uint16 lo_sur = in[i + 1]; if (hi_sur >> 10 == 0x36 && lo_sur >> 10 == 0x37) { // surrogate pair ++i; hi_sur &= (1 << 10) - 1; lo_sur &= (1 << 10) - 1; ucs4 = (static_cast(hi_sur) << 10) | (static_cast(lo_sur) << 0); } else { // no surrogate pair ucs4 = static_cast(c); } } else { // no surrogate possible ucs4 = static_cast(c); } return ucs4; } inline void encode_single_wide(mpt::widestring & out, char32_t ucs4) { if constexpr (sizeof(mpt::widechar) == 2) { if (ucs4 <= 0xffff) { out.push_back(static_cast(static_cast(static_cast(ucs4)))); } else { uint32 surrogate = static_cast(ucs4) - 0x10000; uint16 hi_sur = static_cast((0x36 << 10) | ((surrogate >> 10) & ((1 << 10) - 1))); uint16 lo_sur = static_cast((0x37 << 10) | ((surrogate >> 0) & ((1 << 10) - 1))); out.push_back(static_cast(hi_sur)); out.push_back(static_cast(lo_sur)); } } else { out.push_back(static_cast(static_cast(ucs4))); } } inline char32_t decode_single_wide(std::size_t & i, const mpt::widestring & in) { char32_t ucs4 = 0; mpt::widechar wc = in[i]; if constexpr (sizeof(mpt::widechar) == 2) { uint16 c = static_cast(wc); if (i + 1 < in.length()) { // check for surrogate pair uint16 hi_sur = in[i + 0]; uint16 lo_sur = in[i + 1]; if (hi_sur >> 10 == 0x36 && lo_sur >> 10 == 0x37) { // surrogate pair ++i; hi_sur &= (1 << 10) - 1; lo_sur &= (1 << 10) - 1; ucs4 = (static_cast(hi_sur) << 10) | (static_cast(lo_sur) << 0); } else { // no surrogate pair ucs4 = static_cast(c); } } else { // no surrogate possible ucs4 = static_cast(c); } } else { ucs4 = static_cast(static_cast(wc)); } return ucs4; } template inline mpt::widestring decode_8bit(const Tsrcstring & str, const char32_t (&table)[256], mpt::widechar replacement = MPT_WIDECHAR('\uFFFD')) { mpt::widestring res; res.reserve(str.length()); for (std::size_t i = 0; i < str.length(); ++i) { std::size_t c = static_cast(mpt::char_value(str[i])); if (c < std::size(table)) { encode_single_wide(res, table[c]); } else { res.push_back(replacement); } } return res; } template inline Tdststring encode_8bit(const mpt::widestring & str, const char32_t (&table)[256], char replacement = '?') { Tdststring res; res.reserve(str.length()); for (std::size_t i = 0; i < str.length(); ++i) { char32_t c = decode_single_wide(i, str); bool found = false; // Try non-control characters first. // In cases where there are actual characters mirrored in this range (like in AMS/AMS2 character sets), // characters in the common range are preferred this way. for (std::size_t x = 0x20; x < std::size(table); ++x) { if (c == table[x]) { res.push_back(static_cast(static_cast(x))); found = true; break; } } if (!found) { // try control characters for (std::size_t x = 0x00; x < std::size(table) && x < 0x20; ++x) { if (c == table[x]) { res.push_back(static_cast(static_cast(x))); found = true; break; } } } if (!found) { res.push_back(replacement); } } return res; } template inline mpt::widestring decode_8bit_no_c1(const Tsrcstring & str, const char32_t (&table)[256], mpt::widechar replacement = MPT_WIDECHAR('\uFFFD')) { mpt::widestring res; res.reserve(str.length()); for (std::size_t i = 0; i < str.length(); ++i) { std::size_t c = static_cast(mpt::char_value(str[i])); if ((0x80 <= c) && (c <= 0x9f)) { res.push_back(replacement); } else if (c < std::size(table)) { encode_single_wide(res, table[c]); } else { res.push_back(replacement); } } return res; } template inline Tdststring encode_8bit_no_c1(const mpt::widestring & str, const char32_t (&table)[256], char replacement = '?') { Tdststring res; res.reserve(str.length()); for (std::size_t i = 0; i < str.length(); ++i) { char32_t c = decode_single_wide(i, str); bool found = false; // Try non-control characters first. // In cases where there are actual characters mirrored in this range (like in AMS/AMS2 character sets), // characters in the common range are preferred this way. for (std::size_t x = 0x20; x < std::size(table); ++x) { if ((0x80 <= c) && (c <= 0x9f)) { continue; } if (c == table[x]) { res.push_back(static_cast(static_cast(x))); found = true; break; } } if (!found) { // try control characters for (std::size_t x = 0x00; x < std::size(table) && x < 0x20; ++x) { if (c == table[x]) { res.push_back(static_cast(static_cast(x))); found = true; break; } } } if (!found) { res.push_back(replacement); } } return res; } template inline mpt::widestring decode_ascii(const Tsrcstring & str, mpt::widechar replacement = MPT_WIDECHAR('\uFFFD')) { mpt::widestring res; res.reserve(str.length()); for (std::size_t i = 0; i < str.length(); ++i) { uint8 c = mpt::char_value(str[i]); if (c <= 0x7f) { encode_single_wide(res, static_cast(static_cast(c))); } else { res.push_back(replacement); } } return res; } template inline Tdststring encode_ascii(const mpt::widestring & str, char replacement = '?') { Tdststring res; res.reserve(str.length()); for (std::size_t i = 0; i < str.length(); ++i) { char32_t c = decode_single_wide(i, str); if (c <= 0x7f) { res.push_back(static_cast(static_cast(static_cast(c)))); } else { res.push_back(replacement); } } return res; } template inline mpt::widestring decode_iso8859_1(const Tsrcstring & str, mpt::widechar replacement = MPT_WIDECHAR('\uFFFD')) { MPT_UNUSED(replacement); mpt::widestring res; res.reserve(str.length()); for (std::size_t i = 0; i < str.length(); ++i) { uint8 c = mpt::char_value(str[i]); encode_single_wide(res, static_cast(static_cast(c))); } return res; } template inline Tdststring encode_iso8859_1(const mpt::widestring & str, char replacement = '?') { Tdststring res; res.reserve(str.length()); for (std::size_t i = 0; i < str.length(); ++i) { char32_t c = decode_single_wide(i, str); if (c <= 0xff) { res.push_back(static_cast(static_cast(c))); } else { res.push_back(replacement); } } return res; } template inline mpt::widestring decode_utf8(const Tsrcstring & str, mpt::widechar replacement = MPT_WIDECHAR('\uFFFD')) { const Tsrcstring & in = str; mpt::widestring out; // state: std::size_t charsleft = 0; char32_t ucs4 = 0; for (uint8 c : in) { if (charsleft == 0) { if ((c & 0x80) == 0x00) { out.push_back(static_cast(c)); } else if ((c & 0xE0) == 0xC0) { ucs4 = c & 0x1F; charsleft = 1; } else if ((c & 0xF0) == 0xE0) { ucs4 = c & 0x0F; charsleft = 2; } else if ((c & 0xF8) == 0xF0) { ucs4 = c & 0x07; charsleft = 3; } else { out.push_back(replacement); ucs4 = 0; charsleft = 0; } } else { if ((c & 0xC0) != 0x80) { out.push_back(replacement); ucs4 = 0; charsleft = 0; } ucs4 <<= 6; ucs4 |= c & 0x3F; charsleft--; if (charsleft == 0) { if constexpr (sizeof(mpt::widechar) == 2) { if (ucs4 > 0x1fffff) { out.push_back(replacement); ucs4 = 0; charsleft = 0; continue; } } encode_single_wide(out, ucs4); ucs4 = 0; } } } if (charsleft != 0) { out.push_back(replacement); ucs4 = 0; charsleft = 0; } return out; } template inline Tdststring encode_utf8(const mpt::widestring & str, typename Tdststring::value_type replacement = static_cast(mpt::char_value('?'))) { const mpt::widestring & in = str; Tdststring out; for (std::size_t i = 0; i < in.length(); i++) { char32_t ucs4 = decode_single_wide(i, in); if (ucs4 > 0x1fffff) { out.push_back(replacement); continue; } uint8 utf8[6]; std::size_t numchars = 0; for (numchars = 0; numchars < 6; numchars++) { utf8[numchars] = ucs4 & 0x3F; ucs4 >>= 6; if (ucs4 == 0) { break; } } numchars++; if (numchars == 1) { out.push_back(utf8[0]); continue; } if (numchars == 2 && utf8[numchars - 1] == 0x01) { // generate shortest form out.push_back(utf8[0] | 0x40); continue; } std::size_t charsleft = numchars; while (charsleft > 0) { if (charsleft == numchars) { out.push_back(static_cast(utf8[charsleft - 1] | (((1 << numchars) - 1) << (8 - numchars)))); } else { // cppcheck false-positive // cppcheck-suppress arrayIndexOutOfBounds out.push_back(static_cast(utf8[charsleft - 1] | 0x80u)); } charsleft--; } } return out; } template inline Tdststring utf32_from_utf16(const Tsrcstring & in, mpt::widechar replacement = MPT_WIDECHAR('\uFFFD')) { static_assert(sizeof(typename Tsrcstring::value_type) == 2); static_assert(sizeof(typename Tdststring::value_type) == 4); MPT_UNUSED(replacement); Tdststring out; out.reserve(in.length()); for (std::size_t i = 0; i < in.length(); i++) { char32_t ucs4 = decode_single_utf16(i, in); out.push_back(static_cast(static_cast(ucs4))); } return out; } template inline Tdststring utf16_from_utf32(const Tsrcstring & in, mpt::widechar replacement = MPT_WIDECHAR('\uFFFD')) { static_assert(sizeof(typename Tsrcstring::value_type) == 4); static_assert(sizeof(typename Tdststring::value_type) == 2); Tdststring out; out.reserve(in.length()); for (std::size_t i = 0; i < in.length(); i++) { char32_t ucs4 = static_cast(static_cast(in[i])); if (ucs4 > 0x1fffff) { out.push_back(static_cast(static_cast(replacement))); continue; } encode_single_utf16(out, ucs4); } return out; } #if MPT_OS_WINDOWS inline bool has_codepage(UINT cp) { return IsValidCodePage(cp) ? true : false; } inline bool windows_has_encoding(common_encoding encoding) { bool result = false; switch (encoding) { case common_encoding::utf8: result = has_codepage(CP_UTF8); break; case common_encoding::ascii: result = has_codepage(20127); break; case common_encoding::iso8859_1: result = has_codepage(28591); break; case common_encoding::iso8859_15: result = has_codepage(28605); break; case common_encoding::cp437: result = has_codepage(437); break; case common_encoding::cp737: result = has_codepage(737); break; case common_encoding::cp775: result = has_codepage(775); break; case common_encoding::cp850: result = has_codepage(850); break; case common_encoding::cp852: result = has_codepage(852); break; case common_encoding::cp855: result = has_codepage(855); break; case common_encoding::cp857: result = has_codepage(857); break; case common_encoding::cp860: result = has_codepage(860); break; case common_encoding::cp861: result = has_codepage(861); break; case common_encoding::cp862: result = has_codepage(862); break; case common_encoding::cp863: result = has_codepage(863); break; case common_encoding::cp864: result = has_codepage(864); break; case common_encoding::cp865: result = has_codepage(865); break; case common_encoding::cp866: result = has_codepage(866); break; case common_encoding::cp869: result = has_codepage(869); break; case common_encoding::cp874: result = has_codepage(874); break; case common_encoding::windows1252: result = has_codepage(1252); break; case common_encoding::amiga: result = false; break; case common_encoding::riscos: result = false; break; case common_encoding::atarist: result = false; break; case common_encoding::iso8859_1_no_c1: result = false; break; case common_encoding::iso8859_15_no_c1: result = false; break; case common_encoding::amiga_no_c1: result = false; break; } return result; } inline bool windows_has_encoding(logical_encoding encoding) { bool result = false; switch (encoding) { case logical_encoding::locale: result = true; break; case logical_encoding::active_locale: result = false; break; } return result; } inline UINT codepage_from_encoding(logical_encoding encoding) { UINT result = 0; switch (encoding) { case logical_encoding::locale: result = CP_ACP; break; case logical_encoding::active_locale: throw std::domain_error("unsupported encoding"); break; } return result; } inline UINT codepage_from_encoding(common_encoding encoding) { UINT result = 0; switch (encoding) { case common_encoding::utf8: result = CP_UTF8; break; case common_encoding::ascii: result = 20127; break; case common_encoding::iso8859_1: result = 28591; break; case common_encoding::iso8859_15: result = 28605; break; case common_encoding::cp437: result = 437; break; case common_encoding::cp737: result = 737; break; case common_encoding::cp775: result = 775; break; case common_encoding::cp850: result = 850; break; case common_encoding::cp852: result = 852; break; case common_encoding::cp855: result = 855; break; case common_encoding::cp857: result = 857; break; case common_encoding::cp860: result = 860; break; case common_encoding::cp861: result = 861; break; case common_encoding::cp862: result = 862; break; case common_encoding::cp863: result = 863; break; case common_encoding::cp864: result = 864; break; case common_encoding::cp865: result = 865; break; case common_encoding::cp866: result = 866; break; case common_encoding::cp869: result = 869; break; case common_encoding::cp874: result = 874; break; case common_encoding::windows1252: result = 1252; break; case common_encoding::amiga: throw std::domain_error("unsupported encoding"); break; case common_encoding::riscos: throw std::domain_error("unsupported encoding"); break; case common_encoding::atarist: throw std::domain_error("unsupported encoding"); break; case common_encoding::iso8859_1_no_c1: throw std::domain_error("unsupported encoding"); break; case common_encoding::iso8859_15_no_c1: throw std::domain_error("unsupported encoding"); break; case common_encoding::amiga_no_c1: throw std::domain_error("unsupported encoding"); break; } return result; } inline std::optional optional_encoding_from_codepage(UINT codepage) { std::optional result = std::nullopt; switch (codepage) { case CP_UTF8: result = common_encoding::utf8; break; case 20127: result = common_encoding::ascii; break; case 28591: result = common_encoding::iso8859_1; break; case 28605: result = common_encoding::iso8859_15; break; case 437: result = common_encoding::cp437; break; case 737: result = common_encoding::cp737; break; case 775: result = common_encoding::cp775; break; case 850: result = common_encoding::cp850; break; case 852: result = common_encoding::cp852; break; case 855: result = common_encoding::cp855; break; case 857: result = common_encoding::cp857; break; case 860: result = common_encoding::cp860; break; case 861: result = common_encoding::cp861; break; case 862: result = common_encoding::cp862; break; case 863: result = common_encoding::cp863; break; case 864: result = common_encoding::cp864; break; case 865: result = common_encoding::cp865; break; case 866: result = common_encoding::cp866; break; case 869: result = common_encoding::cp869; break; case 874: result = common_encoding::cp874; break; case 1252: result = common_encoding::windows1252; break; default: result = std::nullopt; break; } return result; } inline common_encoding encoding_from_codepage(UINT codepage) { std::optional optional_result = optional_encoding_from_codepage(codepage); if (!optional_result) { throw std::domain_error("unsupported encoding"); } return *optional_result; } #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template inline Tdststring encode_codepage(UINT codepage, const mpt::widestring & src) { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); Tdststring encoded_string; int required_size = WideCharToMultiByte(codepage, 0, src.data(), mpt::saturate_cast(src.size()), nullptr, 0, nullptr, nullptr); if (required_size > 0) { encoded_string.resize(required_size); WideCharToMultiByte(codepage, 0, src.data(), mpt::saturate_cast(src.size()), reinterpret_cast(encoded_string.data()), required_size, nullptr, nullptr); } return encoded_string; } template inline mpt::widestring decode_codepage(UINT codepage, const Tsrcstring & src) { static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); mpt::widestring decoded_string; int required_size = MultiByteToWideChar(codepage, 0, reinterpret_cast(src.data()), mpt::saturate_cast(src.size()), nullptr, 0); if (required_size > 0) { decoded_string.resize(required_size); MultiByteToWideChar(codepage, 0, reinterpret_cast(src.data()), mpt::saturate_cast(src.size()), decoded_string.data(), required_size); } return decoded_string; } #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #endif // MPT_OS_WINDOWS #if MPT_OS_DJGPP inline common_encoding djgpp_get_locale_encoding() { uint16 active_codepage = 437; uint16 system_codepage = 437; __dpmi_regs regs; std::memset(®s, 0, sizeof(__dpmi_regs)); regs.x.ax = 0x6601; if (__dpmi_int(0x21, ®s) == 0) { int cf = (regs.x.flags >> 0) & 1; if (cf == 0) { active_codepage = regs.x.bx; system_codepage = regs.x.dx; } } common_encoding result = common_encoding::cp437; if (active_codepage == 0) { result = common_encoding::cp437; } else if (active_codepage == 437) { result = common_encoding::cp437; } else if (active_codepage == 737) { result = common_encoding::cp737; } else if (active_codepage == 775) { result = common_encoding::cp775; } else if (active_codepage == 850) { result = common_encoding::cp850; } else if (active_codepage == 852) { result = common_encoding::cp852; } else if (active_codepage == 855) { result = common_encoding::cp855; } else if (active_codepage == 857) { result = common_encoding::cp857; } else if (active_codepage == 860) { result = common_encoding::cp860; } else if (active_codepage == 861) { result = common_encoding::cp861; } else if (active_codepage == 862) { result = common_encoding::cp862; } else if (active_codepage == 863) { result = common_encoding::cp863; } else if (active_codepage == 864) { result = common_encoding::cp864; } else if (active_codepage == 865) { result = common_encoding::cp865; } else if (active_codepage == 866) { result = common_encoding::cp866; } else if (active_codepage == 869) { result = common_encoding::cp869; } else if (active_codepage == 874) { result = common_encoding::cp874; } else if (system_codepage == 437) { result = common_encoding::cp437; } else if (system_codepage == 737) { result = common_encoding::cp737; } else if (system_codepage == 775) { result = common_encoding::cp775; } else if (system_codepage == 850) { result = common_encoding::cp850; } else if (system_codepage == 852) { result = common_encoding::cp852; } else if (system_codepage == 855) { result = common_encoding::cp855; } else if (system_codepage == 857) { result = common_encoding::cp857; } else if (system_codepage == 860) { result = common_encoding::cp860; } else if (system_codepage == 861) { result = common_encoding::cp861; } else if (system_codepage == 862) { result = common_encoding::cp862; } else if (system_codepage == 863) { result = common_encoding::cp863; } else if (system_codepage == 864) { result = common_encoding::cp864; } else if (system_codepage == 865) { result = common_encoding::cp865; } else if (system_codepage == 866) { result = common_encoding::cp866; } else if (system_codepage == 869) { result = common_encoding::cp869; } else if (system_codepage == 874) { result = common_encoding::cp874; } else { result = common_encoding::cp437; } return result; } #endif // MPT_OS_DJGPP inline std::optional optional_encoding_from_codepage(uint16 codepage) { std::optional result = std::nullopt; switch (codepage) { case 65001: result = common_encoding::utf8; break; case 20127: result = common_encoding::ascii; break; case 28591: result = common_encoding::iso8859_1; break; case 28605: result = common_encoding::iso8859_15; break; case 437: result = common_encoding::cp437; break; case 737: result = common_encoding::cp737; break; case 775: result = common_encoding::cp775; break; case 850: result = common_encoding::cp850; break; case 852: result = common_encoding::cp852; break; case 855: result = common_encoding::cp855; break; case 857: result = common_encoding::cp857; break; case 860: result = common_encoding::cp860; break; case 861: result = common_encoding::cp861; break; case 862: result = common_encoding::cp862; break; case 863: result = common_encoding::cp863; break; case 864: result = common_encoding::cp864; break; case 865: result = common_encoding::cp865; break; case 866: result = common_encoding::cp866; break; case 869: result = common_encoding::cp869; break; case 874: result = common_encoding::cp874; break; case 1252: result = common_encoding::windows1252; break; default: result = std::nullopt; break; } return result; } inline common_encoding encoding_from_codepage(uint16 codepage) { std::optional optional_result = optional_encoding_from_codepage(codepage); if (!optional_result) { throw std::domain_error("unsupported encoding"); } return *optional_result; } #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) // Note: // // std::codecvt::out in LLVM libc++ does not advance in and out pointers when // running into a non-convertible character. This can happen when no locale is // set on FreeBSD or MacOSX. This behaviour violates the C++ standard. // // We apply the following (albeit costly, even on other platforms) work-around: // If the conversion errors out and does not advance the pointers at all, we // retry the conversion with a space character prepended to the string. If it // still does error out, we retry the whole conversion character by character. // This is costly even on other platforms in one single case: The first // character is an invalid Unicode code point or otherwise not convertible. Any // following non-convertible characters are not a problem. inline std::wstring decode_locale_impl(const std::string & str, const std::locale & locale, wchar_t replacement = L'\uFFFD', int retry = 0, bool * progress = nullptr) { if (str.empty()) { return std::wstring(); } std::vector out; using codecvt_type = std::codecvt; std::mbstate_t state = std::mbstate_t(); const codecvt_type & facet = std::use_facet(locale); codecvt_type::result result = codecvt_type::partial; const char * in_begin = str.data(); const char * in_end = in_begin + str.size(); out.resize((in_end - in_begin) * (mpt::saturate_cast(facet.max_length()) + 1)); wchar_t * out_begin = out.data(); wchar_t * out_end = out.data() + out.size(); const char * in_next = nullptr; wchar_t * out_next = nullptr; do { if (retry == 2) { for (;;) { in_next = nullptr; out_next = nullptr; result = facet.in(state, in_begin, in_begin + 1, in_next, out_begin, out_end, out_next); if (result == codecvt_type::partial && in_next == in_begin + 1) { in_begin = in_next; out_begin = out_next; continue; } else { break; } } } else { in_next = nullptr; out_next = nullptr; result = facet.in(state, in_begin, in_end, in_next, out_begin, out_end, out_next); } if (result == codecvt_type::partial || (result == codecvt_type::error && out_next == out_end)) { out.resize(out.size() * 2); in_begin = in_next; out_begin = out.data() + (out_next - out_begin); out_end = out.data() + out.size(); continue; } if (retry == 0) { if (result == codecvt_type::error && in_next == in_begin && out_next == out_begin) { bool made_progress = true; decode_locale_impl(std::string(" ") + str, locale, replacement, 1, &made_progress); if (!made_progress) { return decode_locale_impl(str, locale, replacement, 2); } } } else if (retry == 1) { if (result == codecvt_type::error && in_next == in_begin && out_next == out_begin) { *progress = false; } else { *progress = true; } return std::wstring(); } if (result == codecvt_type::error) { ++in_next; *out_next = replacement; ++out_next; } in_begin = in_next; out_begin = out_next; } while ((result == codecvt_type::error && in_next < in_end && out_next < out_end) || (retry == 2 && in_next < in_end)); return std::wstring(out.data(), out_next); } template inline mpt::widestring decode_locale(const std::locale & locale, const Tsrcstring & src) { if constexpr (std::is_same::value) { return decode_locale_impl(src, locale); } else { return decode_locale_impl(std::string(src.begin(), src.end()), locale); } } inline std::string encode_locale_impl(const std::wstring & str, const std::locale & locale, char replacement = '?', int retry = 0, bool * progress = nullptr) { if (str.empty()) { return std::string(); } std::vector out; using codecvt_type = std::codecvt; std::mbstate_t state = std::mbstate_t(); const codecvt_type & facet = std::use_facet(locale); codecvt_type::result result = codecvt_type::partial; const wchar_t * in_begin = str.data(); const wchar_t * in_end = in_begin + str.size(); out.resize((in_end - in_begin) * (mpt::saturate_cast(facet.max_length()) + 1)); char * out_begin = out.data(); char * out_end = out.data() + out.size(); const wchar_t * in_next = nullptr; char * out_next = nullptr; do { if (retry == 2) { for (;;) { in_next = nullptr; out_next = nullptr; result = facet.out(state, in_begin, in_begin + 1, in_next, out_begin, out_end, out_next); if (result == codecvt_type::partial && in_next == in_begin + 1) { in_begin = in_next; out_begin = out_next; continue; } else { break; } } } else { in_next = nullptr; out_next = nullptr; result = facet.out(state, in_begin, in_end, in_next, out_begin, out_end, out_next); } if (result == codecvt_type::partial || (result == codecvt_type::error && out_next == out_end)) { out.resize(out.size() * 2); in_begin = in_next; out_begin = out.data() + (out_next - out_begin); out_end = out.data() + out.size(); continue; } if (retry == 0) { if (result == codecvt_type::error && in_next == in_begin && out_next == out_begin) { bool made_progress = true; encode_locale_impl(std::wstring(L" ") + str, locale, replacement, 1, &made_progress); if (!made_progress) { return encode_locale_impl(str, locale, replacement, 2); } } } else if (retry == 1) { if (result == codecvt_type::error && in_next == in_begin && out_next == out_begin) { *progress = false; } else { *progress = true; } return std::string(); } if (result == codecvt_type::error) { ++in_next; *out_next = replacement; ++out_next; } in_begin = in_next; out_begin = out_next; } while ((result == codecvt_type::error && in_next < in_end && out_next < out_end) || (retry == 2 && in_next < in_end)); return std::string(out.data(), out_next); } template inline Tdststring encode_locale(const std::locale & locale, const mpt::widestring & src) { if constexpr (std::is_same::value) { return encode_locale_impl(src, locale); } else { const std::string tmp = encode_locale_impl(src, locale); return Tdststring(tmp.begin(), tmp.end()); } } #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template inline Tdststring encode(UINT codepage, const mpt::widestring & src) { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); return encode_codepage(codepage, src); } #endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template inline Tdststring encode(const std::locale & locale, const mpt::widestring & src) { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); return encode_locale(src, locale); } #endif // !MPT_COMPILER_QUIRK_NO_WCHAR template inline Tdststring encode(const char32_t (&table)[256], const mpt::widestring & src) { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); return encode_8bit(src, table); } template inline Tdststring encode(common_encoding encoding, const mpt::widestring & src) { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) if (windows_has_encoding(encoding)) { return encode_codepage(codepage_from_encoding(encoding), src); } #endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR switch (encoding) { case common_encoding::utf8: return encode_utf8(src); break; case common_encoding::ascii: return encode_ascii(src); break; case common_encoding::iso8859_1: return encode_iso8859_1(src); break; case common_encoding::iso8859_15: return encode_8bit(src, CharsetTableISO8859_15); break; case common_encoding::cp437: return encode_8bit(src, CharsetTableCP437); break; case common_encoding::cp737: return encode_8bit(src, CharsetTableCP737); break; case common_encoding::cp775: return encode_8bit(src, CharsetTableCP775); break; case common_encoding::cp850: return encode_8bit(src, CharsetTableCP850); break; case common_encoding::cp852: return encode_8bit(src, CharsetTableCP852); break; case common_encoding::cp855: return encode_8bit(src, CharsetTableCP855); break; case common_encoding::cp857: return encode_8bit(src, CharsetTableCP857); break; case common_encoding::cp860: return encode_8bit(src, CharsetTableCP860); break; case common_encoding::cp861: return encode_8bit(src, CharsetTableCP861); break; case common_encoding::cp862: return encode_8bit(src, CharsetTableCP862); break; case common_encoding::cp863: return encode_8bit(src, CharsetTableCP863); break; case common_encoding::cp864: return encode_8bit(src, CharsetTableCP864); break; case common_encoding::cp865: return encode_8bit(src, CharsetTableCP865); break; case common_encoding::cp866: return encode_8bit(src, CharsetTableCP866); break; case common_encoding::cp869: return encode_8bit(src, CharsetTableCP869); break; case common_encoding::cp874: return encode_8bit(src, CharsetTableCP874); break; case common_encoding::windows1252: return encode_8bit(src, CharsetTableWindows1252); break; case common_encoding::amiga: return encode_8bit(src, CharsetTableAmiga); break; case common_encoding::riscos: return encode_8bit(src, CharsetTableRISC_OS); break; case common_encoding::atarist: return encode_8bit(src, CharsetTableAtariST); break; case common_encoding::iso8859_1_no_c1: return encode_8bit_no_c1(src, CharsetTableISO8859_1); break; case common_encoding::iso8859_15_no_c1: return encode_8bit_no_c1(src, CharsetTableISO8859_15); break; case common_encoding::amiga_no_c1: return encode_8bit_no_c1(src, CharsetTableAmiga); break; } throw std::domain_error("unsupported encoding"); } template inline Tdststring encode(logical_encoding encoding, const mpt::widestring & src) { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) if (windows_has_encoding(encoding)) { return encode_codepage(codepage_from_encoding(encoding), src); } #elif MPT_OS_WINDOWS && defined(MPT_COMPILER_QUIRK_NO_WCHAR) switch (encoding) { case logical_encoding::locale: return encode(optional_encoding_from_codepage(GetACP()).value_or(common_encoding::windows1252), src); break; case logical_encoding::active_locale: return encode(optional_encoding_from_codepage(GetACP()).value_or(common_encoding::windows1252), src); break; } throw std::domain_error("unsupported encoding"); #endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_OS_DJGPP switch (encoding) { case logical_encoding::locale: return encode(djgpp_get_locale_encoding(), src); break; case logical_encoding::active_locale: return encode(djgpp_get_locale_encoding(), src); break; } throw std::domain_error("unsupported encoding"); #elif !defined(MPT_COMPILER_QUIRK_NO_WCHAR) switch (encoding) { case logical_encoding::locale: #if defined(MPT_LIBCXX_QUIRK_BROKEN_USER_LOCALE) #if defined(MPT_LIBCXX_QUIRK_ASSUME_USER_LOCALE_UTF8) return encode_utf8(src); #else try { return encode_locale(std::locale(""), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } try { return encode_locale(std::locale(), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } try { return encode_locale(std::locale::classic(), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } return encode_ascii(src); #endif #else return encode_locale(std::locale(""), src); #endif break; case logical_encoding::active_locale: #if defined(MPT_LIBCXX_QUIRK_BROKEN_ACTIVE_LOCALE) try { return encode_locale(std::locale(), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } try { return encode_locale(std::locale(""), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } try { return encode_locale(std::locale::classic(), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } return encode_ascii(src); #else return encode_locale(std::locale(), src); #endif break; } throw std::domain_error("unsupported encoding"); #else throw std::domain_error("unsupported encoding"); #endif } template inline auto encode(Ttranscoder transcoder, const mpt::widestring & src) -> decltype(transcoder.template encode(src)) { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); return transcoder.template encode(src); } #if MPT_OS_WINDOWS template inline mpt::widestring decode(UINT codepage, const Tsrcstring & src) { static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); return decode_codepage(codepage, src); } #endif // MPT_OS_WINDOWS #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template inline mpt::widestring decode(const std::locale & locale, const Tsrcstring & src) { static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); return decode_locale(src, locale); } #endif // !MPT_COMPILER_QUIRK_NO_WCHAR template inline mpt::widestring decode(const char32_t (&table)[256], const Tsrcstring & src) { static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); return decode_8bit(src, table); } template inline mpt::widestring decode(common_encoding encoding, const Tsrcstring & src) { static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) if (windows_has_encoding(encoding)) { return decode_codepage(codepage_from_encoding(encoding), src); } #endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR switch (encoding) { case common_encoding::utf8: return decode_utf8(src); break; case common_encoding::ascii: return decode_ascii(src); break; case common_encoding::iso8859_1: return decode_iso8859_1(src); break; case common_encoding::iso8859_15: return decode_8bit(src, CharsetTableISO8859_15); break; case common_encoding::cp437: return decode_8bit(src, CharsetTableCP437); break; case common_encoding::cp737: return decode_8bit(src, CharsetTableCP737); break; case common_encoding::cp775: return decode_8bit(src, CharsetTableCP775); break; case common_encoding::cp850: return decode_8bit(src, CharsetTableCP850); break; case common_encoding::cp852: return decode_8bit(src, CharsetTableCP852); break; case common_encoding::cp855: return decode_8bit(src, CharsetTableCP855); break; case common_encoding::cp857: return decode_8bit(src, CharsetTableCP857); break; case common_encoding::cp860: return decode_8bit(src, CharsetTableCP860); break; case common_encoding::cp861: return decode_8bit(src, CharsetTableCP861); break; case common_encoding::cp862: return decode_8bit(src, CharsetTableCP862); break; case common_encoding::cp863: return decode_8bit(src, CharsetTableCP863); break; case common_encoding::cp864: return decode_8bit(src, CharsetTableCP864); break; case common_encoding::cp865: return decode_8bit(src, CharsetTableCP865); break; case common_encoding::cp866: return decode_8bit(src, CharsetTableCP866); break; case common_encoding::cp869: return decode_8bit(src, CharsetTableCP869); break; case common_encoding::cp874: return decode_8bit(src, CharsetTableCP874); break; case common_encoding::windows1252: return decode_8bit(src, CharsetTableWindows1252); break; case common_encoding::amiga: return decode_8bit(src, CharsetTableAmiga); break; case common_encoding::riscos: return decode_8bit(src, CharsetTableRISC_OS); break; case common_encoding::atarist: return decode_8bit(src, CharsetTableAtariST); break; case common_encoding::iso8859_1_no_c1: return decode_8bit_no_c1(src, CharsetTableISO8859_1); break; case common_encoding::iso8859_15_no_c1: return decode_8bit_no_c1(src, CharsetTableISO8859_15); break; case common_encoding::amiga_no_c1: return decode_8bit_no_c1(src, CharsetTableAmiga); break; } throw std::domain_error("unsupported encoding"); } template inline mpt::widestring decode(logical_encoding encoding, const Tsrcstring & src) { static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) if (windows_has_encoding(encoding)) { return decode_codepage(codepage_from_encoding(encoding), src); } #elif MPT_OS_WINDOWS && defined(MPT_COMPILER_QUIRK_NO_WCHAR) switch (encoding) { case logical_encoding::locale: return decode(optional_encoding_from_codepage(GetACP()).value_or(common_encoding::windows1252), src); break; case logical_encoding::active_locale: return decode(optional_encoding_from_codepage(GetACP()).value_or(common_encoding::windows1252), src); break; } throw std::domain_error("unsupported encoding"); #endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_OS_DJGPP switch (encoding) { case logical_encoding::locale: return decode(djgpp_get_locale_encoding(), src); break; case logical_encoding::active_locale: return decode(djgpp_get_locale_encoding(), src); break; } throw std::domain_error("unsupported encoding"); #elif !defined(MPT_COMPILER_QUIRK_NO_WCHAR) switch (encoding) { case logical_encoding::locale: #if defined(MPT_LIBCXX_QUIRK_BROKEN_USER_LOCALE) #if defined(MPT_LIBCXX_QUIRK_ASSUME_USER_LOCALE_UTF8) return decode_utf8(src); #else try { return decode_locale(std::locale(""), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } try { return decode_locale(std::locale(), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } try { return decode_locale(std::locale::classic(), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } return decode_ascii(src); #endif #else return decode_locale(std::locale(""), src); #endif break; case logical_encoding::active_locale: #if defined(MPT_LIBCXX_QUIRK_BROKEN_ACTIVE_LOCALE) try { return decode_locale(std::locale(), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } try { return decode_locale(std::locale(""), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } try { return decode_locale(std::locale::classic(), src); } catch (mpt::out_of_memory e) { mpt::rethrow_out_of_memory(e); } catch (...) { // nothing } return decode_ascii(src); #else return decode_locale(std::locale(), src); #endif break; } throw std::domain_error("unsupported encoding"); #else throw std::domain_error("unsupported encoding"); #endif } template inline auto decode(Ttranscoder transcoder, const Tsrcstring & src) -> decltype(transcoder.template decode(src)) { static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); return transcoder.template decode(src); } inline bool is_utf8(const std::string & str) { return (str == encode(common_encoding::utf8, decode(common_encoding::utf8, str))); } template struct string_transcoder { }; #if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) template struct string_transcoder>> { using string_type = std::basic_string>; static inline mpt::widestring decode(const string_type & src) { return mpt::decode(encoding, src); } static inline string_type encode(const mpt::widestring & src) { return mpt::encode(encoding, src); } }; #else template struct string_transcoder>> { using string_type = std::basic_string>; static inline mpt::widestring decode(const string_type & src) { return mpt::decode(encoding, src); } static inline string_type encode(const mpt::widestring & src) { return mpt::encode(encoding, src); } }; #endif #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> struct string_transcoder { using string_type = std::wstring; static inline mpt::widestring decode(const string_type & src) { return src; } static inline string_type encode(const mpt::widestring & src) { return src; } }; #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_CXX_AT_LEAST(20) template <> struct string_transcoder { using string_type = std::u8string; static inline mpt::widestring decode(const string_type & src) { return mpt::decode_utf8(src); } static inline string_type encode(const mpt::widestring & src) { return mpt::encode_utf8(src); } }; #endif // C++10 template <> struct string_transcoder { using string_type = std::u16string; static inline mpt::widestring decode(const string_type & src) { if constexpr (sizeof(mpt::widechar) == sizeof(char16_t)) { return mpt::widestring(src.begin(), src.end()); } else { return utf32_from_utf16(src); } } static inline string_type encode(const mpt::widestring & src) { if constexpr (sizeof(mpt::widechar) == sizeof(char16_t)) { return string_type(src.begin(), src.end()); } else { return utf16_from_utf32(src); } } }; #if defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> struct string_transcoder { using string_type = std::u32string; static inline mpt::widestring decode(const string_type & src) { return src; } static inline string_type encode(const mpt::widestring & src) { return src; } }; #else // !MPT_COMPILER_QUIRK_NO_WCHAR template <> struct string_transcoder { using string_type = std::u32string; static inline mpt::widestring decode(const string_type & src) { if constexpr (sizeof(mpt::widechar) == sizeof(char32_t)) { return mpt::widestring(src.begin(), src.end()); } else { return utf16_from_utf32(src); } } static inline string_type encode(const mpt::widestring & src) { if constexpr (sizeof(mpt::widechar) == sizeof(char32_t)) { return string_type(src.begin(), src.end()); } else { return utf32_from_utf16(src); } } }; #endif // MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_DETECTED_MFC template <> struct string_transcoder { using string_type = CStringW; static inline mpt::widestring decode(const string_type & src) { return mpt::widestring(src.GetString()); } static inline string_type encode(const mpt::widestring & src) { return src.c_str(); } }; template <> struct string_transcoder { using string_type = CStringA; static inline mpt::widestring decode(const string_type & src) { return mpt::decode(mpt::logical_encoding::locale, std::string(src.GetString())); } static inline string_type encode(const mpt::widestring & src) { return mpt::encode(mpt::logical_encoding::locale, src).c_str(); } }; #endif // MPT_DETECTED_MFC template ::type>::type>::value, bool> = true> inline Tdststring transcode(Tsrcstring && src) { if constexpr (std::is_same::type>::type>::value) { return mpt::as_string(std::forward(src)); } else { return string_transcoder::encode(string_transcoder(src)))>::decode(mpt::as_string(std::forward(src)))); } } template ::value, bool> = true, std::enable_if_t::type>::type>::value, bool> = true> inline Tdststring transcode(Tencoding to, Tsrcstring && src) { if constexpr (std::is_same::value) { if constexpr (std::is_same(src))), mpt::u8string>::value) { if (to == mpt::common_encoding::utf8) { auto src_ = mpt::as_string(std::forward(src)); Tdststring dst; mpt::string_traits::reserve(dst, mpt::string_traits(src)))>::length(src_)); for (std::size_t i = 0; i < mpt::saturate_cast(mpt::string_traits(src)))>::length(src_)); ++i) { mpt::string_traits::append(dst, static_cast::unsigned_char_type>(static_cast(src)))>::unsigned_char_type>(src_[i]))); } return dst; } } } return mpt::encode(to, string_transcoder(src)))>::decode(mpt::as_string(std::forward(src)))); } template ::type>::type, std::string>::value, bool> = true, std::enable_if_t::type>::type>::value, bool> = true> inline Tdststring transcode(Tencoding from, Tsrcstring && src) { if constexpr (std::is_same::value) { if constexpr (std::is_same::value) { if (from == mpt::common_encoding::utf8) { auto src_ = mpt::as_string(std::forward(src)); Tdststring dst; mpt::string_traits::reserve(dst, mpt::string_traits(src)))>::length(src_)); for (std::size_t i = 0; i < mpt::saturate_cast(mpt::string_traits(src)))>::length(src_)); ++i) { mpt::string_traits::append(dst, static_cast::unsigned_char_type>(static_cast(src)))>::unsigned_char_type>(src_[i]))); } return dst; } } } return string_transcoder::encode(mpt::decode(src)))>(from, mpt::as_string(std::forward(src)))); } template ::type>::type>::value, bool> = true> inline Tdststring transcode(Tto to, Tfrom from, Tsrcstring && src) { if constexpr (std::is_same::value) { if constexpr (std::is_same(src))), Tdststring>::value) { if (to == from) { return mpt::as_string(std::forward(src)); } } } return mpt::encode(to, mpt::decode(src)))>(from, mpt::as_string(std::forward(src)))); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_STRING_TRANSCODE_TRANSCODE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/string_transcode/tests/0000755000175000017500000000000015023302361022432 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/string_transcode/tests/tests_string_transcode.hpp0000644000175000017500000005254314736004310027671 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_STRING_TRANSCODE_TESTS_STRING_TRANSCODE_HPP #define MPT_STRING_TRANSCODE_TESTS_STRING_TRANSCODE_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/macros.hpp" #include "mpt/string_transcode/transcode.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace string_transcode { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/string_transcode") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { // MPT_UTF8_STRING version // Charset conversions (basic sanity checks) MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, MPT_USTRING("a")), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::iso8859_1, MPT_USTRING("a")), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::ascii, MPT_USTRING("a")), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, "a"), MPT_USTRING("a")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::iso8859_1, "a"), MPT_USTRING("a")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::ascii, "a"), MPT_USTRING("a")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::locale, MPT_USTRING("a")), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::locale, "a"), MPT_USTRING("a")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::active_locale, MPT_USTRING("a")), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::active_locale, "a"), MPT_USTRING("a")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, MPT_UTF8_STRING("a")), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::iso8859_1, MPT_UTF8_STRING("a")), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::ascii, MPT_UTF8_STRING("a")), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, "a"), MPT_UTF8_STRING("a")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::iso8859_1, "a"), MPT_UTF8_STRING("a")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::ascii, "a"), MPT_UTF8_STRING("a")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::locale, MPT_UTF8_STRING("a")), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::locale, "a"), MPT_UTF8_STRING("a")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::active_locale, MPT_UTF8_STRING("a")), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::active_locale, "a"), MPT_UTF8_STRING("a")); #if MPT_OS_EMSCRIPTEN MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::locale, MPT_UTF8_STRING("\xe2\x8c\x82")), "\xe2\x8c\x82"); #endif // MPT_OS_EMSCRIPTEN // Check that some character replacement is done (and not just empty strings or truncated strings are returned) // We test german umlaut-a (U+00E4) (\xC3\xA4) and CJK U+5BB6 (\xE5\xAE\xB6) MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::ascii, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::iso8859_1, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::cp437, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::utf8, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::ascii, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::iso8859_1, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::cp437, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::utf8, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::locale, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::locale, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::active_locale, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::active_locale, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::ascii, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::iso8859_1, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::cp437, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::utf8, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::ascii, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::iso8859_1, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::cp437, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::utf8, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::locale, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::locale, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::active_locale, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::active_locale, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::ascii, "abc\xC3\xA4xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::iso8859_1, "abc\xC3\xA4xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::cp437, "abc\xC3\xA4xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::utf8, "abc\xC3\xA4xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::ascii, "abc\xC3\xA4xyz"), MPT_USTRING("abc"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::iso8859_1, "abc\xC3\xA4xyz"), MPT_USTRING("abc"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::cp437, "abc\xC3\xA4xyz"), MPT_USTRING("abc"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::utf8, "abc\xC3\xA4xyz"), MPT_USTRING("abc"))); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::locale, "abc\xC3\xA4xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::locale, "abc\xC3\xA4xyz"), MPT_USTRING("abc"))); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::active_locale, "abc\xC3\xA4xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::active_locale, "abc\xC3\xA4xyz"), MPT_USTRING("abc"))); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::ascii, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::iso8859_1, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::cp437, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::utf8, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::ascii, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("abc"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::iso8859_1, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("abc"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::cp437, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("abc"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::utf8, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("abc"))); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::locale, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::locale, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("abc"))); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::active_locale, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("xyz"))); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::active_locale, "abc\xE5\xAE\xB6xyz"), MPT_USTRING("abc"))); // Check that characters are correctly converted // We test german umlaut-a (U+00E4) and CJK U+5BB6 // cp437 MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::cp437, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "abc\x84xyz"); MPT_TEST_EXPECT_EQUAL(MPT_UTF8_STRING("abc\xC3\xA4xyz"), mpt::transcode(mpt::common_encoding::cp437, "abc\x84xyz")); // iso8859 MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::iso8859_1, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "abc\xE4xyz"); MPT_TEST_EXPECT_EQUAL(MPT_UTF8_STRING("abc\xC3\xA4xyz"), mpt::transcode(mpt::common_encoding::iso8859_1, "abc\xE4xyz")); // utf8 MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, MPT_UTF8_STRING("abc\xC3\xA4xyz")), "abc\xC3\xA4xyz"); MPT_TEST_EXPECT_EQUAL(MPT_UTF8_STRING("abc\xC3\xA4xyz"), mpt::transcode(mpt::common_encoding::utf8, "abc\xC3\xA4xyz")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz")), "abc\xE5\xAE\xB6xyz"); MPT_TEST_EXPECT_EQUAL(MPT_UTF8_STRING("abc\xE5\xAE\xB6xyz"), mpt::transcode(mpt::common_encoding::utf8, "abc\xE5\xAE\xB6xyz")); // utf16 MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, std::u16string(1, char16_t{0xe4})), "\xC3\xA4"); MPT_TEST_EXPECT_EQUAL(std::u16string(1, char16_t{0xe4}), mpt::transcode(mpt::common_encoding::utf8, "\xC3\xA4")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, std::u16string(1, char16_t{0x5BB6})), "\xE5\xAE\xB6"); MPT_TEST_EXPECT_EQUAL(std::u16string(1, char16_t{0x5BB6}), mpt::transcode(mpt::common_encoding::utf8, "\xE5\xAE\xB6")); // utf32 MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, std::u32string(1, char32_t{0xe4})), "\xC3\xA4"); MPT_TEST_EXPECT_EQUAL(std::u32string(1, char32_t{0xe4}), mpt::transcode(mpt::common_encoding::utf8, "\xC3\xA4")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, std::u32string(1, char32_t{0x5BB6})), "\xE5\xAE\xB6"); MPT_TEST_EXPECT_EQUAL(std::u32string(1, char32_t{0x5BB6}), mpt::transcode(mpt::common_encoding::utf8, "\xE5\xAE\xB6")); #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) // wide L"" version // Charset conversions (basic sanity checks) MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, L"a"), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::iso8859_1, L"a"), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::ascii, L"a"), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, "a"), L"a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::iso8859_1, "a"), L"a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::ascii, "a"), L"a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::locale, L"a"), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::locale, "a"), L"a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::active_locale, L"a"), "a"); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::logical_encoding::active_locale, "a"), L"a"); // Check that some character replacement is done (and not just empty strings or truncated strings are returned) // We test german umlaut-a (U+00E4) and CJK U+5BB6 #if MPT_COMPILER_MSVC #pragma warning(push) #pragma warning(disable : 4428) // universal-character-name encountered in source #endif MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::ascii, L"abc\u00E4xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::iso8859_1, L"abc\u00E4xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::cp437, L"abc\u00E4xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::utf8, L"abc\u00E4xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::ascii, L"abc\u00E4xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::iso8859_1, L"abc\u00E4xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::cp437, L"abc\u00E4xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::utf8, L"abc\u00E4xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::locale, L"abc\u00E4xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::locale, L"abc\u00E4xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::active_locale, L"abc\u00E4xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::active_locale, L"abc\u00E4xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::ascii, L"abc\u5BB6xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::iso8859_1, L"abc\u5BB6xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::cp437, L"abc\u5BB6xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::utf8, L"abc\u5BB6xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::ascii, L"abc\u5BB6xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::iso8859_1, L"abc\u5BB6xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::cp437, L"abc\u5BB6xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::utf8, L"abc\u5BB6xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::locale, L"abc\u5BB6xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::locale, L"abc\u5BB6xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::active_locale, L"abc\u5BB6xyz"), "xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::active_locale, L"abc\u5BB6xyz"), "abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::ascii, "abc\xC3\xA4xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::iso8859_1, "abc\xC3\xA4xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::cp437, "abc\xC3\xA4xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::utf8, "abc\xC3\xA4xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::ascii, "abc\xC3\xA4xyz"), L"abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::iso8859_1, "abc\xC3\xA4xyz"), L"abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::cp437, "abc\xC3\xA4xyz"), L"abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::utf8, "abc\xC3\xA4xyz"), L"abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::locale, "abc\xC3\xA4xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::locale, "abc\xC3\xA4xyz"), L"abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::active_locale, "abc\xC3\xA4xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::active_locale, "abc\xC3\xA4xyz"), L"abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::ascii, "abc\xE5\xAE\xB6xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::iso8859_1, "abc\xE5\xAE\xB6xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::cp437, "abc\xE5\xAE\xB6xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::common_encoding::utf8, "abc\xE5\xAE\xB6xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::ascii, "abc\xE5\xAE\xB6xyz"), L"abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::iso8859_1, "abc\xE5\xAE\xB6xyz"), L"abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::cp437, "abc\xE5\xAE\xB6xyz"), L"abc")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::common_encoding::utf8, "abc\xE5\xAE\xB6xyz"), L"abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::locale, "abc\xE5\xAE\xB6xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::locale, "abc\xE5\xAE\xB6xyz"), L"abc")); MPT_TEST_EXPECT_EXPR(mpt::ends_with(mpt::transcode(mpt::logical_encoding::active_locale, "abc\xE5\xAE\xB6xyz"), L"xyz")); MPT_TEST_EXPECT_EXPR(mpt::starts_with(mpt::transcode(mpt::logical_encoding::active_locale, "abc\xE5\xAE\xB6xyz"), L"abc")); // Check that characters are correctly converted // We test german umlaut-a (U+00E4) and CJK U+5BB6 // cp437 MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::cp437, L"abc\u00E4xyz"), "abc\x84xyz"); MPT_TEST_EXPECT_EQUAL(L"abc\u00E4xyz", mpt::transcode(mpt::common_encoding::cp437, "abc\x84xyz")); // iso8859 MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::iso8859_1, L"abc\u00E4xyz"), "abc\xE4xyz"); MPT_TEST_EXPECT_EQUAL(L"abc\u00E4xyz", mpt::transcode(mpt::common_encoding::iso8859_1, "abc\xE4xyz")); // utf8 MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, L"abc\u00E4xyz"), "abc\xC3\xA4xyz"); MPT_TEST_EXPECT_EQUAL(L"abc\u00E4xyz", mpt::transcode(mpt::common_encoding::utf8, "abc\xC3\xA4xyz")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(mpt::common_encoding::utf8, L"abc\u5BB6xyz"), "abc\xE5\xAE\xB6xyz"); MPT_TEST_EXPECT_EQUAL(L"abc\u5BB6xyz", mpt::transcode(mpt::common_encoding::utf8, "abc\xE5\xAE\xB6xyz")); #if MPT_COMPILER_MSVC #pragma warning(pop) #endif #endif // !MPT_COMPILER_QUIRK_NO_WCHAR // string_view MPT_TEST_EXPECT_EQUAL(mpt::transcode(U"foo"), MPT_USTRING("foo")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(std::u32string_view(U"foo")), MPT_USTRING("foo")); MPT_TEST_EXPECT_EQUAL(mpt::transcode(std::u32string(U"foo")), MPT_USTRING("foo")); // bogus unknown -> unknown transcode MPT_TEST_EXPECT_EQUAL(mpt::transcode(std::string("foo")), std::string("foo")); } } // namespace string_transcode } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_STRING_TRANSCODE_TESTS_STRING_TRANSCODE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/string/0000755000175000017500000000000015023302361017226 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/string/utility.hpp0000644000175000017500000002746114365210657021412 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_STRING_UTILITY_HPP #define MPT_STRING_UTILITY_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/detect/mfc.hpp" #include "mpt/string/types.hpp" #include #include #include #if MPT_DETECTED_MFC // cppcheck-suppress missingInclude #include #endif // MPT_DETECTED_MFC namespace mpt { inline namespace MPT_INLINE_NS { template struct char_constants { }; template <> struct char_constants { static inline constexpr char null = '\0'; static inline constexpr char tab = '\t'; static inline constexpr char lf = '\n'; static inline constexpr char cr = '\r'; static inline constexpr char space = ' '; static inline constexpr char plus = '+'; static inline constexpr char comma = ','; static inline constexpr char minus = '-'; static inline constexpr char number0 = '0'; static inline constexpr char number1 = '1'; static inline constexpr char number9 = '9'; static inline constexpr char A = 'A'; static inline constexpr char Z = 'Z'; static inline constexpr char a = 'a'; static inline constexpr char z = 'z'; }; #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> struct char_constants { static inline constexpr wchar_t null = L'\0'; static inline constexpr wchar_t tab = L'\t'; static inline constexpr wchar_t lf = L'\n'; static inline constexpr wchar_t cr = L'\r'; static inline constexpr wchar_t space = L' '; static inline constexpr wchar_t plus = L'+'; static inline constexpr wchar_t comma = L','; static inline constexpr wchar_t minus = L'-'; static inline constexpr wchar_t number0 = L'0'; static inline constexpr wchar_t number1 = L'1'; static inline constexpr wchar_t number9 = L'9'; static inline constexpr wchar_t A = L'A'; static inline constexpr wchar_t Z = L'Z'; static inline constexpr wchar_t a = L'a'; static inline constexpr wchar_t z = L'z'; }; #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_CXX_AT_LEAST(20) template <> struct char_constants { static inline constexpr char8_t null = u8'\0'; static inline constexpr char8_t tab = u8'\t'; static inline constexpr char8_t lf = u8'\n'; static inline constexpr char8_t cr = u8'\r'; static inline constexpr char8_t space = u8' '; static inline constexpr char8_t plus = u8'+'; static inline constexpr char8_t comma = u8','; static inline constexpr char8_t minus = u8'-'; static inline constexpr char8_t number0 = u8'0'; static inline constexpr char8_t number1 = u8'1'; static inline constexpr char8_t number9 = u8'9'; static inline constexpr char8_t A = u8'A'; static inline constexpr char8_t Z = u8'Z'; static inline constexpr char8_t a = u8'a'; static inline constexpr char8_t z = u8'z'; }; #endif template <> struct char_constants { static inline constexpr char16_t null = u'\0'; static inline constexpr char16_t tab = u'\t'; static inline constexpr char16_t lf = u'\n'; static inline constexpr char16_t cr = u'\r'; static inline constexpr char16_t space = u' '; static inline constexpr char16_t plus = u'+'; static inline constexpr char16_t comma = u','; static inline constexpr char16_t minus = u'-'; static inline constexpr char16_t number0 = u'0'; static inline constexpr char16_t number1 = u'1'; static inline constexpr char16_t number9 = u'9'; static inline constexpr char16_t A = u'A'; static inline constexpr char16_t Z = u'Z'; static inline constexpr char16_t a = u'a'; static inline constexpr char16_t z = u'z'; }; template <> struct char_constants { static inline constexpr char32_t null = U'\0'; static inline constexpr char32_t tab = U'\t'; static inline constexpr char32_t lf = U'\n'; static inline constexpr char32_t cr = U'\r'; static inline constexpr char32_t space = U' '; static inline constexpr char32_t plus = U'+'; static inline constexpr char32_t comma = U','; static inline constexpr char32_t minus = U'-'; static inline constexpr char32_t number0 = U'0'; static inline constexpr char32_t number1 = U'1'; static inline constexpr char32_t number9 = U'9'; static inline constexpr char32_t A = U'A'; static inline constexpr char32_t Z = U'Z'; static inline constexpr char32_t a = U'a'; static inline constexpr char32_t z = U'z'; }; // string_traits abstract the API of underlying string classes, in particular they allow adopting to CString without having to specialize for CString explicitly template struct string_traits { using string_type = Tstring; using size_type = typename string_type::size_type; using char_type = typename string_type::value_type; using unsigned_char_type = typename std::make_unsigned::type; static inline std::size_t length(const string_type & str) { return str.length(); } static inline void reserve(string_type & str, std::size_t size) { str.reserve(size); } static inline void set_at(string_type & str, size_type pos, char_type c) { str.data()[pos] = c; } static inline void append(string_type & str, const string_type & a) { str.append(a); } static inline void append(string_type & str, string_type && a) { str.append(std::move(a)); } static inline void append(string_type & str, std::size_t count, char_type c) { str.append(count, c); } static inline void append(string_type & str, char_type c) { str.append(1, c); } static inline string_type pad(string_type str, std::size_t left, std::size_t right) { str.insert(str.begin(), left, char_constants::space); str.insert(str.end(), right, char_constants::space); return str; } }; #if MPT_DETECTED_MFC template <> struct string_traits { using string_type = CStringA; using size_type = int; using char_type = typename CStringA::XCHAR; using unsigned_char_type = typename std::make_unsigned::type; static inline size_type length(const string_type & str) { return str.GetLength(); } static inline void reserve(string_type & str, size_type size) { str.Preallocate(size); } static inline void set_at(string_type & str, size_type pos, char_type c) { str.SetAt(pos, c); } static inline void append(string_type & str, const string_type & a) { str.Append(a); } static inline void append(string_type & str, size_type count, char_type c) { while (count--) { str.AppendChar(c); } } static inline void append(string_type & str, char_type c) { str.AppendChar(c); } static inline string_type pad(const string_type & str, size_type left, size_type right) { string_type tmp; while (left--) { tmp.AppendChar(char_constants::space); } tmp += str; while (right--) { tmp.AppendChar(char_constants::space); } return tmp; } }; template <> struct string_traits { using string_type = CStringW; using size_type = int; using char_type = typename CStringW::XCHAR; using unsigned_char_type = typename std::make_unsigned::type; static inline size_type length(const string_type & str) { return str.GetLength(); } static inline void reserve(string_type & str, size_type size) { str.Preallocate(size); } static inline void set_at(string_type & str, size_type pos, char_type c) { str.SetAt(pos, c); } static inline void append(string_type & str, const string_type & a) { str.Append(a); } static inline void append(string_type & str, size_type count, char_type c) { while (count--) { str.AppendChar(c); } } static inline void append(string_type & str, char_type c) { str.AppendChar(c); } static inline string_type pad(const string_type & str, size_type left, size_type right) { string_type tmp; while (left--) { tmp.AppendChar(char_constants::space); } tmp += str; while (right--) { tmp.AppendChar(char_constants::space); } return tmp; } }; #endif // MPT_DETECTED_MFC template constexpr bool is_any_line_ending(Tchar c) noexcept { return (c == char_constants::cr) || (c == char_constants::lf); } template inline Tstring default_whitespace() { Tstring result; result.reserve(4); result.push_back(char_constants::space); result.push_back(char_constants::lf); result.push_back(char_constants::cr); result.push_back(char_constants::tab); return result; } // Remove whitespace at start of string template inline Tstring trim_left(Tstring str, const Tstring & whitespace = default_whitespace()) { typename Tstring::size_type pos = str.find_first_not_of(whitespace); if (pos != Tstring::npos) { str.erase(str.begin(), str.begin() + pos); } else if (pos == Tstring::npos && str.length() > 0 && str.find_last_of(whitespace) == str.length() - 1) { return Tstring(); } return str; } // Remove whitespace at end of string template inline Tstring trim_right(Tstring str, const Tstring & whitespace = default_whitespace()) { typename Tstring::size_type pos = str.find_last_not_of(whitespace); if (pos != Tstring::npos) { str.erase(str.begin() + pos + 1, str.end()); } else if (pos == Tstring::npos && str.length() > 0 && str.find_first_of(whitespace) == 0) { return Tstring(); } return str; } // Remove whitespace at start and end of string template inline Tstring trim(Tstring str, const Tstring & whitespace = default_whitespace()) { return trim_right(trim_left(str, whitespace), whitespace); } template inline bool starts_with(const Tstring & str, const Tmatch & match) { return (str.find(typename mpt::make_string_type::type{match}) == 0); } template inline bool ends_with(const Tstring & str, const Tmatch & match) { return (str.rfind(typename mpt::make_string_type::type{match}) == (str.length() - typename mpt::make_string_type::type{match}.length())); } template inline Tstring replace(Tstring str, const Treplace & old_str, const Treplace & new_str) { std::size_t pos = 0; while ((pos = str.find(typename mpt::make_string_type::type{old_str}, pos)) != Tstring::npos) { str.replace(pos, typename mpt::make_string_type::type{old_str}.length(), typename mpt::make_string_type::type{new_str}); pos += typename mpt::make_string_type::type{new_str}.length(); } return str; } template inline Tstring truncate(Tstring str, std::size_t max_len) { if (str.length() > max_len) { str.resize(max_len); } return str; } template inline constexpr Tchar to_lower_ascii(Tchar c) noexcept { if (char_constants::A <= c && c <= char_constants::Z) { c += char_constants::a - char_constants::A; } return c; } template inline constexpr Tchar to_upper_ascii(Tchar c) noexcept { if (char_constants::a <= c && c <= char_constants::z) { c -= char_constants::a - char_constants::A; } return c; } template inline std::vector split(const Tstring & str, const Tstring & sep = Tstring(1, char_constants::comma)) { std::vector vals; std::size_t pos = 0; while (str.find(sep, pos) != std::string::npos) { vals.push_back(str.substr(pos, str.find(sep, pos) - pos)); pos = str.find(sep, pos) + sep.length(); } if (!vals.empty() || (str.substr(pos).length() > 0)) { vals.push_back(str.substr(pos)); } return vals; } template inline Tstring join(const std::vector & vals, const Tstring & sep = Tstring(1, char_constants::comma)) { Tstring str; for (std::size_t i = 0; i < vals.size(); ++i) { if (i > 0) { str += sep; } str += vals[i]; } return str; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_STRING_UTILITY_HPP libopenmpt-0.8.1+release.autotools/src/mpt/string/buffer.hpp0000644000175000017500000003407514731263064021154 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_STRING_BUFFER_HPP #define MPT_STRING_BUFFER_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/detect/mfc.hpp" #include "mpt/string/types.hpp" #include "mpt/string/utility.hpp" #include #include #include #include #include #include #include #include #if MPT_DETECTED_MFC // cppcheck-suppress missingInclude #include #endif // MPT_DETECTED_MFC namespace mpt { inline namespace MPT_INLINE_NS { template class StringBufRefImpl { private: Tchar * buf; std::size_t size; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar explicit StringBufRefImpl(Tchar * buf_, std::size_t size_) : buf(buf_) , size(size_) { static_assert(sizeof(Tchar) == sizeof(typename Tstring::value_type)); assert(size > 0); } StringBufRefImpl(const StringBufRefImpl &) = delete; StringBufRefImpl(StringBufRefImpl &&) = default; StringBufRefImpl & operator=(const StringBufRefImpl &) = delete; StringBufRefImpl & operator=(StringBufRefImpl &&) = delete; operator Tstring() const { std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return Tstring(buf, buf + len); } explicit operator std::basic_string_view() const { std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return std::basic_string_view(buf, buf + len); } bool empty() const { return buf[0] == char_constants::null; } StringBufRefImpl & operator=(const Tstring & str) { std::copy(str.data(), str.data() + std::min(str.length(), size - 1), buf); std::fill(buf + std::min(str.length(), size - 1), buf + size, char_constants::null); return *this; } }; template class StringBufRefImpl { private: const Tchar * buf; std::size_t size; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar explicit StringBufRefImpl(const Tchar * buf_, std::size_t size_) : buf(buf_) , size(size_) { static_assert(sizeof(Tchar) == sizeof(typename Tstring::value_type)); assert(size > 0); } StringBufRefImpl(const StringBufRefImpl &) = delete; StringBufRefImpl(StringBufRefImpl &&) = default; StringBufRefImpl & operator=(const StringBufRefImpl &) = delete; StringBufRefImpl & operator=(StringBufRefImpl &&) = delete; operator Tstring() const { std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return Tstring(buf, buf + len); } explicit operator std::basic_string_view() const { std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return std::basic_string_view(buf, len); } bool empty() const { return buf[0] == char_constants::null; } }; template struct make_string_type> { using type = Tstring; }; template struct make_string_view_type> { using type = typename mpt::make_string_view_type::type; }; template inline StringBufRefImpl::type> ReadTypedBuf(const std::array & buf) { return StringBufRefImpl::type>(buf.data(), size); } template inline StringBufRefImpl::type> ReadTypedBuf(const Tchar (&buf)[size]) { return StringBufRefImpl::type>(buf, size); } template inline StringBufRefImpl::type> ReadTypedBuf(const Tchar * buf, std::size_t size) { return StringBufRefImpl::type>(buf, size); } template inline StringBufRefImpl WriteTypedBuf(std::array & buf) { return StringBufRefImpl(buf.data(), size); } template inline StringBufRefImpl WriteTypedBuf(Tchar (&buf)[size]) { return StringBufRefImpl(buf, size); } template inline StringBufRefImpl WriteTypedBuf(Tchar * buf, std::size_t size) { return StringBufRefImpl(buf, size); } template inline StringBufRefImpl::type>, typename std::add_const::type> ReadAutoBuf(const std::array & buf) { return StringBufRefImpl::type>, typename std::add_const::type>(buf.data(), size); } template inline StringBufRefImpl::type>, typename std::add_const::type> ReadAutoBuf(const Tchar (&buf)[size]) { return StringBufRefImpl::type>, typename std::add_const::type>(buf, size); } template inline StringBufRefImpl::type>, typename std::add_const::type> ReadAutoBuf(const Tchar * buf, std::size_t size) { return StringBufRefImpl::type>, typename std::add_const::type>(buf, size); } template inline StringBufRefImpl::type>, Tchar> WriteAutoBuf(std::array & buf) { return StringBufRefImpl::type>, Tchar>(buf.data(), size); } template inline StringBufRefImpl::type>, Tchar> WriteAutoBuf(Tchar (&buf)[size]) { return StringBufRefImpl::type>, Tchar>(buf, size); } template inline StringBufRefImpl::type>, Tchar> WriteAutoBuf(Tchar * buf, std::size_t size) { return StringBufRefImpl::type>, Tchar>(buf, size); } #if MPT_OS_WINDOWS template inline StringBufRefImpl::type>::string_type, typename std::add_const::type> ReadWinBuf(const std::array & buf) { return StringBufRefImpl::type>::string_type, typename std::add_const::type>(buf.data(), size); } template inline StringBufRefImpl::type>::string_type, typename std::add_const::type> ReadWinBuf(const Tchar (&buf)[size]) { return StringBufRefImpl::type>::string_type, typename std::add_const::type>(buf, size); } template inline StringBufRefImpl::type>::string_type, typename std::add_const::type> ReadWinBuf(const Tchar * buf, std::size_t size) { return StringBufRefImpl::type>::string_type, typename std::add_const::type>(buf, size); } template inline StringBufRefImpl::type>::string_type, Tchar> WriteWinBuf(std::array & buf) { return StringBufRefImpl::type>::string_type, Tchar>(buf.data(), size); } template inline StringBufRefImpl::type>::string_type, Tchar> WriteWinBuf(Tchar (&buf)[size]) { return StringBufRefImpl::type>::string_type, Tchar>(buf, size); } template inline StringBufRefImpl::type>::string_type, Tchar> WriteWinBuf(Tchar * buf, std::size_t size) { return StringBufRefImpl::type>::string_type, Tchar>(buf, size); } #endif // MPT_OS_WINDOWS #if MPT_DETECTED_MFC template class CStringBufRefImpl { private: Tchar * buf; std::size_t size; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar explicit CStringBufRefImpl(Tchar * buf_, std::size_t size_) : buf(buf_) , size(size_) { assert(size > 0); } CStringBufRefImpl(const CStringBufRefImpl &) = delete; CStringBufRefImpl(CStringBufRefImpl &&) = default; CStringBufRefImpl & operator=(const CStringBufRefImpl &) = delete; CStringBufRefImpl & operator=(CStringBufRefImpl &&) = delete; operator CString() const { std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return CString(buf, mpt::saturate_cast(len)); } CStringBufRefImpl & operator=(const CString & str) { std::copy(str.GetString(), str.GetString() + std::min(static_cast(str.GetLength()), size - 1), buf); std::fill(buf + std::min(static_cast(str.GetLength()), size - 1), buf + size, char_constants::null); return *this; } }; template class CStringBufRefImpl { private: const Tchar * buf; std::size_t size; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar explicit CStringBufRefImpl(const Tchar * buf_, std::size_t size_) : buf(buf_) , size(size_) { assert(size > 0); } CStringBufRefImpl(const CStringBufRefImpl &) = delete; CStringBufRefImpl(CStringBufRefImpl &&) = default; CStringBufRefImpl & operator=(const CStringBufRefImpl &) = delete; CStringBufRefImpl & operator=(CStringBufRefImpl &&) = delete; operator CString() const { std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return CString(buf, mpt::saturate_cast(len)); } }; template struct make_string_type> { using type = CString; }; template struct make_string_view_type> { using type = CString; }; template inline CStringBufRefImpl::type> ReadCStringBuf(const std::array & buf) { return CStringBufRefImpl::type>(buf.data(), size); } template inline CStringBufRefImpl::type> ReadCStringBuf(const Tchar (&buf)[size]) { return CStringBufRefImpl::type>(buf, size); } template inline CStringBufRefImpl::type> ReadCStringBuf(const Tchar * buf, std::size_t size) { return CStringBufRefImpl::type>(buf, size); } template inline CStringBufRefImpl WriteCStringBuf(std::array & buf) { return CStringBufRefImpl(buf.data(), size); } template inline CStringBufRefImpl WriteCStringBuf(Tchar (&buf)[size]) { return CStringBufRefImpl(buf, size); } template inline CStringBufRefImpl WriteCStringBuf(Tchar * buf, std::size_t size) { return CStringBufRefImpl(buf, size); } #endif // MPT_DETECTED_MFC template struct charbuf { public: using Tchar = char; using char_type = Tchar; using string_type = std::basic_string; using string_view_type = std::basic_string_view; constexpr std::size_t static_length() const { return len; } public: Tchar buf[len]{}; public: constexpr charbuf() { for (std::size_t i = 0; i < len; ++i) { buf[i] = char_constants::null; } } constexpr charbuf(const charbuf &) = default; constexpr charbuf(charbuf &&) = default; constexpr charbuf & operator=(const charbuf &) = default; constexpr charbuf & operator=(charbuf &&) = default; const Tchar & operator[](std::size_t i) const { return buf[i]; } std::string str() const { return static_cast(*this); } operator string_type() const { return mpt::ReadAutoBuf(buf); } explicit operator string_view_type() const { return static_cast(mpt::ReadAutoBuf(buf)); } bool empty() const { return mpt::ReadAutoBuf(buf).empty(); } charbuf & operator=(const string_type & str) { mpt::WriteAutoBuf(buf) = str; return *this; } public: friend bool operator!=(const charbuf & a, const charbuf & b) { return static_cast(a) != static_cast(b); } friend bool operator!=(const std::string & a, const charbuf & b) { return a != static_cast(b); } friend bool operator!=(const charbuf & a, const std::string & b) { return static_cast(a) != b; } friend bool operator==(const charbuf & a, const charbuf & b) { return static_cast(a) == static_cast(b); } friend bool operator==(const std::string & a, const charbuf & b) { return a == static_cast(b); } friend bool operator==(const charbuf & a, const std::string & b) { return static_cast(a) == b; } }; template struct make_string_type> { using type = std::string; }; template struct make_string_view_type> { using type = std::string_view; }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_STRING_BUFFER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/string/types.hpp0000644000175000017500000004136214711627422021044 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_STRING_TYPES_HPP #define MPT_STRING_TYPES_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/detect/mfc.hpp" #include #include #include #include #include #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { enum class common_encoding { utf8, ascii, // strictly 7-bit ASCII iso8859_1, iso8859_15, cp437, cp737, cp775, cp850, cp852, cp855, cp857, cp860, cp861, cp862, cp863, cp864, cp865, cp866, cp869, cp874, windows1252, amiga, riscos, atarist, iso8859_1_no_c1, iso8859_15_no_c1, amiga_no_c1, }; enum class logical_encoding { locale, // CP_ACP on windows, system configured C locale otherwise active_locale, // active C/C++ global locale }; // source code / preprocessor (i.e. # token) inline constexpr auto source_encoding = common_encoding::ascii; // debug log files inline constexpr auto logfile_encoding = common_encoding::utf8; // std::clog / std::cout / std::cerr inline constexpr auto stdio_encoding = logical_encoding::locale; // getenv inline constexpr auto environment_encoding = logical_encoding::locale; // std::exception::what() inline constexpr auto exception_encoding = logical_encoding::locale; template struct is_character : public std::false_type { }; template <> struct is_character : public std::true_type { }; #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> struct is_character : public std::true_type { }; #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_CXX_AT_LEAST(20) template <> struct is_character : public std::true_type { }; #endif // C++20 template <> struct is_character : public std::true_type { }; template <> struct is_character : public std::true_type { }; template ::value, bool>::type = true> MPT_CONSTEXPRINLINE typename std::make_unsigned::type char_value(T x) noexcept { return static_cast::type>(x); } template struct unsafe_char_converter { }; template <> struct unsafe_char_converter { static constexpr char32_t decode(char c) noexcept { return static_cast(static_cast(static_cast(c))); } static constexpr char encode(char32_t c) noexcept { return static_cast(static_cast(static_cast(c))); } }; #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> struct unsafe_char_converter { static constexpr char32_t decode(wchar_t c) noexcept { return static_cast(static_cast(static_cast::type>(c))); } static constexpr wchar_t encode(char32_t c) noexcept { return static_cast(static_cast::type>(static_cast(c))); } }; #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_CXX_AT_LEAST(20) template <> struct unsafe_char_converter { static constexpr char32_t decode(char8_t c) noexcept { return static_cast(static_cast(static_cast(c))); } static constexpr char8_t encode(char32_t c) noexcept { return static_cast(static_cast(static_cast(c))); } }; #endif // C++20 template <> struct unsafe_char_converter { static constexpr char32_t decode(char16_t c) noexcept { return static_cast(static_cast(static_cast(c))); } static constexpr char16_t encode(char32_t c) noexcept { return static_cast(static_cast(static_cast(c))); } }; template <> struct unsafe_char_converter { static constexpr char32_t decode(char32_t c) noexcept { return c; } static constexpr char32_t encode(char32_t c) noexcept { return c; } }; template constexpr Tdstchar unsafe_char_convert(Tsrcchar src) noexcept { return mpt::unsafe_char_converter::encode(mpt::unsafe_char_converter::decode(src)); } #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) using widestring = std::wstring; using widestring_view = std::wstring_view; using widechar = wchar_t; #define MPT_WIDECHAR(x) L##x #define MPT_WIDELITERAL(x) L##x #define MPT_WIDESTRING(x) std::wstring(L##x) #define MPT_WIDESTRINGVIEW(x) std::wstring_view(L##x) #else // MPT_COMPILER_QUIRK_NO_WCHAR using widestring = std::u32string; using widestring_view = std::u32string_view; using widechar = char32_t; #define MPT_WIDECHAR(x) U##x #define MPT_WIDELITERAL(x) U##x #define MPT_WIDESTRING(x) std::u32string(U##x) #define MPT_WIDESTRINGVIEW(x) std::u32string_view(U##x) #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) // Work-around for VS2017 auto template argument ICE. // Use as encoding_char_traits::type, foo> instead of encoding_char_traits template struct encoding_char_traits : std::char_traits { static constexpr auto encoding() noexcept { return encoding_tag; } }; #else template struct encoding_char_traits : std::char_traits { static constexpr auto encoding() noexcept { return encoding_tag; } }; #endif #if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) using lstring = std::basic_string>; using lstring_view = std::basic_string_view>; #else using lstring = std::basic_string>; using lstring_view = std::basic_string_view>; #endif #if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) using utf8string = std::basic_string>; using utf8string_view = std::basic_string_view>; #else using utf8string = std::basic_string>; using utf8string_view = std::basic_string_view>; #endif #if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) using source_string = std::basic_string::type, source_encoding>>; using source_string_view = std::basic_string_view::type, source_encoding>>; #else using source_string = std::basic_string>; using source_string_view = std::basic_string_view>; #endif #if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) using exception_string = std::basic_string::type, exception_encoding>>; using exception_string_view = std::basic_string_view::type, exception_encoding>>; #else using exception_string = std::basic_string>; using exception_string_view = std::basic_string_view>; #endif #if MPT_OS_WINDOWS template struct windows_char_traits { }; template <> struct windows_char_traits { using string_type = mpt::lstring; using string_view_type = mpt::lstring_view; }; #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> struct windows_char_traits { using string_type = std::wstring; using string_view_type = std::wstring_view; }; #endif // !MPT_COMPILER_QUIRK_NO_WCHAR using tstring = windows_char_traits::string_type; using tstring_view = windows_char_traits::string_view_type; using winstring = mpt::tstring; using winstring_view = mpt::tstring_view; #endif // MPT_OS_WINDOWS #if MPT_CXX_AT_LEAST(20) using u8string = std::u8string; using u8string_view = std::u8string_view; using u8char = char8_t; #define MPT_U8CHAR(x) u8##x #define MPT_U8LITERAL(x) u8##x #define MPT_U8STRING(x) std::u8string(u8##x) #define MPT_U8STRINGVIEW(x) std::u8string_view(u8##x) #else // !C++20 #if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) using u8string = std::basic_string>; using u8string_view = std::basic_string_view>; #else using u8string = std::basic_string>; using u8string_view = std::basic_string_view>; #endif using u8char = char; #define MPT_U8CHAR(x) x #define MPT_U8LITERAL(x) x #define MPT_U8STRING(x) mpt::u8string(x) #define MPT_U8STRINGVIEW(x) mpt::u8string_view(x) // mpt::u8string is a moderately type-safe string that is meant to contain // UTF-8 encoded char bytes. // // mpt::u8string is not implicitely convertible to/from std::string, but // it is convertible to/from C strings the same way as std::string is. // // The implementation of mpt::u8string is a compromise of compatibilty // with implementation-defined STL details, efficiency, source code size, // executable bloat, type-safety and simplicity. // // mpt::u8string is not meant to be used directly though. // mpt::u8string is meant as an alternative implementaion to std::wstring // for implementing the unicode string type mpt::ustring. #endif // C++20 #if !defined(MPT_USTRING_MODE_UTF8_FORCE) && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) && (MPT_COMPILER_MSVC || (MPT_DETECTED_MFC && defined(UNICODE))) // Use wide strings for MSVC because this is the native encoding on // microsoft platforms. #define MPT_USTRING_MODE_WIDE 1 #define MPT_USTRING_MODE_UTF8 0 #else #define MPT_USTRING_MODE_WIDE 0 #define MPT_USTRING_MODE_UTF8 1 #endif // mpt::ustring // // mpt::ustring is a string type that can hold unicode strings. // It is implemented as a std::basic_string either based on wchar_t (i.e. the // same as std::wstring) or a custom-defined char_traits class that is derived // from std::char_traits. // The selection of the underlying implementation is done at compile-time. // MPT_UCHAR, MPT_ULITERAL and MPT_USTRING are macros that ease construction // of ustring char literals, ustring char array literals and ustring objects // from ustring char literals that work consistently in both modes. // Note that these are not supported for non-ASCII characters appearing in // the macro argument. // Also note that, as both UTF8 and UTF16 (it is less of an issue for UTF32) // are variable-length encodings and mpt::ustring is implemented as a // std::basic_string, all member functions that require individual character // access will not work consistently or even at all in a meaningful way. // This in particular affects operator[], find() and substr(). // The code makes no effort in preventing these or generating warnings when // these are used on mpt::ustring objects. However, compiling in the // respectively other mpt::ustring mode will catch most of these anyway. #if MPT_USTRING_MODE_WIDE && MPT_USTRING_MODE_UTF8 #error "MPT_USTRING_MODE_WIDE and MPT_USTRING_MODE_UTF8 are mutually exclusive." #endif #if MPT_USTRING_MODE_WIDE using ustring = std::wstring; using ustring_view = std::wstring_view; using uchar = wchar_t; #define MPT_UCHAR(x) L##x #define MPT_ULITERAL(x) L##x #define MPT_USTRING(x) std::wstring(L##x) #define MPT_USTRINGVIEW(x) std::wstring_view(L##x) #endif // MPT_USTRING_MODE_WIDE #if MPT_USTRING_MODE_UTF8 using ustring = mpt::u8string; using ustring_view = mpt::u8string_view; using uchar = mpt::u8char; #define MPT_UCHAR(x) MPT_U8CHAR(x) #define MPT_ULITERAL(x) MPT_U8LITERAL(x) #define MPT_USTRING(x) MPT_U8STRING(x) #define MPT_USTRINGVIEW(x) MPT_U8STRINGVIEW(x) #endif // MPT_USTRING_MODE_UTF8 template struct make_string_type { }; template struct make_string_type> { using type = std::basic_string; }; template struct make_string_type> { using type = std::basic_string; }; template struct make_string_type { using type = std::basic_string; }; template struct make_string_type { using type = std::basic_string; }; template struct make_string_type { using type = typename make_string_type::type; }; #if MPT_DETECTED_MFC template <> struct make_string_type { using type = CStringW; }; template <> struct make_string_type { using type = CStringA; }; #endif // MPT_DETECTED_MFC template struct make_string_view_type { }; template struct make_string_view_type> { using type = std::basic_string_view; }; template struct make_string_view_type> { using type = std::basic_string_view; }; template struct make_string_view_type { using type = std::basic_string_view; }; template struct make_string_view_type { using type = std::basic_string_view; }; template struct make_string_view_type { using type = typename make_string_view_type::type; }; #if MPT_DETECTED_MFC template <> struct make_string_view_type { using type = CStringW; }; template <> struct make_string_view_type { using type = CStringA; }; #endif // MPT_DETECTED_MFC template struct is_string_type : public std::false_type { }; template <> struct is_string_type : public std::true_type { }; #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> struct is_string_type : public std::true_type { }; #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_CXX_AT_LEAST(20) template <> struct is_string_type : public std::true_type { }; #endif // C++20 template <> struct is_string_type : public std::true_type { }; template <> struct is_string_type : public std::true_type { }; #if MPT_DETECTED_MFC template <> struct is_string_type : public std::true_type { }; template <> struct is_string_type : public std::true_type { }; #endif // MPT_DETECTED_MFC template struct is_string_type> : public std::true_type { }; template struct is_string_view_type : public std::false_type { }; template struct is_string_view_type> : public std::true_type { }; template inline typename mpt::make_string_type::type>::type as_string(T && str) { if constexpr (std::is_pointer::type>::type>::value) { return str ? typename mpt::make_string_type::type>::type{std::forward(str)} : typename mpt::make_string_type::type>::type{}; } else if constexpr (std::is_pointer::type>::value) { return typename mpt::make_string_type::type>::type{std::forward(str)}; } else if constexpr (mpt::is_string_view_type::type>::value) { return typename mpt::make_string_type::type>::type{std::forward(str)}; } else { return std::forward(str); } } template inline typename mpt::make_string_view_type::type>::type as_string_view(T && str) { if constexpr (std::is_pointer::type>::type>::value) { return str ? typename mpt::make_string_view_type::type>::type{std::forward(str)} : typename mpt::make_string_view_type::type>::type{}; } else if constexpr (std::is_pointer::type>::value) { return typename mpt::make_string_view_type::type>::type{std::forward(str)}; } else if constexpr (mpt::is_string_view_type::type>::value) { return typename mpt::make_string_view_type::type>::type{std::forward(str)}; } else { return std::forward(str); } } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_STRING_TYPES_HPP libopenmpt-0.8.1+release.autotools/src/mpt/string/tests/0000755000175000017500000000000015023302361020370 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/string/tests/tests_string_utility.hpp0000644000175000017500000000257414044173026025352 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_STRING_TESTS_STRING_UTILITY_HPP #define MPT_STRING_TESTS_STRING_UTILITY_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/utility.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace string { namespace utility { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/string/utility") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { MPT_TEST_EXPECT_EQUAL(mpt::trim_left(std::string(" ")), ""); MPT_TEST_EXPECT_EQUAL(mpt::trim_right(std::string(" ")), ""); MPT_TEST_EXPECT_EQUAL(mpt::trim(std::string(" ")), ""); // weird things with std::string containing \0 in the middle and trimming \0 MPT_TEST_EXPECT_EQUAL(std::string("\0\ta\0b ", 6).length(), (std::size_t)6); MPT_TEST_EXPECT_EQUAL(mpt::trim_right(std::string("\0\ta\0b ", 6)), std::string("\0\ta\0b", 5)); MPT_TEST_EXPECT_EQUAL(mpt::trim(std::string("\0\ta\0b\0", 6), std::string("\0", 1)), std::string("\ta\0b", 4)); } } // namespace utility } // namespace string } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_STRING_TESTS_STRING_UTILITY_HPP libopenmpt-0.8.1+release.autotools/src/mpt/string/tests/tests_string_buffer.hpp0000644000175000017500000000377714044173026025126 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_STRING_TESTS_STRING_BUFFER_HPP #define MPT_STRING_TESTS_STRING_BUFFER_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/buffer.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace string { namespace buffer { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/string/buffer") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { { char buf[4] = {'x', 'x', 'x', 'x'}; mpt::WriteAutoBuf(buf) = std::string("foobar"); MPT_TEST_EXPECT_EQUAL(buf[0], 'f'); MPT_TEST_EXPECT_EQUAL(buf[1], 'o'); MPT_TEST_EXPECT_EQUAL(buf[2], 'o'); MPT_TEST_EXPECT_EQUAL(buf[3], '\0'); } { char buf[4] = {'x', 'x', 'x', 'x'}; char foobar[] = {'f', 'o', 'o', 'b', 'a', 'r', '\0'}; mpt::WriteTypedBuf(buf) = (char *)foobar; MPT_TEST_EXPECT_EQUAL(buf[0], 'f'); MPT_TEST_EXPECT_EQUAL(buf[1], 'o'); MPT_TEST_EXPECT_EQUAL(buf[2], 'o'); MPT_TEST_EXPECT_EQUAL(buf[3], '\0'); } { char buf[4] = {'x', 'x', 'x', 'x'}; mpt::WriteTypedBuf(buf) = (const char *)"foobar"; MPT_TEST_EXPECT_EQUAL(buf[0], 'f'); MPT_TEST_EXPECT_EQUAL(buf[1], 'o'); MPT_TEST_EXPECT_EQUAL(buf[2], 'o'); MPT_TEST_EXPECT_EQUAL(buf[3], '\0'); } { char buf[4] = {'x', 'x', 'x', 'x'}; mpt::WriteTypedBuf(buf) = "foobar"; MPT_TEST_EXPECT_EQUAL(buf[0], 'f'); MPT_TEST_EXPECT_EQUAL(buf[1], 'o'); MPT_TEST_EXPECT_EQUAL(buf[2], 'o'); MPT_TEST_EXPECT_EQUAL(buf[3], '\0'); } { const char buf[4] = {'f', 'o', 'o', 'b'}; std::string foo = mpt::ReadAutoBuf(buf); MPT_TEST_EXPECT_EQUAL(foo, std::string("foob")); } } } // namespace buffer } // namespace string } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_STRING_TESTS_STRING_BUFFER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/arch/0000755000175000017500000000000015023302361016635 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/arch/feature_flags.hpp0000644000175000017500000000435514226550757022126 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_ARCH_FEATURE_FLAGS_HPP #define MPT_ARCH_FEATURE_FLAGS_HPP #include "mpt/base/namespace.hpp" namespace mpt { inline namespace MPT_INLINE_NS { namespace arch { template struct [[nodiscard]] basic_feature_flags { private: bitset m_flags{}; public: constexpr basic_feature_flags() noexcept = default; explicit constexpr basic_feature_flags(bitset flags) noexcept : m_flags(flags) { return; } [[nodiscard]] constexpr basic_feature_flags operator~() noexcept { return basic_feature_flags{~m_flags}; } constexpr basic_feature_flags & operator&=(basic_feature_flags o) noexcept { m_flags &= o.m_flags; return *this; } constexpr basic_feature_flags & operator|=(basic_feature_flags o) noexcept { m_flags |= o.m_flags; return *this; } constexpr basic_feature_flags & operator^=(basic_feature_flags o) noexcept { m_flags ^= o.m_flags; return *this; } [[nodiscard]] friend constexpr basic_feature_flags operator&(basic_feature_flags a, basic_feature_flags b) noexcept { return basic_feature_flags{static_cast(a.m_flags & b.m_flags)}; } [[nodiscard]] friend constexpr basic_feature_flags operator|(basic_feature_flags a, basic_feature_flags b) noexcept { return basic_feature_flags{static_cast(a.m_flags | b.m_flags)}; } [[nodiscard]] friend constexpr basic_feature_flags operator^(basic_feature_flags a, basic_feature_flags b) noexcept { return basic_feature_flags{static_cast(a.m_flags ^ b.m_flags)}; } [[nodiscard]] friend constexpr bool operator==(basic_feature_flags a, basic_feature_flags b) noexcept { return a.m_flags == b.m_flags; } [[nodiscard]] friend constexpr bool operator!=(basic_feature_flags a, basic_feature_flags b) noexcept { return a.m_flags != b.m_flags; } [[nodiscard]] constexpr bool supports(basic_feature_flags query) noexcept { return (m_flags & query.m_flags) == query.m_flags; } [[nodiscard]] explicit constexpr operator bool() const noexcept { return m_flags ? true : false; } [[nodiscard]] constexpr bool operator!() const noexcept { return m_flags ? false : true; } }; } // namespace arch } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_ARCH_FEATURE_FLAGS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/arch/x86_amd64.hpp0000644000175000017500000016462514767255435020753 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_ARCH_X86_AMD64_HPP #define MPT_ARCH_X86_AMD64_HPP #include "mpt/arch/feature_flags.hpp" #include "mpt/base/bit.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/utility.hpp" #include "mpt/osinfo/windows_version.hpp" #include #include #if MPT_ARCH_X86 || MPT_ARCH_AMD64 #if MPT_COMPILER_GCC #include #endif #endif #include #include #include #include #if MPT_OS_DJGPP #include #include #endif #if MPT_OS_WINDOWS #include #endif #if MPT_ARCH_X86 || MPT_ARCH_AMD64 #if MPT_COMPILER_MSVC #include #endif #if MPT_COMPILER_MSVC #include #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG #include #include #endif #endif // skip assumed features for amd64 #define MPT_ARCH_X86_AMD64_FAST_DETECT 0 namespace mpt { inline namespace MPT_INLINE_NS { namespace arch { namespace x86 { using feature_flags = mpt::arch::basic_feature_flags; using mode_flags = mpt::arch::basic_feature_flags; // clang-format off namespace feature { inline constexpr feature_flags none = feature_flags{}; inline constexpr feature_flags intel386 = feature_flags{ 0x0000'0001 }; inline constexpr feature_flags fpu = feature_flags{ 0x0000'0002 }; inline constexpr feature_flags fsin = feature_flags{ 0x0000'0004 }; inline constexpr feature_flags intel486 = feature_flags{ 0x0000'0008 }; // XADD, BSWAP, CMPXCHG inline constexpr feature_flags cpuid = feature_flags{ 0x0000'0010 }; inline constexpr feature_flags tsc = feature_flags{ 0x0000'0020 }; inline constexpr feature_flags cx8 = feature_flags{ 0x0000'0040 }; inline constexpr feature_flags cmov = feature_flags{ 0x0000'0080 }; inline constexpr feature_flags mmx = feature_flags{ 0x0000'0100 }; inline constexpr feature_flags mmxext = feature_flags{ 0x0000'0200 }; inline constexpr feature_flags x3dnow = feature_flags{ 0x0000'0400 }; inline constexpr feature_flags x3dnowext = feature_flags{ 0x0000'0800 }; inline constexpr feature_flags x3dnowprefetch = feature_flags{ 0x0000'1000 }; inline constexpr feature_flags fxsr = feature_flags{ 0x0000'2000 }; inline constexpr feature_flags sse = feature_flags{ 0x0000'4000 }; inline constexpr feature_flags sse2 = feature_flags{ 0x0000'8000 }; inline constexpr feature_flags sse3 = feature_flags{ 0x0001'0000 }; inline constexpr feature_flags ssse3 = feature_flags{ 0x0002'0000 }; inline constexpr feature_flags sse4_1 = feature_flags{ 0x0004'0000 }; inline constexpr feature_flags sse4_2 = feature_flags{ 0x0008'0000 }; inline constexpr feature_flags xsave = feature_flags{ 0x0010'0000 }; inline constexpr feature_flags avx = feature_flags{ 0x0020'0000 }; inline constexpr feature_flags avx2 = feature_flags{ 0x0040'0000 }; inline constexpr feature_flags cx16 = feature_flags{ 0x0080'0000 }; inline constexpr feature_flags lahf = feature_flags{ 0x0100'0000 }; inline constexpr feature_flags popcnt = feature_flags{ 0x0200'0000 }; inline constexpr feature_flags bmi1 = feature_flags{ 0x0400'0000 }; inline constexpr feature_flags bmi2 = feature_flags{ 0x0800'0000 }; inline constexpr feature_flags f16c = feature_flags{ 0x1000'0000 }; inline constexpr feature_flags fma = feature_flags{ 0x2000'0000 }; inline constexpr feature_flags lzcnt = feature_flags{ 0x4000'0000 }; inline constexpr feature_flags movbe = feature_flags{ 0x8000'0000 }; } // namespace feature namespace mode { inline constexpr mode_flags base = mode_flags{ 0x00 }; inline constexpr mode_flags xmm128sse = mode_flags{ 0x01 }; inline constexpr mode_flags ymm256avx = mode_flags{ 0x02 }; } // namespace mode namespace featureset { inline constexpr feature_flags intel386 = feature::intel386; inline constexpr feature_flags intel486SX = featureset::intel386 | feature::intel486; inline constexpr feature_flags intel486DX = featureset::intel486SX | feature::fpu | feature::fsin; inline constexpr feature_flags intel586 = featureset::intel486DX | feature::cpuid | feature::tsc | feature::cx8; inline constexpr feature_flags intel586_mmx = featureset::intel586 | feature::mmx; inline constexpr feature_flags intel686 = featureset::intel586 | feature::cmov; inline constexpr feature_flags intel686_mmx = featureset::intel686 | feature::mmx; inline constexpr feature_flags intel686_sse = featureset::intel686_mmx | feature::mmxext | feature::fxsr | feature::sse; inline constexpr feature_flags intel686_sse2 = featureset::intel686_sse | feature::sse2; inline constexpr feature_flags intel786 = featureset::intel686_sse2; inline constexpr feature_flags amd64 = featureset::intel686_sse2; inline constexpr feature_flags amd64_v2 = featureset::amd64 | feature::cx16 | feature::lahf | feature::popcnt | feature::sse3 | feature::ssse3 | feature::sse4_1 | feature::sse4_2; inline constexpr feature_flags amd64_v3 = featureset::amd64_v2 | feature::xsave | feature::avx | feature::avx2 | feature::bmi1 | feature::bmi2 | feature::f16c | feature::fma | feature::lzcnt | feature::movbe; inline constexpr feature_flags msvc_x86_1998 = featureset::intel386 | feature::fpu | feature::fsin; inline constexpr feature_flags msvc_x86_2005 = featureset::intel486DX; inline constexpr feature_flags msvc_x86_2008 = featureset::intel586; inline constexpr feature_flags msvc_x86_sse = featureset::intel686_sse; inline constexpr feature_flags msvc_x86_sse2 = featureset::intel686_sse2; inline constexpr feature_flags msvc_x86_avx = featureset::intel686_sse2 | feature::x3dnowprefetch | feature::xsave | feature::avx; inline constexpr feature_flags msvc_x86_avx2 = featureset::intel686_sse2 | feature::x3dnowprefetch | feature::xsave | feature::avx | feature::avx2 | feature::fma | feature::bmi1; inline constexpr feature_flags msvc_amd64 = featureset::amd64; inline constexpr feature_flags msvc_amd64_avx = featureset::amd64 | feature::xsave | feature::avx; inline constexpr feature_flags msvc_amd64_avx2 = featureset::amd64 | feature::xsave | feature::avx | feature::avx2 | feature::fma | feature::bmi1; } // namespace featureset namespace modeset { inline constexpr mode_flags intel386 = mode::base; inline constexpr mode_flags intel486SX = mode::base; inline constexpr mode_flags intel486DX = mode::base; inline constexpr mode_flags intel586 = mode::base; inline constexpr mode_flags intel586_mmx = mode::base; inline constexpr mode_flags intel686 = mode::base; inline constexpr mode_flags intel686_mmx = mode::base; inline constexpr mode_flags intel686_sse = mode::base | mode::xmm128sse; inline constexpr mode_flags intel686_sse2 = mode::base | mode::xmm128sse; inline constexpr mode_flags intel786 = mode::base | mode::xmm128sse; inline constexpr mode_flags amd64 = mode::base | mode::xmm128sse; inline constexpr mode_flags amd64_v2 = mode::base | mode::xmm128sse; inline constexpr mode_flags amd64_v3 = mode::base | mode::xmm128sse | mode::ymm256avx; inline constexpr mode_flags msvc_x86_1998 = mode::base; inline constexpr mode_flags msvc_x86_2005 = mode::base; inline constexpr mode_flags msvc_x86_2008 = mode::base; inline constexpr mode_flags msvc_x86_sse = mode::base | mode::xmm128sse; inline constexpr mode_flags msvc_x86_sse2 = mode::base | mode::xmm128sse; inline constexpr mode_flags msvc_x86_avx = mode::base | mode::xmm128sse | mode::ymm256avx; inline constexpr mode_flags msvc_x86_avx2 = mode::base | mode::xmm128sse | mode::ymm256avx; inline constexpr mode_flags msvc_amd64 = mode::base | mode::xmm128sse; inline constexpr mode_flags msvc_amd64_avx = mode::base | mode::xmm128sse | mode::ymm256avx; inline constexpr mode_flags msvc_amd64_avx2 = mode::base | mode::xmm128sse | mode::ymm256avx; } // namespace modeset // clang-format on enum class vendor : uint8 { unknown = 0, AMD, Centaur, Cyrix, Intel, Transmeta, NSC, NexGen, Rise, SiS, UMC, VIA, DMnP, Zhaoxin, Hygon, Elbrus, MiSTer, bhyve, KVM, QEMU, HyperV, Parallels, VMWare, Xen, ACRN, QNX, }; // enum class vendor // clang-format off [[nodiscard]] MPT_CONSTEVAL feature_flags assumed_features() noexcept { feature_flags flags{}; #if MPT_ARCH_X86 || MPT_ARCH_AMD64 #ifdef MPT_ARCH_X86_I386 flags |= feature::intel386; #endif #ifdef MPT_ARCH_X86_FPU flags |= feature::fpu; #endif #ifdef MPT_ARCH_X86_FSIN flags |= feature::fsin; #endif #ifdef MPT_ARCH_X86_I486 flags |= feature::intel486; #endif #ifdef MPT_ARCH_X86_CPUID flags |= feature::cpuid; #endif #ifdef MPT_ARCH_X86_TSC flags |= feature::tsc; #endif #ifdef MPT_ARCH_X86_CX8 flags |= feature::cx8; #endif #ifdef MPT_ARCH_X86_CMOV flags |= feature::cmov; #endif #ifdef MPT_ARCH_X86_MMX flags |= feature::mmx; #endif #ifdef MPT_ARCH_X86_MMXEXT flags |= feature::mmxext; #endif #ifdef MPT_ARCH_X86_3DNOW flags |= feature::x3dnow; #endif #ifdef MPT_ARCH_X86_3DNOWEXT flags |= feature::x3dnowext; #endif #ifdef MPT_ARCH_X86_3DNOWPREFETCH flags |= feature::x3dnowprefetch; #endif #ifdef MPT_ARCH_X86_FXSR flags |= feature::fxsr; #endif #ifdef MPT_ARCH_X86_SSE flags |= feature::sse; #endif #ifdef MPT_ARCH_X86_SSE2 flags |= feature::sse2; #endif #ifdef MPT_ARCH_X86_SSE3 flags |= feature::sse3; #endif #ifdef MPT_ARCH_X86_SSSE3 flags |= feature::ssse3; #endif #ifdef MPT_ARCH_X86_SSE4_1 flags |= feature::sse4_1; #endif #ifdef MPT_ARCH_X86_SSE4_2 flags |= feature::sse4_2; #endif #ifdef MPT_ARCH_X86_XSAVE flags |= feature::xsave; #endif #ifdef MPT_ARCH_X86_AVX flags |= feature::avx; #endif #ifdef MPT_ARCH_X86_AVX2 flags |= feature::avx2; #endif #ifdef MPT_ARCH_X86_CX16 flags |= feature::cx16; #endif #ifdef MPT_ARCH_X86_LAHF flags |= feature::lahf; #endif #ifdef MPT_ARCH_X86_POPCNT flags |= feature::popcnt; #endif #ifdef MPT_ARCH_X86_BMI1 flags |= feature::bmi1; #endif #ifdef MPT_ARCH_X86_BMI2 flags |= feature::bmi2; #endif #ifdef MPT_ARCH_X86_F16C flags |= feature::f16c; #endif #ifdef MPT_ARCH_X86_FMA flags |= feature::fma; #endif #ifdef MPT_ARCH_X86_LZCNT flags |= feature::lzcnt; #endif #ifdef MPT_ARCH_X86_MOVBE flags |= feature::movbe; #endif #endif // MPT_ARCH_X86 || MPT_ARCH_AMD64 return flags; } // clang-format on // clang-format off [[nodiscard]] MPT_CONSTEVAL mode_flags assumed_modes() noexcept { mode_flags flags{}; #if MPT_ARCH_X86 || MPT_ARCH_AMD64 #ifdef MPT_ARCH_X86_SSE flags |= mode::xmm128sse; #endif #ifdef MPT_ARCH_X86_AVX flags |= mode::ymm256avx; #endif #endif // MPT_ARCH_X86 || MPT_ARCH_AMD64 return flags; } // clang-format on template struct fixed_string { std::array m_data = {}; [[nodiscard]] constexpr const char & operator[](std::size_t i) const noexcept { return m_data[i]; } [[nodiscard]] constexpr char & operator[](std::size_t i) noexcept { return m_data[i]; } [[nodiscard]] constexpr std::size_t size() const noexcept { return m_data.size(); } [[nodiscard]] constexpr const char * data() const noexcept { return m_data.data(); } [[nodiscard]] constexpr char * data() noexcept { return m_data.data(); } [[nodiscard]] constexpr const char * begin() const noexcept { return m_data.data(); } [[nodiscard]] constexpr char * begin() noexcept { return m_data.data(); } [[nodiscard]] constexpr const char * end() const noexcept { return m_data.data() + m_data.size(); } [[nodiscard]] constexpr char * end() noexcept { return m_data.data() + m_data.size(); } [[nodiscard]] constexpr operator std::string_view() const noexcept { #if MPT_CXX_AT_LEAST(20) && !defined(MPT_COMPILER_QUIRK_NO_STRING_VIEW_ITERATOR_CTOR) return std::string_view(m_data.begin(), std::find(m_data.begin(), m_data.end(), '\0')); #else return std::string_view(m_data.data(), std::find(m_data.begin(), m_data.end(), '\0') - m_data.begin()); #endif } template [[nodiscard]] friend MPT_CONSTEXPR20_FUN auto operator+(fixed_string a, fixed_string b) -> fixed_string { fixed_string result; std::copy(a.begin(), a.end(), result.data() + 0); std::copy(b.begin(), b.end(), result.data() + N); return result; } [[nodiscard]] inline explicit operator std::string() const { return std::string(m_data.begin(), std::find(m_data.begin(), m_data.end(), '\0')); } }; struct cpu_info { private: feature_flags Features{}; mode_flags Modes{}; uint32 CPUID = 0; vendor Vendor = vendor::unknown; uint16 Family = 0; uint8 Model = 0; uint8 Stepping = 0; fixed_string<12> VendorID; fixed_string<48> BrandID; bool Virtualized = false; fixed_string<12> HypervisorVendor; fixed_string<4> HypervisorInterface; #if !MPT_ARCH_AMD64 bool LongMode = false; #endif // !MPT_ARCH_AMD64 public: [[nodiscard]] MPT_CONSTEXPRINLINE bool operator[](feature_flags query_features) const noexcept { return ((Features & query_features) == query_features); } [[nodiscard]] MPT_CONSTEXPRINLINE bool has_features(feature_flags query_features) const noexcept { return ((Features & query_features) == query_features); } [[nodiscard]] MPT_CONSTEXPRINLINE feature_flags get_features() const noexcept { return Features; } [[nodiscard]] MPT_CONSTEXPRINLINE bool operator[](mode_flags query_modes) const noexcept { return ((Modes & query_modes) == query_modes); } [[nodiscard]] MPT_CONSTEXPRINLINE bool enabled_modes(mode_flags query_modes) const noexcept { return ((Modes & query_modes) == query_modes); } [[nodiscard]] MPT_CONSTEXPRINLINE mode_flags get_modes() const noexcept { return Modes; } [[nodiscard]] MPT_CONSTEXPRINLINE uint32 get_cpuid() const noexcept { return CPUID; } [[nodiscard]] MPT_CONSTEXPRINLINE vendor get_vendor() const noexcept { return Vendor; } [[nodiscard]] MPT_CONSTEXPRINLINE uint16 get_family() const noexcept { return Family; } [[nodiscard]] MPT_CONSTEXPRINLINE uint8 get_model() const noexcept { return Model; } [[nodiscard]] MPT_CONSTEXPRINLINE uint8 get_stepping() const noexcept { return Stepping; } [[nodiscard]] inline std::string get_vendor_string() const { return std::string(VendorID); } [[nodiscard]] inline std::string get_brand_string() const { return std::string(BrandID); } [[nodiscard]] MPT_CONSTEXPRINLINE bool is_virtual() const noexcept { return Virtualized; } [[nodiscard]] MPT_CONSTEXPRINLINE bool can_long_mode() const noexcept { #if !MPT_ARCH_AMD64 return LongMode; #else // MPT_ARCH_AMD64 return true; #endif // !MPT_ARCH_AMD64 } private: #if MPT_ARCH_X86 || MPT_ARCH_AMD64 struct cpuid_result { uint32 a = 0; uint32 b = 0; uint32 c = 0; uint32 d = 0; [[nodiscard]] MPT_CONSTEXPR20_FUN fixed_string<4> as_text4() const noexcept { fixed_string<4> result; result[0 + 0] = static_cast((a >> 0) & 0xff); result[0 + 1] = static_cast((a >> 8) & 0xff); result[0 + 2] = static_cast((a >> 16) & 0xff); result[0 + 3] = static_cast((a >> 24) & 0xff); return result; } [[nodiscard]] MPT_CONSTEXPR20_FUN fixed_string<12> as_text12bcd() const noexcept { fixed_string<12> result; result[0 + 0] = static_cast((b >> 0) & 0xff); result[0 + 1] = static_cast((b >> 8) & 0xff); result[0 + 2] = static_cast((b >> 16) & 0xff); result[0 + 3] = static_cast((b >> 24) & 0xff); result[4 + 0] = static_cast((c >> 0) & 0xff); result[4 + 1] = static_cast((c >> 8) & 0xff); result[4 + 2] = static_cast((c >> 16) & 0xff); result[4 + 3] = static_cast((c >> 24) & 0xff); result[8 + 0] = static_cast((d >> 0) & 0xff); result[8 + 1] = static_cast((d >> 8) & 0xff); result[8 + 2] = static_cast((d >> 16) & 0xff); result[8 + 3] = static_cast((d >> 24) & 0xff); return result; } [[nodiscard]] MPT_CONSTEXPR20_FUN fixed_string<12> as_text12bdc() const noexcept { fixed_string<12> result; result[0 + 0] = static_cast((b >> 0) & 0xff); result[0 + 1] = static_cast((b >> 8) & 0xff); result[0 + 2] = static_cast((b >> 16) & 0xff); result[0 + 3] = static_cast((b >> 24) & 0xff); result[4 + 0] = static_cast((d >> 0) & 0xff); result[4 + 1] = static_cast((d >> 8) & 0xff); result[4 + 2] = static_cast((d >> 16) & 0xff); result[4 + 3] = static_cast((d >> 24) & 0xff); result[8 + 0] = static_cast((c >> 0) & 0xff); result[8 + 1] = static_cast((c >> 8) & 0xff); result[8 + 2] = static_cast((c >> 16) & 0xff); result[8 + 3] = static_cast((c >> 24) & 0xff); return result; } [[nodiscard]] MPT_CONSTEXPR20_FUN fixed_string<16> as_text16() const noexcept { fixed_string<16> result; result[0 + 0] = static_cast((a >> 0) & 0xff); result[0 + 1] = static_cast((a >> 8) & 0xff); result[0 + 2] = static_cast((a >> 16) & 0xff); result[0 + 3] = static_cast((a >> 24) & 0xff); result[4 + 0] = static_cast((b >> 0) & 0xff); result[4 + 1] = static_cast((b >> 8) & 0xff); result[4 + 2] = static_cast((b >> 16) & 0xff); result[4 + 3] = static_cast((b >> 24) & 0xff); result[8 + 0] = static_cast((c >> 0) & 0xff); result[8 + 1] = static_cast((c >> 8) & 0xff); result[8 + 2] = static_cast((c >> 16) & 0xff); result[8 + 3] = static_cast((c >> 24) & 0xff); result[12 + 0] = static_cast((d >> 0) & 0xff); result[12 + 1] = static_cast((d >> 8) & 0xff); result[12 + 2] = static_cast((d >> 16) & 0xff); result[12 + 3] = static_cast((d >> 24) & 0xff); return result; } }; #if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG [[nodiscard]] static cpuid_result cpuid(uint32 function) noexcept { #if MPT_COMPILER_MSVC cpuid_result result; int CPUInfo[4]{}; __cpuid(CPUInfo, function); result.a = CPUInfo[0]; result.b = CPUInfo[1]; result.c = CPUInfo[2]; result.d = CPUInfo[3]; return result; #elif MPT_COMPILER_GCC || (MPT_COMPILER_CLANG && !MPT_ARCH_AMD64) || MPT_CLANG_AT_LEAST(13, 0, 0) // cpuid_result result; unsigned int regeax{}; unsigned int regebx{}; unsigned int regecx{}; unsigned int regedx{}; __cpuid(function, regeax, regebx, regecx, regedx); result.a = regeax; result.b = regebx; result.c = regecx; result.d = regedx; return result; #elif MPT_COMPILER_CLANG && MPT_ARCH_AMD64 // cpuid_result result; unsigned int a{}; unsigned int b{}; unsigned int c{}; unsigned int d{}; // clang-format off __asm__ __volatile__ ( "xchgq %%rbx,%q1 \n\t" "cpuid \n\t" "xchgq %%rbx,%q1 \n\t" : "=a" (a), "=r" (b), "=c" (c), "=d" (d) : "0" (function)); // clang-format on result.a = a; result.b = b; result.c = c; result.d = d; return result; #elif 0 cpuid_result result; unsigned int a{}; unsigned int b{}; unsigned int c{}; unsigned int d{}; // clang-format off __asm__ __volatile__ ( "cpuid \n\t" : "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "0" (function)); // clang-format on result.a = a; result.b = b; result.c = c; result.d = d; return result; #else // MPT_COMPILER return cpuid_result result{}; #endif // MPT_COMPILER } [[nodiscard]] static cpuid_result cpuidex(uint32 function_a, uint32 function_c) noexcept { #if MPT_COMPILER_MSVC cpuid_result result; int CPUInfo[4]{}; __cpuidex(CPUInfo, function_a, function_c); result.a = CPUInfo[0]; result.b = CPUInfo[1]; result.c = CPUInfo[2]; result.d = CPUInfo[3]; return result; #elif MPT_COMPILER_GCC || (MPT_COMPILER_CLANG && !MPT_ARCH_AMD64) || MPT_CLANG_AT_LEAST(13, 0, 0) // cpuid_result result; unsigned int regeax{}; unsigned int regebx{}; unsigned int regecx{}; unsigned int regedx{}; __cpuid_count(function_a, function_c, regeax, regebx, regecx, regedx); result.a = regeax; result.b = regebx; result.c = regecx; result.d = regedx; return result; #elif MPT_COMPILER_CLANG && MPT_ARCH_AMD64 // cpuid_result result; unsigned int a{}; unsigned int b{}; unsigned int c{}; unsigned int d{}; // clang-format off __asm__ __volatile__ ( "xchgq %%rbx,%q1 \n\t" "cpuid \n\t" "xchgq %%rbx,%q1 \n\t" : "=a" (a), "=r" (b), "=c" (c), "=d" (d) : "0" (function_a), "2" (function_c)); // clang-format on result.a = a; result.b = b; result.c = c; result.d = d; return result; #elif 0 cpuid_result result; unsigned int a{}; unsigned int b{}; unsigned int c{}; unsigned int d{}; // clang-format off __asm__ __volatile__ ( "cpuid \n\t" : "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "0" (function_a), "2" (function_c)); // clang-format on result.a = a; result.b = b; result.c = c; result.d = d; return result; #else // MPT_COMPILER return cpuid_result result{}; #endif // MPT_COMPILER } #if MPT_MODE_KERNEL [[nodiscard]] static uint32 read_cr4() noexcept { return __readcr4(); } #endif // MPT_MODE_KERNEL [[nodiscard]] static uint64 read_xcr(uint32 num) noexcept { #if MPT_COMPILER_MSVC return _xgetbv(num); #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG uint32 param_ecx = num; uint32 result_eax = 0; uint32 result_edx = 0; // clang-format off __asm__ __volatile__("xgetbv" : "=a" (result_eax), "=d" (result_edx) : "c" (param_ecx)); // clang-format on return static_cast(result_eax) + (static_cast(result_edx) << 32); #else return _xgetbv(num); #endif } #endif // MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG private: #if MPT_ARCH_X86 || !MPT_ARCH_X86_AMD64_FAST_DETECT #if MPT_OS_DJGPP [[nodiscard]] static uint8 detect_cpu_level() noexcept { #if 0 uint8 result = 0; __dpmi_version_ret dpmi_version{}; if (__dpmi_get_version(&dpmi_version) == 0) { result = dpmi_version.cpu; } return result; #else uint8 result = 0; __dpmi_regs regs{}; regs.x.ax = 0x0400; if (__dpmi_int(0x31, ®s) == 0) { unsigned int cf = (regs.x.flags >> 0) & 1u; if (cf == 0) { result = regs.h.cl; } } return result; #endif } #endif // MPT_OS_DJGPP [[nodiscard]] static uint8 detect_fpu_level() noexcept { #if MPT_OS_DJGPP #if 1 uint8 result = 0; int coprocessor_status = __dpmi_get_coprocessor_status(); if (coprocessor_status == -1) { // error = __dpmi_error return 0; } result = (static_cast(coprocessor_status) & 0x00f0u) >> 4; return result; #else uint8 result = 0; __dpmi_regs regs{}; regs.x.ax = 0x0e00; if (__dpmi_int(0x31, ®s) == 0) { unsigned int cf = (regs.x.flags >> 0) & 1u; if (cf == 0) { result = (regs.x.ax & 0x00f0u) >> 4; } } return result; #endif #elif MPT_OS_WINDOWS uint8 result = 0; #if MPT_WINNT_AT_LEAST(MPT_WIN_NT4) if (mpt::osinfo::windows::Version::Current().IsAtLeast(mpt::osinfo::windows::Version::Win2000)) { if (IsProcessorFeaturePresent(PF_FLOATING_POINT_EMULATED) == 0) { result = 3; } } else { // logic is inverted on NT4 if (IsProcessorFeaturePresent(PF_FLOATING_POINT_EMULATED) != 0) { result = 3; } } #else if ((assumed_features() & feature::fpu) && (assumed_features() & feature::fsin)) { result = 3; } else if (assumed_features() & feature::fpu) { result = 2; } else { result = 0; } #endif return result; #elif MPT_COMPILER_MSVC && MPT_MODE_KERNEL uint8 result = 0; const std::size_t cr0 = __readcr0(); if (!(cr0 & (1u << 2))) { // EM result = 2; if (cr0 & (1u << 4)) { // ET result = 3; } } return result; #else uint8 result = 0; if ((assumed_features() & feature::fpu) && (assumed_features() & feature::fsin)) { result = 3; } else if (assumed_features() & feature::fpu) { result = 2; } else { result = 0; } return result; #endif } #if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG [[nodiscard]] static bool can_toggle_eflags(std::size_t mask) noexcept { std::size_t eflags_old = __readeflags(); std::size_t eflags_flipped = eflags_old ^ mask; __writeeflags(eflags_flipped); std::size_t eflags_testchanged = __readeflags(); __writeeflags(eflags_old); return ((eflags_testchanged ^ eflags_old) & mask) == mask; } #endif [[nodiscard]] static bool can_toggle_eflags_ac() noexcept { #if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG return can_toggle_eflags(0x0004'0000); #else // MPT_COMPILER return (assumed_features() & feature::intel486) != 0; #endif // MPT_COMPILER } [[nodiscard]] static bool can_toggle_eflags_id() noexcept { #if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG return can_toggle_eflags(0x0020'0000); #else // MPT_COMPILER return (assumed_features() & feature::tsc) != 0; #endif // MPT_COMPILER } [[nodiscard]] static bool detect_nexgen() noexcept { #if MPT_ARCH_X86 && MPT_COMPILER_MSVC uint8 result = 0; // clang-format off _asm { mov eax, 0x5555 xor edx, edx mov ecx, 2 clc div ecx jz found jmp done found: mov result, 1 jmp done done: } // clang-format on return (result != 0); #elif MPT_ARCH_X86 && (MPT_COMPILER_GCC || MPT_COMPILER_CLANG) unsigned int result = 0; // clang-format off __asm__ __volatile( "movl $0x5555, %%eax\n" "xorl %%edx, %%edx\n" "movl $2, %%ecx\n" "clc\n" "divl %%ecx\n" "jz detect_nexgen_found\n" "movl $0, %%eax\n" "jmp detect_nexgen_done\n" "detect_nexgen_found:\n" "movl $0, %%eax\n" "jmp detect_nexgen_done\n" "detect_nexgen_done:\n" : "=a" (result) : : "%ebx", "%ecx" ); // clang-format on return (result != 0); #else // assume false return false; #endif } [[nodiscard]] static bool detect_cyrix() noexcept { #if MPT_ARCH_X86 && MPT_COMPILER_MSVC uint8 result = 0; // clang-format off _asm { xor ax, ax sahf mov ax, 5 mov bx, 2 div bl lahf cmp ah, 2 jne not_cyrix mov result, 1 not_cyrix: } // clang-format on return (result != 0); #elif MPT_ARCH_X86 && (MPT_COMPILER_GCC || MPT_COMPILER_CLANG) unsigned int result = 0; // clang-format off __asm__ __volatile( "xor %%ax, %%ax\n" "sahf\n" "movw $5, %%ax\n" "movw $2, %%bx\n" "divb %%bl\n" "lahf\n" "cmpb $2, %%ah\n" "jne detect_cyrix_done_not_cyrix\n" "movl $1, %%eax\n" "jmp detect_cyrix_done\n" "detect_cyrix_done_not_cyrix:\n" "movl $0, %%eax\n" "jmp detect_cyrix_done\n" "detect_cyrix_done:\n" : "=a" (result) : : "%ebx" ); // clang-format on return (result != 0); #else // assume false return false; #endif } [[nodiscard]] static uint16 read_cyrix_id() noexcept { #if MPT_OS_DJGPP uint16 result = 0; outportb(0x22, 0x00); result |= static_cast(inportb(0x23)) << 8; outportb(0x22, 0x01); result |= static_cast(inportb(0x23)) << 0; outportb(0x22, 0x00); inportb(0x23); return result; #elif MPT_COMPILER_MSVC && MPT_MODE_KERNEL uint16 result = 0; __outbyte(0x22, 0x00); result |= static_cast(__inbyte(0x23)) << 8; __outbyte(0x22, 0x01); result |= static_cast(__inbyte(0x23)) << 0; __outbyte(0x22, 0x00); __inbyte(0x23); return result; #else return 0x00'00; #endif } #endif // MPT_ARCH_X86 #endif // MPT_ARCH_X86 || MPT_ARCH_AMD64 public: cpu_info() noexcept { #if MPT_ARCH_X86 || MPT_ARCH_AMD64 #if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG #if MPT_ARCH_X86 || !MPT_ARCH_X86_AMD64_FAST_DETECT Features |= featureset::intel386; if (can_toggle_eflags_ac()) { Features |= feature::intel486; } if (can_toggle_eflags_id()) { Features |= feature::cpuid; } if (!Features.supports(feature::cpuid)) { // without cpuid if (!Features.supports(feature::intel486)) { // 386 const uint8 fpu_level = detect_fpu_level(); if (fpu_level >= 2) { Features |= feature::fpu; } if (fpu_level >= 3) { Features |= feature::fsin; } if (detect_nexgen()) { Vendor = vendor::NexGen; } else { Vendor = vendor::unknown; } } else { // 486+ const uint8 fpu_level = detect_fpu_level(); if (fpu_level >= 2) { Features |= feature::fpu; } if (fpu_level >= 3) { Features |= feature::fsin; } if (detect_cyrix()) { Vendor = vendor::Cyrix; uint16 id = read_cyrix_id(); if (id <= 0x07'00) { // Cx486SLC / Cx486DLC Family = 3; Model = static_cast((id & 0xff'00) >> 8); Stepping = static_cast(id & 0x00'ff); } else if ((0x10'00 <= id) && (id <= 0x13'00)) { // Cx486S Family = 4; Model = static_cast((id & 0xff'00) >> 8); Stepping = static_cast(id & 0x00'ff); } else if ((0x1a'00 <= id) && (id <= 0x1f'00)) { // Cx486DX Family = 4; Model = static_cast((id & 0xff'00) >> 8); Stepping = static_cast(id & 0x00'ff); } else if ((0x28'00 <= id) && (id <= 0x2e'00)) { // Cx5x86 Family = 4; Model = static_cast((id & 0xff'00) >> 8); Stepping = static_cast(id & 0x00'ff); } else if ((0x40'00 <= id) && (id <= 0x4f'00)) { // MediaGx / MediaGXm Family = 4; Model = 4; Stepping = static_cast(id & 0x00'ff); } else if ((0x30'00 <= id) && (id <= 0x34'00)) { // Cx6x86 / Cx6x86L Family = 5; Model = 2; Stepping = static_cast(id & 0x00'ff); if ((id & 0x00'ff) > 0x21) { // Cx6x86L Features |= feature::cx8; } } else if ((0x50'00 <= id) && (id <= 0x5f'00)) { // Cx6x86MX Family = 6; Model = 0; Stepping = static_cast(id & 0x00'ff); Features |= feature::cx8; Features |= feature::tsc; Features |= feature::mmx; Features |= feature::cmov; } } else { Vendor = vendor::unknown; } } } #elif MPT_ARCH_AMD64 Features |= featureset::amd64; Modes |= modeset::amd64; #endif // MPT_ARCH bool have_osxsave = false; if (Features.supports(feature::cpuid)) { // with cpuid cpuid_result VendorString = cpuid(0x0000'0000u); VendorID = VendorString.as_text12bdc(); if (VendorID == std::string_view(" ")) { Vendor = vendor::unknown; } else if (VendorID == std::string_view("AMDisbetter!")) { Vendor = vendor::AMD; } else if (VendorID == std::string_view("AuthenticAMD")) { Vendor = vendor::AMD; } else if (VendorID == std::string_view("CentaurHauls")) { Vendor = vendor::Centaur; } else if (VendorID == std::string_view("CyrixInstead")) { Vendor = vendor::Cyrix; } else if (VendorID == std::string_view("GenuineIntel")) { Vendor = vendor::Intel; } else if (VendorID == std::string_view("TransmetaCPU")) { Vendor = vendor::Transmeta; } else if (VendorID == std::string_view("GenuineTMx86")) { Vendor = vendor::Transmeta; } else if (VendorID == std::string_view("Geode by NSC")) { Vendor = vendor::NSC; } else if (VendorID == std::string_view("NexGenDriven")) { Vendor = vendor::NexGen; } else if (VendorID == std::string_view("RiseRiseRise")) { Vendor = vendor::Rise; } else if (VendorID == std::string_view("SiS SiS SiS ")) { Vendor = vendor::SiS; } else if (VendorID == std::string_view("UMC UMC UMC ")) { Vendor = vendor::UMC; } else if (VendorID == std::string_view("VIA VIA VIA ")) { Vendor = vendor::VIA; } else if (VendorID == std::string_view("Vortex86 SoC")) { Vendor = vendor::DMnP; } else if (VendorID == std::string_view(" Shanghai ")) { Vendor = vendor::Zhaoxin; } else if (VendorID == std::string_view("HygonGenuine")) { Vendor = vendor::Hygon; } else if (VendorID == std::string_view("E2K MACHINE")) { Vendor = vendor::Elbrus; } else if (VendorID == std::string_view("MiSTer AO486")) { Vendor = vendor::MiSTer; } else if (VendorID == std::string_view("bhyve bhyve ")) { Vendor = vendor::bhyve; } else if (VendorID == std::string_view(" KVMKVMKVM ")) { Vendor = vendor::KVM; } else if (VendorID == std::string_view("TCGTCGTCGTCG")) { Vendor = vendor::QEMU; } else if (VendorID == std::string_view("Microsoft Hv")) { Vendor = vendor::HyperV; } else if (VendorID == std::string_view(" lrpepyh vr")) { Vendor = vendor::Parallels; } else if (VendorID == std::string_view("VMwareVMware")) { Vendor = vendor::VMWare; } else if (VendorID == std::string_view("XenVMMXenVMM")) { Vendor = vendor::Xen; } else if (VendorID == std::string_view("ACRNACRNACRN")) { Vendor = vendor::ACRN; } else if (VendorID == std::string_view(" QNXQVMBSQG ")) { Vendor = vendor::QNX; } // Cyrix 6x86 and 6x86MX do not specify the value returned in eax. // They both support 0x00000001u however. if ((VendorString.a >= 0x0000'0001u) || (Vendor == vendor::Cyrix)) { cpuid_result StandardFeatureFlags = cpuid(0x0000'0001u); CPUID = StandardFeatureFlags.a; // clang-format off uint32 BaseStepping = (StandardFeatureFlags.a >> 0) & 0x0f; uint32 BaseModel = (StandardFeatureFlags.a >> 4) & 0x0f; uint32 BaseFamily = (StandardFeatureFlags.a >> 8) & 0x0f; uint32 ExtModel = (StandardFeatureFlags.a >> 16) & 0x0f; uint32 ExtFamily = (StandardFeatureFlags.a >> 20) & 0xff; // clang-format on if (BaseFamily == 0xf) { Family = static_cast(ExtFamily + BaseFamily); } else { Family = static_cast(BaseFamily); } if ((Vendor == vendor::AMD) && (BaseFamily == 0xf)) { Model = static_cast((ExtModel << 4) | (BaseModel << 0)); } else if ((Vendor == vendor::Centaur) && (BaseFamily >= 0x6)) { // Newer Zhaoxin CPUs use extended family also with BaseFamily=7. Model = static_cast((ExtModel << 4) | (BaseModel << 0)); } else if ((BaseFamily == 0x6) || (BaseFamily == 0xf)) { Model = static_cast((ExtModel << 4) | (BaseModel << 0)); } else { Model = static_cast(BaseModel); } Stepping = static_cast(BaseStepping); // clang-format off Features |= (StandardFeatureFlags.d & (1u << 0)) ? (feature::fpu | feature::fsin) : feature::none; Features |= (StandardFeatureFlags.d & (1u << 4)) ? (feature::tsc) : feature::none; Features |= (StandardFeatureFlags.d & (1u << 8)) ? (feature::cx8) : feature::none; Features |= (StandardFeatureFlags.d & (1u << 15)) ? (feature::cmov) : feature::none; Features |= (StandardFeatureFlags.d & (1u << 23)) ? (feature::mmx) : feature::none; Features |= (StandardFeatureFlags.d & (1u << 24)) ? (feature::fxsr) : feature::none; Features |= (StandardFeatureFlags.d & (1u << 25)) ? (feature::sse | feature::mmxext) : feature::none; Features |= (StandardFeatureFlags.d & (1u << 26)) ? (feature::sse2) : feature::none; Features |= (StandardFeatureFlags.c & (1u << 0)) ? (feature::sse3) : feature::none; Features |= (StandardFeatureFlags.c & (1u << 9)) ? (feature::ssse3) : feature::none; Features |= (StandardFeatureFlags.c & (1u << 12)) ? (feature::fma) : feature::none; Features |= (StandardFeatureFlags.c & (1u << 13)) ? (feature::cx16) : feature::none; Features |= (StandardFeatureFlags.c & (1u << 19)) ? (feature::sse4_1) : feature::none; Features |= (StandardFeatureFlags.c & (1u << 20)) ? (feature::sse4_2) : feature::none; Features |= (StandardFeatureFlags.c & (1u << 22)) ? (feature::movbe) : feature::none; Features |= (StandardFeatureFlags.c & (1u << 23)) ? (feature::popcnt) : feature::none; Features |= (StandardFeatureFlags.c & (1u << 26)) ? (feature::xsave) : feature::none; Features |= (StandardFeatureFlags.c & (1u << 28)) ? (feature::avx) : feature::none; Features |= (StandardFeatureFlags.c & (1u << 29)) ? (feature::f16c) : feature::none; // clang-format on if (StandardFeatureFlags.c & (1u << 27)) { have_osxsave = true; } if (StandardFeatureFlags.c & (1u << 31)) { Virtualized = true; } } if (VendorString.a >= 0x0000'0007u) { cpuid_result ExtendedFeatures = cpuidex(0x0000'0007u, 0x0000'0000u); // clang-format off Features |= (ExtendedFeatures.b & (1u << 3)) ? (feature::bmi1) : feature::none; Features |= (ExtendedFeatures.b & (1u << 5)) ? (feature::avx2) : feature::none; Features |= (ExtendedFeatures.b & (1u << 8)) ? (feature::bmi2) : feature::none; // clang-format on } // 3DNow! manual recommends to just execute 0x8000'0000u. // It is totally unknown how earlier CPUs from other vendors // would behave. // Thus we only execute 0x80000000u on other vendors CPUs for the earliest // that we found it documented for and that actually supports 3DNow!. bool ecpuid = false; bool x3dnowknown = false; if (Vendor == vendor::Intel) { ecpuid = true; } else if (Vendor == vendor::AMD) { if ((Family > 5) || ((Family == 5) && (Model >= 8))) { // >= K6-2 (K6 = Family 5, K6-2 = Model 8) // Not sure if earlier AMD CPUs support 0x80000000u. // AMD 5k86 and AMD K5 manuals do not mention it. ecpuid = true; x3dnowknown = true; } } else if (Vendor == vendor::Centaur) { // Centaur (IDT WinChip or VIA C3) if (Family == 5) { // IDT if (Model >= 8) { // >= WinChip 2 ecpuid = true; x3dnowknown = true; } } else if (Family >= 6) { // VIA if ((Family >= 7) || ((Family == 6) && (Model >= 7))) { // >= C3 Samuel 2 ecpuid = true; x3dnowknown = true; } } } else if (Vendor == vendor::Cyrix) { // Cyrix // 6x86 : 5.2.x // 6x86L : 5.2.x // MediaGX : 4.4.x // 6x86MX : 6.0.x // MII : 6.0.x // MediaGXm: 5.4.x // well, doh ... if ((Family == 5) && (Model >= 4)) { // Cyrix MediaGXm ecpuid = true; x3dnowknown = true; } } else if (Vendor == vendor::NSC) { // National Semiconductor if ((Family > 5) || ((Family == 5) && (Model >= 5))) { // >= Geode GX2 ecpuid = true; x3dnowknown = true; } } else { // Intel specification allows 0x8000'0000u on earlier CPUs, // thus we execute it on unknown vendors. ecpuid = true; } if (ecpuid) { cpuid_result ExtendedVendorString = cpuid(0x8000'0000u); if ((ExtendedVendorString.a & 0xffff'0000u) == 0x8000'0000u) { if (ExtendedVendorString.a >= 0x8000'0001u) { // clang-format off cpuid_result ExtendedFeatureFlags = cpuid(0x8000'0001u); #if !MPT_ARCH_AMD64 if (ExtendedFeatureFlags.d & (1u << 29)) { LongMode = true; } #endif // !MPT_ARCH_AMD64 Features |= (ExtendedFeatureFlags.c & (1u << 0)) ? (feature::lahf) : feature::none; Features |= (ExtendedFeatureFlags.c & (1u << 5)) ? (feature::lzcnt) : feature::none; if (x3dnowknown) { Features |= (ExtendedFeatureFlags.d & (1u << 31)) ? (feature::x3dnow) : feature::none; } if (Vendor == vendor::AMD) { Features |= (ExtendedFeatureFlags.d & (1u << 22)) ? (feature::mmxext) : feature::none; Features |= (ExtendedFeatureFlags.d & (1u << 30)) ? (feature::x3dnowext) : feature::none; Features |= (ExtendedFeatureFlags.c & (1u << 5)) ? (feature::popcnt) : feature::none; Features |= (ExtendedFeatureFlags.c & (1u << 8)) ? (feature::x3dnowprefetch) : feature::none; } // clang-format on } if (ExtendedVendorString.a >= 0x8000'0004u) { BrandID = cpuid(0x8000'0002u).as_text16() + cpuid(0x8000'0003u).as_text16() + cpuid(0x8000'0004u).as_text16(); } } } #if MPT_ARCH_AMD64 // clang-format off Modes |= mode::xmm128sse; const bool have_xsave = #ifdef MPT_ARCH_X86_XSAVE true; #else Features.supports(feature::xsave); #endif MPT_MAYBE_CONSTANT_IF (have_xsave && have_osxsave) { const uint64 xcr0 = read_xcr(0x0000'0000u); Modes |= (xcr0 & (1ull << 2)) ? mode::ymm256avx : mode::base; } // clang-format on #else // !MPT_ARCH_AMD64 // clang-format off const bool have_xsave = #ifdef MPT_ARCH_X86_XSAVE true; #else Features.supports(feature::xsave); #endif MPT_MAYBE_CONSTANT_IF (have_xsave && have_osxsave) { const uint64 xcr0 = read_xcr(0x0000'0000u); Modes |= (xcr0 & (1ull << 1)) ? mode::xmm128sse : mode::base; Modes |= (xcr0 & (1ull << 2)) ? mode::ymm256avx : mode::base; } else { const bool have_fxsr = #ifdef MPT_ARCH_X86_FXSR true; #else Features.supports(feature::fxsr); #endif MPT_MAYBE_CONSTANT_IF (have_fxsr) { #if MPT_MODE_KERNEL const uint32 cr4 = read_cr4(); Modes |= (cr4 & (1u << 9)) ? mode::xmm128sse : mode::base; #else // !MPT_MODE_KERNEL // There is no way for user-mode code to check for SSE enabled in CR4. // Assume based on FXSR and SSE and platform heuristics. // Avoid assumption on DOS. #if MPT_OS_WINDOWS // get from platform API #if MPT_OS_WINDOWS_WINNT #ifdef PF_XMMI_INSTRUCTIONS_AVAILABLE Modes |= (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; #endif #elif MPT_WIN9X_AT_LEAST(MPT_WIN_WIN98) const bool have_sse = #ifdef MPT_ARCH_X86_SSE true; #else Features.supports(feature::sse); #endif MPT_MAYBE_CONSTANT_IF (have_sse) { Modes |= mode::xmm128sse; } #else // MPT_OS_WINDOWS // nothing #endif // MPT_OS_WINDOWS #elif MPT_OS_DJGPP || MPT_OS_UNKNOWN // avoid SSE on DOS and unknown systems, // however if we directly targeting >= SSE, then assume it's activated because the process will crash otherwise anyway #ifdef MPT_ARCH_X86_SSE Modes |= mode::xmm128sse; #endif #else // MPT_OS // assume based on FXSR and SSE const bool have_sse = #ifdef MPT_ARCH_X86_SSE true; #else Features.supports(feature::sse); #endif MPT_MAYBE_CONSTANT_IF (have_sse) { Modes |= mode::xmm128sse; } #endif // MPT_OS #endif // MPT_MODE_KERNEL } } // clang-format on #endif // MPT_ARCH_AMD64 if (Virtualized) { cpuid_result HypervisorVendorID = cpuid(0x4000'0000u); if (HypervisorVendorID.a >= 0x4000'0000u) { HypervisorVendor = HypervisorVendorID.as_text12bcd(); if (HypervisorVendor == std::string_view("Microsoft Hv")) { if (HypervisorVendorID.a >= 0x4000'0001u) { cpuid_result HypervisorInterfaceID = cpuid(0x4000'0001u); HypervisorInterface = HypervisorInterfaceID.as_text4(); } } else if (HypervisorVendor == std::string_view("KVMKVMKVM")) { // nothing } } } } #elif MPT_OS_WINDOWS #if MPT_ARCH_X86 || !MPT_ARCH_X86_AMD64_FAST_DETECT SYSTEM_INFO si = {}; GetSystemInfo(&si); switch (si.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL: case PROCESSOR_ARCHITECTURE_AMD64: case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: case PROCESSOR_ARCHITECTURE_IA32_ON_ARM64: switch (si.dwProcessorType) { case PROCESSOR_INTEL_386: Family = si.wProcessorLevel; if (((si.wProcessorRevision & 0xff00) >> 8) == 0xff) { Model = ((si.wProcessorRevision & 0x00f0) >> 4) - 0xa; Stepping = ((si.wProcessorRevision & 0x000f) >> 0); } else { Model = ((si.wProcessorRevision & 0xff00) >> 8) + static_cast('A'); Stepping = ((si.wProcessorRevision & 0x00ff) >> 0); } Model = (si.wProcessorRevision & 0xff00) >> 8; Stepping = (si.wProcessorRevision & 0x00ff) >> 0; Features |= featureset::intel386; break; case PROCESSOR_INTEL_486: Family = si.wProcessorLevel; if (((si.wProcessorRevision & 0xff00) >> 8) == 0xff) { Model = ((si.wProcessorRevision & 0x00f0) >> 4) - 0xa; Stepping = ((si.wProcessorRevision & 0x000f) >> 0); } else { Model = ((si.wProcessorRevision & 0xff00) >> 8) + static_cast('A'); Stepping = ((si.wProcessorRevision & 0x00ff) >> 0); } Model = (si.wProcessorRevision & 0xff00) >> 8; Stepping = (si.wProcessorRevision & 0x00ff) >> 0; Features |= featureset::intel486SX; break; case PROCESSOR_INTEL_PENTIUM: Family = si.wProcessorLevel; Model = (si.wProcessorRevision & 0xff00) >> 8; Stepping = (si.wProcessorRevision & 0x00ff) >> 0; // rely on IsProcessorFeaturePresent() for > 486 features // Features |= featureset::intel586; Features |= featureset::intel486SX; break; } break; } Features |= featureset::intel386; const uint8 fpu_level = detect_fpu_level(); if (fpu_level >= 2) { Features |= feature::fpu; } if (fpu_level >= 3) { Features |= feature::fsin; } #elif MPT_ARCH_AMD64 Features |= featureset::amd64; #endif // MPT_ARCH #if MPT_OS_WINDOWS_WINNT // clang-format off Features |= (IsProcessorFeaturePresent(PF_RDTSC_INSTRUCTION_AVAILABLE) != 0) ? (feature::tsc | feature::intel486) : feature::none; Features |= (IsProcessorFeaturePresent(PF_COMPARE_EXCHANGE_DOUBLE) != 0) ? (feature::cx8 | feature::intel486) : feature::none; Features |= (IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::mmx | feature::intel486) : feature::none; Features |= (IsProcessorFeaturePresent(PF_3DNOW_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::x3dnow) : feature::none; Features |= (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse | feature::mmxext | feature::fxsr | feature::cmov) : feature::none; Features |= (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse2) : feature::none; Features |= (IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse3) : feature::none; Features |= (IsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::ssse3) : feature::none; Features |= (IsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse4_1) : feature::none; Features |= (IsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse4_1) : feature::none; Features |= (IsProcessorFeaturePresent(PF_AVX_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::avx | feature::xsave) : feature::none; Features |= (IsProcessorFeaturePresent(PF_AVX2_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::avx2 | feature::fma | feature::bmi1) : feature::none; Modes |= (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; Modes |= (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; Modes |= (IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; Modes |= (IsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; Modes |= (IsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; Modes |= (IsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; Modes |= (IsProcessorFeaturePresent(PF_AVX_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse | mode::ymm256avx) : mode::base; Modes |= (IsProcessorFeaturePresent(PF_AVX2_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse | mode::ymm256avx) : mode::base; // clang-format on #endif #elif MPT_OS_DJGPP const uint8 cpu_level = detect_cpu_level(); Features |= (cpu_level >= 3) ? featureset::intel386 : feature::none; Features |= (cpu_level >= 4) ? featureset::intel486SX : feature::none; const uint8 fpu_level = detect_fpu_level(); Features |= (fpu_level >= 2) ? feature::fpu : feature::none; Features |= (fpu_level >= 3) ? feature::fsin : feature::none; #endif #endif // MPT_ARCH_X86 || MPT_ARCH_AMD64 } }; struct floating_point { public: static inline constexpr uint16 FCW_IM = (1 << 0); static inline constexpr uint16 FCW_DM = (1 << 1); static inline constexpr uint16 FCW_ZM = (1 << 2); static inline constexpr uint16 FCW_OM = (1 << 3); static inline constexpr uint16 FCW_UM = (1 << 4); static inline constexpr uint16 FCW_PM = (1 << 5); static inline constexpr uint16 FCW_PC = 0x0300; static inline constexpr uint16 FCW_RC = 0x0c00; static inline constexpr uint16 FCW_X = (1 << 12); static inline constexpr uint32 MXCSR_IE = (1 << 0); static inline constexpr uint32 MXCSR_DE = (1 << 1); static inline constexpr uint32 MXCSR_ZE = (1 << 2); static inline constexpr uint32 MXCSR_OE = (1 << 3); static inline constexpr uint32 MXCSR_UE = (1 << 4); static inline constexpr uint32 MXCSR_PE = (1 << 5); static inline constexpr uint32 MXCSR_DAZ = (1 << 6); static inline constexpr uint32 MXCSR_IM = (1 << 7); static inline constexpr uint32 MXCSR_DM = (1 << 8); static inline constexpr uint32 MXCSR_ZM = (1 << 9); static inline constexpr uint32 MXCSR_OM = (1 << 10); static inline constexpr uint32 MXCSR_UM = (1 << 11); static inline constexpr uint32 MXCSR_PM = (1 << 12); static inline constexpr uint32 MXCSR_RC = (1 << 13) | (1 << 14); static inline constexpr uint32 MXCSR_FTZ = (1 << 15); enum class precision : uint8 { single24 = 0, reserved = 1, double53 = 2, extended64 = 3, }; enum class rounding : uint8 { nearest = 0, down = 1, up = 2, zero = 3, }; struct alignas(16) fxsave_state { uint16 fcw; uint16 fsw; uint16 ftw; uint16 fop; uint32 fip; uint32 fcs; uint32 foo; uint32 fos; uint32 mxcsr; uint32 mxcsr_mask; uint32 st_space[32]; uint32 xmm_space[32]; uint8 padding[224]; }; static_assert(sizeof(fxsave_state) == 512); struct control_state { uint8 x87_level = 0; uint16 x87fcw = 0; // default 0x37f (glibc) / 0x27f (msvc) uint32 mxcsr_mask = 0; uint32 mxcsr = 0; // default: 0x00001f80 }; #if MPT_ARCH_X86 #if MPT_COMPILER_MSVC [[nodiscard]] static MPT_FORCEINLINE uint16 get_x87fcw() noexcept { uint16 tmp = 0; // clang-format off _asm { fwait fnstcw tmp } // clang-format on return tmp; } static MPT_FORCEINLINE void set_x87fcw(uint16 fcw) noexcept { // clang-format off _asm { fldcw fcw } // clang-format on } [[nodiscard]] static MPT_FORCEINLINE uint32 get_mxcsr() noexcept { return _mm_getcsr(); } static MPT_FORCEINLINE void set_mxcsr(uint32 csr) noexcept { _mm_setcsr(csr); } static MPT_FORCEINLINE void fxsave(fxsave_state * state) noexcept { _fxsave(state); } static MPT_FORCEINLINE void fxrstor(const fxsave_state * state) noexcept { _fxrstor(state); } #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG [[nodiscard]] static MPT_FORCEINLINE uint16 get_x87fcw() noexcept { typedef unsigned int fpu_control_t __attribute__((__mode__(__HI__))); fpu_control_t tmp = 0; // clang-format off __asm__ __volatile__("fwait" "\n" "fnstcw %0" : "=m" (*&tmp)); // clang-format on return static_cast(tmp); } static MPT_FORCEINLINE void set_x87fcw(uint16 fcw) noexcept { typedef unsigned int fpu_control_t __attribute__((__mode__(__HI__))); fpu_control_t tmp = fcw; // clang-format off __asm__ __volatile__("fldcw %0" : : "m" (*&tmp)); // clang-format on } [[nodiscard]] static MPT_FORCEINLINE uint32 get_mxcsr() noexcept { #ifdef MPT_ARCH_X86_SSE return __builtin_ia32_stmxcsr(); #else uint32 csr = 0; // clang-format off __asm__ __volatile__("stmxcsr %0" : "=m" (csr)); // clang-format on return csr; #endif } static MPT_FORCEINLINE void set_mxcsr(uint32 csr) noexcept { #ifdef MPT_ARCH_X86_SSE #if MPT_COMPILER_GCC // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55752 std::atomic_thread_fence(std::memory_order_seq_cst); #endif __builtin_ia32_ldmxcsr(csr); #if MPT_COMPILER_GCC // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55752 std::atomic_thread_fence(std::memory_order_seq_cst); #endif #else // clang-format off __asm__ __volatile__("ldmxcsr %0" : : "m" (csr)); // clang-format on #endif } static MPT_FORCEINLINE void fxsave(fxsave_state * state) noexcept { #ifdef MPT_ARCH_X86_FXSR __builtin_ia32_fxsave(state); #else // clang-format off __asm__ __volatile__("fxsave %0" : : "m" (*state)); // clang-format on #endif } static MPT_FORCEINLINE void fxrstor(const fxsave_state * state) noexcept { #ifdef MPT_ARCH_X86_FXSR __builtin_ia32_fxrstor(const_cast(state)); #else // clang-format off __asm__ __volatile__("fxrstor %0" : : "m" (*state)); // clang-format on #endif } #endif // MPT_COMPILER static MPT_FORCEINLINE bool have_fxsr() noexcept { #ifdef MPT_ARCH_X86_FXSR return true; #else return cpu_info{}[mpt::arch::x86::feature::fxsr]; #endif } static MPT_FORCEINLINE bool have_sse() noexcept { #ifdef MPT_ARCH_X86_SSE return true; #else const cpu_info cpu_info; return cpu_info[mpt::arch::x86::feature::sse] && cpu_info[mpt::arch::x86::mode::xmm128sse]; #endif } static MPT_FORCEINLINE uint8 get_fpu_level() noexcept { #ifdef MPT_ARCH_X86_FSIN return 3; #elif defined(MPT_ARCH_X86_FPU) return cpu_info{}[mpt::arch::x86::feature::fsin] ? 3 : 2; #else cpu_info tmp{}; return tmp[mpt::arch::x86::feature::fsin] ? 3 : tmp[mpt::arch::x86::feature::fpu] ? 2 : 0; #endif } static MPT_FORCEINLINE control_state get_state() noexcept { control_state result; #ifdef MPT_ARCH_X86_FXSR fxsave_state tmp = {}; fxsave(&tmp); result.x87_level = 3; result.x87fcw = tmp.fcw; result.mxcsr_mask = tmp.mxcsr_mask; result.mxcsr = tmp.mxcsr; #else if (have_fxsr()) { fxsave_state tmp = {}; fxsave(&tmp); result.x87_level = 3; result.x87fcw = tmp.fcw; result.mxcsr_mask = tmp.mxcsr_mask; result.mxcsr = tmp.mxcsr; } else { result.x87_level = get_fpu_level(); if (result.x87_level > 0) { result.x87fcw = get_x87fcw(); } } #endif return result; } static MPT_FORCEINLINE void set_state(control_state state) noexcept { #ifdef MPT_ARCH_X86_SSE if (state.x87_level) { set_x87fcw(state.x87fcw); } if (state.mxcsr_mask) { set_mxcsr(state.mxcsr); } #else if (have_sse()) { if (state.x87_level) { set_x87fcw(state.x87fcw); } if (state.mxcsr_mask) { set_mxcsr(state.mxcsr); } } else { #ifdef MPT_ARCH_X86_FXSR fxsave_state tmp = {}; fxsave(&tmp); if (state.x87_level) { tmp.fcw = state.x87fcw; } if (state.mxcsr_mask) { tmp.mxcsr = state.mxcsr; } fxrstor(&tmp); #else if (have_fxsr()) { fxsave_state tmp = {}; fxsave(&tmp); if (state.x87_level) { tmp.fcw = state.x87fcw; } if (state.mxcsr_mask) { tmp.mxcsr = state.mxcsr; } fxrstor(&tmp); } else { if (state.x87_level) { set_x87fcw(state.x87fcw); } } #endif } #endif } #elif MPT_ARCH_AMD64 #if MPT_COMPILER_MSVC [[nodiscard]] static MPT_FORCEINLINE uint16 get_x87fcw() noexcept { fxsave_state state = {}; fxsave(&state); return state.fcw; } static MPT_FORCEINLINE void set_x87fcw(uint16 fcw) noexcept { fxsave_state state = {}; fxsave(&state); state.fcw = fcw; fxrstor(&state); } [[nodiscard]] static MPT_FORCEINLINE uint32 get_mxcsr() noexcept { return _mm_getcsr(); } static MPT_FORCEINLINE void set_mxcsr(uint32 csr) noexcept { _mm_setcsr(csr); } static MPT_FORCEINLINE void fxsave(fxsave_state * state) noexcept { _fxsave(state); } static MPT_FORCEINLINE void fxrstor(const fxsave_state * state) noexcept { _fxrstor(state); } static MPT_FORCEINLINE bool have_fxsr() noexcept { return true; } static MPT_FORCEINLINE control_state get_state() noexcept { control_state result; fxsave_state tmp = {}; fxsave(&tmp); result.x87_level = 3; result.x87fcw = tmp.fcw; result.mxcsr_mask = tmp.mxcsr_mask; result.mxcsr = tmp.mxcsr; return result; } static MPT_FORCEINLINE void set_state(control_state state) noexcept { fxsave_state tmp = {}; fxsave(&tmp); tmp.fcw = state.x87fcw; tmp.mxcsr_mask = state.mxcsr_mask; tmp.mxcsr = state.mxcsr; fxrstor(&tmp); } #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG [[nodiscard]] static MPT_FORCEINLINE uint16 get_x87fcw() noexcept { typedef unsigned int fpu_control_t __attribute__((__mode__(__HI__))); fpu_control_t tmp = 0; // clang-format off __asm__ __volatile__("fwait" "\n" "fnstcw %0" : "=m" (*&tmp)); // clang-format on return static_cast(tmp); } static MPT_FORCEINLINE void set_x87fcw(uint16 fcw) noexcept { typedef unsigned int fpu_control_t __attribute__((__mode__(__HI__))); fpu_control_t tmp = fcw; // clang-format off __asm__ __volatile__("fldcw %0" : : "m" (*&tmp)); // clang-format on } [[nodiscard]] static MPT_FORCEINLINE uint32 get_mxcsr() noexcept { return __builtin_ia32_stmxcsr(); } static MPT_FORCEINLINE void set_mxcsr(uint32 csr) noexcept { #if MPT_COMPILER_GCC // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55752 std::atomic_thread_fence(std::memory_order_seq_cst); #endif __builtin_ia32_ldmxcsr(csr); #if MPT_COMPILER_GCC // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55752 std::atomic_thread_fence(std::memory_order_seq_cst); #endif } static MPT_FORCEINLINE void fxsave(fxsave_state * state) noexcept { __builtin_ia32_fxsave(state); } static MPT_FORCEINLINE void fxrstor(const fxsave_state * state) noexcept { __builtin_ia32_fxrstor(const_cast(state)); } static MPT_FORCEINLINE bool have_fxsr() noexcept { return true; } static MPT_FORCEINLINE control_state get_state() noexcept { control_state result; result.x87_level = 3; result.x87fcw = get_x87fcw(); result.mxcsr_mask = 0x0000'ffff; result.mxcsr = get_mxcsr(); return result; } static MPT_FORCEINLINE void set_state(control_state state) noexcept { set_x87fcw(state.x87fcw); set_mxcsr(state.mxcsr); } #endif // MPT_COMPILER class guard { private: const control_state m_oldstate; public: MPT_FORCEINLINE guard(std::optional rounding, std::optional denormals_as_zero, std::optional precision, std::optional infinity_projective) noexcept : m_oldstate(get_state()) { control_state state = m_oldstate; if (rounding) { if (state.x87_level) { state.x87fcw = (state.x87fcw & ~FCW_RC) | (mpt::to_underlying(*rounding) << mpt::countr_zero(FCW_RC)); } if ((state.mxcsr_mask & MXCSR_RC) == MXCSR_RC) { state.mxcsr = (state.mxcsr & ~MXCSR_RC) | (mpt::to_underlying(*rounding) << mpt::countr_zero(MXCSR_RC)); } } if (denormals_as_zero) { if (state.mxcsr_mask) { state.mxcsr = (state.mxcsr & ~(MXCSR_FTZ | MXCSR_DAZ)) | ((*denormals_as_zero) ? ((MXCSR_FTZ | MXCSR_DAZ) & state.mxcsr_mask) : 0); } } if (precision) { if (state.x87_level) { state.x87fcw = (state.x87fcw & ~FCW_PC) | (mpt::to_underlying(*precision) << mpt::countr_zero(FCW_PC)); } } if (infinity_projective) { if (state.x87_level <= 2) { state.x87fcw = (state.x87fcw & ~FCW_X) | ((*infinity_projective) ? 0 : FCW_X); } } set_state(state); } MPT_FORCEINLINE ~guard() { set_state(m_oldstate); } }; #endif // MPT_ARCH }; } // namespace x86 namespace amd64 = x86; } // namespace arch } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_ARCH_X86_AMD64_HPP libopenmpt-0.8.1+release.autotools/src/mpt/arch/arch.hpp0000644000175000017500000001077315020030355020211 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_ARCH_ARCH_HPP #define MPT_ARCH_ARCH_HPP #include "mpt/arch/feature_flags.hpp" #include "mpt/arch/x86_amd64.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace arch { namespace unknown { template struct no_flags { constexpr no_flags() noexcept = default; constexpr no_flags operator~() noexcept { return no_flags{}; } constexpr no_flags & operator&=(no_flags) noexcept { return *this; } constexpr no_flags & operator|=(no_flags) noexcept { return *this; } constexpr no_flags & operator^=(no_flags) noexcept { return *this; } friend constexpr no_flags operator&(no_flags, no_flags) noexcept { return no_flags{}; } friend constexpr no_flags operator|(no_flags, no_flags) noexcept { return no_flags{}; } friend constexpr no_flags operator^(no_flags, no_flags) noexcept { return no_flags{}; } friend constexpr bool operator==(no_flags, no_flags) noexcept { return true; } friend constexpr bool operator!=(no_flags, no_flags) noexcept { return false; } constexpr bool supports(no_flags) noexcept { return true; } explicit constexpr operator bool() const noexcept { return true; } constexpr bool operator!() const noexcept { return false; } }; struct no_feature_flags_tag { }; struct no_mode_flags_tag { }; using feature_flags = mpt::arch::basic_feature_flags>; using mode_flags = mpt::arch::basic_feature_flags>; namespace feature { inline constexpr feature_flags none = feature_flags{}; } // namespace feature namespace mode { inline constexpr mode_flags none = mode_flags{}; } // namespace mode struct cpu_info { public: cpu_info() = default; public: MPT_CONSTEXPRINLINE bool operator[](feature_flags) const noexcept { return true; } MPT_CONSTEXPRINLINE bool has_features(feature_flags) const noexcept { return true; } MPT_CONSTEXPRINLINE feature_flags get_features() const noexcept { return {}; } MPT_CONSTEXPRINLINE bool operator[](mode_flags) const noexcept { return true; } MPT_CONSTEXPRINLINE bool enabled_modes(mode_flags) const noexcept { return true; } MPT_CONSTEXPRINLINE mode_flags get_modes() const noexcept { return {}; } }; [[nodiscard]] MPT_CONSTEVAL feature_flags assumed_features() noexcept { return {}; } [[nodiscard]] MPT_CONSTEVAL mode_flags assumed_modes() noexcept { return {}; } } // namespace unknown #if MPT_ARCH_X86 namespace current = x86; #elif MPT_ARCH_AMD64 namespace current = amd64; #else namespace current = unknown; #endif using cpu_info = mpt::arch::current::cpu_info; inline const cpu_info & get_cpu_info() { static cpu_info info; return info; } namespace detail { struct info_initializer { inline info_initializer() noexcept { get_cpu_info(); } }; #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif // MPT_COMPILER_CLANG inline info_initializer g_info_initializer; #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG } // namespace detail struct flags_cache { private: const mpt::arch::current::feature_flags Features; const mpt::arch::current::mode_flags Modes; public: MPT_CONSTEXPRINLINE flags_cache(const mpt::arch::cpu_info & info) noexcept : Features(info.get_features()) , Modes(info.get_modes()) { return; } [[nodiscard]] MPT_CONSTEXPRINLINE bool operator[](mpt::arch::current::feature_flags query_features) const noexcept { return ((Features & query_features) == query_features); } [[nodiscard]] MPT_CONSTEXPRINLINE bool has_features(mpt::arch::current::feature_flags query_features) const noexcept { return ((Features & query_features) == query_features); } [[nodiscard]] MPT_CONSTEXPRINLINE mpt::arch::current::feature_flags get_features() const noexcept { return Features; } [[nodiscard]] MPT_CONSTEXPRINLINE bool operator[](mpt::arch::current::mode_flags query_modes) const noexcept { return ((Modes & query_modes) == query_modes); } [[nodiscard]] MPT_CONSTEXPRINLINE bool has_features(mpt::arch::current::mode_flags query_modes) const noexcept { return ((Modes & query_modes) == query_modes); } [[nodiscard]] MPT_CONSTEXPRINLINE mpt::arch::current::mode_flags get_modes() const noexcept { return Modes; } }; } // namespace arch } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_ARCH_ARCH_HPP libopenmpt-0.8.1+release.autotools/src/mpt/io_write/0000755000175000017500000000000015023302361017541 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/io_write/buffer.hpp0000644000175000017500000001037714707233006021462 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_IO_WRITE_BUFFER_HPP #define MPT_IO_WRITE_BUFFER_HPP #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/span.hpp" #include "mpt/io/base.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace IO { // WriteBuffer class that avoids calling to the underlying file writing // functions for every operation, which would involve rather slow un-inlinable // virtual calls in the iostream and FILE* cases. It is the users responabiliy // to call HasWriteError() to check for writeback errors at this buffering // level. template class WriteBuffer { private: mpt::byte_span buffer; std::size_t size = 0; Tfile & f; bool writeError = false; public: WriteBuffer(const WriteBuffer &) = delete; WriteBuffer & operator=(const WriteBuffer &) = delete; public: inline WriteBuffer(Tfile & f_, mpt::byte_span buffer_) : buffer(buffer_) , f(f_) { return; } inline ~WriteBuffer() noexcept(false) { if (!writeError) { FlushLocal(); } } public: inline Tfile & file() const { if (IsDirty()) { FlushLocal(); } return f; } public: inline bool HasWriteError() const { return writeError; } inline void ClearError() { writeError = false; } inline bool IsDirty() const { return size > 0; } inline bool IsClean() const { return size == 0; } inline bool IsFull() const { return size == buffer.size(); } inline std::size_t GetCurrentSize() const { return size; } inline bool Write(mpt::const_byte_span data) { bool result = true; for (std::size_t i = 0; i < data.size(); ++i) { buffer[size] = data[i]; size++; if (IsFull()) { FlushLocal(); } } return result; } inline void FlushLocal() { if (IsClean()) { return; } try { if (!mpt::IO::WriteRaw(f, mpt::as_span(buffer.data(), size))) { writeError = true; } } catch (const std::exception &) { writeError = true; throw; } size = 0; } }; template struct FileOperations> { private: WriteBuffer & f; public: FileOperations(WriteBuffer & f_) : f(f_) { return; } public: // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsValid() { return IsValid(f.file()); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsReadSeekable() { return IsReadSeekable(f.file()); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsWriteSeekable() { return IsWriteSeekable(f.file()); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline IO::Offset TellRead() { f.FlushLocal(); return TellRead(f.file()); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline IO::Offset TellWrite() { return TellWrite(f.file()) + f.GetCurrentSize(); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekBegin() { f.FlushLocal(); return SeekBegin(f.file()); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekEnd() { f.FlushLocal(); return SeekEnd(f.file()); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekAbsolute(IO::Offset pos) { f.FlushLocal(); return SeekAbsolute(f.file(), pos); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool SeekRelative(IO::Offset off) { f.FlushLocal(); return SeekRelative(f.file(), off); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline mpt::byte_span ReadRawImpl(mpt::byte_span data) { f.FlushLocal(); return ReadRawImpl(f.file(), data); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool WriteRawImpl(mpt::const_byte_span data) { return f.Write(data); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool IsEof() { f.FlushLocal(); return IsEof(f.file()); } // cppcheck false-positive // cppcheck-suppress duplInheritedMember inline bool Flush() { f.FlushLocal(); return Flush(f.file()); } }; } // namespace IO } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_IO_WRITE_BUFFER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/environment/0000755000175000017500000000000015023302361020264 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/environment/environment.hpp0000644000175000017500000000267514107230757023306 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_ENVIRONMENT_ENVIRONMENT_HPP #define MPT_ENVIRONMENT_ENVIRONMENT_HPP #include "mpt/base/detect.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include "mpt/system_error/system_error.hpp" #include #if MPT_OS_WINDOWS #if defined(UNICODE) && !MPT_OS_WINDOWS_WINRT #include #endif // !MPT_OS_WINDOWS_WINRT #endif // MPT_OS_WINDOWS #include #if MPT_OS_WINDOWS #include #endif // MPT_OS_WINDOWS namespace mpt { inline namespace MPT_INLINE_NS { inline std::optional getenv(const mpt::ustring & env_var) { #if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT MPT_UNUSED(env_var); return std::nullopt; #elif MPT_OS_WINDOWS && defined(UNICODE) std::vector buf(32767); DWORD size = GetEnvironmentVariable(mpt::transcode(env_var).c_str(), buf.data(), 32767); if (size == 0) { mpt::windows::ExpectError(ERROR_ENVVAR_NOT_FOUND); return std::nullopt; } return mpt::transcode(buf.data()); #else const char * val = std::getenv(mpt::transcode(mpt::environment_encoding, env_var).c_str()); if (!val) { return std::nullopt; } return mpt::transcode(mpt::environment_encoding, val); #endif } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_ENVIRONMENT_ENVIRONMENT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/crc/0000755000175000017500000000000015023302361016467 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/crc/crc.hpp0000644000175000017500000001141214044173026017674 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_CRC_CRC_HPP #define MPT_CRC_CRC_HPP #include "mpt/base/array.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/memory.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { template class crc { public: using self_type = crc; using value_type = T; using byte_type = uint8; static constexpr std::size_t size_bytes = sizeof(value_type); static constexpr std::size_t size_bits = sizeof(value_type) * 8; static constexpr value_type top_bit = static_cast(1) << ((sizeof(value_type) * 8) - 1); private: template static constexpr Tint reverse(Tint value) noexcept { const std::size_t bits = sizeof(Tint) * 8; Tint result = 0; for (std::size_t i = 0; i < bits; ++i) { result <<= 1; result |= static_cast(value & 0x1); value >>= 1; } return result; } static constexpr value_type calculate_table_entry(byte_type pos) noexcept { value_type value = 0; value = (static_cast(reverseData ? reverse(pos) : pos) << (size_bits - 8)); for (std::size_t bit = 0; bit < 8; ++bit) { if (value & top_bit) { value = (value << 1) ^ polynomial; } else { value = (value << 1); } } value = (reverseData ? reverse(value) : value); return value; } private: static constexpr std::array calculate_table() noexcept { std::array t = mpt::init_array(value_type{}); for (std::size_t i = 0; i < 256; ++i) { t[i] = calculate_table_entry(static_cast(i)); } return t; } static constexpr std::array table = calculate_table(); private: constexpr value_type read_table(byte_type pos) const noexcept { return table[pos]; } private: value_type value; public: constexpr crc() noexcept : value(initial) { return; } constexpr void processByte(byte_type byte) noexcept { if constexpr (reverseData) { value = (value >> 8) ^ read_table(static_cast((value & 0xff) ^ byte)); } else { value = (value << 8) ^ read_table(static_cast(((value >> (size_bits - 8)) & 0xff) ^ byte)); } } constexpr value_type result() const noexcept { return (value ^ resultXOR); } public: constexpr operator value_type() const noexcept { return result(); } inline crc & process(char c) noexcept { processByte(mpt::byte_cast(c)); return *this; } inline crc & process(signed char c) noexcept { processByte(static_cast(c)); return *this; } inline crc & process(unsigned char c) noexcept { processByte(mpt::byte_cast(c)); return *this; } inline crc & process(std::byte c) noexcept { processByte(mpt::byte_cast(c)); return *this; } template inline crc & process(InputIt beg, InputIt end) { for (InputIt it = beg; it != end; ++it) { static_assert(sizeof(*it) == 1, "1 byte type required"); process(*it); } return *this; } template inline crc & process(const Container & data) { operator()(data.begin(), data.end()); return *this; } inline crc & operator()(char c) noexcept { processByte(mpt::byte_cast(c)); return *this; } inline crc & operator()(signed char c) noexcept { processByte(static_cast(c)); return *this; } inline crc & operator()(unsigned char c) noexcept { processByte(mpt::byte_cast(c)); return *this; } inline crc & operator()(std::byte c) noexcept { processByte(mpt::byte_cast(c)); return *this; } template crc & operator()(InputIt beg, InputIt end) { for (InputIt it = beg; it != end; ++it) { static_assert(sizeof(*it) == 1, "1 byte type required"); operator()(*it); } return *this; } template inline crc & operator()(const Container & data) { operator()(data.begin(), data.end()); return *this; } template crc(InputIt beg, InputIt end) : value(initial) { for (InputIt it = beg; it != end; ++it) { static_assert(sizeof(*it) == 1, "1 byte type required"); process(*it); } } template inline crc(const Container & data) : value(initial) { process(data.begin(), data.end()); } }; using crc16 = crc; using crc32 = crc; using crc32_ogg = crc; using crc32c = crc; using crc64_jones = crc; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_CRC_CRC_HPP libopenmpt-0.8.1+release.autotools/src/mpt/crc/tests/0000755000175000017500000000000015023302361017631 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/crc/tests/tests_crc.hpp0000644000175000017500000000157314044173026022267 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_TESTS_CRC_HPP #define MPT_BASE_TESTS_CRC_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/namespace.hpp" #include "mpt/crc/crc.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace crc { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/crc") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { MPT_TEST_EXPECT_EQUAL(mpt::crc32(std::string("123456789")), 0xCBF43926u); MPT_TEST_EXPECT_EQUAL(mpt::crc32_ogg(std::string("123456789")), 0x89a1897fu); } } // namespace crc } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_TESTS_CRC_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/0000755000175000017500000000000015023302361017210 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/format/simple_spec.hpp0000644000175000017500000002042314275170614022161 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_SIMPLE_SPEC_HPP #define MPT_FORMAT_SIMPLE_SPEC_HPP #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string_transcode/transcode.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { struct format_simple_base { enum FormatFlagsEnum { BaseDec = 0x0001, // base 10 (integers only) // int+float BaseHex = 0x0002, // base 16 (integers only) // int+float CaseLow = 0x0010, // lower case hex digits // int+float CaseUpp = 0x0020, // upper case hex digits // int+float FillOff = 0x0100, // do not fill up width // int+float FillNul = 0x0400, // fill up width with zeros // int+float NotaNrm = 0x1000, // float: normal/default notation // float NotaFix = 0x2000, // float: fixed point notation // float NotaSci = 0x4000, // float: scientific notation // float }; }; // struct format_simple_base using format_simple_flags = unsigned int; static_assert(sizeof(format_simple_flags) >= sizeof(format_simple_base::FormatFlagsEnum)); template class format_simple_spec { private: format_simple_flags flags; std::size_t width; // int+float int precision; // float unsigned int group; // int Tstring group_sep; // int public: MPT_CONSTEXPRINLINE format_simple_spec() noexcept : flags(0) , width(0) , precision(-1) , group(0) , group_sep() { } MPT_CONSTEXPRINLINE format_simple_flags GetFlags() const noexcept { return flags; } MPT_CONSTEXPRINLINE std::size_t GetWidth() const noexcept { return width; } MPT_CONSTEXPRINLINE int GetPrecision() const noexcept { return precision; } MPT_CONSTEXPRINLINE unsigned int GetGroup() const noexcept { return group; } MPT_CONSTEXPRINLINE Tstring GetGroupSep() const { return group_sep; } MPT_CONSTEXPRINLINE format_simple_spec & SetFlags(format_simple_flags f) noexcept { flags = f; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & SetWidth(std::size_t w) noexcept { width = w; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & SetPrecision(int p) noexcept { precision = p; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & SetGroup(unsigned int g) noexcept { group = g; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & SetGroupSep(Tstring s) { group_sep = std::move(s); return *this; } public: MPT_CONSTEXPRINLINE format_simple_spec & BaseDec() noexcept { flags &= ~(format_simple_base::BaseDec | format_simple_base::BaseHex); flags |= format_simple_base::BaseDec; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & BaseHex() noexcept { flags &= ~(format_simple_base::BaseDec | format_simple_base::BaseHex); flags |= format_simple_base::BaseHex; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & CaseLow() noexcept { flags &= ~(format_simple_base::CaseLow | format_simple_base::CaseUpp); flags |= format_simple_base::CaseLow; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & CaseUpp() noexcept { flags &= ~(format_simple_base::CaseLow | format_simple_base::CaseUpp); flags |= format_simple_base::CaseUpp; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & FillOff() noexcept { flags &= ~(format_simple_base::FillOff | format_simple_base::FillNul); flags |= format_simple_base::FillOff; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & FillNul() noexcept { flags &= ~(format_simple_base::FillOff | format_simple_base::FillNul); flags |= format_simple_base::FillNul; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & NotaNrm() noexcept { flags &= ~(format_simple_base::NotaNrm | format_simple_base::NotaFix | format_simple_base::NotaSci); flags |= format_simple_base::NotaNrm; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & NotaFix() noexcept { flags &= ~(format_simple_base::NotaNrm | format_simple_base::NotaFix | format_simple_base::NotaSci); flags |= format_simple_base::NotaFix; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & NotaSci() noexcept { flags &= ~(format_simple_base::NotaNrm | format_simple_base::NotaFix | format_simple_base::NotaSci); flags |= format_simple_base::NotaSci; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & Width(std::size_t w) noexcept { width = w; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & Prec(int p) noexcept { precision = p; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & Group(unsigned int g) noexcept { group = g; return *this; } MPT_CONSTEXPRINLINE format_simple_spec & GroupSep(Tstring s) { group_sep = std::move(s); return *this; } public: MPT_CONSTEXPRINLINE format_simple_spec & Dec() noexcept { return BaseDec(); } MPT_CONSTEXPRINLINE format_simple_spec & Hex() noexcept { return BaseHex(); } MPT_CONSTEXPRINLINE format_simple_spec & Low() noexcept { return CaseLow(); } MPT_CONSTEXPRINLINE format_simple_spec & Upp() noexcept { return CaseUpp(); } MPT_CONSTEXPRINLINE format_simple_spec & Off() noexcept { return FillOff(); } MPT_CONSTEXPRINLINE format_simple_spec & Nul() noexcept { return FillNul(); } MPT_CONSTEXPRINLINE format_simple_spec & Nrm() noexcept { return NotaNrm(); } MPT_CONSTEXPRINLINE format_simple_spec & Fix() noexcept { return NotaFix(); } MPT_CONSTEXPRINLINE format_simple_spec & Sci() noexcept { return NotaSci(); } public: MPT_CONSTEXPRINLINE format_simple_spec & Decimal() noexcept { return BaseDec(); } MPT_CONSTEXPRINLINE format_simple_spec & Hexadecimal() noexcept { return BaseHex(); } MPT_CONSTEXPRINLINE format_simple_spec & Lower() noexcept { return CaseLow(); } MPT_CONSTEXPRINLINE format_simple_spec & Upper() noexcept { return CaseUpp(); } MPT_CONSTEXPRINLINE format_simple_spec & FillNone() noexcept { return FillOff(); } MPT_CONSTEXPRINLINE format_simple_spec & FillZero() noexcept { return FillNul(); } MPT_CONSTEXPRINLINE format_simple_spec & FloatNormal() noexcept { return NotaNrm(); } MPT_CONSTEXPRINLINE format_simple_spec & FloatFixed() noexcept { return NotaFix(); } MPT_CONSTEXPRINLINE format_simple_spec & FloatScientific() noexcept { return NotaSci(); } MPT_CONSTEXPRINLINE format_simple_spec & Precision(int p) noexcept { return Prec(p); } }; template inline format_simple_spec transcode_format_simple_spec(const format_simple_spec & src) { format_simple_spec dst; dst.SetFlags(src.GetFlags()); dst.SetWidth(src.GetWidth()); dst.SetPrecision(src.GetPrecision()); dst.SetGroup(src.GetGroup()); dst.SetGroupSep(mpt::transcode(src.GetGroupSep())); return dst; } template ::value, bool> = true> inline format_simple_spec transcode_format_simple_spec(Tencoding to, const format_simple_spec & src) { format_simple_spec dst; dst.SetFlags(src.GetFlags()); dst.SetWidth(src.GetWidth()); dst.SetPrecision(src.GetPrecision()); dst.SetGroup(src.GetGroup()); dst.SetGroupSep(mpt::transcode(to, src.GetGroupSep())); return dst; } template ::type, std::string>::value, bool> = true> inline format_simple_spec transcode_format_simple_spec(Tencoding from, const format_simple_spec & src) { format_simple_spec dst; dst.SetFlags(src.GetFlags()); dst.SetWidth(src.GetWidth()); dst.SetPrecision(src.GetPrecision()); dst.SetGroup(src.GetGroup()); dst.SetGroupSep(mpt::transcode(from, src.GetGroupSep())); return dst; } template inline format_simple_spec transcode_format_simple_spec(Tto to, Tfrom from, const format_simple_spec & src) { format_simple_spec dst; dst.SetFlags(src.GetFlags()); dst.SetWidth(src.GetWidth()); dst.SetPrecision(src.GetPrecision()); dst.SetGroup(src.GetGroup()); dst.SetGroupSep(mpt::transcode(to, from, src.GetGroupSep())); return dst; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_SIMPLE_SPEC_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/default_floatingpoint.hpp0000644000175000017500000000512414257074355024245 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_DETAULT_FLOATINGPOINT_HPP #define MPT_FORMAT_DETAULT_FLOATINGPOINT_HPP #include "mpt/base/detect.hpp" #if !defined(MPT_LIBCXX_QUIRK_NO_TO_CHARS_FLOAT) #define MPT_FORMAT_FORMAT_DEFAULT_FLOAT_CXX17 1 #else #define MPT_FORMAT_FORMAT_DEFAULT_FLOAT_CXX17 0 #endif #if MPT_FORMAT_FORMAT_DEFAULT_FLOAT_CXX17 #include "mpt/base/algorithm.hpp" #endif #include "mpt/base/namespace.hpp" #include "mpt/format/helpers.hpp" #include "mpt/string_transcode/transcode.hpp" #if MPT_FORMAT_FORMAT_DEFAULT_FLOAT_CXX17 #include #endif #if !MPT_FORMAT_FORMAT_DEFAULT_FLOAT_CXX17 #include #include #include #include #include #endif #include #if MPT_FORMAT_FORMAT_DEFAULT_FLOAT_CXX17 #include #endif #include namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_FORMAT_FORMAT_DEFAULT_FLOAT_CXX17 template ::value, bool> = true> inline Tstring to_chars_string(const T & x) { std::string str(1, '\0'); bool done = false; while (!done) { std::to_chars_result result = std::to_chars(str.data(), str.data() + str.size(), x); if (result.ec != std::errc{}) { str.resize(mpt::exponential_grow(str.size()), '\0'); } else { str.resize(result.ptr - str.data()); done = true; } } return mpt::convert_formatted_simple(str); } template ::value, bool> = true> inline Tstring format_value_default(const T & x) { return mpt::transcode(mpt::to_chars_string::type>(x)); } #endif #if !MPT_FORMAT_FORMAT_DEFAULT_FLOAT_CXX17 template ::value, bool> = true> inline Tstring to_stream_string(const T & x) { using stream_char_type = typename mpt::select_format_char_type::type; std::basic_ostringstream s; s.imbue(std::locale::classic()); s << std::setprecision(std::numeric_limits::max_digits10) << x; return mpt::convert_formatted_simple(s.str()); } template ::value, bool> = true> inline Tstring format_value_default(const T & x) { return mpt::transcode(mpt::to_stream_string::type>(x)); } #endif } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_DETAULT_FLOATINGPOINT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/concat.hpp0000644000175000017500000000101414351626453021122 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_CONCAT_HPP #define MPT_FORMAT_CONCAT_HPP #include "mpt/base/namespace.hpp" #include "mpt/format/default_formatter.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { template inline Tstring concat(Ts &&... xs) { return (default_formatter::template format(std::forward(xs)) + ...); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_CONCAT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/simple_integer.hpp0000644000175000017500000002162514257267744022704 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_SIMPLE_INTEGER_HPP #define MPT_FORMAT_SIMPLE_INTEGER_HPP #include "mpt/base/detect.hpp" #if !defined(MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT) #define MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 1 #else // MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT #define MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 0 #endif // !MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT #include "mpt/base/algorithm.hpp" #include "mpt/base/namespace.hpp" #include "mpt/format/helpers.hpp" #include "mpt/format/simple_spec.hpp" #include "mpt/string/types.hpp" #if !MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #include #endif // !MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #if MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #include #endif // MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #if !MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #include #include #endif // !MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #if MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #include #endif // MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #if !MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #include #endif // !MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #if MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #include #endif // MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #include #include namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 template ::value, bool> = true> inline Tstring format_simple_integer_to_chars(const T & x, int base) { std::string str(1, '\0'); bool done = false; while (!done) { if constexpr (std::is_same::value) { std::to_chars_result result = std::to_chars(str.data(), str.data() + str.size(), static_cast(x), base); if (result.ec != std::errc{}) { str.resize(mpt::exponential_grow(str.size()), '\0'); } else { str.resize(result.ptr - str.data()); done = true; } } else { std::to_chars_result result = std::to_chars(str.data(), str.data() + str.size(), x, base); if (result.ec != std::errc{}) { str.resize(mpt::exponential_grow(str.size()), '\0'); } else { str.resize(result.ptr - str.data()); done = true; } } } return mpt::convert_formatted_simple(str); } #else // !MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 template ::value, bool> = true> inline Tstring format_simple_integer_to_stream(const T & x, int base) { using stream_char_type = typename mpt::select_format_char_type::type; if ((base == 10) || ((base == 16) && std::is_unsigned::value) || ((base == 8) && std::is_unsigned::value)) { // fast path std::basic_ostringstream s; s.imbue(std::locale::classic()); if (base == 16) { s << std::hex; } else if (base == 8) { s << std::oct; } if constexpr (std::is_same::value) { s << static_cast(x); } else if constexpr (mpt::is_character::value) { s << (x + 0); // force integral promotion } else { s << x; } return mpt::convert_formatted_simple(s.str()); } else { if constexpr (std::is_same::value) { return x ? Tstring(1, mpt::char_constants::number1) : Tstring(1, mpt::char_constants::number0); } else if constexpr (std::is_unsigned::value) { Tstring result; T val = x; if (val == 0) { result += Tstring(1, mpt::char_constants::number0); } else { using Tunsigned = typename std::make_unsigned::type; while (val > 0) { Tunsigned digit = static_cast(val % static_cast(base)); val = static_cast(val / static_cast(base)); if (digit >= 10) { result += Tstring(1, static_cast(mpt::char_constants::a - 10 + digit)); } else { result += Tstring(1, static_cast(mpt::char_constants::number0 + digit)); } } std::reverse(result.begin(), result.end()); } return result; } else { Tstring result; if (x == 0) { result += Tstring(1, mpt::char_constants::number0); } else { using Tunsigned = typename std::make_unsigned::type; Tunsigned val = (x != -x) ? ((x >= 0) ? x : -x) : (static_cast(-(x + 1)) + 1); while (val > 0) { Tunsigned digit = static_cast(val % static_cast(base)); val = static_cast(val / static_cast(base)); if (digit >= 10) { result += Tstring(1, static_cast(mpt::char_constants::a - 10 + digit)); } else { result += Tstring(1, static_cast(mpt::char_constants::number0 + digit)); } } if (x < 0) { result += Tstring(1, mpt::char_constants::minus); } std::reverse(result.begin(), result.end()); } return result; } } } #endif // MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 template inline Tstring format_simple_integer_postprocess_case(Tstring str, const format_simple_spec & format) { format_simple_flags f = format.GetFlags(); if (f & format_simple_base::CaseUpp) { for (auto & c : str) { if (mpt::char_constants::a <= c && c <= mpt::char_constants::z) { c -= mpt::char_constants::a - mpt::char_constants::A; } } } return str; } template inline Tstring format_simple_integer_postprocess_digits(Tstring str, const format_simple_spec & format) { format_simple_flags f = format.GetFlags(); std::size_t width = format.GetWidth(); if (f & format_simple_base::FillNul) { auto pos = str.begin(); if (str.length() > 0) { if (str[0] == mpt::char_constants::plus) { pos++; width++; } else if (str[0] == mpt::char_constants::minus) { pos++; width++; } } if (str.length() < width) { str.insert(pos, width - str.length(), mpt::char_constants::number0); } } return str; } #if MPT_COMPILER_MSVC #pragma warning(push) #pragma warning(disable : 4723) // potential divide by 0 #endif // MPT_COMPILER_MSVC template inline Tstring format_simple_integer_postprocess_group(Tstring str, const format_simple_spec & format) { if (format.GetGroup() > 0) { const unsigned int groupSize = format.GetGroup(); const Tstring groupSep = format.GetGroupSep(); std::size_t len = str.length(); for (std::size_t n = 0; n < len; ++n) { if (n > 0 && (n % groupSize) == 0) { if (!(n == (len - 1) && (str[0] == mpt::char_constants::plus || str[0] == mpt::char_constants::minus))) { str.insert(len - n, groupSep); } } } } return str; } #if MPT_COMPILER_MSVC #pragma warning(pop) #endif // MPT_COMPILER_MSVC #if MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 template ::value, bool> = true> inline Tstring format_simple(const T & x, const format_simple_spec & format) { int base = 10; if (format.GetFlags() & format_simple_base::BaseDec) { base = 10; } if (format.GetFlags() & format_simple_base::BaseHex) { base = 16; } using format_string_type = typename mpt::select_format_string_type::type; const format_simple_spec f = mpt::transcode_format_simple_spec(format); return mpt::transcode(mpt::format_simple_integer_postprocess_group(mpt::format_simple_integer_postprocess_digits(mpt::format_simple_integer_postprocess_case(mpt::format_simple_integer_to_chars(x, base), f), f), f)); } #else // !MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 template ::value, bool> = true> inline Tstring format_simple(const T & x, const format_simple_spec & format) { int base = 10; if (format.GetFlags() & format_simple_base::BaseDec) { base = 10; } if (format.GetFlags() & format_simple_base::BaseHex) { base = 16; } using format_string_type = typename mpt::select_format_string_type::type; const format_simple_spec f = mpt::transcode_format_simple_spec(format); return mpt::transcode(mpt::format_simple_integer_postprocess_group(mpt::format_simple_integer_postprocess_digits(mpt::format_simple_integer_postprocess_case(mpt::format_simple_integer_to_stream(x, base), f), f), f)); } #endif // MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_SIMPLE_INTEGER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/message_macros.hpp0000644000175000017500000000320414053176735022650 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_MESSAGE_MACROS_HPP #define MPT_FORMAT_MESSAGE_MACROS_HPP #include "mpt/base/detect.hpp" #include "mpt/detect/mfc.hpp" #include "mpt/format/default_formatter.hpp" #include "mpt/format/message.hpp" #define MPT_AFORMAT_MESSAGE(f) mpt::format_message(f) #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) #define MPT_WFORMAT_MESSAGE(f) mpt::format_message_typed(L##f) #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #define MPT_UFORMAT_MESSAGE(f) mpt::format_message_typed(MPT_ULITERAL(f)) #define MPT_LFORMAT_MESSAGE(f) mpt::format_message_typed(f) #if MPT_OS_WINDOWS #define MPT_TFORMAT_MESSAGE(f) mpt::format_message_typed(TEXT(f)) #endif // MPT_OS_WINDOWS #if MPT_DETECTED_MFC #define MPT_CWFORMAT_MESSAGE(f) mpt::format_message_typed(L##f) #define MPT_CAFORMAT_MESSAGE(f) mpt::format_message_typed(f) #define MPT_CFORMAT_MESSAGE(f) mpt::format_message_typed(TEXT(f)) #endif // MPT_DETECTED_MFC #endif // MPT_FORMAT_MESSAGE_MACROS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/default_formatter.hpp0000644000175000017500000000121314351670710023356 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_DEFAULT_FORMATTER_HPP #define MPT_FORMAT_DEFAULT_FORMATTER_HPP #include "mpt/base/namespace.hpp" #include "mpt/format/default_floatingpoint.hpp" #include "mpt/format/default_integer.hpp" #include "mpt/format/default_string.hpp" namespace mpt { inline namespace MPT_INLINE_NS { struct default_formatter { template static inline Tstring format(const T & value) { using namespace mpt; return format_value_default(value); } }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_DEFAULT_FORMATTER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/default_string.hpp0000644000175000017500000000102014107230757022657 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_DEFAULT_STRING_HPP #define MPT_FORMAT_DEFAULT_STRING_HPP #include "mpt/base/namespace.hpp" #include "mpt/string_transcode/transcode.hpp" namespace mpt { inline namespace MPT_INLINE_NS { template inline auto format_value_default(const T & x) -> decltype(mpt::transcode(x)) { return mpt::transcode(x); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_DEFAULT_STRING_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/default_integer.hpp0000644000175000017500000000675314257074450023032 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_DEFAULT_INTEGER_HPP #define MPT_FORMAT_DEFAULT_INTEGER_HPP #include "mpt/base/detect.hpp" #if !defined(MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT) #define MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 1 #else // MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT #define MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 0 #endif // !MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT #if MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 #include "mpt/base/algorithm.hpp" #endif // MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 #include "mpt/base/namespace.hpp" #include "mpt/base/utility.hpp" #include "mpt/format/helpers.hpp" #include "mpt/string_transcode/transcode.hpp" #if MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 #include #endif // MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 #if !MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 #include #include #endif // !MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 #include #if MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 #include #endif // MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 #include namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 template ::value, bool> = true> inline Tstring to_chars_string(const T & x) { std::string str(1, '\0'); bool done = false; while (!done) { if constexpr (std::is_same::value) { std::to_chars_result result = std::to_chars(str.data(), str.data() + str.size(), static_cast(x)); if (result.ec != std::errc{}) { str.resize(mpt::exponential_grow(str.size()), '\0'); } else { str.resize(result.ptr - str.data()); done = true; } } else { std::to_chars_result result = std::to_chars(str.data(), str.data() + str.size(), x); if (result.ec != std::errc{}) { str.resize(mpt::exponential_grow(str.size()), '\0'); } else { str.resize(result.ptr - str.data()); done = true; } } } return mpt::convert_formatted_simple(str); } template ::value, bool> = true> inline Tstring format_value_default(const T & x) { return mpt::transcode(mpt::to_chars_string::type>(x)); } #endif // MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 #if !MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 template ::value, bool> = true> inline Tstring to_stream_string(const T & x) { using stream_char_type = typename mpt::select_format_char_type::type; std::basic_ostringstream s; s.imbue(std::locale::classic()); if constexpr (std::is_same::value) { s << static_cast(x); } else if constexpr (mpt::is_character::value) { s << (x + 0); // force integral promotion } else { s << x; } return mpt::convert_formatted_simple(s.str()); } template ::value, bool> = true> inline Tstring format_value_default(const T & x) { return mpt::transcode(mpt::to_stream_string::type>(x)); } #endif // !MPT_FORMAT_FORMAT_DEFAULT_INT_CXX17 template ::value, bool> = true> inline Tstring format_value_default(const T & x) { return mpt::format_value_default(mpt::to_underlying(x)); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_DEFAULT_INTEGER_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/helpers.hpp0000644000175000017500000000413114107230757021315 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_HELPERS_HPP #define MPT_FORMAT_HELPERS_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { template inline Tdststring convert_formatted_simple(const Tsrcstring & src) { if constexpr (std::is_same::value) { return src; } else { Tdststring dst; dst.reserve(src.length()); for (std::size_t i = 0; i < src.length(); ++i) { dst.push_back(mpt::unsafe_char_convert(src[i])); } return dst; } } template struct select_format_char_type { using type = char; }; #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> struct select_format_char_type { using type = wchar_t; }; #if MPT_USTRING_MODE_WIDE #if MPT_CXX_AT_LEAST(20) template <> struct select_format_char_type { using type = wchar_t; }; #endif // C++20 template <> struct select_format_char_type { using type = wchar_t; }; template <> struct select_format_char_type { using type = wchar_t; }; #endif // MPT_USTRING_MODE_WIDE #endif // !MPT_COMPILER_QUIRK_NO_WCHAR template struct select_format_string_type { using type = mpt::ustring; }; template <> struct select_format_string_type { using type = std::string; }; #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> struct select_format_string_type { using type = std::wstring; }; #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_CXX_AT_LEAST(20) template <> struct select_format_string_type { using type = std::u8string; }; #endif // C++20 template <> struct select_format_string_type { using type = std::u16string; }; template <> struct select_format_string_type { using type = std::u32string; }; } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_HELPERS_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/join.hpp0000644000175000017500000000133414053446153020613 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_JOIN_HPP #define MPT_FORMAT_JOIN_HPP #include "mpt/base/namespace.hpp" #include "mpt/format/simple.hpp" #include "mpt/string/utility.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { template Tstring join_format(const std::vector & vals, const Tstring & sep = Tstring(1, char_constants::comma)) { Tstring str; for (std::size_t i = 0; i < vals.size(); ++i) { if (i > 0) { str += sep; } str += mpt::format::val(vals[i]); } return str; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_JOIN_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/message.hpp0000644000175000017500000002014614365207773021313 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_MESSAGE_HPP #define MPT_FORMAT_MESSAGE_HPP #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/span.hpp" #include "mpt/string/types.hpp" #include "mpt/string/utility.hpp" #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { class format_message_syntax_error : public std::domain_error { public: format_message_syntax_error() : std::domain_error("format string syntax error") { return; } }; template class message_formatter { private: using Tstringview = typename mpt::make_string_view_type::type; private: Tstring format; private: MPT_NOINLINE Tstring do_format(const mpt::span vals) const { using traits = typename mpt::string_traits; using char_type = typename traits::char_type; using size_type = typename traits::size_type; Tstring result; const size_type len = traits::length(format); traits::reserve(result, len); std::size_t max_arg = 0; //std::size_t args = 0; bool success = true; enum class state : int { error = -1, text = 0, open_seen = 1, number_seen = 2, close_seen = 3, }; state state = state::text; bool numbered_args = false; bool unnumbered_args = false; std::size_t last_arg = 0; std::size_t this_arg = 0; std::size_t current_arg = 0; for (size_type pos = 0; pos != len; ++pos) { char_type c = format[pos]; switch (state) { case state::text: if (c == char_type('{')) { state = state::open_seen; } else if (c == char_type('}')) { state = state::close_seen; } else { state = state::text; traits::append(result, c); // output c here } break; case state::open_seen: if (c == char_type('{')) { state = state::text; traits::append(result, char_type('{')); // output { here } else if (c == char_type('}')) { state = state::text; unnumbered_args = true; last_arg++; this_arg = last_arg; { // output this_arg here const std::size_t n = this_arg - 1; if (n < std::size(vals)) { traits::append(result, vals[n]); } } if (this_arg > max_arg) { max_arg = this_arg; } //args += 1; } else if (char_type('0') <= c && c <= char_type('9')) { state = state::number_seen; numbered_args = true; current_arg = c - char_type('0'); } else { state = state::error; } break; case state::number_seen: if (c == char_type('{')) { state = state::error; } else if (c == char_type('}')) { state = state::text; this_arg = current_arg + 1; { // output this_arg here const std::size_t n = this_arg - 1; if (n < std::size(vals)) { traits::append(result, vals[n]); } } if (this_arg > max_arg) { max_arg = this_arg; } //args += 1; } else if (char_type('0') <= c && c <= char_type('9')) { state = state::number_seen; numbered_args = true; current_arg = (current_arg * 10) + (c - char_type('0')); } else { state = state::error; } break; case state::close_seen: if (c == char_type('{')) { state = state::error; } else if (c == char_type('}')) { state = state::text; traits::append(result, char_type('}')); // output } here } else { state = state::error; } break; case state::error: state = state::error; break; } } if (state == state::error) { success = false; } if (state != state::text) { success = false; } if (numbered_args && unnumbered_args) { success = false; } if (!success) { throw format_message_syntax_error(); } return result; } public: MPT_FORCEINLINE message_formatter(Tstring format_) : format(std::move(format_)) { } public: template MPT_NOINLINE Tstring operator()(Ts &&... xs) const { const std::array vals{{Tformatter::template format(std::forward(xs))...}}; return do_format(mpt::as_span(vals)); } }; // class message_formatter template class message_formatter_counted { private: using Tstringview = typename mpt::make_string_view_type::type; private: message_formatter formatter; public: template inline message_formatter_counted(const Tchar (&format)[literal_length]) : formatter(Tstring(format)) { return; } public: template inline Tstring operator()(Ts &&... xs) const { static_assert(static_cast(sizeof...(xs)) == N); return formatter(std::forward(xs)...); } }; // struct message_formatter_counted template MPT_CONSTEXPRINLINE std::ptrdiff_t parse_format_string_argument_count_impl(const Tchar * const format, const std::size_t len) { std::size_t max_arg = 0; std::size_t args = 0; bool success = true; enum class state : int { error = -1, text = 0, open_seen = 1, number_seen = 2, close_seen = 3, }; state state = state::text; bool numbered_args = false; bool unnumbered_args = false; std::size_t last_arg = 0; std::size_t this_arg = 0; std::size_t current_arg = 0; for (std::size_t pos = 0; pos != len; ++pos) { Tchar c = format[pos]; switch (state) { case state::text: if (c == Tchar('{')) { state = state::open_seen; } else if (c == Tchar('}')) { state = state::close_seen; } else { state = state::text; // output c here } break; case state::open_seen: if (c == Tchar('{')) { state = state::text; // output { here } else if (c == Tchar('}')) { state = state::text; unnumbered_args = true; last_arg++; this_arg = last_arg; // output this_arg here if (this_arg > max_arg) { max_arg = this_arg; } args += 1; } else if (Tchar('0') <= c && c <= Tchar('9')) { state = state::number_seen; numbered_args = true; current_arg = c - Tchar('0'); } else { state = state::error; } break; case state::number_seen: if (c == Tchar('{')) { state = state::error; } else if (c == Tchar('}')) { state = state::text; this_arg = current_arg + 1; // output this_arg here if (this_arg > max_arg) { max_arg = this_arg; } args += 1; } else if (Tchar('0') <= c && c <= Tchar('9')) { state = state::number_seen; numbered_args = true; current_arg = (current_arg * 10) + (c - Tchar('0')); } else { state = state::error; } break; case state::close_seen: if (c == Tchar('{')) { state = state::error; } else if (c == Tchar('}')) { state = state::text; // output } here } else { state = state::error; } break; case state::error: state = state::error; break; } } if (state == state::error) { success = false; } if (state != state::text) { success = false; } if (numbered_args && unnumbered_args) { success = false; } if (!success) { throw format_message_syntax_error(); } if (max_arg != args) { throw format_message_syntax_error(); } return max_arg; } template MPT_CONSTEXPRINLINE std::ptrdiff_t parse_format_string_argument_count(const Tchar (&format)[literal_length]) { return parse_format_string_argument_count_impl(format, literal_length - 1); } template inline auto format_message(const Tchar (&format)[N]) { using Tstring = typename mpt::make_string_type::type; return message_formatter_counted(format); } template inline auto format_message_typed(const Tchar (&format)[N]) { return message_formatter_counted(format); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_MESSAGE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/simple.hpp0000644000175000017500000001517614174573504021163 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_SIMPLE_HPP #define MPT_FORMAT_SIMPLE_HPP #include "mpt/base/namespace.hpp" #include "mpt/base/pointer.hpp" #include "mpt/format/default_formatter.hpp" #include "mpt/format/simple_floatingpoint.hpp" #include "mpt/format/simple_integer.hpp" #include "mpt/format/simple_spec.hpp" #include "mpt/string/utility.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { template struct format : format_simple_base { template static inline Tstring val(const T & x) { return mpt::default_formatter::format(x); } template static inline Tstring fmt(const T & x, const format_simple_spec & f) { return mpt::format_simple(x, f); } template static inline Tstring dec(const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseDec().FillOff()); } template static inline Tstring dec0(const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseDec().FillNul().Width(width)); } template static inline Tstring dec(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseDec().FillOff().Group(g).GroupSep(s)); } template static inline Tstring dec0(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseDec().FillNul().Width(width).Group(g).GroupSep(s)); } template static inline Tstring hex(const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillOff()); } template static inline Tstring HEX(const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillOff()); } template static inline Tstring hex0(const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillNul().Width(width)); } template static inline Tstring HEX0(const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillNul().Width(width)); } template static inline Tstring hex(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillOff().Group(g).GroupSep(s)); } template static inline Tstring HEX(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillOff().Group(g).GroupSep(s)); } template static inline Tstring hex0(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillNul().Width(width).Group(g).GroupSep(s)); } template static inline Tstring HEX0(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillNul().Width(width).Group(g).GroupSep(s)); } template static inline Tstring flt(const T & x, int precision = -1) { static_assert(std::is_floating_point::value); return mpt::format_simple(x, format_simple_spec().NotaNrm().FillOff().Precision(precision)); } template static inline Tstring fix(const T & x, int precision = -1) { static_assert(std::is_floating_point::value); return mpt::format_simple(x, format_simple_spec().NotaFix().FillOff().Precision(precision)); } template static inline Tstring sci(const T & x, int precision = -1) { static_assert(std::is_floating_point::value); return mpt::format_simple(x, format_simple_spec().NotaSci().FillOff().Precision(precision)); } template static inline Tstring ptr(const T & x) { static_assert(std::is_pointer::value || std::is_same::value || std::is_same::value, ""); return hex0(mpt::pointer_cast(x)); } template static inline Tstring PTR(const T & x) { static_assert(std::is_pointer::value || std::is_same::value || std::is_same::value, ""); return HEX0(mpt::pointer_cast(x)); } static inline Tstring pad_left(std::size_t width_, const Tstring & str) { typedef mpt::string_traits traits; typename traits::size_type width = static_cast(width_); return traits::pad(str, width, 0); } static inline Tstring pad_right(std::size_t width_, const Tstring & str) { typedef mpt::string_traits traits; typename traits::size_type width = static_cast(width_); return traits::pad(str, 0, width); } static inline Tstring left(std::size_t width_, const Tstring & str) { typedef mpt::string_traits traits; typename traits::size_type width = static_cast(width_); return (traits::length(str) < width) ? traits::pad(str, 0, width - traits::length(str)) : str; } static inline Tstring right(std::size_t width_, const Tstring & str) { typedef mpt::string_traits traits; typename traits::size_type width = static_cast(width_); return (traits::length(str) < width) ? traits::pad(str, width - traits::length(str), 0) : str; } static inline Tstring center(std::size_t width_, const Tstring & str) { typedef mpt::string_traits traits; typename traits::size_type width = static_cast(width_); return (traits::length(str) < width) ? traits::pad(str, (width - traits::length(str)) / 2, (width - traits::length(str) + 1) / 2) : str; } }; // struct format } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_SIMPLE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/simple_floatingpoint.hpp0000644000175000017500000002055714257074355024121 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_SIMPLE_FLOATINGPOINT_HPP #define MPT_FORMAT_SIMPLE_FLOATINGPOINT_HPP #include "mpt/base/detect.hpp" #if !defined(MPT_LIBCXX_QUIRK_NO_TO_CHARS_FLOAT) #define MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 1 #else #define MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 0 #endif #if MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 #include "mpt/base/algorithm.hpp" #endif #include "mpt/base/namespace.hpp" #include "mpt/format/default_floatingpoint.hpp" #include "mpt/format/helpers.hpp" #include "mpt/format/simple_spec.hpp" #include "mpt/string/utility.hpp" #include "mpt/string_transcode/transcode.hpp" #if MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 #include #endif #if !MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 #include #include #endif #if MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 #include #endif #if !MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 #include #include #include #endif #include #if MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 #include #endif #include namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 template inline Tstring format_simple_floatingpoint_to_chars(const T & x, std::chars_format fmt) { std::string str(1, '\0'); bool done = false; while (!done) { std::to_chars_result result = std::to_chars(str.data(), str.data() + str.size(), x, fmt); if (result.ec != std::errc{}) { str.resize(mpt::exponential_grow(str.size()), '\0'); } else { str.resize(result.ptr - str.data()); done = true; } } return mpt::convert_formatted_simple(str); } template inline Tstring format_simple_floatingpoint_to_chars(const T & x, std::chars_format fmt, int precision) { std::string str(1, '\0'); bool done = false; while (!done) { std::to_chars_result result = std::to_chars(str.data(), str.data() + str.size(), x, fmt, precision); if (result.ec != std::errc{}) { str.resize(mpt::exponential_grow(str.size()), '\0'); } else { str.resize(result.ptr - str.data()); done = true; } } return mpt::convert_formatted_simple(str); } template inline Tstring format_simple_floatingpoint_postprocess_width(Tstring str, const format_simple_spec & format) { format_simple_flags f = format.GetFlags(); std::size_t width = format.GetWidth(); if (f & format_simple_base::FillNul) { auto pos = str.begin(); if (str.length() > 0) { if (str[0] == mpt::char_constants::plus) { pos++; width++; } else if (str[0] == mpt::char_constants::minus) { pos++; width++; } } if (str.length() - std::distance(str.begin(), pos) < width) { str.insert(pos, width - str.length() - std::distance(str.begin(), pos), mpt::char_constants::number0); } } else { if (str.length() < width) { str.insert(0, width - str.length(), mpt::char_constants::space); } } return str; } template ::value, bool> = true> inline Tstring format_simple(const T & x, const format_simple_spec & format) { using format_string_type = typename mpt::select_format_string_type::type; const format_simple_spec f = mpt::transcode_format_simple_spec(format); if (f.GetPrecision() != -1) { if (f.GetFlags() & format_simple_base::NotaSci) { return mpt::transcode(mpt::format_simple_floatingpoint_postprocess_width(format_simple_floatingpoint_to_chars(x, std::chars_format::scientific, f.GetPrecision()), f)); } else if (f.GetFlags() & format_simple_base::NotaFix) { return mpt::transcode(mpt::format_simple_floatingpoint_postprocess_width(format_simple_floatingpoint_to_chars(x, std::chars_format::fixed, f.GetPrecision()), f)); } else { return mpt::transcode(mpt::format_simple_floatingpoint_postprocess_width(format_simple_floatingpoint_to_chars(x, std::chars_format::general, f.GetPrecision()), f)); } } else { if (f.GetFlags() & format_simple_base::NotaSci) { return mpt::transcode(mpt::format_simple_floatingpoint_postprocess_width(format_simple_floatingpoint_to_chars(x, std::chars_format::scientific), f)); } else if (f.GetFlags() & format_simple_base::NotaFix) { return mpt::transcode(mpt::format_simple_floatingpoint_postprocess_width(format_simple_floatingpoint_to_chars(x, std::chars_format::fixed), f)); } else { return mpt::transcode(mpt::format_simple_floatingpoint_postprocess_width(format_simple_floatingpoint_to_chars(x, std::chars_format::general), f)); } } } #else // !MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 template struct NumPunct : std::numpunct { private: unsigned int group; Tchar sep; public: NumPunct(unsigned int g, Tchar s) : group(g) , sep(s) { } std::string do_grouping() const override { return std::string(1, static_cast(group)); } Tchar do_thousands_sep() const override { return sep; } }; template inline void format_simple_floatingpoint_apply_stream_format(Tostream & o, const format_simple_spec & format, const T &) { if (format.GetGroup() > 0) { if (mpt::string_traits::length(format.GetGroupSep()) >= 1) { o.imbue(std::locale(o.getloc(), new NumPunct(format.GetGroup(), format.GetGroupSep()[0]))); } } format_simple_flags f = format.GetFlags(); std::size_t width = format.GetWidth(); int precision = format.GetPrecision(); if (precision != -1 && width != 0 && !(f & format_simple_base::NotaFix) && !(f & format_simple_base::NotaSci)) { // fixup: // precision behaves differently from .# // avoid default format when precision and width are set f &= ~format_simple_base::NotaNrm; f |= format_simple_base::NotaFix; } if (f & format_simple_base::BaseDec) { o << std::dec; } else if (f & format_simple_base::BaseHex) { o << std::hex; } if (f & format_simple_base::NotaNrm) { /*nothing*/ } else if (f & format_simple_base::NotaFix) { o << std::setiosflags(std::ios::fixed); } else if (f & format_simple_base::NotaSci) { o << std::setiosflags(std::ios::scientific); } if (f & format_simple_base::CaseLow) { o << std::nouppercase; } else if (f & format_simple_base::CaseUpp) { o << std::uppercase; } if (f & format_simple_base::FillOff) { /* nothing */ } else if (f & format_simple_base::FillNul) { o << std::setw(width) << std::setfill(mpt::char_constants::number0); } if (precision != -1) { o << std::setprecision(precision); } else { if constexpr (std::is_floating_point::value) { if (f & format_simple_base::NotaNrm) { o << std::setprecision(std::numeric_limits::max_digits10); } else if (f & format_simple_base::NotaFix) { o << std::setprecision(std::numeric_limits::digits10); } else if (f & format_simple_base::NotaSci) { o << std::setprecision(std::numeric_limits::max_digits10 - 1); } else { o << std::setprecision(std::numeric_limits::max_digits10); } } } } template inline Tstring format_simple_floatingpoint_stream(const T & x, const format_simple_spec & f) { using stream_char_type = typename mpt::select_format_char_type::type; std::basic_ostringstream s; s.imbue(std::locale::classic()); mpt::format_simple_floatingpoint_apply_stream_format(s, f, x); s << x; return mpt::convert_formatted_simple(s.str()); } template ::value, bool> = true> inline Tstring format_simple(const T & x, const format_simple_spec & format) { using format_string_type = typename mpt::select_format_string_type::type; const format_simple_spec f = mpt::transcode_format_simple_spec(format); return mpt::transcode(mpt::format_simple_floatingpoint_stream(x, f)); } #endif // MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_SIMPLE_FLOATINGPOINT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/tests/0000755000175000017500000000000015023302361020352 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/format/tests/tests_format_simple.hpp0000644000175000017500000003331014357021415025075 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_TESTS_FORMAT_SIMPLE_HPP #define MPT_FORMAT_TESTS_FORMAT_SIMPLE_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/detect/mfc.hpp" #include "mpt/format/simple.hpp" #include "mpt/format/simple_integer.hpp" #include "mpt/string/types.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace format { namespace simple { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/format/simple") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { MPT_TEST_EXPECT_EQUAL(mpt::format::val(1.5f), "1.5"); MPT_TEST_EXPECT_EQUAL(mpt::format::val(true), "1"); MPT_TEST_EXPECT_EQUAL(mpt::format::val(false), "0"); MPT_TEST_EXPECT_EQUAL(mpt::format::val(0), "0"); MPT_TEST_EXPECT_EQUAL(mpt::format::val(-23), "-23"); MPT_TEST_EXPECT_EQUAL(mpt::format::val(42), "42"); MPT_TEST_EXPECT_EQUAL(mpt::format::hex0<3>((int32)-1), "-001"); MPT_TEST_EXPECT_EQUAL(mpt::format::hex((int32)-1), "-1"); MPT_TEST_EXPECT_EQUAL(mpt::format::hex(-0xabcde), "-abcde"); MPT_TEST_EXPECT_EQUAL(mpt::format::hex(std::numeric_limits::min()), "-80000000"); MPT_TEST_EXPECT_EQUAL(mpt::format::hex(std::numeric_limits::min() + 1), "-7fffffff"); MPT_TEST_EXPECT_EQUAL(mpt::format::hex(0x123e), "123e"); MPT_TEST_EXPECT_EQUAL(mpt::format::hex0<6>(0x123e), "00123e"); MPT_TEST_EXPECT_EQUAL(mpt::format::hex0<2>(0x123e), "123e"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<0>(1), "1"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<1>(1), "1"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<2>(1), "01"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<3>(1), "001"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<0>(11), "11"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<1>(11), "11"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<2>(11), "11"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<3>(11), "011"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<0>(-1), "-1"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<1>(-1), "-1"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<2>(-1), "-01"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec0<3>(-1), "-001"); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(0xa2345678), MPT_USTRING("A2345678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<8>(0xa2345678), MPT_USTRING("A2345678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<9>(0xa2345678), MPT_USTRING("0A2345678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<10>(0xa2345678), MPT_USTRING("00A2345678")); #if MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 MPT_TEST_EXPECT_EQUAL(mpt::format_simple_integer_to_chars(std::numeric_limits::min(), 10), "-32768"); MPT_TEST_EXPECT_EQUAL(mpt::format_simple_integer_to_chars(std::numeric_limits::max(), 10), "32767"); MPT_TEST_EXPECT_EQUAL(mpt::format_simple_integer_to_chars(std::numeric_limits::min(), 7), "-164351"); MPT_TEST_EXPECT_EQUAL(mpt::format_simple_integer_to_chars(std::numeric_limits::min() + 1, 7), "-164350"); MPT_TEST_EXPECT_EQUAL(mpt::format_simple_integer_to_chars(std::numeric_limits::max(), 7), "164350"); #else // !MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 MPT_TEST_EXPECT_EQUAL(mpt::format_simple_integer_to_stream(std::numeric_limits::min(), 10), "-32768"); MPT_TEST_EXPECT_EQUAL(mpt::format_simple_integer_to_stream(std::numeric_limits::max(), 10), "32767"); MPT_TEST_EXPECT_EQUAL(mpt::format_simple_integer_to_stream(std::numeric_limits::min(), 7), "-164351"); MPT_TEST_EXPECT_EQUAL(mpt::format_simple_integer_to_stream(std::numeric_limits::min() + 1, 7), "-164350"); MPT_TEST_EXPECT_EQUAL(mpt::format_simple_integer_to_stream(std::numeric_limits::max(), 7), "164350"); #endif // MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) MPT_TEST_EXPECT_EQUAL(mpt::format::hex(0x123e), L"123e"); MPT_TEST_EXPECT_EQUAL(mpt::format::hex0<6>(0x123e), L"00123e"); MPT_TEST_EXPECT_EQUAL(mpt::format::hex0<2>(0x123e), L"123e"); #endif // !MPT_COMPILER_QUIRK_NO_WCHAR MPT_TEST_EXPECT_EQUAL(mpt::format::val(-87.0f), "-87"); if (mpt::format::val(-0.5e-6) != "-5e-007" && mpt::format::val(-0.5e-6) != "-5e-07" && mpt::format::val(-0.5e-6) != "-5e-7" && mpt::format::val(-0.5e-6) != "-4.9999999999999998e-7" && mpt::format::val(-0.5e-6) != "-4.9999999999999998e-07" && mpt::format::val(-0.5e-6) != "-4.9999999999999998e-007") { MPT_TEST_EXPECT_EQUAL(true, false); } if (mpt::format::val(-1.0 / 65536.0) != "-1.52587890625e-005" && mpt::format::val(-1.0 / 65536.0) != "-1.52587890625e-05" && mpt::format::val(-1.0 / 65536.0) != "-1.52587890625e-5") { MPT_TEST_EXPECT_EQUAL(true, false); } if (mpt::format::val(-1.0f / 65536.0f) != "-1.52587891e-005" && mpt::format::val(-1.0f / 65536.0f) != "-1.52587891e-05" && mpt::format::val(-1.0f / 65536.0f) != "-1.52587891e-5" && mpt::format::val(-1.0f / 65536.0f) != "-1.5258789e-005" && mpt::format::val(-1.0f / 65536.0f) != "-1.5258789e-05" && mpt::format::val(-1.0f / 65536.0f) != "-1.5258789e-5") { MPT_TEST_EXPECT_EQUAL(true, false); } if (mpt::format::val(58.65403492763) != "58.654034927630001" && mpt::format::val(58.65403492763) != "58.65403492763") { MPT_TEST_EXPECT_EQUAL(true, false); } MPT_TEST_EXPECT_EQUAL(mpt::format::flt(58.65403492763, 6), "58.654"); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(23.42, 1), "23.4"); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(234.2, 1), "234.2"); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(2342.0, 1), "2342.0"); MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, ";", 2345678), std::string("2;34;56;78")); MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, ";", 12345678), std::string("12;34;56;78")); MPT_TEST_EXPECT_EQUAL(mpt::format::hex(3, ":", 0xa2345678), std::string("a2:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, MPT_USTRING(";"), 12345678), MPT_USTRING("12;34;56;78")); MPT_TEST_EXPECT_EQUAL(mpt::format::hex(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("a2:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("A2:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<8>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("A2:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<9>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("0A2:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<10>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("0:0A2:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<11>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("00:0A2:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<12>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("000:0A2:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-12:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<8>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-12:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<9>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-012:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<10>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-0:012:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<11>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-00:012:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<12>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-000:012:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<5>(3, MPT_USTRING(":"), 0x345678), MPT_USTRING("345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<6>(3, MPT_USTRING(":"), 0x345678), MPT_USTRING("345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, MPT_USTRING(":"), 0x345678), MPT_USTRING("0:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<5>(3, MPT_USTRING(":"), -0x345678), MPT_USTRING("-345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<6>(3, MPT_USTRING(":"), -0x345678), MPT_USTRING("-345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, MPT_USTRING(":"), -0x345678), MPT_USTRING("-0:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::left(3, "a"), "a "); MPT_TEST_EXPECT_EQUAL(mpt::format::right(3, "a"), " a"); MPT_TEST_EXPECT_EQUAL(mpt::format::center(3, "a"), " a "); MPT_TEST_EXPECT_EQUAL(mpt::format::center(4, "a"), " a "); MPT_TEST_EXPECT_EQUAL(mpt::format::flt(6.12345, 3), "6.12"); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(6.12345, 3), "6.123"); MPT_TEST_EXPECT_EQUAL(mpt::format::flt(6.12345, 4), "6.123"); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(6.12345, 4), "6.1235"); MPT_TEST_EXPECT_EQUAL(mpt::format::val(std::u32string(U"foo")), U"foo"); MPT_TEST_EXPECT_EQUAL(mpt::format::val(std::u32string_view(U"foo")), U"foo"); #if MPT_DETECTED_MFC MPT_TEST_EXPECT_EQUAL(mpt::format::flt(58.65403492763, 6), TEXT("58.654")); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(23.42, 1), TEXT("23.4")); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(234.2, 1), TEXT("234.2")); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(2342.0, 1), TEXT("2342.0")); MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, TEXT(";"), 2345678), CString(TEXT("2;34;56;78"))); MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, TEXT(";"), 12345678), CString(TEXT("12;34;56;78"))); MPT_TEST_EXPECT_EQUAL(mpt::format::hex(3, TEXT(":"), 0xa2345678), CString(TEXT("a2:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, TEXT(";"), 12345678), CString(TEXT("12;34;56;78"))); MPT_TEST_EXPECT_EQUAL(mpt::format::hex(3, TEXT(":"), 0xa2345678), CString(TEXT("a2:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, TEXT(":"), 0xa2345678), CString(TEXT("A2:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<8>(3, TEXT(":"), 0xa2345678), CString(TEXT("A2:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<9>(3, TEXT(":"), 0xa2345678), CString(TEXT("0A2:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<10>(3, TEXT(":"), 0xa2345678), CString(TEXT("0:0A2:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<11>(3, TEXT(":"), 0xa2345678), CString(TEXT("00:0A2:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<12>(3, TEXT(":"), 0xa2345678), CString(TEXT("000:0A2:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, TEXT(":"), -0x12345678), CString(TEXT("-12:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<8>(3, TEXT(":"), -0x12345678), CString(TEXT("-12:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<9>(3, TEXT(":"), -0x12345678), CString(TEXT("-012:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<10>(3, TEXT(":"), -0x12345678), CString(TEXT("-0:012:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<11>(3, TEXT(":"), -0x12345678), CString(TEXT("-00:012:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<12>(3, TEXT(":"), -0x12345678), CString(TEXT("-000:012:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<5>(3, TEXT(":"), 0x345678), CString(TEXT("345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<6>(3, TEXT(":"), 0x345678), CString(TEXT("345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, TEXT(":"), 0x345678), CString(TEXT("0:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<5>(3, TEXT(":"), -0x345678), CString(TEXT("-345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<6>(3, TEXT(":"), -0x345678), CString(TEXT("-345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, TEXT(":"), -0x345678), CString(TEXT("-0:345:678"))); MPT_TEST_EXPECT_EQUAL(mpt::format::left(3, TEXT("a")), TEXT("a ")); MPT_TEST_EXPECT_EQUAL(mpt::format::right(3, TEXT("a")), TEXT(" a")); MPT_TEST_EXPECT_EQUAL(mpt::format::center(3, TEXT("a")), TEXT(" a ")); MPT_TEST_EXPECT_EQUAL(mpt::format::center(4, TEXT("a")), TEXT(" a ")); MPT_TEST_EXPECT_EQUAL(mpt::format::flt(6.12345, 3), TEXT("6.12")); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(6.12345, 3), TEXT("6.123")); MPT_TEST_EXPECT_EQUAL(mpt::format::flt(6.12345, 4), TEXT("6.123")); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(6.12345, 4), TEXT("6.1235")); #endif #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) MPT_TEST_EXPECT_EQUAL(mpt::format::flt(6.12345, 3), L"6.12"); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(6.12345, 3), L"6.123"); MPT_TEST_EXPECT_EQUAL(mpt::format::flt(6.12345, 4), L"6.123"); #endif // !MPT_COMPILER_QUIRK_NO_WCHAR } } // namespace simple } // namespace format } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_TESTS_FORMAT_SIMPLE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/format/tests/tests_format_message.hpp0000644000175000017500000000527314357021415025237 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_FORMAT_TESTS_FORMAT_MESSAGE_HPP #define MPT_FORMAT_TESTS_FORMAT_MESSAGE_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/format/message.hpp" #include "mpt/format/message_macros.hpp" #include "mpt/string/types.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace format { namespace message { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/format/message") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { static_assert(mpt::parse_format_string_argument_count("") == 0); static_assert(mpt::parse_format_string_argument_count("{{") == 0); static_assert(mpt::parse_format_string_argument_count("}}") == 0); static_assert(mpt::parse_format_string_argument_count("{}") == 1); static_assert(mpt::parse_format_string_argument_count("{}{}") == 2); static_assert(mpt::parse_format_string_argument_count("{0}{1}") == 2); // basic MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("{}{}{}")(1, 2, 3), "123"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("{2}{1}{0}")(1, 2, 3), "321"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("{2}{1}{0}{4}{3}{6}{5}{7}{10}{9}{8}")(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "a"), "21043657a98"); #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE(L"{}{}{}")(1, 2, 3), L"123"); #endif // !MPT_COMPILER_QUIRK_NO_WCHAR // escaping behviour MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("%")(), "%"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("%")(), "%"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("%%")(), "%%"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("{}")("a"), "a"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("{}%")("a"), "a%"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("{}%")("a"), "a%"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("{}%%")("a"), "a%%"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("%1")(), "%1"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("%{}")("a"), "%a"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("%b")(), "%b"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("{{}}")(), "{}"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("{{{}}}")("a"), "{a}"); // formatting string_view MPT_TEST_EXPECT_EQUAL(MPT_UFORMAT_MESSAGE("{}")(mpt::ustring(MPT_ULITERAL("foo"))), MPT_USTRING("foo")); MPT_TEST_EXPECT_EQUAL(MPT_UFORMAT_MESSAGE("{}")(mpt::ustring_view(MPT_ULITERAL("foo"))), MPT_USTRING("foo")); } } // namespace message } // namespace format } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_FORMAT_TESTS_FORMAT_MESSAGE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/parse/0000755000175000017500000000000015023302361017032 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/parse/parse.hpp0000644000175000017500000001270714351611430020607 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_PARSE_PARSE_HPP #define MPT_PARSE_PARSE_HPP #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include #include #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { inline std::string parse_as_internal_string_type(const std::string & s) { return s; } #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) inline std::wstring parse_as_internal_string_type(const std::wstring & s) { return s; } #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_USTRING_MODE_WIDE template inline std::wstring parse_as_internal_string_type(const Tstring & s) { return mpt::transcode(s); } #else // !MPT_USTRING_MODE_WIDE template inline std::string parse_as_internal_string_type(const Tstring & s) { return mpt::transcode(mpt::common_encoding::utf8, s); } #endif // MPT_USTRING_MODE_WIDE template inline bool parse_into(T & dst, const Tstring & str) { std::basic_istringstream stream(mpt::parse_as_internal_string_type(mpt::as_string(str))); stream.imbue(std::locale::classic()); if constexpr (std::is_same::value) { signed int tmp; if (!(stream >> tmp)) { return false; } dst = tmp ? true : false; } else if constexpr (std::is_same::value) { signed int tmp; if (!(stream >> tmp)) { return false; } dst = static_cast(tmp); } else if constexpr (std::is_same::value) { unsigned int tmp; if (!(stream >> tmp)) { return false; } dst = static_cast(tmp); } else { if (!(stream >> dst)) { return false; } } return true; } template inline T parse_or(const Tstring & str, T def) { std::basic_istringstream stream(mpt::parse_as_internal_string_type(mpt::as_string(str))); stream.imbue(std::locale::classic()); T value = def; if constexpr (std::is_same::value) { int tmp; if (!(stream >> tmp)) { return def; } value = tmp ? true : false; } else if constexpr (std::is_same::value) { signed int tmp; if (!(stream >> tmp)) { return def; } value = static_cast(tmp); } else if constexpr (std::is_same::value) { unsigned int tmp; if (!(stream >> tmp)) { return def; } value = static_cast(tmp); } else { if (!(stream >> value)) { return def; } } return value; } template inline T parse(const Tstring & str) { return mpt::parse_or(str, T{}); } template inline bool locale_parse_into(const std::locale & loc, T & dst, const Tstring & str) { std::basic_istringstream stream(mpt::parse_as_internal_string_type(mpt::as_string(str))); stream.imbue(loc); if constexpr (std::is_same::value) { int tmp; if (!(stream >> tmp)) { return false; } dst = tmp ? true : false; } else if constexpr (std::is_same::value) { signed int tmp; if (!(stream >> tmp)) { return false; } dst = static_cast(tmp); } else if constexpr (std::is_same::value) { unsigned int tmp; if (!(stream >> tmp)) { return false; } dst = static_cast(tmp); } else { if (!(stream >> dst)) { return false; } } return true; } template inline T locale_parse_or(const std::locale & loc, const Tstring & str, T def) { std::basic_istringstream stream(mpt::parse_as_internal_string_type(mpt::as_string(str))); stream.imbue(loc); T value = def; if constexpr (std::is_same::value) { signed int tmp; if (!(stream >> tmp)) { return def; } value = tmp ? true : false; } else if constexpr (std::is_same::value) { signed int tmp; if (!(stream >> tmp)) { return def; } value = static_cast(tmp); } else if constexpr (std::is_same::value) { unsigned int tmp; if (!(stream >> tmp)) { return def; } value = static_cast(tmp); } else { if (!(stream >> value)) { return def; } } return value; } template inline T locale_parse(const std::locale & loc, const Tstring & str) { return mpt::parse_or(loc, str, T{}); } template inline T parse_hex(const Tstring & str) { std::basic_istringstream stream(mpt::parse_as_internal_string_type(mpt::as_string(str))); stream.imbue(std::locale::classic()); T value; if constexpr (std::is_same::value) { signed int tmp; if (!(stream >> std::hex >> tmp)) { return T{}; } value = static_cast(tmp); } else if constexpr (std::is_same::value) { unsigned int tmp; if (!(stream >> std::hex >> tmp)) { return T{}; } value = static_cast(tmp); } else { if (!(stream >> std::hex >> value)) { return T{}; } } return value; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_PARSE_PARSE_HPP libopenmpt-0.8.1+release.autotools/src/mpt/parse/split.hpp0000644000175000017500000000161714344622654020642 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_PARSE_SPLIT_HPP #define MPT_PARSE_SPLIT_HPP #include "mpt/base/namespace.hpp" #include "mpt/parse/parse.hpp" #include "mpt/string/utility.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { template std::vector split_parse(const Tstring & str, const Tstring & sep = Tstring(1, char_constants::comma)) { std::vector vals; std::size_t pos = 0; while (str.find(sep, pos) != std::string::npos) { vals.push_back(mpt::parse(str.substr(pos, str.find(sep, pos) - pos))); pos = str.find(sep, pos) + sep.length(); } if (!vals.empty() || (str.substr(pos).length() > 0)) { vals.push_back(mpt::parse(str.substr(pos))); } return vals; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_PARSE_SPLIT_HPP libopenmpt-0.8.1+release.autotools/src/mpt/parse/tests/0000755000175000017500000000000015023302361020174 500000000000000libopenmpt-0.8.1+release.autotools/src/mpt/parse/tests/tests_parse.hpp0000644000175000017500000000611614564653435023211 00000000000000/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_PARSE_TESTS_PARSE_HPP #define MPT_PARSE_TESTS_PARSE_HPP #include "mpt/base/detect.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/namespace.hpp" #include "mpt/format/simple.hpp" #include "mpt/parse/parse.hpp" #include "mpt/string/types.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { namespace tests { namespace parse { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif MPT_TEST_GROUP_INLINE("mpt/parse") #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif { MPT_TEST_EXPECT_EQUAL(mpt::parse("1"), true); MPT_TEST_EXPECT_EQUAL(mpt::parse("0"), false); MPT_TEST_EXPECT_EQUAL(mpt::parse("2"), true); MPT_TEST_EXPECT_EQUAL(mpt::parse("-0"), false); MPT_TEST_EXPECT_EQUAL(mpt::parse("-1"), true); MPT_TEST_EXPECT_EQUAL(mpt::parse("586"), 586u); MPT_TEST_EXPECT_EQUAL(mpt::parse("2147483647"), (uint32)std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::parse("4294967295"), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::parse("-9223372036854775808"), std::numeric_limits::min()); MPT_TEST_EXPECT_EQUAL(mpt::parse("-159"), -159); MPT_TEST_EXPECT_EQUAL(mpt::parse("9223372036854775807"), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::parse("85059"), 85059u); MPT_TEST_EXPECT_EQUAL(mpt::parse("9223372036854775807"), (uint64)std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::parse("18446744073709551615"), std::numeric_limits::max()); MPT_TEST_EXPECT_EQUAL(mpt::parse("-87.0"), -87.0f); #if !MPT_OS_DJGPP MPT_TEST_EXPECT_EQUAL(mpt::parse("-0.5e-6"), -0.5e-6); #endif #if !MPT_OS_DJGPP MPT_TEST_EXPECT_EQUAL(mpt::parse("58.65403492763"), 58.65403492763); #else MPT_TEST_EXPECT_EQUAL(std::abs(mpt::parse("58.65403492763") - 58.65403492763) <= 0.0001, true); #endif MPT_TEST_EXPECT_EQUAL(mpt::parse(mpt::format::val(-87.0)), -87.0f); // VS2022 17.7.2 parses "-5e-07" as -5.0000000000000004e-06 instead of -4.9999999999999998e-07 which is closer // // #if !MPT_OS_DJGPP && !(MPT_MSVC_AT_LEAST(2022, 7) && MPT_MSVC_BEFORE(2022, 9)) MPT_TEST_EXPECT_EQUAL(mpt::parse(mpt::format::val(-0.5e-6)), -0.5e-6); #endif MPT_TEST_EXPECT_EQUAL(mpt::parse_hex("fe"), 254); #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) MPT_TEST_EXPECT_EQUAL(mpt::parse_hex(L"fe"), 254); #endif // !MPT_COMPILER_QUIRK_NO_WCHAR MPT_TEST_EXPECT_EQUAL(mpt::parse_hex(MPT_USTRING("ffff")), 65535u); } } // namespace parse } // namespace tests } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_PARSE_TESTS_PARSE_HPP libopenmpt-0.8.1+release.autotools/m4/0000755000175000017500000000000015023302363014653 500000000000000libopenmpt-0.8.1+release.autotools/m4/ltversion.m40000644000175000017500000000131215023302302017050 00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004, 2011-2019, 2021-2022 Free Software Foundation, # Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 4245 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.7]) m4_define([LT_PACKAGE_REVISION], [2.4.7]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.7' macro_revision='2.4.7' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) libopenmpt-0.8.1+release.autotools/m4/ltsugar.m40000644000175000017500000001045315023302302016512 00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007-2008, 2011-2019, 2021-2022 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59, which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) libopenmpt-0.8.1+release.autotools/m4/ax_compiler_vendor.m40000644000175000017500000001036215023302302020707 00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html # =========================================================================== # # SYNOPSIS # # AX_COMPILER_VENDOR # # DESCRIPTION # # Determine the vendor of the C, C++ or Fortran compiler. The vendor is # returned in the cache variable $ax_cv_c_compiler_vendor for C, # $ax_cv_cxx_compiler_vendor for C++ or $ax_cv_fc_compiler_vendor for # (modern) Fortran. The value is one of "intel", "ibm", "pathscale", # "clang" (LLVM), "cray", "fujitsu", "sdcc", "sx", "nvhpc" (NVIDIA HPC # Compiler), "portland" (PGI), "gnu" (GCC), "sun" (Oracle Developer # Studio), "hp", "dec", "borland", "comeau", "kai", "lcc", "sgi", # "microsoft", "metrowerks", "watcom", "tcc" (Tiny CC) or "unknown" (if # the compiler cannot be determined). # # To check for a Fortran compiler, you must first call AC_FC_PP_SRCEXT # with an appropriate preprocessor-enabled extension. For example: # # AC_LANG_PUSH([Fortran]) # AC_PROG_FC # AC_FC_PP_SRCEXT([F]) # AX_COMPILER_VENDOR # AC_LANG_POP([Fortran]) # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2008 Matteo Frigo # Copyright (c) 2018-19 John Zaitseff # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 32 AC_DEFUN([AX_COMPILER_VENDOR], [dnl AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, [dnl dnl If you modify this list of vendors, please add similar support dnl to ax_compiler_version.m4 if at all possible. dnl dnl Note: Do NOT check for GCC first since some other compilers dnl define __GNUC__ to remain compatible with it. Compilers that dnl are very slow to start (such as Intel) are listed first. vendors=" intel: __ICC,__ECC,__INTEL_COMPILER ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__,__ibmxl__ pathscale: __PATHCC__,__PATHSCALE__ clang: __clang__ cray: _CRAYC fujitsu: __FUJITSU sdcc: SDCC,__SDCC sx: _SX nvhpc: __NVCOMPILER portland: __PGI gnu: __GNUC__ sun: __SUNPRO_C,__SUNPRO_CC,__SUNPRO_F90,__SUNPRO_F95 hp: __HP_cc,__HP_aCC dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland: __BORLANDC__,__CODEGEARC__,__TURBOC__ comeau: __COMO__ kai: __KCC lcc: __LCC__ sgi: __sgi,sgi microsoft: _MSC_VER metrowerks: __MWERKS__ watcom: __WATCOMC__ tcc: __TINYC__ unknown: UNKNOWN " for ventest in $vendors; do case $ventest in *:) vendor=$ventest continue ;; *) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;; esac AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[ #if !($vencpp) thisisanerror; #endif ]])], [break]) done ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1` ]) ])dnl libopenmpt-0.8.1+release.autotools/m4/ax_require_defined.m40000644000175000017500000000230215023302302020645 00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_require_defined.html # =========================================================================== # # SYNOPSIS # # AX_REQUIRE_DEFINED(MACRO) # # DESCRIPTION # # AX_REQUIRE_DEFINED is a simple helper for making sure other macros have # been defined and thus are available for use. This avoids random issues # where a macro isn't expanded. Instead the configure script emits a # non-fatal: # # ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found # # It's like AC_REQUIRE except it doesn't expand the required macro. # # Here's an example: # # AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) # # LICENSE # # Copyright (c) 2014 Mike Frysinger # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 2 AC_DEFUN([AX_REQUIRE_DEFINED], [dnl m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) ])dnl AX_REQUIRE_DEFINED libopenmpt-0.8.1+release.autotools/m4/ax_prepend_flag.m40000644000175000017500000000311115023302302020140 00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_prepend_flag.html # =========================================================================== # # SYNOPSIS # # AX_PREPEND_FLAG(FLAG, [FLAGS-VARIABLE]) # # DESCRIPTION # # FLAG is added to the front of the FLAGS-VARIABLE shell variable, with a # space added in between. # # If FLAGS-VARIABLE is not specified, the current language's flags (e.g. # CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains # FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly # FLAG. # # NOTE: Implementation based on AX_APPEND_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # Copyright (c) 2018 John Zaitseff # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 2 AC_DEFUN([AX_PREPEND_FLAG], [dnl AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) AS_VAR_SET_IF(FLAGS,[ AS_CASE([" AS_VAR_GET(FLAGS) "], [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], [ FLAGS="$1 $FLAGS" AC_RUN_LOG([: FLAGS="$FLAGS"]) ]) ], [ AS_VAR_SET(FLAGS,[$1]) AC_RUN_LOG([: FLAGS="$FLAGS"]) ]) AS_VAR_POPDEF([FLAGS])dnl ])dnl AX_PREPEND_FLAG libopenmpt-0.8.1+release.autotools/m4/ltoptions.m40000644000175000017500000003427515023302302017074 00000000000000# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004-2005, 2007-2009, 2011-2019, 2021-2022 Free # Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 8 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option '$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl 'shared' nor 'disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], [_LT_WITH_AIX_SONAME([aix])]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the 'shared' and # 'disable-shared' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the 'static' and # 'disable-static' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the 'fast-install' # and 'disable-fast-install' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_AIX_SONAME([DEFAULT]) # ---------------------------------- # implement the --with-aix-soname flag, and support the `aix-soname=aix' # and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT # is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. m4_define([_LT_WITH_AIX_SONAME], [m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[[5-9]]*,yes) AC_MSG_CHECKING([which variant of shared library versioning to provide]) AC_ARG_WITH([aix-soname], [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], [case $withval in aix|svr4|both) ;; *) AC_MSG_ERROR([Unknown argument to --with-aix-soname]) ;; esac lt_cv_with_aix_soname=$with_aix_soname], [AC_CACHE_VAL([lt_cv_with_aix_soname], [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) with_aix_soname=$lt_cv_with_aix_soname]) AC_MSG_RESULT([$with_aix_soname]) if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac _LT_DECL([], [shared_archive_member_spec], [0], [Shared archive member basename, for filename based shared library versioning on AIX])dnl ])# _LT_WITH_AIX_SONAME LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the 'pic-only' and 'no-pic' # LT_INIT options. # MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac], [pic_mode=m4_default([$1], [default])]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) libopenmpt-0.8.1+release.autotools/m4/ax_cxx_rtti.m40000644000175000017500000000303415023302302017362 00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_cxx_rtti.html # =========================================================================== # # SYNOPSIS # # AX_CXX_RTTI # # DESCRIPTION # # If the compiler supports Run-Time Type Identification (typeinfo header # and typeid keyword), define HAVE_RTTI. # # LICENSE # # Copyright (c) 2008 Todd Veldhuizen # Copyright (c) 2008 Luc Maisonobe # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 8 AU_ALIAS([AC_CXX_RTTI], [AX_CXX_RTTI]) AC_DEFUN([AX_CXX_RTTI], [AC_CACHE_CHECK(whether the compiler supports Run-Time Type Identification, ax_cv_cxx_rtti, [AC_LANG_PUSH([C++]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include class Base { public : Base () {} virtual int f () { return 0; } }; class Derived : public Base { public : Derived () {} virtual int f () { return 1; } }; ]], [[Derived d; Base *ptr = &d; return typeid (*ptr) == typeid (Derived); ]])], [ax_cv_cxx_rtti=yes], [ax_cv_cxx_rtti=no]) AC_LANG_POP([C++]) ]) if test "$ax_cv_cxx_rtti" = yes; then AC_DEFINE(HAVE_RTTI,, [define if the compiler supports Run-Time Type Identification]) fi ]) libopenmpt-0.8.1+release.autotools/m4/lt~obsolete.m40000644000175000017500000001400715023302302017402 00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007, 2009, 2011-2019, 2021-2022 Free # Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) libopenmpt-0.8.1+release.autotools/m4/ax_cxx_exceptions.m40000644000175000017500000000232215023302302020560 00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_cxx_exceptions.html # =========================================================================== # # SYNOPSIS # # AX_CXX_EXCEPTIONS # # DESCRIPTION # # If the C++ compiler supports exceptions handling (try, throw and catch), # define HAVE_EXCEPTIONS. # # LICENSE # # Copyright (c) 2008 Todd Veldhuizen # Copyright (c) 2008 Luc Maisonobe # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 8 AU_ALIAS([AC_CXX_EXCEPTIONS], [AX_CXX_EXCEPTIONS]) AC_DEFUN([AX_CXX_EXCEPTIONS], [AC_CACHE_CHECK(whether the compiler supports exceptions, ax_cv_cxx_exceptions, [AC_LANG_PUSH([C++]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[try { throw 1; } catch (int i) { return i; }]])], [ax_cv_cxx_exceptions=yes], [ax_cv_cxx_exceptions=no]) AC_LANG_POP([C++]) ]) if test "$ax_cv_cxx_exceptions" = yes; then AC_DEFINE(HAVE_EXCEPTIONS,,[define if the compiler supports exceptions]) fi ]) libopenmpt-0.8.1+release.autotools/m4/ax_prog_doxygen.m40000644000175000017500000005002215023302302020221 00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_prog_doxygen.html # =========================================================================== # # SYNOPSIS # # DX_INIT_DOXYGEN(PROJECT-NAME, [DOXYFILE-PATH], [OUTPUT-DIR], ...) # DX_DOXYGEN_FEATURE(ON|OFF) # DX_DOT_FEATURE(ON|OFF) # DX_HTML_FEATURE(ON|OFF) # DX_CHM_FEATURE(ON|OFF) # DX_CHI_FEATURE(ON|OFF) # DX_MAN_FEATURE(ON|OFF) # DX_RTF_FEATURE(ON|OFF) # DX_XML_FEATURE(ON|OFF) # DX_PDF_FEATURE(ON|OFF) # DX_PS_FEATURE(ON|OFF) # # DESCRIPTION # # The DX_*_FEATURE macros control the default setting for the given # Doxygen feature. Supported features are 'DOXYGEN' itself, 'DOT' for # generating graphics, 'HTML' for plain HTML, 'CHM' for compressed HTML # help (for MS users), 'CHI' for generating a separate .chi file by the # .chm file, and 'MAN', 'RTF', 'XML', 'PDF' and 'PS' for the appropriate # output formats. The environment variable DOXYGEN_PAPER_SIZE may be # specified to override the default 'a4wide' paper size. # # By default, HTML, PDF and PS documentation is generated as this seems to # be the most popular and portable combination. MAN pages created by # Doxygen are usually problematic, though by picking an appropriate subset # and doing some massaging they might be better than nothing. CHM and RTF # are specific for MS (note that you can't generate both HTML and CHM at # the same time). The XML is rather useless unless you apply specialized # post-processing to it. # # The macros mainly control the default state of the feature. The use can # override the default by specifying --enable or --disable. The macros # ensure that contradictory flags are not given (e.g., # --enable-doxygen-html and --enable-doxygen-chm, # --enable-doxygen-anything with --disable-doxygen, etc.) Finally, each # feature will be automatically disabled (with a warning) if the required # programs are missing. # # Once all the feature defaults have been specified, call DX_INIT_DOXYGEN # with the following parameters: a one-word name for the project for use # as a filename base etc., an optional configuration file name (the # default is '$(srcdir)/Doxyfile', the same as Doxygen's default), and an # optional output directory name (the default is 'doxygen-doc'). To run # doxygen multiple times for different configuration files and output # directories provide more parameters: the second, forth, sixth, etc # parameter are configuration file names and the third, fifth, seventh, # etc parameter are output directories. No checking is done to catch # duplicates. # # Automake Support # # The DX_RULES substitution can be used to add all needed rules to the # Makefile. Note that this is a substitution without being a variable: # only the @DX_RULES@ syntax will work. # # The provided targets are: # # doxygen-doc: Generate all doxygen documentation. # # doxygen-run: Run doxygen, which will generate some of the # documentation (HTML, CHM, CHI, MAN, RTF, XML) # but will not do the post processing required # for the rest of it (PS, PDF). # # doxygen-ps: Generate doxygen PostScript documentation. # # doxygen-pdf: Generate doxygen PDF documentation. # # Note that by default these are not integrated into the automake targets. # If doxygen is used to generate man pages, you can achieve this # integration by setting man3_MANS to the list of man pages generated and # then adding the dependency: # # $(man3_MANS): doxygen-doc # # This will cause make to run doxygen and generate all the documentation. # # The following variable is intended for use in Makefile.am: # # DX_CLEANFILES = everything to clean. # # Then add this variable to MOSTLYCLEANFILES. # # LICENSE # # Copyright (c) 2009 Oren Ben-Kiki # Copyright (c) 2015 Olaf Mandel # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 24 ## ----------## ## Defaults. ## ## ----------## DX_ENV="" AC_DEFUN([DX_FEATURE_doc], ON) AC_DEFUN([DX_FEATURE_dot], OFF) AC_DEFUN([DX_FEATURE_man], OFF) AC_DEFUN([DX_FEATURE_html], ON) AC_DEFUN([DX_FEATURE_chm], OFF) AC_DEFUN([DX_FEATURE_chi], OFF) AC_DEFUN([DX_FEATURE_rtf], OFF) AC_DEFUN([DX_FEATURE_xml], OFF) AC_DEFUN([DX_FEATURE_pdf], ON) AC_DEFUN([DX_FEATURE_ps], ON) ## --------------- ## ## Private macros. ## ## --------------- ## # DX_ENV_APPEND(VARIABLE, VALUE) # ------------------------------ # Append VARIABLE="VALUE" to DX_ENV for invoking doxygen and add it # as a substitution (but not a Makefile variable). The substitution # is skipped if the variable name is VERSION. AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])dnl m4_if([$1], [VERSION], [], [AC_SUBST([$1], [$2])dnl AM_SUBST_NOTMAKE([$1])])dnl ]) # DX_DIRNAME_EXPR # --------------- # Expand into a shell expression prints the directory part of a path. AC_DEFUN([DX_DIRNAME_EXPR], [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']]) # DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF) # ------------------------------------- # Expands according to the M4 (static) status of the feature. AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])]) # DX_REQUIRE_PROG(VARIABLE, PROGRAM) # ---------------------------------- # Require the specified program to be found for the DX_CURRENT_FEATURE to work. AC_DEFUN([DX_REQUIRE_PROG], [ AC_PATH_TOOL([$1], [$2]) if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION]) AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0) fi ]) # DX_TEST_FEATURE(FEATURE) # ------------------------ # Expand to a shell expression testing whether the feature is active. AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1]) # DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE) # ------------------------------------------------- # Verify that a required features has the right state before trying to turn on # the DX_CURRENT_FEATURE. AC_DEFUN([DX_CHECK_DEPEND], [ test "$DX_FLAG_$1" = "$2" \ || AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1, requires, contradicts) doxygen-$1]) ]) # DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE) # ---------------------------------------------------------- # Turn off the DX_CURRENT_FEATURE if the required feature is off. AC_DEFUN([DX_CLEAR_DEPEND], [ test "$DX_FLAG_$1" = "$2" || AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0) ]) # DX_FEATURE_ARG(FEATURE, DESCRIPTION, # CHECK_DEPEND, CLEAR_DEPEND, # REQUIRE, DO-IF-ON, DO-IF-OFF) # -------------------------------------------- # Parse the command-line option controlling a feature. CHECK_DEPEND is called # if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND), # otherwise CLEAR_DEPEND is called to turn off the default state if a required # feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional # requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and # DO-IF-ON or DO-IF-OFF are called according to the final state of the feature. AC_DEFUN([DX_ARG_ABLE], [ AC_DEFUN([DX_CURRENT_FEATURE], [$1]) AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2]) AC_ARG_ENABLE(doxygen-$1, [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1], [--enable-doxygen-$1]), DX_IF_FEATURE([$1], [don't $2], [$2]))], [ case "$enableval" in #( y|Y|yes|Yes|YES) AC_SUBST([DX_FLAG_$1], 1) $3 ;; #( n|N|no|No|NO) AC_SUBST([DX_FLAG_$1], 0) ;; #( *) AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1]) ;; esac ], [ AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)]) $4 ]) if DX_TEST_FEATURE([$1]); then $5 : fi if DX_TEST_FEATURE([$1]); then $6 : else $7 : fi ]) ## -------------- ## ## Public macros. ## ## -------------- ## # DX_XXX_FEATURE(DEFAULT_STATE) # ----------------------------- AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])]) AC_DEFUN([DX_DOT_FEATURE], [AC_DEFUN([DX_FEATURE_dot], [$1])]) AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])]) AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])]) AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])]) AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])]) AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])]) AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])]) AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])]) # DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR], ...) # -------------------------------------------------------------- # PROJECT also serves as the base name for the documentation files. # The default CONFIG-FILE is "$(srcdir)/Doxyfile" and OUTPUT-DOC-DIR is # "doxygen-doc". # More arguments are interpreted as interleaved CONFIG-FILE and # OUTPUT-DOC-DIR values. AC_DEFUN([DX_INIT_DOXYGEN], [ # Files: AC_SUBST([DX_PROJECT], [$1]) AC_SUBST([DX_CONFIG], ['ifelse([$2], [], [$(srcdir)/Doxyfile], [$2])']) AC_SUBST([DX_DOCDIR], ['ifelse([$3], [], [doxygen-doc], [$3])']) m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 4, m4_count($@), 2, [AC_SUBST([DX_CONFIG]m4_eval(DX_i[/2]), 'm4_default_nblank_quoted(m4_argn(DX_i, $@), [$(srcdir)/Doxyfile])')])])dnl m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 5, m4_count($@,), 2, [AC_SUBST([DX_DOCDIR]m4_eval([(]DX_i[-1)/2]), 'm4_default_nblank_quoted(m4_argn(DX_i, $@), [doxygen-doc])')])])dnl m4_define([DX_loop], m4_dquote(m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 4, m4_count($@), 2, [, m4_eval(DX_i[/2])])], [])))dnl # Environment variables used inside doxygen.cfg: DX_ENV_APPEND(SRCDIR, $srcdir) DX_ENV_APPEND(PROJECT, $DX_PROJECT) DX_ENV_APPEND(VERSION, $PACKAGE_VERSION) # Doxygen itself: DX_ARG_ABLE(doc, [generate any doxygen documentation], [], [], [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen) DX_REQUIRE_PROG([DX_PERL], perl)], [DX_ENV_APPEND(PERL_PATH, $DX_PERL)]) # Dot for graphics: DX_ARG_ABLE(dot, [generate graphics for doxygen documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [DX_REQUIRE_PROG([DX_DOT], dot)], [DX_ENV_APPEND(HAVE_DOT, YES) DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])], [DX_ENV_APPEND(HAVE_DOT, NO)]) # Man pages generation: DX_ARG_ABLE(man, [generate doxygen manual pages], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [], [DX_ENV_APPEND(GENERATE_MAN, YES)], [DX_ENV_APPEND(GENERATE_MAN, NO)]) # RTF file generation: DX_ARG_ABLE(rtf, [generate doxygen RTF documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [], [DX_ENV_APPEND(GENERATE_RTF, YES)], [DX_ENV_APPEND(GENERATE_RTF, NO)]) # XML file generation: DX_ARG_ABLE(xml, [generate doxygen XML documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [], [DX_ENV_APPEND(GENERATE_XML, YES)], [DX_ENV_APPEND(GENERATE_XML, NO)]) # (Compressed) HTML help generation: DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [DX_REQUIRE_PROG([DX_HHC], hhc)], [DX_ENV_APPEND(HHC_PATH, $DX_HHC) DX_ENV_APPEND(GENERATE_HTML, YES) DX_ENV_APPEND(GENERATE_HTMLHELP, YES)], [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)]) # Separate CHI file generation. DX_ARG_ABLE(chi, [generate doxygen separate compressed HTML help index file], [DX_CHECK_DEPEND(chm, 1)], [DX_CLEAR_DEPEND(chm, 1)], [], [DX_ENV_APPEND(GENERATE_CHI, YES)], [DX_ENV_APPEND(GENERATE_CHI, NO)]) # Plain HTML pages generation: DX_ARG_ABLE(html, [generate doxygen plain HTML documentation], [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)], [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)], [], [DX_ENV_APPEND(GENERATE_HTML, YES)], [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)]) # PostScript file generation: DX_ARG_ABLE(ps, [generate doxygen PostScript documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [DX_REQUIRE_PROG([DX_LATEX], latex) DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) DX_REQUIRE_PROG([DX_DVIPS], dvips) DX_REQUIRE_PROG([DX_EGREP], egrep)]) # PDF file generation: DX_ARG_ABLE(pdf, [generate doxygen PDF documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex) DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) DX_REQUIRE_PROG([DX_EGREP], egrep)]) # LaTeX generation for PS and/or PDF: if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then DX_ENV_APPEND(GENERATE_LATEX, YES) else DX_ENV_APPEND(GENERATE_LATEX, NO) fi # Paper size for PS and/or PDF: AC_ARG_VAR(DOXYGEN_PAPER_SIZE, [a4wide (default), a4, letter, legal or executive]) case "$DOXYGEN_PAPER_SIZE" in #( "") AC_SUBST(DOXYGEN_PAPER_SIZE, "") ;; #( a4wide|a4|letter|legal|executive) DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE) ;; #( *) AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE']) ;; esac # Rules: AS_IF([[test $DX_FLAG_html -eq 1]], [[DX_SNIPPET_html="## ------------------------------- ## ## Rules specific for HTML output. ## ## ------------------------------- ## DX_CLEAN_HTML = \$(DX_DOCDIR)/html]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/html]])[ "]], [[DX_SNIPPET_html=""]]) AS_IF([[test $DX_FLAG_chi -eq 1]], [[DX_SNIPPET_chi=" DX_CLEAN_CHI = \$(DX_DOCDIR)/\$(PACKAGE).chi]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).chi]])["]], [[DX_SNIPPET_chi=""]]) AS_IF([[test $DX_FLAG_chm -eq 1]], [[DX_SNIPPET_chm="## ------------------------------ ## ## Rules specific for CHM output. ## ## ------------------------------ ## DX_CLEAN_CHM = \$(DX_DOCDIR)/chm]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/chm]])[\ ${DX_SNIPPET_chi} "]], [[DX_SNIPPET_chm=""]]) AS_IF([[test $DX_FLAG_man -eq 1]], [[DX_SNIPPET_man="## ------------------------------ ## ## Rules specific for MAN output. ## ## ------------------------------ ## DX_CLEAN_MAN = \$(DX_DOCDIR)/man]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/man]])[ "]], [[DX_SNIPPET_man=""]]) AS_IF([[test $DX_FLAG_rtf -eq 1]], [[DX_SNIPPET_rtf="## ------------------------------ ## ## Rules specific for RTF output. ## ## ------------------------------ ## DX_CLEAN_RTF = \$(DX_DOCDIR)/rtf]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/rtf]])[ "]], [[DX_SNIPPET_rtf=""]]) AS_IF([[test $DX_FLAG_xml -eq 1]], [[DX_SNIPPET_xml="## ------------------------------ ## ## Rules specific for XML output. ## ## ------------------------------ ## DX_CLEAN_XML = \$(DX_DOCDIR)/xml]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/xml]])[ "]], [[DX_SNIPPET_xml=""]]) AS_IF([[test $DX_FLAG_ps -eq 1]], [[DX_SNIPPET_ps="## ----------------------------- ## ## Rules specific for PS output. ## ## ----------------------------- ## DX_CLEAN_PS = \$(DX_DOCDIR)/\$(PACKAGE).ps]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps]])[ DX_PS_GOAL = doxygen-ps doxygen-ps: \$(DX_CLEAN_PS) ]m4_foreach([DX_i], [DX_loop], [[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\ \$(DX_LATEX) refman.tex; \\ \$(DX_MAKEINDEX) refman.idx; \\ \$(DX_LATEX) refman.tex; \\ countdown=5; \\ while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\ refman.log > /dev/null 2>&1 \\ && test \$\$countdown -gt 0; do \\ \$(DX_LATEX) refman.tex; \\ countdown=\`expr \$\$countdown - 1\`; \\ done; \\ \$(DX_DVIPS) -o ../\$(PACKAGE).ps refman.dvi ]])["]], [[DX_SNIPPET_ps=""]]) AS_IF([[test $DX_FLAG_pdf -eq 1]], [[DX_SNIPPET_pdf="## ------------------------------ ## ## Rules specific for PDF output. ## ## ------------------------------ ## DX_CLEAN_PDF = \$(DX_DOCDIR)/\$(PACKAGE).pdf]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf]])[ DX_PDF_GOAL = doxygen-pdf doxygen-pdf: \$(DX_CLEAN_PDF) ]m4_foreach([DX_i], [DX_loop], [[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\ \$(DX_PDFLATEX) refman.tex; \\ \$(DX_MAKEINDEX) refman.idx; \\ \$(DX_PDFLATEX) refman.tex; \\ countdown=5; \\ while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\ refman.log > /dev/null 2>&1 \\ && test \$\$countdown -gt 0; do \\ \$(DX_PDFLATEX) refman.tex; \\ countdown=\`expr \$\$countdown - 1\`; \\ done; \\ mv refman.pdf ../\$(PACKAGE).pdf ]])["]], [[DX_SNIPPET_pdf=""]]) AS_IF([[test $DX_FLAG_ps -eq 1 -o $DX_FLAG_pdf -eq 1]], [[DX_SNIPPET_latex="## ------------------------------------------------- ## ## Rules specific for LaTeX (shared for PS and PDF). ## ## ------------------------------------------------- ## DX_V_LATEX = \$(_DX_v_LATEX_\$(V)) _DX_v_LATEX_ = \$(_DX_v_LATEX_\$(AM_DEFAULT_VERBOSITY)) _DX_v_LATEX_0 = @echo \" LATEX \" \$][@; DX_CLEAN_LATEX = \$(DX_DOCDIR)/latex]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/latex]])[ "]], [[DX_SNIPPET_latex=""]]) AS_IF([[test $DX_FLAG_doc -eq 1]], [[DX_SNIPPET_doc="## --------------------------------- ## ## Format-independent Doxygen rules. ## ## --------------------------------- ## ${DX_SNIPPET_html}\ ${DX_SNIPPET_chm}\ ${DX_SNIPPET_man}\ ${DX_SNIPPET_rtf}\ ${DX_SNIPPET_xml}\ ${DX_SNIPPET_ps}\ ${DX_SNIPPET_pdf}\ ${DX_SNIPPET_latex}\ DX_V_DXGEN = \$(_DX_v_DXGEN_\$(V)) _DX_v_DXGEN_ = \$(_DX_v_DXGEN_\$(AM_DEFAULT_VERBOSITY)) _DX_v_DXGEN_0 = @echo \" DXGEN \" \$<; .PHONY: doxygen-run doxygen-doc \$(DX_PS_GOAL) \$(DX_PDF_GOAL) .INTERMEDIATE: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL) doxygen-run:]m4_foreach([DX_i], [DX_loop], [[ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag]])[ doxygen-doc: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL) ]m4_foreach([DX_i], [DX_loop], [[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag: \$(DX_CONFIG]DX_i[) \$(pkginclude_HEADERS) \$(A""M_V_at)rm -rf \$(DX_DOCDIR]DX_i[) \$(DX_V_DXGEN)\$(DX_ENV) DOCDIR=\$(DX_DOCDIR]DX_i[) \$(DX_DOXYGEN) \$(DX_CONFIG]DX_i[) \$(A""M_V_at)echo Timestamp >\$][@ ]])dnl [DX_CLEANFILES = \\] m4_foreach([DX_i], [DX_loop], [[ \$(DX_DOCDIR]DX_i[)/doxygen_sqlite3.db \\ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \\ ]])dnl [ -r \\ \$(DX_CLEAN_HTML) \\ \$(DX_CLEAN_CHM) \\ \$(DX_CLEAN_CHI) \\ \$(DX_CLEAN_MAN) \\ \$(DX_CLEAN_RTF) \\ \$(DX_CLEAN_XML) \\ \$(DX_CLEAN_PS) \\ \$(DX_CLEAN_PDF) \\ \$(DX_CLEAN_LATEX)"]], [[DX_SNIPPET_doc=""]]) AC_SUBST([DX_RULES], ["${DX_SNIPPET_doc}"])dnl AM_SUBST_NOTMAKE([DX_RULES]) #For debugging: #echo DX_FLAG_doc=$DX_FLAG_doc #echo DX_FLAG_dot=$DX_FLAG_dot #echo DX_FLAG_man=$DX_FLAG_man #echo DX_FLAG_html=$DX_FLAG_html #echo DX_FLAG_chm=$DX_FLAG_chm #echo DX_FLAG_chi=$DX_FLAG_chi #echo DX_FLAG_rtf=$DX_FLAG_rtf #echo DX_FLAG_xml=$DX_FLAG_xml #echo DX_FLAG_pdf=$DX_FLAG_pdf #echo DX_FLAG_ps=$DX_FLAG_ps #echo DX_ENV=$DX_ENV ]) libopenmpt-0.8.1+release.autotools/m4/libtool.m40000644000175000017500000113165215023302302016503 00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996-2001, 2003-2019, 2021-2022 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 2014 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ]) # serial 59 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_PREPARE_CC_BASENAME # ----------------------- m4_defun([_LT_PREPARE_CC_BASENAME], [ # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } ])# _LT_PREPARE_CC_BASENAME # _LT_CC_BASENAME(CC) # ------------------- # It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, # but that macro is also expanded into generated libtool script, which # arranges for $SED and $ECHO to be set by different means. m4_defun([_LT_CC_BASENAME], [m4_require([_LT_PREPARE_CC_BASENAME])dnl AC_REQUIRE([_LT_DECL_SED])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl func_cc_basename $1 cc_basename=$func_cc_basename_result ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_DECL_FILECMD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl m4_require([_LT_CMD_TRUNCATE])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC and # ICC, which need '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from 'configure', and 'config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # 'config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain=$ac_aux_dir/ltmain.sh ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the 'libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to 'config.status' so that its # declaration there will have the same value as in 'configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags='_LT_TAGS'dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into 'config.status', and then the shell code to quote escape them in # for loops in 'config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # '#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test 0 = "$lt_write_fail" && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ '$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test 0 != $[#] do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try '$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try '$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test yes = "$silent" && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 _LT_COPYING _LT_LIBTOOL_TAGS # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE _LT_PREPARE_MUNGE_PATH_LIST _LT_PREPARE_CC_BASENAME # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? $SED '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS=$save_LDFLAGS ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR $AR_FLAGS libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR $AR_FLAGS libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) case $MACOSX_DEPLOYMENT_TARGET,$host in 10.[[012]],*|,*powerpc*-darwin[[5-8]]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; *) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test yes = "$lt_cv_ld_force_load"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" _LT_TAGVAR(module_expsym_cmds, $1)="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" m4_if([$1], [CXX], [ if test yes != "$lt_cv_apple_cc_single_mod"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script that will find a shell with a builtin # printf (that we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case $ECHO in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [m4_require([_LT_DECL_SED])dnl AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], [Search for dependent libraries within DIR (or the compiler's sysroot if not specified).])], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([$with_sysroot]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and where our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `$FILECMD conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test yes = "$lt_cv_prog_gnu_ld"; then case `$FILECMD conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `$FILECMD conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then emul=elf case `$FILECMD conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `$FILECMD conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `$FILECMD conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `$FILECMD conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `$FILECMD conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `$FILECMD conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} _LT_DECL([], [AR], [1], [The archiver]) # Use ARFLAGS variable as AR's operation code to sync the variable naming with # Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have # higher priority because thats what people were doing historically (setting # ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS # variable obsoleted/removed. test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} lt_ar_flags=$AR_FLAGS _LT_DECL([], [lt_ar_flags], [0], [Flags to create an archive (by configure)]) # Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override # by AR_FLAGS because that was never working and AR_FLAGS is about to die. _LT_DECL([], [AR_FLAGS], [\@S|@{ARFLAGS-"\@S|@lt_ar_flags"}], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test yes = "[$]$2"; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS ]) if test yes = "[$]$2"; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n "$lt_cv_sys_max_cmd_len"; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes = "$cross_compiling"; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen=shl_load], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen=dlopen], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) ]) ]) ]) ]) ]) ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links=nottested if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test no = "$hard_links"; then AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", [Define to the sub-directory where libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then # We can hardcode non-existent directories. if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -z "$STRIP"; then AC_MSG_RESULT([no]) else if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else case $host_os in darwin*) # FIXME - insert some real tests, host_os isn't really good enough striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) ;; freebsd*) if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_PREPARE_MUNGE_PATH_LIST # --------------------------- # Make sure func_munge_path_list() is defined correctly. m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], [[# func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ]])# _LT_PREPARE_PATH_LIST # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown AC_ARG_VAR([LT_SYS_LIBRARY_PATH], [User-defined run-time library search path.]) case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a[(]lib.so.V[)]' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl* | *,icl*) # Native MSVC or ICC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC and ICC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly* | midnightbsd*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], [Detected run-time system search path for libraries]) _LT_DECL([], [configure_time_lt_sys_library_path], [2], [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program that can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$1"; then lt_cv_path_MAGIC_CMD=$ac_dir/"$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac]) MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program that can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test no = "$withval" || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], [if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi]) rm -f conftest.i conftest2.i conftest.out]) ])# _LT_PATH_DD # _LT_CMD_TRUNCATE # ---------------- # find command to truncate a binary pipe m4_defun([_LT_CMD_TRUNCATE], [m4_require([_LT_PATH_DD]) AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], [printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) _LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], [Command to truncate a binary pipe]) ])# _LT_CMD_TRUNCATE # _LT_CHECK_MAGIC_METHOD # ---------------------- # how to check for library dependencies # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_MAGIC_METHOD], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) AC_CACHE_CHECK([how to recognize dependent libraries], lt_cv_deplibs_check_method, [lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure # whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[[4-9]]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[[45]]*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='$FILECMD -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly* | midnightbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=$FILECMD lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=$FILECMD case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=$FILECMD lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_nm if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi]) if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # _LT_DLL_DEF_P([FILE]) # --------------------- # True iff FILE is a Windows DLL '.def' file. # Keep in sync with func_dll_def_p in the libtool script AC_DEFUN([_LT_DLL_DEF_P], [dnl test DEF = "`$SED -n dnl -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl -e q dnl Only consider the first "real" line $1`" dnl ])# _LT_DLL_DEF_P # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM=-lm) ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test yes = "$GCC"; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++ or ICC, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], [Transform the output of nm into a list of symbols to manually relocate]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([nm_interface], [lt_cv_nm_interface], [1], [The name lister interface]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly* | midnightbsd*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' if test ia64 != "$host_cpu"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64, which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | $SED 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test yes = "$GCC"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | $SED 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl* | icl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ' (' and ')$', so one must not match beginning or # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', # as well as any symbol that contains 'd'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/([[^)]]\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | $SED 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl* | icl*) # Native MSVC or ICC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC and ICC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly* | midnightbsd*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS=$save_LDFLAGS]) if test yes = "$lt_cv_irix_exported_symbol"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi _LT_TAGVAR(link_all_deplibs, $1)=no else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(ld_shlibs, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; esac ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' ;; osf3*) if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test yes = "$GCC"; then wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test yes,yes = "$GCC,$enable_shared"; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting $shlibpath_var if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC=$CC AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report what library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC=$lt_save_CC ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test no != "$CXX" && ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || (test g++ != "$CXX"))); then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_caught_CXX_error"; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test yes = "$GXX"; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test yes = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='$wl' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GXX"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag=$shared_flag' $wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. # The "-G" linker flag allows undefined symbols. _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl* | ,icl* | no,icl*) # Native MSVC or ICC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ func_to_tool_file "$lt_outputfile"~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly* | midnightbsd*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | $SED 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(GCC, $1)=$GXX _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test yes != "$_lt_caught_CXX_error" AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case @S|@2 in .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $prev$p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test x-L = "$p" || test x-R = "$p"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test no = "$pre_test_object_deps_done"; then case $prev in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)=$prev$p else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test no = "$pre_test_object_deps_done"; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)=$p else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)=$p else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test no = "$F77"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_F77"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$G77 _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_F77" AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test no = "$FC"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_FC"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_FC" AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code=$lt_simple_compile_test_code # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_FILECMD # ---------------- # Check for a file(cmd) program that can be used to detect file type and magic m4_defun([_LT_DECL_FILECMD], [AC_CHECK_TOOL([FILECMD], [file], [:]) _LT_DECL([], [FILECMD], [1], [A file(cmd) program that detects file types]) ])# _LD_DECL_FILECMD # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f "$lt_ac_sed" && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test 10 -lt "$lt_ac_count" && break lt_ac_count=`expr $lt_ac_count + 1` if test "$lt_ac_count" -gt "$lt_ac_max"; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine what file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS libopenmpt-0.8.1+release.autotools/m4/ax_cxx_compile_stdcxx.m40000644000175000017500000005501714704420722021451 00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html # =========================================================================== # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the specified # version of the C++ standard. If necessary, add switches to CXX and # CXXCPP to enable support. VERSION may be '11', '14', '17', '20', or # '23' for the respective C++ standard version. # # The second argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for no added switch, and then for an extended mode. # # The third argument, if specified 'mandatory' or if left unspecified, # indicates that baseline support for the specified C++ standard is # required and that the macro should error out if no mode with that # support is found. If specified 'optional', then configuration proceeds # regardless, after defining HAVE_CXX${VERSION} if and only if a # supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov # Copyright (c) 2015 Paul Norman # Copyright (c) 2015 Moritz Klammler # Copyright (c) 2016, 2018 Krzesimir Nowak # Copyright (c) 2019 Enji Cooper # Copyright (c) 2020 Jason Merrill # Copyright (c) 2021, 2024 JÜrn Heusipp # Copyright (c) 2015, 2022, 2023, 2024 Olly Betts # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 25 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], [$1], [14], [ax_cxx_compile_alternatives="14 1y"], [$1], [17], [ax_cxx_compile_alternatives="17 1z"], [$1], [20], [ax_cxx_compile_alternatives="20"], [$1], [23], [ax_cxx_compile_alternatives="23"], [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$2], [], [], [$2], [ext], [], [$2], [noext], [], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], [$3], [optional], [ax_cxx_compile_cxx$1_required=false], [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) AC_LANG_PUSH([C++])dnl ac_success=no m4_if([$2], [], [dnl AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, ax_cv_cxx_compile_cxx$1, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [ax_cv_cxx_compile_cxx$1=yes], [ax_cv_cxx_compile_cxx$1=no])]) if test x$ax_cv_cxx_compile_cxx$1 = xyes; then ac_success=yes fi]) m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do switch="-std=gnu++${alternative}" cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done fi]) m4_if([$2], [ext], [], [dnl if test x$ac_success = xno; then dnl HP's aCC needs +std=c++11 according to: dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf dnl Cray's crayCC needs "-h std=c++11" dnl MSVC needs -std:c++NN for C++17 and later (default is C++14) for alternative in ${ax_cxx_compile_alternatives}; do for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do if test x"$switch" = xMSVC; then dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide dnl with -std=c++17. We suffix the cache variable name with _MSVC to dnl avoid this. switch=-std:c++${alternative} cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC]) else cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) fi AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done if test x$ac_success = xyes; then break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx$1_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) fi fi if test x$ac_success = xno; then HAVE_CXX$1=0 AC_MSG_NOTICE([No compiler with C++$1 support was found]) else HAVE_CXX$1=1 AC_DEFINE(HAVE_CXX$1,1, [define if the compiler supports basic C++$1 syntax]) fi AC_SUBST(HAVE_CXX$1) ]) dnl Test body for checking C++11 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11] ) dnl Test body for checking C++14 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14] ) dnl Test body for checking C++17 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17] ) dnl Test body for checking C++20 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20], [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 _AX_CXX_COMPILE_STDCXX_testbody_new_in_20] ) dnl Test body for checking C++23 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_23], [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 _AX_CXX_COMPILE_STDCXX_testbody_new_in_20 _AX_CXX_COMPILE_STDCXX_testbody_new_in_23] ) dnl Tests for new features in C++11 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ // If the compiler admits that it is not ready for C++11, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" // MSVC always sets __cplusplus to 199711L in older versions; newer versions // only set it correctly if /Zc:__cplusplus is specified as well as a // /std:c++NN switch: // // https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ // // The value __cplusplus ought to have is available in _MSVC_LANG since // Visual Studio 2015 Update 3: // // https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros // // This was also the first MSVC version to support C++14 so we can't use the // value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having // C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later. #elif __cplusplus < 201103L && !defined _MSC_VER #error "This is not a C++11 compiler" #else namespace cxx11 { namespace test_static_assert { template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; } namespace test_final_override { struct Base { virtual ~Base() {} virtual void f() {} }; struct Derived : public Base { virtual ~Derived() override {} virtual void f() override {} }; } namespace test_double_right_angle_brackets { template < typename T > struct check {}; typedef check single_type; typedef check> double_type; typedef check>> triple_type; typedef check>>> quadruple_type; } namespace test_decltype { int f() { int a = 1; decltype(a) b = 2; return a + b; } } namespace test_type_deduction { template < typename T1, typename T2 > struct is_same { static const bool value = false; }; template < typename T > struct is_same { static const bool value = true; }; template < typename T1, typename T2 > auto add(T1 a1, T2 a2) -> decltype(a1 + a2) { return a1 + a2; } int test(const int c, volatile int v) { static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == false, ""); auto ac = c; auto av = v; auto sumi = ac + av + 'x'; auto sumf = ac + av + 1.0; static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == true, ""); return (sumf > 0.0) ? sumi : add(c, v); } } namespace test_noexcept { int f() { return 0; } int g() noexcept { return 0; } static_assert(noexcept(f()) == false, ""); static_assert(noexcept(g()) == true, ""); } namespace test_constexpr { template < typename CharT > unsigned long constexpr strlen_c_r(const CharT *const s, const unsigned long acc) noexcept { return *s ? strlen_c_r(s + 1, acc + 1) : acc; } template < typename CharT > unsigned long constexpr strlen_c(const CharT *const s) noexcept { return strlen_c_r(s, 0UL); } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("1") == 1UL, ""); static_assert(strlen_c("example") == 7UL, ""); static_assert(strlen_c("another\0example") == 7UL, ""); } namespace test_rvalue_references { template < int N > struct answer { static constexpr int value = N; }; answer<1> f(int&) { return answer<1>(); } answer<2> f(const int&) { return answer<2>(); } answer<3> f(int&&) { return answer<3>(); } void test() { int i = 0; const int c = 0; static_assert(decltype(f(i))::value == 1, ""); static_assert(decltype(f(c))::value == 2, ""); static_assert(decltype(f(0))::value == 3, ""); } } namespace test_uniform_initialization { struct test { static const int zero {}; static const int one {1}; }; static_assert(test::zero == 0, ""); static_assert(test::one == 1, ""); } namespace test_lambdas { void test1() { auto lambda1 = [](){}; auto lambda2 = lambda1; lambda1(); lambda2(); } int test2() { auto a = [](int i, int j){ return i + j; }(1, 2); auto b = []() -> int { return '0'; }(); auto c = [=](){ return a + b; }(); auto d = [&](){ return c; }(); auto e = [a, &b](int x) mutable { const auto identity = [](int y){ return y; }; for (auto i = 0; i < a; ++i) a += b--; return x + identity(a + b); }(0); return a + b + c + d + e; } int test3() { const auto nullary = [](){ return 0; }; const auto unary = [](int x){ return x; }; using nullary_t = decltype(nullary); using unary_t = decltype(unary); const auto higher1st = [](nullary_t f){ return f(); }; const auto higher2nd = [unary](nullary_t f1){ return [unary, f1](unary_t f2){ return f2(unary(f1())); }; }; return higher1st(nullary) + higher2nd(nullary)(unary); } } namespace test_variadic_templates { template struct sum; template struct sum { static constexpr auto value = N0 + sum::value; }; template <> struct sum<> { static constexpr auto value = 0; }; static_assert(sum<>::value == 0, ""); static_assert(sum<1>::value == 1, ""); static_assert(sum<23>::value == 23, ""); static_assert(sum<1, 2>::value == 3, ""); static_assert(sum<5, 5, 11>::value == 21, ""); static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); } // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function // because of this. namespace test_template_alias_sfinae { struct foo {}; template using member = typename T::member_type; template void func(...) {} template void func(member*) {} void test(); void test() { func(0); } } } // namespace cxx11 #endif // __cplusplus >= 201103L ]]) dnl Tests for new features in C++14 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ // If the compiler admits that it is not ready for C++14, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201402L && !defined _MSC_VER #error "This is not a C++14 compiler" #else namespace cxx14 { namespace test_polymorphic_lambdas { int test() { const auto lambda = [](auto&&... args){ const auto istiny = [](auto x){ return (sizeof(x) == 1UL) ? 1 : 0; }; const int aretiny[] = { istiny(args)... }; return aretiny[0]; }; return lambda(1, 1L, 1.0f, '1'); } } namespace test_binary_literals { constexpr auto ivii = 0b0000000000101010; static_assert(ivii == 42, "wrong value"); } namespace test_generalized_constexpr { template < typename CharT > constexpr unsigned long strlen_c(const CharT *const s) noexcept { auto length = 0UL; for (auto p = s; *p; ++p) ++length; return length; } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("x") == 1UL, ""); static_assert(strlen_c("test") == 4UL, ""); static_assert(strlen_c("another\0test") == 7UL, ""); } namespace test_lambda_init_capture { int test() { auto x = 0; const auto lambda1 = [a = x](int b){ return a + b; }; const auto lambda2 = [a = lambda1(x)](){ return a; }; return lambda2(); } } namespace test_digit_separators { constexpr auto ten_million = 100'000'000; static_assert(ten_million == 100000000, ""); } namespace test_return_type_deduction { auto f(int& x) { return x; } decltype(auto) g(int& x) { return x; } template < typename T1, typename T2 > struct is_same { static constexpr auto value = false; }; template < typename T > struct is_same { static constexpr auto value = true; }; int test() { auto x = 0; static_assert(is_same::value, ""); static_assert(is_same::value, ""); return x; } } } // namespace cxx14 #endif // __cplusplus >= 201402L ]]) dnl Tests for new features in C++17 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ // If the compiler admits that it is not ready for C++17, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L #error "This is not a C++17 compiler" #else #include #include #include namespace cxx17 { namespace test_constexpr_lambdas { constexpr int foo = [](){return 42;}(); } namespace test::nested_namespace::definitions { } namespace test_fold_expression { template int multiply(Args... args) { return (args * ... * 1); } template bool all(Args... args) { return (args && ...); } } namespace test_extended_static_assert { static_assert (true); } namespace test_auto_brace_init_list { auto foo = {5}; auto bar {5}; static_assert(std::is_same, decltype(foo)>::value); static_assert(std::is_same::value); } namespace test_typename_in_template_template_parameter { template typename X> struct D; } namespace test_fallthrough_nodiscard_maybe_unused_attributes { int f1() { return 42; } [[nodiscard]] int f2() { [[maybe_unused]] auto unused = f1(); switch (f1()) { case 17: f1(); [[fallthrough]]; case 42: f1(); } return f1(); } } namespace test_extended_aggregate_initialization { struct base1 { int b1, b2 = 42; }; struct base2 { base2() { b3 = 42; } int b3; }; struct derived : base1, base2 { int d; }; derived d1 {{1, 2}, {}, 4}; // full initialization derived d2 {{}, {}, 4}; // value-initialized bases } namespace test_general_range_based_for_loop { struct iter { int i; int& operator* () { return i; } const int& operator* () const { return i; } iter& operator++() { ++i; return *this; } }; struct sentinel { int i; }; bool operator== (const iter& i, const sentinel& s) { return i.i == s.i; } bool operator!= (const iter& i, const sentinel& s) { return !(i == s); } struct range { iter begin() const { return {0}; } sentinel end() const { return {5}; } }; void f() { range r {}; for (auto i : r) { [[maybe_unused]] auto v = i; } } } namespace test_lambda_capture_asterisk_this_by_value { struct t { int i; int foo() { return [*this]() { return i; }(); } }; } namespace test_enum_class_construction { enum class byte : unsigned char {}; byte foo {42}; } namespace test_constexpr_if { template int f () { if constexpr(cond) { return 13; } else { return 42; } } } namespace test_selection_statement_with_initializer { int f() { return 13; } int f2() { if (auto i = f(); i > 0) { return 3; } switch (auto i = f(); i + 4) { case 17: return 2; default: return 1; } } } namespace test_template_argument_deduction_for_class_templates { template struct pair { pair (T1 p1, T2 p2) : m1 {p1}, m2 {p2} {} T1 m1; T2 m2; }; void f() { [[maybe_unused]] auto p = pair{13, 42u}; } } namespace test_non_type_auto_template_parameters { template struct B {}; B<5> b1; B<'a'> b2; } namespace test_structured_bindings { int arr[2] = { 1, 2 }; std::pair pr = { 1, 2 }; auto f1() -> int(&)[2] { return arr; } auto f2() -> std::pair& { return pr; } struct S { int x1 : 2; volatile double y1; }; S f3() { return {}; } auto [ x1, y1 ] = f1(); auto& [ xr1, yr1 ] = f1(); auto [ x2, y2 ] = f2(); auto& [ xr2, yr2 ] = f2(); const auto [ x3, y3 ] = f3(); } namespace test_exception_spec_type_system { struct Good {}; struct Bad {}; void g1() noexcept; void g2(); template Bad f(T*, T*); template Good f(T1*, T2*); static_assert (std::is_same_v); } namespace test_inline_variables { template void f(T) {} template inline T g(T) { return T{}; } template<> inline void f<>(int) {} template<> int g<>(int) { return 5; } } } // namespace cxx17 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L ]]) dnl Tests for new features in C++20 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[ #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L #error "This is not a C++20 compiler" #else #include namespace cxx20 { // As C++20 supports feature test macros in the standard, there is no // immediate need to actually test for feature availability on the // Autoconf side. } // namespace cxx20 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L ]]) dnl Tests for new features in C++23 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_23], [[ #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L #error "This is not a C++23 compiler" #else #include namespace cxx23 { // As C++23 supports feature test macros in the standard, there is no // immediate need to actually test for feature availability on the // Autoconf side. } // namespace cxx23 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L ]]) libopenmpt-0.8.1+release.autotools/m4/ax_pthread.m40000644000175000017500000005403415023302302017153 00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is # needed for multi-threaded programs (defaults to the value of CC # respectively CXX otherwise). (This is necessary on e.g. AIX to use the # special cc_r/CC_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also to link with them as well. For example, you might link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threaded programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # CXX="$PTHREAD_CXX" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to # that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # Copyright (c) 2019 Marc Stevens # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 31 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PROG_SED]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then ax_pthread_save_CC="$CC" ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"]) CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) AC_MSG_RESULT([$ax_pthread_ok]) if test "x$ax_pthread_ok" = "xno"; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi CC="$ax_pthread_save_CC" CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items with a "," contain both # C compiler flags (before ",") and linker flags (after ","). Other items # starting with a "-" are C compiler flags, and remaining items are # library names, except for "none" which indicates that we try without # any flags at all, and "pthread-config" which is a program returning # the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 # (Note: HP C rejects this with "bad form for `-t' option") # -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads and # -D_REENTRANT too), HP C (must be checked before -lpthread, which # is present but should not be used directly; and before -mthreads, # because the compiler interprets this as "-mt" + "-hreads") # -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case $host_os in freebsd*) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) ax_pthread_flags="-kthread lthread $ax_pthread_flags" ;; hpux*) # From the cc(1) man page: "[-mt] Sets various -D flags to enable # multi-threading and also sets -lpthread." ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" ;; openedition*) # IBM z/OS requires a feature-test macro to be defined in order to # enable POSIX threads at all, so give the user a hint if this is # not set. (We don't define these ourselves, as they can affect # other portions of the system API in unpredictable ways.) AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], [ # if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) AX_PTHREAD_ZOS_MISSING # endif ], [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) ;; solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (N.B.: The stubs are missing # pthread_cleanup_push, or rather a function called by this macro, # so we could check for that, but who knows whether they'll stub # that too in a future libc.) So we'll check first for the # standard Solaris way of linking pthreads (-mt -lpthread). ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags" ;; esac # Are we compiling with Clang? AC_CACHE_CHECK([whether $CC is Clang], [ax_cv_PTHREAD_CLANG], [ax_cv_PTHREAD_CLANG=no # Note that Autoconf sets GCC=yes for Clang as well as GCC if test "x$GCC" = "xyes"; then AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ # if defined(__clang__) && defined(__llvm__) AX_PTHREAD_CC_IS_CLANG # endif ], [ax_cv_PTHREAD_CLANG=yes]) fi ]) ax_pthread_clang="$ax_cv_PTHREAD_CLANG" # GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) # Note that for GCC and Clang -pthread generally implies -lpthread, # except when -nostdlib is passed. # This is problematic using libtool to build C++ shared libraries with pthread: # [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460 # [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333 # [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555 # To solve this, first try -pthread together with -lpthread for GCC AS_IF([test "x$GCC" = "xyes"], [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"]) # Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first AS_IF([test "x$ax_pthread_clang" = "xyes"], [ax_pthread_flags="-pthread,-lpthread -pthread"]) # The presence of a feature test macro requesting re-entrant function # definitions is, on some systems, a strong hint that pthreads support is # correctly enabled case $host_os in darwin* | hpux* | linux* | osf* | solaris*) ax_pthread_check_macro="_REENTRANT" ;; aix*) ax_pthread_check_macro="_THREAD_SAFE" ;; *) ax_pthread_check_macro="--" ;; esac AS_IF([test "x$ax_pthread_check_macro" = "x--"], [ax_pthread_check_cond=0], [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) if test "x$ax_pthread_ok" = "xno"; then for ax_pthread_try_flag in $ax_pthread_flags; do case $ax_pthread_try_flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; *,*) PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"` PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"` AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) PTHREAD_CFLAGS="$ax_pthread_try_flag" ;; pthread-config) AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) PTHREAD_LIBS="-l$ax_pthread_try_flag" ;; esac ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include # if $ax_pthread_check_cond # error "$ax_pthread_check_macro must be defined" # endif static void *some_global = NULL; static void routine(void *a) { /* To avoid any unused-parameter or unused-but-set-parameter warning. */ some_global = a; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" AC_MSG_RESULT([$ax_pthread_ok]) AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Clang needs special handling, because older versions handle the -pthread # option in a rather... idiosyncratic way if test "x$ax_pthread_clang" = "xyes"; then # Clang takes -pthread; it has never supported any other flag # (Note 1: This will need to be revisited if a system that Clang # supports has POSIX threads in a separate library. This tends not # to be the way of modern systems, but it's conceivable.) # (Note 2: On some systems, notably Darwin, -pthread is not needed # to get POSIX threads support; the API is always present and # active. We could reasonably leave PTHREAD_CFLAGS empty. But # -pthread does define _REENTRANT, and while the Darwin headers # ignore this macro, third-party headers might not.) # However, older versions of Clang make a point of warning the user # that, in an invocation where only linking and no compilation is # taking place, the -pthread option has no effect ("argument unused # during compilation"). They expect -pthread to be passed in only # when source code is being compiled. # # Problem is, this is at odds with the way Automake and most other # C build frameworks function, which is that the same flags used in # compilation (CFLAGS) are also used in linking. Many systems # supported by AX_PTHREAD require exactly this for POSIX threads # support, and in fact it is often not straightforward to specify a # flag that is used only in the compilation phase and not in # linking. Such a scenario is extremely rare in practice. # # Even though use of the -pthread flag in linking would only print # a warning, this can be a nuisance for well-run software projects # that build with -Werror. So if the active version of Clang has # this misfeature, we search for an option to squash it. AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown # Create an alternate version of $ac_link that compiles and # links in two steps (.c -> .o, .o -> exe) instead of one # (.c -> exe), because the warning occurs only in the second # step ax_pthread_save_ac_link="$ac_link" ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"` ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" ax_pthread_save_CFLAGS="$CFLAGS" for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" ac_link="$ax_pthread_save_ac_link" AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], [ac_link="$ax_pthread_2step_ac_link" AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], [break]) ]) done ac_link="$ax_pthread_save_ac_link" CFLAGS="$ax_pthread_save_CFLAGS" AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" ]) case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in no | unknown) ;; *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; esac fi # $ax_pthread_clang = yes # Various other checks: if test "x$ax_pthread_ok" = "xyes"; then ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_CACHE_CHECK([for joinable pthread attribute], [ax_cv_PTHREAD_JOINABLE_ATTR], [ax_cv_PTHREAD_JOINABLE_ATTR=unknown for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $ax_pthread_attr; return attr /* ; */])], [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], []) done ]) AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ test "x$ax_pthread_joinable_attr_defined" != "xyes"], [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$ax_cv_PTHREAD_JOINABLE_ATTR], [Define to necessary symbol if this constant uses a non-standard name on your system.]) ax_pthread_joinable_attr_defined=yes ]) AC_CACHE_CHECK([whether more special flags are required for pthreads], [ax_cv_PTHREAD_SPECIAL_FLAGS], [ax_cv_PTHREAD_SPECIAL_FLAGS=no case $host_os in solaris*) ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" ;; esac ]) AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ test "x$ax_pthread_special_flags_added" != "xyes"], [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" ax_pthread_special_flags_added=yes]) AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], [ax_cv_PTHREAD_PRIO_INHERIT], [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT; return i;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ test "x$ax_pthread_prio_inherit_defined" != "xyes"], [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) ax_pthread_prio_inherit_defined=yes ]) CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" # More AIX lossage: compile with *_r variant if test "x$GCC" != "xyes"; then case $host_os in aix*) AS_CASE(["x/$CC"], [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], [#handle absolute path differently from PATH based program lookup AS_CASE(["x$CC"], [x/*], [ AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"]) AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])]) ], [ AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC]) AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])]) ] ) ]) ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" AC_SUBST([PTHREAD_LIBS]) AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) AC_SUBST([PTHREAD_CXX]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test "x$ax_pthread_ok" = "xyes"; then ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD libopenmpt-0.8.1+release.autotools/m4/ax_check_compile_flag.m40000644000175000017500000000407015023302302021275 00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 6 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS libopenmpt-0.8.1+release.autotools/m4/ax_cflags_warn_all.m40000644000175000017500000001351115023302302020635 00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_cflags_warn_all.html # =========================================================================== # # SYNOPSIS # # AX_CFLAGS_WARN_ALL [(shellvar[, default[, action-if-found[, action-if-not-found]]])] # AX_CXXFLAGS_WARN_ALL [(shellvar[, default[, action-if-found[, action-if-not-found]]])] # AX_FCFLAGS_WARN_ALL [(shellvar[, default[, action-if-found[, action-if-not-found]]])] # # DESCRIPTION # # Specify compiler options that enable most reasonable warnings. For the # GNU Compiler Collection (GCC), for example, it will be "-Wall". The # result is added to shellvar, one of CFLAGS, CXXFLAGS or FCFLAGS if the # first parameter is not specified. # # Each of these macros accepts the following optional arguments: # # - $1 - shellvar # shell variable to use (CFLAGS, CXXFLAGS or FCFLAGS if not # specified, depending on macro) # # - $2 - default # value to use for flags if compiler vendor cannot be determined (by # default, "") # # - $3 - action-if-found # action to take if the compiler vendor has been successfully # determined (by default, add the appropriate compiler flags to # shellvar) # # - $4 - action-if-not-found # action to take if the compiler vendor has not been determined or # is unknown (by default, add the default flags, or "" if not # specified, to shellvar) # # These macros use AX_COMPILER_VENDOR to determine which flags should be # returned for a given compiler. Not all compilers currently have flags # defined for them; patches are welcome. If need be, compiler flags may # be made language-dependent: use a construct like the following: # # [vendor_name], [m4_if(_AC_LANG_PREFIX,[C], VAR="--relevant-c-flags",dnl # m4_if(_AC_LANG_PREFIX,[CXX], VAR="--relevant-c++-flags",dnl # m4_if(_AC_LANG_PREFIX,[FC], VAR="--relevant-fortran-flags",dnl # VAR="$2"; FOUND="no")))], # # Note: These macros also depend on AX_PREPEND_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2010 Rhys Ulerich # Copyright (c) 2018 John Zaitseff # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 25 AC_DEFUN([AX_FLAGS_WARN_ALL], [ AX_REQUIRE_DEFINED([AX_PREPEND_FLAG])dnl AC_REQUIRE([AX_COMPILER_VENDOR])dnl AS_VAR_PUSHDEF([FLAGS], [m4_default($1,_AC_LANG_PREFIX[]FLAGS)])dnl AS_VAR_PUSHDEF([VAR], [ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl AS_VAR_PUSHDEF([FOUND], [ac_save_[]_AC_LANG_ABBREV[]flags_warn_all_found])dnl AC_CACHE_CHECK([FLAGS for most reasonable warnings], VAR, [ VAR="" FOUND="yes" dnl Cases are listed in the order found in ax_compiler_vendor.m4 AS_CASE("$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor", [intel], [VAR="-w2"], [ibm], [VAR="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd"], [pathscale], [], [clang], [VAR="-Wall"], [cray], [VAR="-h msglevel 2"], [fujitsu], [], [sdcc], [], [sx], [VAR="-pvctl[,]fullmsg"], [portland], [], [gnu], [VAR="-Wall"], [sun], [VAR="-v"], [hp], [VAR="+w1"], [dec], [VAR="-verbose -w0 -warnprotos"], [borland], [], [comeau], [], [kai], [], [lcc], [], [sgi], [VAR="-fullwarn"], [microsoft], [], [metrowerks], [], [watcom], [], [tcc], [], [unknown], [ VAR="$2" FOUND="no" ], [ AC_MSG_WARN([Unknown compiler vendor returned by [AX_COMPILER_VENDOR]]) VAR="$2" FOUND="no" ] ) AS_IF([test "x$FOUND" = "xyes"], [dnl m4_default($3, [AS_IF([test "x$VAR" != "x"], [AX_PREPEND_FLAG([$VAR], [FLAGS])])]) ], [dnl m4_default($4, [m4_ifval($2, [AX_PREPEND_FLAG([$VAR], [FLAGS])], [true])]) ])dnl ])dnl AS_VAR_POPDEF([FOUND])dnl AS_VAR_POPDEF([VAR])dnl AS_VAR_POPDEF([FLAGS])dnl ])dnl AX_FLAGS_WARN_ALL AC_DEFUN([AX_CFLAGS_WARN_ALL], [dnl AC_LANG_PUSH([C]) AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) AC_LANG_POP([C]) ])dnl AC_DEFUN([AX_CXXFLAGS_WARN_ALL], [dnl AC_LANG_PUSH([C++]) AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) AC_LANG_POP([C++]) ])dnl AC_DEFUN([AX_FCFLAGS_WARN_ALL], [dnl AC_LANG_PUSH([Fortran]) AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) AC_LANG_POP([Fortran]) ])dnl libopenmpt-0.8.1+release.autotools/m4/pkg.m40000644000175000017500000003067715023302302015624 00000000000000# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- # serial 12 (pkg-config-0.29.2) dnl Copyright Š 2004 Scott James Remnant . dnl Copyright Š 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurrence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------ dnl dnl Prepare a "--with-" configure option using the lowercase dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and dnl PKG_CHECK_MODULES in a single macro. AC_DEFUN([PKG_WITH_MODULES], [ m4_pushdef([with_arg], m4_tolower([$1])) m4_pushdef([description], [m4_default([$5], [build with ]with_arg[ support])]) m4_pushdef([def_arg], [m4_default([$6], [auto])]) m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) m4_case(def_arg, [yes],[m4_pushdef([with_without], [--without-]with_arg)], [m4_pushdef([with_without],[--with-]with_arg)]) AC_ARG_WITH(with_arg, AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, [AS_TR_SH([with_]with_arg)=def_arg]) AS_CASE([$AS_TR_SH([with_]with_arg)], [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], [auto],[PKG_CHECK_MODULES([$1],[$2], [m4_n([def_action_if_found]) $3], [m4_n([def_action_if_not_found]) $4])]) m4_popdef([with_arg]) m4_popdef([description]) m4_popdef([def_arg]) ])dnl PKG_WITH_MODULES dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ----------------------------------------------- dnl dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES dnl check._[VARIABLE-PREFIX] is exported as make variable. AC_DEFUN([PKG_HAVE_WITH_MODULES], [ PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) AM_CONDITIONAL([HAVE_][$1], [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) ])dnl PKG_HAVE_WITH_MODULES dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------------------ dnl dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make dnl and preprocessor variable. AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) ])dnl PKG_HAVE_DEFINE_WITH_MODULES libopenmpt-0.8.1+release.autotools/m4/emptydir0000644000175000017500000000000015023301060016332 00000000000000libopenmpt-0.8.1+release.autotools/Makefile.in0000644000175000017500000324461615023302326016337 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = $(am__EXEEXT_1) check_PROGRAMS = $(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4) \ $(am__EXEEXT_5) @ENABLE_TESTS_TRUE@TESTS = libopenmpttest$(EXEEXT) @ENABLE_EXAMPLES_TRUE@am__append_1 = libopenmpt_example_c_pipe \ @ENABLE_EXAMPLES_TRUE@ libopenmpt_example_c_probe \ @ENABLE_EXAMPLES_TRUE@ libopenmpt_example_c_stdout @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@am__append_2 = libopenmpt_example_c \ @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@ libopenmpt_example_c_mem \ @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@ libopenmpt_example_c_unsafe @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIOCPP_TRUE@am__append_3 = libopenmpt_example_cxx @ENABLE_TESTS_TRUE@am__append_4 = libopenmpttest @ENABLE_OPENMPT123_TRUE@am__append_5 = bin/openmpt123 subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cflags_warn_all.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compiler_vendor.m4 \ $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ $(top_srcdir)/m4/ax_cxx_exceptions.m4 \ $(top_srcdir)/m4/ax_cxx_rtti.m4 \ $(top_srcdir)/m4/ax_prepend_flag.m4 \ $(top_srcdir)/m4/ax_prog_doxygen.m4 \ $(top_srcdir)/m4/ax_pthread.m4 \ $(top_srcdir)/m4/ax_require_defined.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(dist_doc_DATA) $(nobase_dist_doc_DATA) \ $(includelibopenmpt_HEADERS) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = libopenmpt/libopenmpt.pc Doxyfile CONFIG_CLEAN_VPATH_FILES = @ENABLE_OPENMPT123_TRUE@am__EXEEXT_1 = bin/openmpt123$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" \ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)" \ "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" \ "$(DESTDIR)$(includelibopenmptdir)" @ENABLE_EXAMPLES_TRUE@am__EXEEXT_2 = \ @ENABLE_EXAMPLES_TRUE@ libopenmpt_example_c_pipe$(EXEEXT) \ @ENABLE_EXAMPLES_TRUE@ libopenmpt_example_c_probe$(EXEEXT) \ @ENABLE_EXAMPLES_TRUE@ libopenmpt_example_c_stdout$(EXEEXT) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@am__EXEEXT_3 = libopenmpt_example_c$(EXEEXT) \ @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@ libopenmpt_example_c_mem$(EXEEXT) \ @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@ libopenmpt_example_c_unsafe$(EXEEXT) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIOCPP_TRUE@am__EXEEXT_4 = libopenmpt_example_cxx$(EXEEXT) @ENABLE_TESTS_TRUE@am__EXEEXT_5 = libopenmpttest$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libopenmpt_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) am__objects_1 = am__dirstamp = $(am__leading_dot)dirstamp am__objects_2 = common/libopenmpt_la-ComponentManager.lo \ common/libopenmpt_la-Logging.lo \ common/libopenmpt_la-mptFileType.lo \ common/libopenmpt_la-mptPathString.lo \ common/libopenmpt_la-mptRandom.lo \ common/libopenmpt_la-mptStringBuffer.lo \ common/libopenmpt_la-mptTime.lo \ common/libopenmpt_la-Profiler.lo \ common/libopenmpt_la-serialization_utils.lo \ common/libopenmpt_la-version.lo am__objects_3 = soundlib/libopenmpt_la-AudioCriticalSection.lo \ soundlib/libopenmpt_la-ContainerMMCMP.lo \ soundlib/libopenmpt_la-ContainerPP20.lo \ soundlib/libopenmpt_la-ContainerUMX.lo \ soundlib/libopenmpt_la-ContainerXPK.lo \ soundlib/libopenmpt_la-Dlsbank.lo \ soundlib/libopenmpt_la-Fastmix.lo \ soundlib/libopenmpt_la-InstrumentExtensions.lo \ soundlib/libopenmpt_la-InstrumentSynth.lo \ soundlib/libopenmpt_la-ITCompression.lo \ soundlib/libopenmpt_la-ITTools.lo \ soundlib/libopenmpt_la-Load_667.lo \ soundlib/libopenmpt_la-Load_669.lo \ soundlib/libopenmpt_la-Load_amf.lo \ soundlib/libopenmpt_la-Load_ams.lo \ soundlib/libopenmpt_la-Load_c67.lo \ soundlib/libopenmpt_la-Load_cba.lo \ soundlib/libopenmpt_la-Load_dbm.lo \ soundlib/libopenmpt_la-Load_digi.lo \ soundlib/libopenmpt_la-Load_dmf.lo \ soundlib/libopenmpt_la-Load_dsm.lo \ soundlib/libopenmpt_la-Load_dsym.lo \ soundlib/libopenmpt_la-Load_dtm.lo \ soundlib/libopenmpt_la-Load_etx.lo \ soundlib/libopenmpt_la-Load_far.lo \ soundlib/libopenmpt_la-Load_fc.lo \ soundlib/libopenmpt_la-Load_fmt.lo \ soundlib/libopenmpt_la-Load_ftm.lo \ soundlib/libopenmpt_la-Load_gdm.lo \ soundlib/libopenmpt_la-Load_gmc.lo \ soundlib/libopenmpt_la-Load_gt2.lo \ soundlib/libopenmpt_la-Load_ice.lo \ soundlib/libopenmpt_la-Load_imf.lo \ soundlib/libopenmpt_la-Load_ims.lo \ soundlib/libopenmpt_la-Load_it.lo \ soundlib/libopenmpt_la-Load_itp.lo \ soundlib/libopenmpt_la-load_j2b.lo \ soundlib/libopenmpt_la-Load_kris.lo \ soundlib/libopenmpt_la-Load_mdl.lo \ soundlib/libopenmpt_la-Load_med.lo \ soundlib/libopenmpt_la-Load_mid.lo \ soundlib/libopenmpt_la-Load_mo3.lo \ soundlib/libopenmpt_la-Load_mod.lo \ soundlib/libopenmpt_la-Load_mt2.lo \ soundlib/libopenmpt_la-Load_mtm.lo \ soundlib/libopenmpt_la-Load_mus_km.lo \ soundlib/libopenmpt_la-Load_okt.lo \ soundlib/libopenmpt_la-Load_plm.lo \ soundlib/libopenmpt_la-Load_psm.lo \ soundlib/libopenmpt_la-Load_pt36.lo \ soundlib/libopenmpt_la-Load_ptm.lo \ soundlib/libopenmpt_la-Load_puma.lo \ soundlib/libopenmpt_la-Load_rtm.lo \ soundlib/libopenmpt_la-Load_s3m.lo \ soundlib/libopenmpt_la-Load_sfx.lo \ soundlib/libopenmpt_la-Load_stk.lo \ soundlib/libopenmpt_la-Load_stm.lo \ soundlib/libopenmpt_la-Load_stp.lo \ soundlib/libopenmpt_la-Load_symmod.lo \ soundlib/libopenmpt_la-Load_tcb.lo \ soundlib/libopenmpt_la-Load_uax.lo \ soundlib/libopenmpt_la-Load_ult.lo \ soundlib/libopenmpt_la-Load_unic.lo \ soundlib/libopenmpt_la-Load_wav.lo \ soundlib/libopenmpt_la-Load_xm.lo \ soundlib/libopenmpt_la-Load_xmf.lo \ soundlib/libopenmpt_la-Message.lo \ soundlib/libopenmpt_la-MIDIEvents.lo \ soundlib/libopenmpt_la-MIDIMacroParser.lo \ soundlib/libopenmpt_la-MIDIMacros.lo \ soundlib/libopenmpt_la-MixerLoops.lo \ soundlib/libopenmpt_la-MixerSettings.lo \ soundlib/libopenmpt_la-MixFuncTable.lo \ soundlib/libopenmpt_la-ModChannel.lo \ soundlib/libopenmpt_la-modcommand.lo \ soundlib/libopenmpt_la-ModInstrument.lo \ soundlib/libopenmpt_la-ModSample.lo \ soundlib/libopenmpt_la-ModSequence.lo \ soundlib/libopenmpt_la-modsmp_ctrl.lo \ soundlib/libopenmpt_la-mod_specifications.lo \ soundlib/libopenmpt_la-MODTools.lo \ soundlib/libopenmpt_la-MPEGFrame.lo \ soundlib/libopenmpt_la-OggStream.lo \ soundlib/libopenmpt_la-OPL.lo soundlib/libopenmpt_la-Paula.lo \ soundlib/libopenmpt_la-patternContainer.lo \ soundlib/libopenmpt_la-pattern.lo \ soundlib/libopenmpt_la-PlaybackTest.lo \ soundlib/libopenmpt_la-PlayState.lo \ soundlib/libopenmpt_la-RowVisitor.lo \ soundlib/libopenmpt_la-S3MTools.lo \ soundlib/libopenmpt_la-SampleFormats.lo \ soundlib/libopenmpt_la-SampleFormatBRR.lo \ soundlib/libopenmpt_la-SampleFormatFLAC.lo \ soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo \ soundlib/libopenmpt_la-SampleFormatMP3.lo \ soundlib/libopenmpt_la-SampleFormatOpus.lo \ soundlib/libopenmpt_la-SampleFormatSFZ.lo \ soundlib/libopenmpt_la-SampleFormatVorbis.lo \ soundlib/libopenmpt_la-SampleIO.lo \ soundlib/libopenmpt_la-Sndfile.lo \ soundlib/libopenmpt_la-Snd_flt.lo \ soundlib/libopenmpt_la-Snd_fx.lo \ soundlib/libopenmpt_la-Sndmix.lo \ soundlib/libopenmpt_la-SoundFilePlayConfig.lo \ soundlib/libopenmpt_la-Tables.lo \ soundlib/libopenmpt_la-Tagging.lo \ soundlib/libopenmpt_la-TinyFFT.lo \ soundlib/libopenmpt_la-tuningCollection.lo \ soundlib/libopenmpt_la-tuning.lo \ soundlib/libopenmpt_la-UMXTools.lo \ soundlib/libopenmpt_la-UpgradeModule.lo \ soundlib/libopenmpt_la-WAVTools.lo \ soundlib/libopenmpt_la-WindowedFIR.lo \ soundlib/libopenmpt_la-XMTools.lo \ soundlib/plugins/dmo/libopenmpt_la-DMOPlugin.lo \ soundlib/plugins/dmo/libopenmpt_la-DMOUtils.lo \ soundlib/plugins/dmo/libopenmpt_la-Chorus.lo \ soundlib/plugins/dmo/libopenmpt_la-Compressor.lo \ soundlib/plugins/dmo/libopenmpt_la-Distortion.lo \ soundlib/plugins/dmo/libopenmpt_la-Echo.lo \ soundlib/plugins/dmo/libopenmpt_la-Flanger.lo \ soundlib/plugins/dmo/libopenmpt_la-Gargle.lo \ soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo \ soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo \ soundlib/plugins/dmo/libopenmpt_la-WavesReverb.lo \ soundlib/plugins/libopenmpt_la-DigiBoosterEcho.lo \ soundlib/plugins/libopenmpt_la-LFOPlugin.lo \ soundlib/plugins/libopenmpt_la-PluginManager.lo \ soundlib/plugins/libopenmpt_la-PlugInterface.lo \ soundlib/plugins/libopenmpt_la-SymMODEcho.lo am__objects_4 = sounddsp/libopenmpt_la-AGC.lo \ sounddsp/libopenmpt_la-DSP.lo sounddsp/libopenmpt_la-EQ.lo \ sounddsp/libopenmpt_la-Reverb.lo am_libopenmpt_la_OBJECTS = $(am__objects_1) $(am__objects_1) \ $(am__objects_2) $(am__objects_3) $(am__objects_4) \ libopenmpt/la-libopenmpt_c.lo libopenmpt/la-libopenmpt_cxx.lo \ libopenmpt/la-libopenmpt_ext_impl.lo \ libopenmpt/la-libopenmpt_impl.lo libopenmpt_la_OBJECTS = $(am_libopenmpt_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libopenmpt_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) $(libopenmpt_la_LDFLAGS) \ $(LDFLAGS) -o $@ am__bin_openmpt123_SOURCES_DIST = src/mpt/arch/arch.hpp \ src/mpt/arch/feature_flags.hpp src/mpt/arch/x86_amd64.hpp \ src/mpt/audio/sample.hpp src/mpt/audio/span.hpp \ src/mpt/base/algorithm.hpp src/mpt/base/aligned_array.hpp \ src/mpt/base/alloc.hpp src/mpt/base/arithmetic_shift.hpp \ src/mpt/base/array.hpp src/mpt/base/bit.hpp \ src/mpt/base/check_platform.hpp \ src/mpt/base/compiletime_warning.hpp \ src/mpt/base/constexpr_throw.hpp src/mpt/base/debugging.hpp \ src/mpt/base/detect.hpp src/mpt/base/detect_arch.hpp \ src/mpt/base/detect_compiler.hpp src/mpt/base/detect_libc.hpp \ src/mpt/base/detect_libcxx.hpp src/mpt/base/detect_os.hpp \ src/mpt/base/detect_quirks.hpp src/mpt/base/float.hpp \ src/mpt/base/integer.hpp src/mpt/base/macros.hpp \ src/mpt/base/math.hpp src/mpt/base/memory.hpp \ src/mpt/base/namespace.hpp src/mpt/base/numbers.hpp \ src/mpt/base/numeric.hpp src/mpt/base/pointer.hpp \ src/mpt/base/preprocessor.hpp src/mpt/base/saturate_cast.hpp \ src/mpt/base/saturate_round.hpp src/mpt/base/secure.hpp \ src/mpt/base/semantic_version.hpp src/mpt/base/size.hpp \ src/mpt/base/source_location.hpp src/mpt/base/span.hpp \ src/mpt/base/type_traits.hpp src/mpt/base/utility.hpp \ src/mpt/base/version.hpp src/mpt/base/wrapping_divide.hpp \ src/mpt/binary/base64.hpp src/mpt/binary/base64url.hpp \ src/mpt/binary/hex.hpp src/mpt/check/compiler.hpp \ src/mpt/check/libc.hpp src/mpt/check/libcxx.hpp \ src/mpt/check/mfc.hpp src/mpt/check/windows.hpp \ src/mpt/crc/crc.hpp src/mpt/detect/dl.hpp \ src/mpt/detect/ltdl.hpp src/mpt/detect/mfc.hpp \ src/mpt/detect/nlohmann_json.hpp \ src/mpt/endian/floatingpoint.hpp src/mpt/endian/int24.hpp \ src/mpt/endian/integer.hpp src/mpt/endian/type_traits.hpp \ src/mpt/environment/environment.hpp \ src/mpt/exception/exception.hpp \ src/mpt/exception/exception_text.hpp \ src/mpt/exception/logic_error.hpp \ src/mpt/exception/runtime_error.hpp src/mpt/format/concat.hpp \ src/mpt/format/default_floatingpoint.hpp \ src/mpt/format/default_formatter.hpp \ src/mpt/format/default_integer.hpp \ src/mpt/format/default_string.hpp src/mpt/format/helpers.hpp \ src/mpt/format/join.hpp src/mpt/format/message.hpp \ src/mpt/format/message_macros.hpp src/mpt/format/simple.hpp \ src/mpt/format/simple_floatingpoint.hpp \ src/mpt/format/simple_integer.hpp \ src/mpt/format/simple_spec.hpp src/mpt/io/base.hpp \ src/mpt/io/io.hpp src/mpt/io/io_span.hpp \ src/mpt/io/io_stdstream.hpp src/mpt/io/io_virtual_wrapper.hpp \ src/mpt/io_file/fileref.hpp src/mpt/io_file/fstream.hpp \ src/mpt/io_file/inputfile.hpp src/mpt/io_file/outputfile.hpp \ src/mpt/io_file_adapter/fileadapter.hpp \ src/mpt/io_file_read/inputfile_filecursor.hpp \ src/mpt/io_file_unique/unique_basename.hpp \ src/mpt/io_file_unique/unique_tempfilename.hpp \ src/mpt/io_read/callbackstream.hpp \ src/mpt/io_read/filecursor.hpp \ src/mpt/io_read/filecursor_callbackstream.hpp \ src/mpt/io_read/filecursor_filename_traits.hpp \ src/mpt/io_read/filecursor_memory.hpp \ src/mpt/io_read/filecursor_stdstream.hpp \ src/mpt/io_read/filecursor_traits_filedata.hpp \ src/mpt/io_read/filecursor_traits_memory.hpp \ src/mpt/io_read/filedata.hpp src/mpt/io_read/filedata_base.hpp \ src/mpt/io_read/filedata_base_buffered.hpp \ src/mpt/io_read/filedata_base_seekable.hpp \ src/mpt/io_read/filedata_base_unseekable.hpp \ src/mpt/io_read/filedata_base_unseekable_buffer.hpp \ src/mpt/io_read/filedata_callbackstream.hpp \ src/mpt/io_read/filedata_memory.hpp \ src/mpt/io_read/filedata_stdstream.hpp \ src/mpt/io_read/filereader.hpp src/mpt/io_write/buffer.hpp \ src/mpt/main/main.hpp src/mpt/mutex/mutex.hpp \ src/mpt/osinfo/class.hpp src/mpt/osinfo/dos_memory.hpp \ src/mpt/osinfo/dos_version.hpp \ src/mpt/osinfo/windows_version.hpp \ src/mpt/osinfo/windows_wine_version.hpp \ src/mpt/out_of_memory/out_of_memory.hpp \ src/mpt/parse/parse.hpp src/mpt/parse/split.hpp \ src/mpt/path/basic_path.hpp src/mpt/path/native_path.hpp \ src/mpt/path/path.hpp src/mpt/path/os_path.hpp \ src/mpt/path/os_path_long.hpp src/mpt/random/any_engine.hpp \ src/mpt/random/crand.hpp src/mpt/random/default_engines.hpp \ src/mpt/random/device.hpp src/mpt/random/engine.hpp \ src/mpt/random/engine_lcg.hpp src/mpt/random/random.hpp \ src/mpt/random/seed.hpp src/mpt/string/buffer.hpp \ src/mpt/string/types.hpp src/mpt/string/utility.hpp \ src/mpt/string_transcode/transcode.hpp \ src/mpt/string_transcode/macros.hpp \ src/mpt/system_error/system_error.hpp src/mpt/test/test.hpp \ src/mpt/test/test_macros.hpp src/mpt/uuid/guid.hpp \ src/mpt/uuid/uuid.hpp \ src/mpt/base/tests/tests_base_arithmetic_shift.hpp \ src/mpt/base/tests/tests_base_bit.hpp \ src/mpt/base/tests/tests_base_math.hpp \ src/mpt/base/tests/tests_base_numeric.hpp \ src/mpt/base/tests/tests_base_saturate_cast.hpp \ src/mpt/base/tests/tests_base_saturate_round.hpp \ src/mpt/base/tests/tests_base_wrapping_divide.hpp \ src/mpt/binary/tests/tests_binary.hpp \ src/mpt/crc/tests/tests_crc.hpp \ src/mpt/endian/tests/tests_endian_floatingpoint.hpp \ src/mpt/endian/tests/tests_endian_int24.hpp \ src/mpt/endian/tests/tests_endian_integer.hpp \ src/mpt/format/tests/tests_format_message.hpp \ src/mpt/format/tests/tests_format_simple.hpp \ src/mpt/io/tests/tests_io.hpp \ src/mpt/parse/tests/tests_parse.hpp \ src/mpt/random/tests/tests_random.hpp \ src/mpt/string/tests/tests_string_buffer.hpp \ src/mpt/string/tests/tests_string_utility.hpp \ src/mpt/string_transcode/tests/tests_string_transcode.hpp \ src/mpt/uuid/tests/tests_uuid.hpp \ openmpt123/openmpt123_allegro42.hpp \ openmpt123/openmpt123_config.hpp openmpt123/openmpt123.cpp \ openmpt123/openmpt123_exception.hpp \ openmpt123/openmpt123_flac.hpp openmpt123/openmpt123.hpp \ openmpt123/openmpt123_mmio.hpp \ openmpt123/openmpt123_portaudio.hpp \ openmpt123/openmpt123_pulseaudio.hpp \ openmpt123/openmpt123_raw.hpp openmpt123/openmpt123_sdl2.hpp \ openmpt123/openmpt123_sndfile.hpp \ openmpt123/openmpt123_stdio.hpp \ openmpt123/openmpt123_stdout.hpp \ openmpt123/openmpt123_terminal.hpp \ openmpt123/openmpt123_waveout.hpp @ENABLE_OPENMPT123_TRUE@am_bin_openmpt123_OBJECTS = $(am__objects_1) \ @ENABLE_OPENMPT123_TRUE@ openmpt123/bin_openmpt123-openmpt123.$(OBJEXT) bin_openmpt123_OBJECTS = $(am_bin_openmpt123_OBJECTS) @ENABLE_OPENMPT123_TRUE@bin_openmpt123_DEPENDENCIES = libopenmpt.la \ @ENABLE_OPENMPT123_TRUE@ $(am__DEPENDENCIES_1) \ @ENABLE_OPENMPT123_TRUE@ $(am__DEPENDENCIES_1) \ @ENABLE_OPENMPT123_TRUE@ $(am__DEPENDENCIES_1) \ @ENABLE_OPENMPT123_TRUE@ $(am__DEPENDENCIES_1) \ @ENABLE_OPENMPT123_TRUE@ $(am__DEPENDENCIES_1) \ @ENABLE_OPENMPT123_TRUE@ $(am__DEPENDENCIES_1) bin_openmpt123_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(bin_openmpt123_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__libopenmpt_example_c_SOURCES_DIST = \ examples/libopenmpt_example_c.c @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@am_libopenmpt_example_c_OBJECTS = examples/libopenmpt_example_c-libopenmpt_example_c.$(OBJEXT) libopenmpt_example_c_OBJECTS = $(am_libopenmpt_example_c_OBJECTS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_DEPENDENCIES = \ @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@ $(lib_LTLIBRARIES) \ @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@ $(am__DEPENDENCIES_1) libopenmpt_example_c_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libopenmpt_example_c_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__libopenmpt_example_c_mem_SOURCES_DIST = \ examples/libopenmpt_example_c_mem.c @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@am_libopenmpt_example_c_mem_OBJECTS = examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.$(OBJEXT) libopenmpt_example_c_mem_OBJECTS = \ $(am_libopenmpt_example_c_mem_OBJECTS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_mem_DEPENDENCIES = \ @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@ $(lib_LTLIBRARIES) \ @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@ $(am__DEPENDENCIES_1) libopenmpt_example_c_mem_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libopenmpt_example_c_mem_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__libopenmpt_example_c_pipe_SOURCES_DIST = \ examples/libopenmpt_example_c_pipe.c @ENABLE_EXAMPLES_TRUE@am_libopenmpt_example_c_pipe_OBJECTS = examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.$(OBJEXT) libopenmpt_example_c_pipe_OBJECTS = \ $(am_libopenmpt_example_c_pipe_OBJECTS) @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_pipe_DEPENDENCIES = \ @ENABLE_EXAMPLES_TRUE@ $(lib_LTLIBRARIES) libopenmpt_example_c_pipe_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libopenmpt_example_c_pipe_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__libopenmpt_example_c_probe_SOURCES_DIST = \ examples/libopenmpt_example_c_probe.c @ENABLE_EXAMPLES_TRUE@am_libopenmpt_example_c_probe_OBJECTS = examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.$(OBJEXT) libopenmpt_example_c_probe_OBJECTS = \ $(am_libopenmpt_example_c_probe_OBJECTS) @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_probe_DEPENDENCIES = \ @ENABLE_EXAMPLES_TRUE@ $(lib_LTLIBRARIES) libopenmpt_example_c_probe_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libopenmpt_example_c_probe_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__libopenmpt_example_c_stdout_SOURCES_DIST = \ examples/libopenmpt_example_c_stdout.c @ENABLE_EXAMPLES_TRUE@am_libopenmpt_example_c_stdout_OBJECTS = examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.$(OBJEXT) libopenmpt_example_c_stdout_OBJECTS = \ $(am_libopenmpt_example_c_stdout_OBJECTS) @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_stdout_DEPENDENCIES = \ @ENABLE_EXAMPLES_TRUE@ $(lib_LTLIBRARIES) libopenmpt_example_c_stdout_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libopenmpt_example_c_stdout_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__libopenmpt_example_c_unsafe_SOURCES_DIST = \ examples/libopenmpt_example_c_unsafe.c @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@am_libopenmpt_example_c_unsafe_OBJECTS = examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.$(OBJEXT) libopenmpt_example_c_unsafe_OBJECTS = \ $(am_libopenmpt_example_c_unsafe_OBJECTS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_unsafe_DEPENDENCIES = \ @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@ $(lib_LTLIBRARIES) \ @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@ $(am__DEPENDENCIES_1) libopenmpt_example_c_unsafe_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libopenmpt_example_c_unsafe_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__libopenmpt_example_cxx_SOURCES_DIST = \ examples/libopenmpt_example_cxx.cpp @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIOCPP_TRUE@am_libopenmpt_example_cxx_OBJECTS = examples/libopenmpt_example_cxx-libopenmpt_example_cxx.$(OBJEXT) libopenmpt_example_cxx_OBJECTS = $(am_libopenmpt_example_cxx_OBJECTS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIOCPP_TRUE@libopenmpt_example_cxx_DEPENDENCIES = $(lib_LTLIBRARIES) \ @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIOCPP_TRUE@ $(am__DEPENDENCIES_1) libopenmpt_example_cxx_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libopenmpt_example_cxx_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__libopenmpttest_SOURCES_DIST = test/mpt_tests_base.cpp \ test/mpt_tests_binary.cpp test/mpt_tests_crc.cpp \ test/mpt_tests_endian.cpp test/mpt_tests_format.cpp \ test/mpt_tests_io.cpp test/mpt_tests_parse.cpp \ test/mpt_tests_random.cpp test/mpt_tests_string.cpp \ test/mpt_tests_string_transcode.cpp test/mpt_tests_uuid.cpp \ test/test.cpp test/test.h test/TestTools.h \ test/TestToolsLib.cpp test/TestToolsLib.h \ test/TestToolsTracker.h build/svn_version/svn_version.h \ src/mpt/arch/arch.hpp src/mpt/arch/feature_flags.hpp \ src/mpt/arch/x86_amd64.hpp src/mpt/audio/sample.hpp \ src/mpt/audio/span.hpp src/mpt/base/algorithm.hpp \ src/mpt/base/aligned_array.hpp src/mpt/base/alloc.hpp \ src/mpt/base/arithmetic_shift.hpp src/mpt/base/array.hpp \ src/mpt/base/bit.hpp src/mpt/base/check_platform.hpp \ src/mpt/base/compiletime_warning.hpp \ src/mpt/base/constexpr_throw.hpp src/mpt/base/debugging.hpp \ src/mpt/base/detect.hpp src/mpt/base/detect_arch.hpp \ src/mpt/base/detect_compiler.hpp src/mpt/base/detect_libc.hpp \ src/mpt/base/detect_libcxx.hpp src/mpt/base/detect_os.hpp \ src/mpt/base/detect_quirks.hpp src/mpt/base/float.hpp \ src/mpt/base/integer.hpp src/mpt/base/macros.hpp \ src/mpt/base/math.hpp src/mpt/base/memory.hpp \ src/mpt/base/namespace.hpp src/mpt/base/numbers.hpp \ src/mpt/base/numeric.hpp src/mpt/base/pointer.hpp \ src/mpt/base/preprocessor.hpp src/mpt/base/saturate_cast.hpp \ src/mpt/base/saturate_round.hpp src/mpt/base/secure.hpp \ src/mpt/base/semantic_version.hpp src/mpt/base/size.hpp \ src/mpt/base/source_location.hpp src/mpt/base/span.hpp \ src/mpt/base/type_traits.hpp src/mpt/base/utility.hpp \ src/mpt/base/version.hpp src/mpt/base/wrapping_divide.hpp \ src/mpt/binary/base64.hpp src/mpt/binary/base64url.hpp \ src/mpt/binary/hex.hpp src/mpt/check/compiler.hpp \ src/mpt/check/libc.hpp src/mpt/check/libcxx.hpp \ src/mpt/check/mfc.hpp src/mpt/check/windows.hpp \ src/mpt/crc/crc.hpp src/mpt/detect/dl.hpp \ src/mpt/detect/ltdl.hpp src/mpt/detect/mfc.hpp \ src/mpt/detect/nlohmann_json.hpp \ src/mpt/endian/floatingpoint.hpp src/mpt/endian/int24.hpp \ src/mpt/endian/integer.hpp src/mpt/endian/type_traits.hpp \ src/mpt/environment/environment.hpp \ src/mpt/exception/exception.hpp \ src/mpt/exception/exception_text.hpp \ src/mpt/exception/logic_error.hpp \ src/mpt/exception/runtime_error.hpp src/mpt/format/concat.hpp \ src/mpt/format/default_floatingpoint.hpp \ src/mpt/format/default_formatter.hpp \ src/mpt/format/default_integer.hpp \ src/mpt/format/default_string.hpp src/mpt/format/helpers.hpp \ src/mpt/format/join.hpp src/mpt/format/message.hpp \ src/mpt/format/message_macros.hpp src/mpt/format/simple.hpp \ src/mpt/format/simple_floatingpoint.hpp \ src/mpt/format/simple_integer.hpp \ src/mpt/format/simple_spec.hpp src/mpt/io/base.hpp \ src/mpt/io/io.hpp src/mpt/io/io_span.hpp \ src/mpt/io/io_stdstream.hpp src/mpt/io/io_virtual_wrapper.hpp \ src/mpt/io_file/fileref.hpp src/mpt/io_file/fstream.hpp \ src/mpt/io_file/inputfile.hpp src/mpt/io_file/outputfile.hpp \ src/mpt/io_file_adapter/fileadapter.hpp \ src/mpt/io_file_read/inputfile_filecursor.hpp \ src/mpt/io_file_unique/unique_basename.hpp \ src/mpt/io_file_unique/unique_tempfilename.hpp \ src/mpt/io_read/callbackstream.hpp \ src/mpt/io_read/filecursor.hpp \ src/mpt/io_read/filecursor_callbackstream.hpp \ src/mpt/io_read/filecursor_filename_traits.hpp \ src/mpt/io_read/filecursor_memory.hpp \ src/mpt/io_read/filecursor_stdstream.hpp \ src/mpt/io_read/filecursor_traits_filedata.hpp \ src/mpt/io_read/filecursor_traits_memory.hpp \ src/mpt/io_read/filedata.hpp src/mpt/io_read/filedata_base.hpp \ src/mpt/io_read/filedata_base_buffered.hpp \ src/mpt/io_read/filedata_base_seekable.hpp \ src/mpt/io_read/filedata_base_unseekable.hpp \ src/mpt/io_read/filedata_base_unseekable_buffer.hpp \ src/mpt/io_read/filedata_callbackstream.hpp \ src/mpt/io_read/filedata_memory.hpp \ src/mpt/io_read/filedata_stdstream.hpp \ src/mpt/io_read/filereader.hpp src/mpt/io_write/buffer.hpp \ src/mpt/main/main.hpp src/mpt/mutex/mutex.hpp \ src/mpt/osinfo/class.hpp src/mpt/osinfo/dos_memory.hpp \ src/mpt/osinfo/dos_version.hpp \ src/mpt/osinfo/windows_version.hpp \ src/mpt/osinfo/windows_wine_version.hpp \ src/mpt/out_of_memory/out_of_memory.hpp \ src/mpt/parse/parse.hpp src/mpt/parse/split.hpp \ src/mpt/path/basic_path.hpp src/mpt/path/native_path.hpp \ src/mpt/path/path.hpp src/mpt/path/os_path.hpp \ src/mpt/path/os_path_long.hpp src/mpt/random/any_engine.hpp \ src/mpt/random/crand.hpp src/mpt/random/default_engines.hpp \ src/mpt/random/device.hpp src/mpt/random/engine.hpp \ src/mpt/random/engine_lcg.hpp src/mpt/random/random.hpp \ src/mpt/random/seed.hpp src/mpt/string/buffer.hpp \ src/mpt/string/types.hpp src/mpt/string/utility.hpp \ src/mpt/string_transcode/transcode.hpp \ src/mpt/string_transcode/macros.hpp \ src/mpt/system_error/system_error.hpp src/mpt/test/test.hpp \ src/mpt/test/test_macros.hpp src/mpt/uuid/guid.hpp \ src/mpt/uuid/uuid.hpp \ src/mpt/base/tests/tests_base_arithmetic_shift.hpp \ src/mpt/base/tests/tests_base_bit.hpp \ src/mpt/base/tests/tests_base_math.hpp \ src/mpt/base/tests/tests_base_numeric.hpp \ src/mpt/base/tests/tests_base_saturate_cast.hpp \ src/mpt/base/tests/tests_base_saturate_round.hpp \ src/mpt/base/tests/tests_base_wrapping_divide.hpp \ src/mpt/binary/tests/tests_binary.hpp \ src/mpt/crc/tests/tests_crc.hpp \ src/mpt/endian/tests/tests_endian_floatingpoint.hpp \ src/mpt/endian/tests/tests_endian_int24.hpp \ src/mpt/endian/tests/tests_endian_integer.hpp \ src/mpt/format/tests/tests_format_message.hpp \ src/mpt/format/tests/tests_format_simple.hpp \ src/mpt/io/tests/tests_io.hpp \ src/mpt/parse/tests/tests_parse.hpp \ src/mpt/random/tests/tests_random.hpp \ src/mpt/string/tests/tests_string_buffer.hpp \ src/mpt/string/tests/tests_string_utility.hpp \ src/mpt/string_transcode/tests/tests_string_transcode.hpp \ src/mpt/uuid/tests/tests_uuid.hpp \ src/openmpt/all/BuildSettings.hpp \ src/openmpt/all/PlatformFixes.hpp src/openmpt/base/Endian.hpp \ src/openmpt/base/FlagSet.hpp src/openmpt/base/Int24.hpp \ src/openmpt/base/Types.hpp \ src/openmpt/fileformat_base/magic.hpp \ src/openmpt/logging/Logger.hpp src/openmpt/random/ModPlug.hpp \ src/openmpt/soundbase/Copy.hpp \ src/openmpt/soundbase/CopyMix.hpp \ src/openmpt/soundbase/Dither.hpp \ src/openmpt/soundbase/DitherModPlug.hpp \ src/openmpt/soundbase/DitherNone.hpp \ src/openmpt/soundbase/DitherSimple.hpp \ src/openmpt/soundbase/MixSample.hpp \ src/openmpt/soundbase/MixSampleConvert.hpp \ src/openmpt/soundbase/SampleClip.hpp \ src/openmpt/soundbase/SampleClipFixedPoint.hpp \ src/openmpt/soundbase/SampleConvert.hpp \ src/openmpt/soundbase/SampleConvertFixedPoint.hpp \ src/openmpt/soundbase/SampleDecode.hpp \ src/openmpt/soundbase/SampleEncode.hpp \ src/openmpt/soundbase/SampleFormat.hpp \ src/openmpt/soundfile_data/tags.hpp \ src/openmpt/soundfile_data/wav.hpp \ src/openmpt/soundfile_write/wav_write.cpp \ src/openmpt/soundfile_write/wav_write.hpp \ common/BuildSettings.h common/BuildSettingsCompiler.h \ common/ComponentManager.cpp common/ComponentManager.h \ common/FileReader.h common/FileReaderFwd.h common/GzipWriter.h \ common/Logging.cpp common/Logging.h common/misc_util.h \ common/mptAssert.h common/mptBaseMacros.h \ common/mptBaseTypes.h common/mptBaseUtils.h common/mptCPU.h \ common/mptFileIO.h common/mptFileTemporary.h \ common/mptFileType.cpp common/mptFileType.h \ common/mptPathString.cpp common/mptPathString.h \ common/mptRandom.cpp common/mptRandom.h common/mptString.h \ common/mptStringBuffer.cpp common/mptStringBuffer.h \ common/mptStringFormat.h common/mptTime.cpp common/mptTime.h \ common/Profiler.cpp common/Profiler.h \ common/serialization_utils.cpp common/serialization_utils.h \ common/stdafx.h common/version.cpp common/version.h \ common/versionNumber.h soundlib/AudioCriticalSection.cpp \ soundlib/AudioCriticalSection.h soundlib/AudioReadTarget.h \ soundlib/BitReader.h soundlib/ContainerMMCMP.cpp \ soundlib/ContainerPP20.cpp soundlib/ContainerUMX.cpp \ soundlib/ContainerXPK.cpp soundlib/Container.h \ soundlib/Dlsbank.cpp soundlib/Dlsbank.h soundlib/Fastmix.cpp \ soundlib/FloatMixer.h soundlib/InstrumentExtensions.cpp \ soundlib/InstrumentSynth.cpp soundlib/InstrumentSynth.h \ soundlib/IntMixer.h soundlib/ITCompression.cpp \ soundlib/ITCompression.h soundlib/ITTools.cpp \ soundlib/ITTools.h soundlib/Load_667.cpp soundlib/Load_669.cpp \ soundlib/Load_amf.cpp soundlib/Load_ams.cpp \ soundlib/Load_c67.cpp soundlib/Load_cba.cpp \ soundlib/Load_dbm.cpp soundlib/Load_digi.cpp \ soundlib/Load_dmf.cpp soundlib/Load_dsm.cpp \ soundlib/Load_dsym.cpp soundlib/Load_dtm.cpp \ soundlib/Loaders.h soundlib/Load_etx.cpp soundlib/Load_far.cpp \ soundlib/Load_fc.cpp soundlib/Load_fmt.cpp \ soundlib/Load_ftm.cpp soundlib/Load_gdm.cpp \ soundlib/Load_gmc.cpp soundlib/Load_gt2.cpp \ soundlib/Load_ice.cpp soundlib/Load_imf.cpp \ soundlib/Load_ims.cpp soundlib/Load_it.cpp \ soundlib/Load_itp.cpp soundlib/load_j2b.cpp \ soundlib/Load_kris.cpp soundlib/Load_mdl.cpp \ soundlib/Load_med.cpp soundlib/Load_mid.cpp \ soundlib/Load_mo3.cpp soundlib/Load_mod.cpp \ soundlib/Load_mt2.cpp soundlib/Load_mtm.cpp \ soundlib/Load_mus_km.cpp soundlib/Load_okt.cpp \ soundlib/Load_plm.cpp soundlib/Load_psm.cpp \ soundlib/Load_pt36.cpp soundlib/Load_ptm.cpp \ soundlib/Load_puma.cpp soundlib/Load_rtm.cpp \ soundlib/Load_s3m.cpp soundlib/Load_sfx.cpp \ soundlib/Load_stk.cpp soundlib/Load_stm.cpp \ soundlib/Load_stp.cpp soundlib/Load_symmod.cpp \ soundlib/Load_tcb.cpp soundlib/Load_uax.cpp \ soundlib/Load_ult.cpp soundlib/Load_unic.cpp \ soundlib/Load_wav.cpp soundlib/Load_xm.cpp \ soundlib/Load_xmf.cpp soundlib/Message.cpp soundlib/Message.h \ soundlib/MIDIEvents.cpp soundlib/MIDIEvents.h \ soundlib/MIDIMacroParser.cpp soundlib/MIDIMacroParser.h \ soundlib/MIDIMacros.cpp soundlib/MIDIMacros.h soundlib/Mixer.h \ soundlib/MixerInterface.h soundlib/MixerLoops.cpp \ soundlib/MixerLoops.h soundlib/MixerSettings.cpp \ soundlib/MixerSettings.h soundlib/MixFuncTable.cpp \ soundlib/MixFuncTable.h soundlib/ModChannel.cpp \ soundlib/ModChannel.h soundlib/modcommand.cpp \ soundlib/modcommand.h soundlib/ModInstrument.cpp \ soundlib/ModInstrument.h soundlib/ModSample.cpp \ soundlib/ModSample.h soundlib/ModSampleCopy.h \ soundlib/ModSequence.cpp soundlib/ModSequence.h \ soundlib/modsmp_ctrl.cpp soundlib/modsmp_ctrl.h \ soundlib/mod_specifications.cpp soundlib/mod_specifications.h \ soundlib/MODTools.cpp soundlib/MODTools.h \ soundlib/MPEGFrame.cpp soundlib/MPEGFrame.h \ soundlib/OggStream.cpp soundlib/OggStream.h soundlib/opal.h \ soundlib/OPL.cpp soundlib/OPL.h soundlib/Paula.cpp \ soundlib/Paula.h soundlib/patternContainer.cpp \ soundlib/patternContainer.h soundlib/pattern.cpp \ soundlib/pattern.h soundlib/PlaybackTest.cpp \ soundlib/PlaybackTest.h soundlib/PlayState.cpp \ soundlib/PlayState.h soundlib/Resampler.h \ soundlib/RowVisitor.cpp soundlib/RowVisitor.h \ soundlib/S3MTools.cpp soundlib/S3MTools.h \ soundlib/SampleCopy.h soundlib/SampleFormats.cpp \ soundlib/SampleFormatBRR.cpp soundlib/SampleFormatFLAC.cpp \ soundlib/SampleFormatMediaFoundation.cpp \ soundlib/SampleFormatMP3.cpp soundlib/SampleFormatOpus.cpp \ soundlib/SampleFormatSFZ.cpp soundlib/SampleFormatVorbis.cpp \ soundlib/SampleIO.cpp soundlib/SampleIO.h \ soundlib/SampleNormalize.h soundlib/Snd_defs.h \ soundlib/Sndfile.cpp soundlib/Sndfile.h soundlib/Snd_flt.cpp \ soundlib/Snd_fx.cpp soundlib/Sndmix.cpp \ soundlib/SoundFilePlayConfig.cpp \ soundlib/SoundFilePlayConfig.h soundlib/Tables.cpp \ soundlib/Tables.h soundlib/Tagging.cpp soundlib/Tagging.h \ soundlib/TinyFFT.cpp soundlib/TinyFFT.h soundlib/tuningbase.h \ soundlib/tuningCollection.cpp soundlib/tuningcollection.h \ soundlib/tuning.cpp soundlib/tuning.h soundlib/UMXTools.cpp \ soundlib/UMXTools.h soundlib/UpgradeModule.cpp \ soundlib/WAVTools.cpp soundlib/WAVTools.h \ soundlib/WindowedFIR.cpp soundlib/WindowedFIR.h \ soundlib/XMTools.cpp soundlib/XMTools.h \ soundlib/plugins/dmo/DMOPlugin.cpp \ soundlib/plugins/dmo/DMOPlugin.h \ soundlib/plugins/dmo/DMOUtils.cpp \ soundlib/plugins/dmo/DMOUtils.h \ soundlib/plugins/dmo/Chorus.cpp soundlib/plugins/dmo/Chorus.h \ soundlib/plugins/dmo/Compressor.cpp \ soundlib/plugins/dmo/Compressor.h \ soundlib/plugins/dmo/Distortion.cpp \ soundlib/plugins/dmo/Distortion.h \ soundlib/plugins/dmo/Echo.cpp soundlib/plugins/dmo/Echo.h \ soundlib/plugins/dmo/Flanger.cpp \ soundlib/plugins/dmo/Flanger.h soundlib/plugins/dmo/Gargle.cpp \ soundlib/plugins/dmo/Gargle.h \ soundlib/plugins/dmo/I3DL2Reverb.cpp \ soundlib/plugins/dmo/I3DL2Reverb.h \ soundlib/plugins/dmo/ParamEq.cpp \ soundlib/plugins/dmo/ParamEq.h \ soundlib/plugins/dmo/WavesReverb.cpp \ soundlib/plugins/dmo/WavesReverb.h \ soundlib/plugins/DigiBoosterEcho.cpp \ soundlib/plugins/DigiBoosterEcho.h \ soundlib/plugins/LFOPlugin.cpp soundlib/plugins/LFOPlugin.h \ soundlib/plugins/PluginManager.cpp \ soundlib/plugins/PluginManager.h \ soundlib/plugins/PluginMixBuffer.h \ soundlib/plugins/PluginStructs.h \ soundlib/plugins/PlugInterface.cpp \ soundlib/plugins/PlugInterface.h \ soundlib/plugins/SymMODEcho.cpp soundlib/plugins/SymMODEcho.h \ sounddsp/AGC.cpp sounddsp/AGC.h sounddsp/DSP.cpp \ sounddsp/DSP.h sounddsp/EQ.cpp sounddsp/EQ.h \ sounddsp/Reverb.cpp sounddsp/Reverb.h \ libopenmpt/libopenmpt_c.cpp libopenmpt/libopenmpt_cxx.cpp \ libopenmpt/libopenmpt_ext_impl.cpp \ libopenmpt/libopenmpt_impl.cpp libopenmpt/libopenmpt_config.h \ libopenmpt/libopenmpt_ext.h libopenmpt/libopenmpt_ext.hpp \ libopenmpt/libopenmpt_ext_impl.hpp libopenmpt/libopenmpt.h \ libopenmpt/libopenmpt.hpp libopenmpt/libopenmpt_impl.hpp \ libopenmpt/libopenmpt_internal.h \ libopenmpt/libopenmpt_stream_callbacks_buffer.h \ libopenmpt/libopenmpt_stream_callbacks_fd.h \ libopenmpt/libopenmpt_stream_callbacks_file.h \ libopenmpt/libopenmpt_stream_callbacks_file_mingw.h \ libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h \ libopenmpt/libopenmpt_stream_callbacks_file_posix.h \ libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h \ libopenmpt/libopenmpt_version.h \ libopenmpt/libopenmpt_test/libopenmpt_test.cpp am__objects_5 = src/openmpt/soundfile_write/libopenmpttest-wav_write.$(OBJEXT) am__objects_6 = common/libopenmpttest-ComponentManager.$(OBJEXT) \ common/libopenmpttest-Logging.$(OBJEXT) \ common/libopenmpttest-mptFileType.$(OBJEXT) \ common/libopenmpttest-mptPathString.$(OBJEXT) \ common/libopenmpttest-mptRandom.$(OBJEXT) \ common/libopenmpttest-mptStringBuffer.$(OBJEXT) \ common/libopenmpttest-mptTime.$(OBJEXT) \ common/libopenmpttest-Profiler.$(OBJEXT) \ common/libopenmpttest-serialization_utils.$(OBJEXT) \ common/libopenmpttest-version.$(OBJEXT) am__objects_7 = \ soundlib/libopenmpttest-AudioCriticalSection.$(OBJEXT) \ soundlib/libopenmpttest-ContainerMMCMP.$(OBJEXT) \ soundlib/libopenmpttest-ContainerPP20.$(OBJEXT) \ soundlib/libopenmpttest-ContainerUMX.$(OBJEXT) \ soundlib/libopenmpttest-ContainerXPK.$(OBJEXT) \ soundlib/libopenmpttest-Dlsbank.$(OBJEXT) \ soundlib/libopenmpttest-Fastmix.$(OBJEXT) \ soundlib/libopenmpttest-InstrumentExtensions.$(OBJEXT) \ soundlib/libopenmpttest-InstrumentSynth.$(OBJEXT) \ soundlib/libopenmpttest-ITCompression.$(OBJEXT) \ soundlib/libopenmpttest-ITTools.$(OBJEXT) \ soundlib/libopenmpttest-Load_667.$(OBJEXT) \ soundlib/libopenmpttest-Load_669.$(OBJEXT) \ soundlib/libopenmpttest-Load_amf.$(OBJEXT) \ soundlib/libopenmpttest-Load_ams.$(OBJEXT) \ soundlib/libopenmpttest-Load_c67.$(OBJEXT) \ soundlib/libopenmpttest-Load_cba.$(OBJEXT) \ soundlib/libopenmpttest-Load_dbm.$(OBJEXT) \ soundlib/libopenmpttest-Load_digi.$(OBJEXT) \ soundlib/libopenmpttest-Load_dmf.$(OBJEXT) \ soundlib/libopenmpttest-Load_dsm.$(OBJEXT) \ soundlib/libopenmpttest-Load_dsym.$(OBJEXT) \ soundlib/libopenmpttest-Load_dtm.$(OBJEXT) \ soundlib/libopenmpttest-Load_etx.$(OBJEXT) \ soundlib/libopenmpttest-Load_far.$(OBJEXT) \ soundlib/libopenmpttest-Load_fc.$(OBJEXT) \ soundlib/libopenmpttest-Load_fmt.$(OBJEXT) \ soundlib/libopenmpttest-Load_ftm.$(OBJEXT) \ soundlib/libopenmpttest-Load_gdm.$(OBJEXT) \ soundlib/libopenmpttest-Load_gmc.$(OBJEXT) \ soundlib/libopenmpttest-Load_gt2.$(OBJEXT) \ soundlib/libopenmpttest-Load_ice.$(OBJEXT) \ soundlib/libopenmpttest-Load_imf.$(OBJEXT) \ soundlib/libopenmpttest-Load_ims.$(OBJEXT) \ soundlib/libopenmpttest-Load_it.$(OBJEXT) \ soundlib/libopenmpttest-Load_itp.$(OBJEXT) \ soundlib/libopenmpttest-load_j2b.$(OBJEXT) \ soundlib/libopenmpttest-Load_kris.$(OBJEXT) \ soundlib/libopenmpttest-Load_mdl.$(OBJEXT) \ soundlib/libopenmpttest-Load_med.$(OBJEXT) \ soundlib/libopenmpttest-Load_mid.$(OBJEXT) \ soundlib/libopenmpttest-Load_mo3.$(OBJEXT) \ soundlib/libopenmpttest-Load_mod.$(OBJEXT) \ soundlib/libopenmpttest-Load_mt2.$(OBJEXT) \ soundlib/libopenmpttest-Load_mtm.$(OBJEXT) \ soundlib/libopenmpttest-Load_mus_km.$(OBJEXT) \ soundlib/libopenmpttest-Load_okt.$(OBJEXT) \ soundlib/libopenmpttest-Load_plm.$(OBJEXT) \ soundlib/libopenmpttest-Load_psm.$(OBJEXT) \ soundlib/libopenmpttest-Load_pt36.$(OBJEXT) \ soundlib/libopenmpttest-Load_ptm.$(OBJEXT) \ soundlib/libopenmpttest-Load_puma.$(OBJEXT) \ soundlib/libopenmpttest-Load_rtm.$(OBJEXT) \ soundlib/libopenmpttest-Load_s3m.$(OBJEXT) \ soundlib/libopenmpttest-Load_sfx.$(OBJEXT) \ soundlib/libopenmpttest-Load_stk.$(OBJEXT) \ soundlib/libopenmpttest-Load_stm.$(OBJEXT) \ soundlib/libopenmpttest-Load_stp.$(OBJEXT) \ soundlib/libopenmpttest-Load_symmod.$(OBJEXT) \ soundlib/libopenmpttest-Load_tcb.$(OBJEXT) \ soundlib/libopenmpttest-Load_uax.$(OBJEXT) \ soundlib/libopenmpttest-Load_ult.$(OBJEXT) \ soundlib/libopenmpttest-Load_unic.$(OBJEXT) \ soundlib/libopenmpttest-Load_wav.$(OBJEXT) \ soundlib/libopenmpttest-Load_xm.$(OBJEXT) \ soundlib/libopenmpttest-Load_xmf.$(OBJEXT) \ soundlib/libopenmpttest-Message.$(OBJEXT) \ soundlib/libopenmpttest-MIDIEvents.$(OBJEXT) \ soundlib/libopenmpttest-MIDIMacroParser.$(OBJEXT) \ soundlib/libopenmpttest-MIDIMacros.$(OBJEXT) \ soundlib/libopenmpttest-MixerLoops.$(OBJEXT) \ soundlib/libopenmpttest-MixerSettings.$(OBJEXT) \ soundlib/libopenmpttest-MixFuncTable.$(OBJEXT) \ soundlib/libopenmpttest-ModChannel.$(OBJEXT) \ soundlib/libopenmpttest-modcommand.$(OBJEXT) \ soundlib/libopenmpttest-ModInstrument.$(OBJEXT) \ soundlib/libopenmpttest-ModSample.$(OBJEXT) \ soundlib/libopenmpttest-ModSequence.$(OBJEXT) \ soundlib/libopenmpttest-modsmp_ctrl.$(OBJEXT) \ soundlib/libopenmpttest-mod_specifications.$(OBJEXT) \ soundlib/libopenmpttest-MODTools.$(OBJEXT) \ soundlib/libopenmpttest-MPEGFrame.$(OBJEXT) \ soundlib/libopenmpttest-OggStream.$(OBJEXT) \ soundlib/libopenmpttest-OPL.$(OBJEXT) \ soundlib/libopenmpttest-Paula.$(OBJEXT) \ soundlib/libopenmpttest-patternContainer.$(OBJEXT) \ soundlib/libopenmpttest-pattern.$(OBJEXT) \ soundlib/libopenmpttest-PlaybackTest.$(OBJEXT) \ soundlib/libopenmpttest-PlayState.$(OBJEXT) \ soundlib/libopenmpttest-RowVisitor.$(OBJEXT) \ soundlib/libopenmpttest-S3MTools.$(OBJEXT) \ soundlib/libopenmpttest-SampleFormats.$(OBJEXT) \ soundlib/libopenmpttest-SampleFormatBRR.$(OBJEXT) \ soundlib/libopenmpttest-SampleFormatFLAC.$(OBJEXT) \ soundlib/libopenmpttest-SampleFormatMediaFoundation.$(OBJEXT) \ soundlib/libopenmpttest-SampleFormatMP3.$(OBJEXT) \ soundlib/libopenmpttest-SampleFormatOpus.$(OBJEXT) \ soundlib/libopenmpttest-SampleFormatSFZ.$(OBJEXT) \ soundlib/libopenmpttest-SampleFormatVorbis.$(OBJEXT) \ soundlib/libopenmpttest-SampleIO.$(OBJEXT) \ soundlib/libopenmpttest-Sndfile.$(OBJEXT) \ soundlib/libopenmpttest-Snd_flt.$(OBJEXT) \ soundlib/libopenmpttest-Snd_fx.$(OBJEXT) \ soundlib/libopenmpttest-Sndmix.$(OBJEXT) \ soundlib/libopenmpttest-SoundFilePlayConfig.$(OBJEXT) \ soundlib/libopenmpttest-Tables.$(OBJEXT) \ soundlib/libopenmpttest-Tagging.$(OBJEXT) \ soundlib/libopenmpttest-TinyFFT.$(OBJEXT) \ soundlib/libopenmpttest-tuningCollection.$(OBJEXT) \ soundlib/libopenmpttest-tuning.$(OBJEXT) \ soundlib/libopenmpttest-UMXTools.$(OBJEXT) \ soundlib/libopenmpttest-UpgradeModule.$(OBJEXT) \ soundlib/libopenmpttest-WAVTools.$(OBJEXT) \ soundlib/libopenmpttest-WindowedFIR.$(OBJEXT) \ soundlib/libopenmpttest-XMTools.$(OBJEXT) \ soundlib/plugins/dmo/libopenmpttest-DMOPlugin.$(OBJEXT) \ soundlib/plugins/dmo/libopenmpttest-DMOUtils.$(OBJEXT) \ soundlib/plugins/dmo/libopenmpttest-Chorus.$(OBJEXT) \ soundlib/plugins/dmo/libopenmpttest-Compressor.$(OBJEXT) \ soundlib/plugins/dmo/libopenmpttest-Distortion.$(OBJEXT) \ soundlib/plugins/dmo/libopenmpttest-Echo.$(OBJEXT) \ soundlib/plugins/dmo/libopenmpttest-Flanger.$(OBJEXT) \ soundlib/plugins/dmo/libopenmpttest-Gargle.$(OBJEXT) \ soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.$(OBJEXT) \ soundlib/plugins/dmo/libopenmpttest-ParamEq.$(OBJEXT) \ soundlib/plugins/dmo/libopenmpttest-WavesReverb.$(OBJEXT) \ soundlib/plugins/libopenmpttest-DigiBoosterEcho.$(OBJEXT) \ soundlib/plugins/libopenmpttest-LFOPlugin.$(OBJEXT) \ soundlib/plugins/libopenmpttest-PluginManager.$(OBJEXT) \ soundlib/plugins/libopenmpttest-PlugInterface.$(OBJEXT) \ soundlib/plugins/libopenmpttest-SymMODEcho.$(OBJEXT) am__objects_8 = sounddsp/libopenmpttest-AGC.$(OBJEXT) \ sounddsp/libopenmpttest-DSP.$(OBJEXT) \ sounddsp/libopenmpttest-EQ.$(OBJEXT) \ sounddsp/libopenmpttest-Reverb.$(OBJEXT) @ENABLE_TESTS_TRUE@am_libopenmpttest_OBJECTS = test/libopenmpttest-mpt_tests_base.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-mpt_tests_binary.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-mpt_tests_crc.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-mpt_tests_endian.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-mpt_tests_format.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-mpt_tests_io.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-mpt_tests_parse.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-mpt_tests_random.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-mpt_tests_string.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-mpt_tests_string_transcode.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-mpt_tests_uuid.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-test.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ test/libopenmpttest-TestToolsLib.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ $(am__objects_1) $(am__objects_1) \ @ENABLE_TESTS_TRUE@ $(am__objects_5) $(am__objects_6) \ @ENABLE_TESTS_TRUE@ $(am__objects_7) $(am__objects_8) \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpttest-libopenmpt_c.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpttest-libopenmpt_cxx.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpttest-libopenmpt_ext_impl.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpttest-libopenmpt_impl.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.$(OBJEXT) libopenmpttest_OBJECTS = $(am_libopenmpttest_OBJECTS) @ENABLE_TESTS_TRUE@libopenmpttest_DEPENDENCIES = \ @ENABLE_TESTS_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @ENABLE_TESTS_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @ENABLE_TESTS_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @ENABLE_TESTS_TRUE@ $(am__DEPENDENCIES_1) libopenmpttest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = \ common/$(DEPDIR)/libopenmpt_la-ComponentManager.Plo \ common/$(DEPDIR)/libopenmpt_la-Logging.Plo \ common/$(DEPDIR)/libopenmpt_la-Profiler.Plo \ common/$(DEPDIR)/libopenmpt_la-mptFileType.Plo \ common/$(DEPDIR)/libopenmpt_la-mptPathString.Plo \ common/$(DEPDIR)/libopenmpt_la-mptRandom.Plo \ common/$(DEPDIR)/libopenmpt_la-mptStringBuffer.Plo \ common/$(DEPDIR)/libopenmpt_la-mptTime.Plo \ common/$(DEPDIR)/libopenmpt_la-serialization_utils.Plo \ common/$(DEPDIR)/libopenmpt_la-version.Plo \ common/$(DEPDIR)/libopenmpttest-ComponentManager.Po \ common/$(DEPDIR)/libopenmpttest-Logging.Po \ common/$(DEPDIR)/libopenmpttest-Profiler.Po \ common/$(DEPDIR)/libopenmpttest-mptFileType.Po \ common/$(DEPDIR)/libopenmpttest-mptPathString.Po \ common/$(DEPDIR)/libopenmpttest-mptRandom.Po \ common/$(DEPDIR)/libopenmpttest-mptStringBuffer.Po \ common/$(DEPDIR)/libopenmpttest-mptTime.Po \ common/$(DEPDIR)/libopenmpttest-serialization_utils.Po \ common/$(DEPDIR)/libopenmpttest-version.Po \ examples/$(DEPDIR)/libopenmpt_example_c-libopenmpt_example_c.Po \ examples/$(DEPDIR)/libopenmpt_example_c_mem-libopenmpt_example_c_mem.Po \ examples/$(DEPDIR)/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.Po \ examples/$(DEPDIR)/libopenmpt_example_c_probe-libopenmpt_example_c_probe.Po \ examples/$(DEPDIR)/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.Po \ examples/$(DEPDIR)/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.Po \ examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Po \ libopenmpt/$(DEPDIR)/la-libopenmpt_c.Plo \ libopenmpt/$(DEPDIR)/la-libopenmpt_cxx.Plo \ libopenmpt/$(DEPDIR)/la-libopenmpt_ext_impl.Plo \ libopenmpt/$(DEPDIR)/la-libopenmpt_impl.Plo \ libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Po \ libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_cxx.Po \ libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Po \ libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Po \ libopenmpt/libopenmpt_test/$(DEPDIR)/libopenmpttest-libopenmpt_test.Po \ openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Po \ sounddsp/$(DEPDIR)/libopenmpt_la-AGC.Plo \ sounddsp/$(DEPDIR)/libopenmpt_la-DSP.Plo \ sounddsp/$(DEPDIR)/libopenmpt_la-EQ.Plo \ sounddsp/$(DEPDIR)/libopenmpt_la-Reverb.Plo \ sounddsp/$(DEPDIR)/libopenmpttest-AGC.Po \ sounddsp/$(DEPDIR)/libopenmpttest-DSP.Po \ sounddsp/$(DEPDIR)/libopenmpttest-EQ.Po \ sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Po \ soundlib/$(DEPDIR)/libopenmpt_la-AudioCriticalSection.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-ContainerMMCMP.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-ContainerPP20.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-ContainerUMX.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-ContainerXPK.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Dlsbank.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Fastmix.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-ITCompression.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-ITTools.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-InstrumentExtensions.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-InstrumentSynth.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_667.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_669.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_amf.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_ams.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_c67.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_cba.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_dbm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_digi.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_dmf.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_dsm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_dsym.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_dtm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_etx.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_far.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_fc.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_fmt.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_ftm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_gdm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_gmc.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_gt2.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_ice.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_imf.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_ims.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_it.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_itp.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_kris.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_mdl.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_med.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_mid.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_mo3.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_mod.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_mt2.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_mtm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_mus_km.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_okt.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_plm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_psm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_pt36.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_ptm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_puma.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_rtm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_s3m.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_sfx.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_stk.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_stm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_stp.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_symmod.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_tcb.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_uax.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_ult.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_unic.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_wav.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_xm.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Load_xmf.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-MIDIEvents.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacroParser.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacros.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-MODTools.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-MPEGFrame.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Message.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-MixFuncTable.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-MixerLoops.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-MixerSettings.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-ModChannel.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-ModInstrument.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-ModSample.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-ModSequence.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-OPL.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-OggStream.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Paula.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-PlayState.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-PlaybackTest.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-RowVisitor.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-S3MTools.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatBRR.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatFLAC.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMP3.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMediaFoundation.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatOpus.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatSFZ.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatVorbis.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-SampleFormats.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-SampleIO.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Snd_flt.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Snd_fx.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Sndfile.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Sndmix.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-SoundFilePlayConfig.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Tables.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-Tagging.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-TinyFFT.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-UMXTools.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-UpgradeModule.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-WAVTools.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-WindowedFIR.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-XMTools.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-load_j2b.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-mod_specifications.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-modcommand.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-modsmp_ctrl.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-pattern.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-patternContainer.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-tuning.Plo \ soundlib/$(DEPDIR)/libopenmpt_la-tuningCollection.Plo \ soundlib/$(DEPDIR)/libopenmpttest-AudioCriticalSection.Po \ soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Po \ soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Po \ soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Po \ soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Po \ soundlib/$(DEPDIR)/libopenmpttest-Dlsbank.Po \ soundlib/$(DEPDIR)/libopenmpttest-Fastmix.Po \ soundlib/$(DEPDIR)/libopenmpttest-ITCompression.Po \ soundlib/$(DEPDIR)/libopenmpttest-ITTools.Po \ soundlib/$(DEPDIR)/libopenmpttest-InstrumentExtensions.Po \ soundlib/$(DEPDIR)/libopenmpttest-InstrumentSynth.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_667.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_669.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_amf.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_ams.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_c67.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_cba.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_dbm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_digi.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_dmf.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_dsm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_dsym.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_etx.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_far.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_fc.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_fmt.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_ftm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_gdm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_gmc.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_gt2.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_ice.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_imf.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_ims.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_it.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_itp.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_kris.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_mdl.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_med.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_mid.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_mo3.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_mod.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_mt2.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_mtm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_mus_km.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_okt.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_plm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_psm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_pt36.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_ptm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_puma.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_rtm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_s3m.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_sfx.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_stk.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_stm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_symmod.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_tcb.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_unic.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_xm.Po \ soundlib/$(DEPDIR)/libopenmpttest-Load_xmf.Po \ soundlib/$(DEPDIR)/libopenmpttest-MIDIEvents.Po \ soundlib/$(DEPDIR)/libopenmpttest-MIDIMacroParser.Po \ soundlib/$(DEPDIR)/libopenmpttest-MIDIMacros.Po \ soundlib/$(DEPDIR)/libopenmpttest-MODTools.Po \ soundlib/$(DEPDIR)/libopenmpttest-MPEGFrame.Po \ soundlib/$(DEPDIR)/libopenmpttest-Message.Po \ soundlib/$(DEPDIR)/libopenmpttest-MixFuncTable.Po \ soundlib/$(DEPDIR)/libopenmpttest-MixerLoops.Po \ soundlib/$(DEPDIR)/libopenmpttest-MixerSettings.Po \ soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Po \ soundlib/$(DEPDIR)/libopenmpttest-ModInstrument.Po \ soundlib/$(DEPDIR)/libopenmpttest-ModSample.Po \ soundlib/$(DEPDIR)/libopenmpttest-ModSequence.Po \ soundlib/$(DEPDIR)/libopenmpttest-OPL.Po \ soundlib/$(DEPDIR)/libopenmpttest-OggStream.Po \ soundlib/$(DEPDIR)/libopenmpttest-Paula.Po \ soundlib/$(DEPDIR)/libopenmpttest-PlayState.Po \ soundlib/$(DEPDIR)/libopenmpttest-PlaybackTest.Po \ soundlib/$(DEPDIR)/libopenmpttest-RowVisitor.Po \ soundlib/$(DEPDIR)/libopenmpttest-S3MTools.Po \ soundlib/$(DEPDIR)/libopenmpttest-SampleFormatBRR.Po \ soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Po \ soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Po \ soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Po \ soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Po \ soundlib/$(DEPDIR)/libopenmpttest-SampleFormatSFZ.Po \ soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Po \ soundlib/$(DEPDIR)/libopenmpttest-SampleFormats.Po \ soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Po \ soundlib/$(DEPDIR)/libopenmpttest-Snd_flt.Po \ soundlib/$(DEPDIR)/libopenmpttest-Snd_fx.Po \ soundlib/$(DEPDIR)/libopenmpttest-Sndfile.Po \ soundlib/$(DEPDIR)/libopenmpttest-Sndmix.Po \ soundlib/$(DEPDIR)/libopenmpttest-SoundFilePlayConfig.Po \ soundlib/$(DEPDIR)/libopenmpttest-Tables.Po \ soundlib/$(DEPDIR)/libopenmpttest-Tagging.Po \ soundlib/$(DEPDIR)/libopenmpttest-TinyFFT.Po \ soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Po \ soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Po \ soundlib/$(DEPDIR)/libopenmpttest-WAVTools.Po \ soundlib/$(DEPDIR)/libopenmpttest-WindowedFIR.Po \ soundlib/$(DEPDIR)/libopenmpttest-XMTools.Po \ soundlib/$(DEPDIR)/libopenmpttest-load_j2b.Po \ soundlib/$(DEPDIR)/libopenmpttest-mod_specifications.Po \ soundlib/$(DEPDIR)/libopenmpttest-modcommand.Po \ soundlib/$(DEPDIR)/libopenmpttest-modsmp_ctrl.Po \ soundlib/$(DEPDIR)/libopenmpttest-pattern.Po \ soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Po \ soundlib/$(DEPDIR)/libopenmpttest-tuning.Po \ soundlib/$(DEPDIR)/libopenmpttest-tuningCollection.Po \ soundlib/plugins/$(DEPDIR)/libopenmpt_la-DigiBoosterEcho.Plo \ soundlib/plugins/$(DEPDIR)/libopenmpt_la-LFOPlugin.Plo \ soundlib/plugins/$(DEPDIR)/libopenmpt_la-PlugInterface.Plo \ soundlib/plugins/$(DEPDIR)/libopenmpt_la-PluginManager.Plo \ soundlib/plugins/$(DEPDIR)/libopenmpt_la-SymMODEcho.Plo \ soundlib/plugins/$(DEPDIR)/libopenmpttest-DigiBoosterEcho.Po \ soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Po \ soundlib/plugins/$(DEPDIR)/libopenmpttest-PlugInterface.Po \ soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Po \ soundlib/plugins/$(DEPDIR)/libopenmpttest-SymMODEcho.Po \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Chorus.Plo \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Compressor.Plo \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOPlugin.Plo \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOUtils.Plo \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Distortion.Plo \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Echo.Plo \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Flanger.Plo \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Gargle.Plo \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-I3DL2Reverb.Plo \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-ParamEq.Plo \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-WavesReverb.Plo \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Po \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Po \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOPlugin.Po \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOUtils.Po \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Distortion.Po \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Echo.Po \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Po \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Po \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Po \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Po \ soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-WavesReverb.Po \ src/openmpt/soundfile_write/$(DEPDIR)/libopenmpttest-wav_write.Po \ test/$(DEPDIR)/libopenmpttest-TestToolsLib.Po \ test/$(DEPDIR)/libopenmpttest-mpt_tests_base.Po \ test/$(DEPDIR)/libopenmpttest-mpt_tests_binary.Po \ test/$(DEPDIR)/libopenmpttest-mpt_tests_crc.Po \ test/$(DEPDIR)/libopenmpttest-mpt_tests_endian.Po \ test/$(DEPDIR)/libopenmpttest-mpt_tests_format.Po \ test/$(DEPDIR)/libopenmpttest-mpt_tests_io.Po \ test/$(DEPDIR)/libopenmpttest-mpt_tests_parse.Po \ test/$(DEPDIR)/libopenmpttest-mpt_tests_random.Po \ test/$(DEPDIR)/libopenmpttest-mpt_tests_string.Po \ test/$(DEPDIR)/libopenmpttest-mpt_tests_string_transcode.Po \ test/$(DEPDIR)/libopenmpttest-mpt_tests_uuid.Po \ test/$(DEPDIR)/libopenmpttest-test.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(libopenmpt_la_SOURCES) $(bin_openmpt123_SOURCES) \ $(libopenmpt_example_c_SOURCES) \ $(libopenmpt_example_c_mem_SOURCES) \ $(libopenmpt_example_c_pipe_SOURCES) \ $(libopenmpt_example_c_probe_SOURCES) \ $(libopenmpt_example_c_stdout_SOURCES) \ $(libopenmpt_example_c_unsafe_SOURCES) \ $(libopenmpt_example_cxx_SOURCES) $(libopenmpttest_SOURCES) DIST_SOURCES = $(libopenmpt_la_SOURCES) \ $(am__bin_openmpt123_SOURCES_DIST) \ $(am__libopenmpt_example_c_SOURCES_DIST) \ $(am__libopenmpt_example_c_mem_SOURCES_DIST) \ $(am__libopenmpt_example_c_pipe_SOURCES_DIST) \ $(am__libopenmpt_example_c_probe_SOURCES_DIST) \ $(am__libopenmpt_example_c_stdout_SOURCES_DIST) \ $(am__libopenmpt_example_c_unsafe_SOURCES_DIST) \ $(am__libopenmpt_example_cxx_SOURCES_DIST) \ $(am__libopenmpttest_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man1_MANS) DATA = $(dist_doc_DATA) $(nobase_dist_doc_DATA) $(pkgconfig_DATA) HEADERS = $(includelibopenmpt_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` AM_RECURSIVE_TARGETS = cscope check recheck am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } am__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' RECHECK_LOGS = $(TEST_LOGS) TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) TEST_LOGS = $(am__test_logs2:.test.log=.log) TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) am__DIST_COMMON = $(srcdir)/Doxyfile.in $(srcdir)/Makefile.in \ $(top_srcdir)/build-aux/ar-lib $(top_srcdir)/build-aux/compile \ $(top_srcdir)/build-aux/config.guess \ $(top_srcdir)/build-aux/config.sub \ $(top_srcdir)/build-aux/depcomp \ $(top_srcdir)/build-aux/install-sh \ $(top_srcdir)/build-aux/ltmain.sh \ $(top_srcdir)/build-aux/missing \ $(top_srcdir)/build-aux/test-driver \ $(top_srcdir)/libopenmpt/libopenmpt.pc.in README.md \ build-aux/ar-lib build-aux/compile build-aux/config.guess \ build-aux/config.sub build-aux/depcomp build-aux/install-sh \ build-aux/ltmain.sh build-aux/missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip # Exists only to be overridden by the user if desired. AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CXXSTDLIB_PCLIBSPRIVATE = @CXXSTDLIB_PCLIBSPRIVATE@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN_PAPER_SIZE = @DOXYGEN_PAPER_SIZE@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ DX_CONFIG = @DX_CONFIG@ DX_DOCDIR = @DX_DOCDIR@ DX_DOT = @DX_DOT@ DX_DOXYGEN = @DX_DOXYGEN@ DX_DVIPS = @DX_DVIPS@ DX_EGREP = @DX_EGREP@ DX_ENV = @DX_ENV@ DX_FLAG_chi = @DX_FLAG_chi@ DX_FLAG_chm = @DX_FLAG_chm@ DX_FLAG_doc = @DX_FLAG_doc@ DX_FLAG_dot = @DX_FLAG_dot@ DX_FLAG_html = @DX_FLAG_html@ DX_FLAG_man = @DX_FLAG_man@ DX_FLAG_pdf = @DX_FLAG_pdf@ DX_FLAG_ps = @DX_FLAG_ps@ DX_FLAG_rtf = @DX_FLAG_rtf@ DX_FLAG_xml = @DX_FLAG_xml@ DX_HHC = @DX_HHC@ DX_LATEX = @DX_LATEX@ DX_MAKEINDEX = @DX_MAKEINDEX@ DX_PDFLATEX = @DX_PDFLATEX@ DX_PERL = @DX_PERL@ DX_PROJECT = @DX_PROJECT@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FILECMD = @FILECMD@ FLAC_CFLAGS = @FLAC_CFLAGS@ FLAC_LIBS = @FLAC_LIBS@ GLOBAL_CFLAGS = @GLOBAL_CFLAGS@ GLOBAL_CPPFLAGS = @GLOBAL_CPPFLAGS@ GLOBAL_CXXFLAGS = @GLOBAL_CXXFLAGS@ GREP = @GREP@ HAVE_CXX17 = @HAVE_CXX17@ HAVE_CXX20 = @HAVE_CXX20@ HAVE_CXX23 = @HAVE_CXX23@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBOPENMPTTEST_WIN32_LIBS = @LIBOPENMPTTEST_WIN32_LIBS@ LIBOPENMPT_LIBS_PRIVATE = @LIBOPENMPT_LIBS_PRIVATE@ LIBOPENMPT_LTVER_AGE = @LIBOPENMPT_LTVER_AGE@ LIBOPENMPT_LTVER_CURRENT = @LIBOPENMPT_LTVER_CURRENT@ LIBOPENMPT_LTVER_REVISION = @LIBOPENMPT_LTVER_REVISION@ LIBOPENMPT_REQUIRES_PRIVATE = @LIBOPENMPT_REQUIRES_PRIVATE@ LIBOPENMPT_WIN32_LIBS = @LIBOPENMPT_WIN32_LIBS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MPG123_CFLAGS = @MPG123_CFLAGS@ MPG123_LIBS = @MPG123_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OGG_CFLAGS = @OGG_CFLAGS@ OGG_LIBS = @OGG_LIBS@ OPENMPT123_WIN32_LIBS = @OPENMPT123_WIN32_LIBS@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORTAUDIOCPP_CFLAGS = @PORTAUDIOCPP_CFLAGS@ PORTAUDIOCPP_LIBS = @PORTAUDIOCPP_LIBS@ PORTAUDIO_CFLAGS = @PORTAUDIO_CFLAGS@ PORTAUDIO_LIBS = @PORTAUDIO_LIBS@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_CXX = @PTHREAD_CXX@ PTHREAD_LIBS = @PTHREAD_LIBS@ PULSEAUDIO_CFLAGS = @PULSEAUDIO_CFLAGS@ PULSEAUDIO_LIBS = @PULSEAUDIO_LIBS@ RANLIB = @RANLIB@ SDL2_CFLAGS = @SDL2_CFLAGS@ SDL2_LIBS = @SDL2_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ VERSION = @VERSION@ VORBISFILE_CFLAGS = @VORBISFILE_CFLAGS@ VORBISFILE_LIBS = @VORBISFILE_LIBS@ VORBIS_CFLAGS = @VORBIS_CFLAGS@ VORBIS_LIBS = @VORBIS_LIBS@ WIN32_CFLAGS = @WIN32_CFLAGS@ WIN32_CONSOLE_CFLAGS = @WIN32_CONSOLE_CFLAGS@ WIN32_CONSOLE_CXXFLAGS = @WIN32_CONSOLE_CXXFLAGS@ WIN32_CPPFLAGS = @WIN32_CPPFLAGS@ WIN32_CXXFLAGS = @WIN32_CXXFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ ax_pthread_config = @ax_pthread_config@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ ACLOCAL_AMFLAGS = -I m4 --install EXTRA_DIST = .clang-format m4/emptydir libopenmpt/libopenmpt.pc.in \ LICENSE README.md Doxyfile.in doc/contributing.md \ doc/libopenmpt_styleguide.md doc/libopenmpt/changelog.md \ doc/libopenmpt/dependencies.md \ doc/libopenmpt/gettingstarted.md doc/libopenmpt/index.dox \ doc/libopenmpt/packaging.md doc/libopenmpt/tests.md \ doc/module_formats.md doc/openmpt_styleguide.md \ libopenmpt/.clang-format libopenmpt/libopenmpt_version.mk \ openmpt123/.clang-format src/mpt/.clang-format \ src/mpt/LICENSE.BSD-3-Clause.txt src/mpt/LICENSE.BSL-1.0.txt \ test/test.xm test/test.s3m test/test.mod test/test.mptm \ man/openmpt123.1 examples/.clang-format \ libopenmpt/bindings/freebasic/libopenmpt.bi \ libopenmpt/bindings/freebasic/libopenmpt_ext.bi MOSTLYCLEANFILES = $(DX_CLEANFILES) dist_doc_DATA = LICENSE README.md nobase_dist_doc_DATA = examples/libopenmpt_example_cxx.cpp \ examples/libopenmpt_example_c_mem.c \ examples/libopenmpt_example_c_unsafe.c \ examples/libopenmpt_example_c.c \ examples/libopenmpt_example_c_pipe.c \ examples/libopenmpt_example_c_probe.c \ examples/libopenmpt_example_c_stdout.c lib_LTLIBRARIES = libopenmpt.la @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_pipe_SOURCES = examples/libopenmpt_example_c_pipe.c @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_probe_SOURCES = examples/libopenmpt_example_c_probe.c @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_stdout_SOURCES = examples/libopenmpt_example_c_stdout.c @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_SOURCES = examples/libopenmpt_example_c.c @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_mem_SOURCES = examples/libopenmpt_example_c_mem.c @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_unsafe_SOURCES = examples/libopenmpt_example_c_unsafe.c @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIOCPP_TRUE@libopenmpt_example_cxx_SOURCES = examples/libopenmpt_example_cxx.cpp @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_pipe_CPPFLAGS = $(WIN32_CPPFLAGS) @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_probe_CPPFLAGS = $(WIN32_CPPFLAGS) @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_stdout_CPPFLAGS = $(WIN32_CPPFLAGS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_CPPFLAGS = $(WIN32_CPPFLAGS) $(PORTAUDIO_CFLAGS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_mem_CPPFLAGS = $(WIN32_CPPFLAGS) $(PORTAUDIO_CFLAGS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_unsafe_CPPFLAGS = $(WIN32_CPPFLAGS) $(PORTAUDIO_CFLAGS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIOCPP_TRUE@libopenmpt_example_cxx_CPPFLAGS = $(WIN32_CPPFLAGS) $(PORTAUDIOCPP_CFLAGS) @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_pipe_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_probe_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_stdout_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_mem_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_unsafe_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIOCPP_TRUE@libopenmpt_example_cxx_CXXFLAGS = $(GLOBAL_CXXFLAGS) $(WIN32_CXXFLAGS) $(WIN32_CONSOLE_CXXFLAGS) @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_pipe_LDADD = $(lib_LTLIBRARIES) @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_probe_LDADD = $(lib_LTLIBRARIES) @ENABLE_EXAMPLES_TRUE@libopenmpt_example_c_stdout_LDADD = $(lib_LTLIBRARIES) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_LDADD = $(lib_LTLIBRARIES) $(PORTAUDIO_LIBS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_mem_LDADD = $(lib_LTLIBRARIES) $(PORTAUDIO_LIBS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE@libopenmpt_example_c_unsafe_LDADD = $(lib_LTLIBRARIES) $(PORTAUDIO_LIBS) @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIOCPP_TRUE@libopenmpt_example_cxx_LDADD = $(lib_LTLIBRARIES) $(PORTAUDIOCPP_LIBS) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libopenmpt/libopenmpt.pc includelibopenmptdir = $(includedir)/libopenmpt includelibopenmpt_HEADERS = libopenmpt/libopenmpt.h \ libopenmpt/libopenmpt.hpp libopenmpt/libopenmpt_version.h \ libopenmpt/libopenmpt_config.h \ libopenmpt/libopenmpt_stream_callbacks_buffer.h \ libopenmpt/libopenmpt_stream_callbacks_fd.h \ libopenmpt/libopenmpt_stream_callbacks_file.h \ libopenmpt/libopenmpt_stream_callbacks_file_mingw.h \ libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h \ libopenmpt/libopenmpt_stream_callbacks_file_posix.h \ libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h \ libopenmpt/libopenmpt_ext.h libopenmpt/libopenmpt_ext.hpp #MPT_FILES_SRC_MPT += src/mpt/crypto/exception.hpp #MPT_FILES_SRC_MPT += src/mpt/crypto/hash.hpp #MPT_FILES_SRC_MPT += src/mpt/crypto/jwk.hpp #MPT_FILES_SRC_MPT += src/mpt/fs/common_directories.hpp #MPT_FILES_SRC_MPT += src/mpt/fs/fs.hpp #MPT_FILES_SRC_MPT += src/mpt/json/json.hpp #MPT_FILES_SRC_MPT += src/mpt/library/library.hpp #MPT_FILES_SRC_MPT += src/mpt/uuid_namespace/uuid_namespace.hpp #MPT_FILES_SRC_MPT += src/mpt/crypto/tests/tests_crypto.hpp MPT_FILES_SRC_MPT = src/mpt/arch/arch.hpp \ src/mpt/arch/feature_flags.hpp src/mpt/arch/x86_amd64.hpp \ src/mpt/audio/sample.hpp src/mpt/audio/span.hpp \ src/mpt/base/algorithm.hpp src/mpt/base/aligned_array.hpp \ src/mpt/base/alloc.hpp src/mpt/base/arithmetic_shift.hpp \ src/mpt/base/array.hpp src/mpt/base/bit.hpp \ src/mpt/base/check_platform.hpp \ src/mpt/base/compiletime_warning.hpp \ src/mpt/base/constexpr_throw.hpp src/mpt/base/debugging.hpp \ src/mpt/base/detect.hpp src/mpt/base/detect_arch.hpp \ src/mpt/base/detect_compiler.hpp src/mpt/base/detect_libc.hpp \ src/mpt/base/detect_libcxx.hpp src/mpt/base/detect_os.hpp \ src/mpt/base/detect_quirks.hpp src/mpt/base/float.hpp \ src/mpt/base/integer.hpp src/mpt/base/macros.hpp \ src/mpt/base/math.hpp src/mpt/base/memory.hpp \ src/mpt/base/namespace.hpp src/mpt/base/numbers.hpp \ src/mpt/base/numeric.hpp src/mpt/base/pointer.hpp \ src/mpt/base/preprocessor.hpp src/mpt/base/saturate_cast.hpp \ src/mpt/base/saturate_round.hpp src/mpt/base/secure.hpp \ src/mpt/base/semantic_version.hpp src/mpt/base/size.hpp \ src/mpt/base/source_location.hpp src/mpt/base/span.hpp \ src/mpt/base/type_traits.hpp src/mpt/base/utility.hpp \ src/mpt/base/version.hpp src/mpt/base/wrapping_divide.hpp \ src/mpt/binary/base64.hpp src/mpt/binary/base64url.hpp \ src/mpt/binary/hex.hpp src/mpt/check/compiler.hpp \ src/mpt/check/libc.hpp src/mpt/check/libcxx.hpp \ src/mpt/check/mfc.hpp src/mpt/check/windows.hpp \ src/mpt/crc/crc.hpp src/mpt/detect/dl.hpp \ src/mpt/detect/ltdl.hpp src/mpt/detect/mfc.hpp \ src/mpt/detect/nlohmann_json.hpp \ src/mpt/endian/floatingpoint.hpp src/mpt/endian/int24.hpp \ src/mpt/endian/integer.hpp src/mpt/endian/type_traits.hpp \ src/mpt/environment/environment.hpp \ src/mpt/exception/exception.hpp \ src/mpt/exception/exception_text.hpp \ src/mpt/exception/logic_error.hpp \ src/mpt/exception/runtime_error.hpp src/mpt/format/concat.hpp \ src/mpt/format/default_floatingpoint.hpp \ src/mpt/format/default_formatter.hpp \ src/mpt/format/default_integer.hpp \ src/mpt/format/default_string.hpp src/mpt/format/helpers.hpp \ src/mpt/format/join.hpp src/mpt/format/message.hpp \ src/mpt/format/message_macros.hpp src/mpt/format/simple.hpp \ src/mpt/format/simple_floatingpoint.hpp \ src/mpt/format/simple_integer.hpp \ src/mpt/format/simple_spec.hpp src/mpt/io/base.hpp \ src/mpt/io/io.hpp src/mpt/io/io_span.hpp \ src/mpt/io/io_stdstream.hpp src/mpt/io/io_virtual_wrapper.hpp \ src/mpt/io_file/fileref.hpp src/mpt/io_file/fstream.hpp \ src/mpt/io_file/inputfile.hpp src/mpt/io_file/outputfile.hpp \ src/mpt/io_file_adapter/fileadapter.hpp \ src/mpt/io_file_read/inputfile_filecursor.hpp \ src/mpt/io_file_unique/unique_basename.hpp \ src/mpt/io_file_unique/unique_tempfilename.hpp \ src/mpt/io_read/callbackstream.hpp \ src/mpt/io_read/filecursor.hpp \ src/mpt/io_read/filecursor_callbackstream.hpp \ src/mpt/io_read/filecursor_filename_traits.hpp \ src/mpt/io_read/filecursor_memory.hpp \ src/mpt/io_read/filecursor_stdstream.hpp \ src/mpt/io_read/filecursor_traits_filedata.hpp \ src/mpt/io_read/filecursor_traits_memory.hpp \ src/mpt/io_read/filedata.hpp src/mpt/io_read/filedata_base.hpp \ src/mpt/io_read/filedata_base_buffered.hpp \ src/mpt/io_read/filedata_base_seekable.hpp \ src/mpt/io_read/filedata_base_unseekable.hpp \ src/mpt/io_read/filedata_base_unseekable_buffer.hpp \ src/mpt/io_read/filedata_callbackstream.hpp \ src/mpt/io_read/filedata_memory.hpp \ src/mpt/io_read/filedata_stdstream.hpp \ src/mpt/io_read/filereader.hpp src/mpt/io_write/buffer.hpp \ src/mpt/main/main.hpp src/mpt/mutex/mutex.hpp \ src/mpt/osinfo/class.hpp src/mpt/osinfo/dos_memory.hpp \ src/mpt/osinfo/dos_version.hpp \ src/mpt/osinfo/windows_version.hpp \ src/mpt/osinfo/windows_wine_version.hpp \ src/mpt/out_of_memory/out_of_memory.hpp \ src/mpt/parse/parse.hpp src/mpt/parse/split.hpp \ src/mpt/path/basic_path.hpp src/mpt/path/native_path.hpp \ src/mpt/path/path.hpp src/mpt/path/os_path.hpp \ src/mpt/path/os_path_long.hpp src/mpt/random/any_engine.hpp \ src/mpt/random/crand.hpp src/mpt/random/default_engines.hpp \ src/mpt/random/device.hpp src/mpt/random/engine.hpp \ src/mpt/random/engine_lcg.hpp src/mpt/random/random.hpp \ src/mpt/random/seed.hpp src/mpt/string/buffer.hpp \ src/mpt/string/types.hpp src/mpt/string/utility.hpp \ src/mpt/string_transcode/transcode.hpp \ src/mpt/string_transcode/macros.hpp \ src/mpt/system_error/system_error.hpp src/mpt/test/test.hpp \ src/mpt/test/test_macros.hpp src/mpt/uuid/guid.hpp \ src/mpt/uuid/uuid.hpp \ src/mpt/base/tests/tests_base_arithmetic_shift.hpp \ src/mpt/base/tests/tests_base_bit.hpp \ src/mpt/base/tests/tests_base_math.hpp \ src/mpt/base/tests/tests_base_numeric.hpp \ src/mpt/base/tests/tests_base_saturate_cast.hpp \ src/mpt/base/tests/tests_base_saturate_round.hpp \ src/mpt/base/tests/tests_base_wrapping_divide.hpp \ src/mpt/binary/tests/tests_binary.hpp \ src/mpt/crc/tests/tests_crc.hpp \ src/mpt/endian/tests/tests_endian_floatingpoint.hpp \ src/mpt/endian/tests/tests_endian_int24.hpp \ src/mpt/endian/tests/tests_endian_integer.hpp \ src/mpt/format/tests/tests_format_message.hpp \ src/mpt/format/tests/tests_format_simple.hpp \ src/mpt/io/tests/tests_io.hpp \ src/mpt/parse/tests/tests_parse.hpp \ src/mpt/random/tests/tests_random.hpp \ src/mpt/string/tests/tests_string_buffer.hpp \ src/mpt/string/tests/tests_string_utility.hpp \ src/mpt/string_transcode/tests/tests_string_transcode.hpp \ src/mpt/uuid/tests/tests_uuid.hpp #MPT_FILES_SRC_MPT += src/mpt/uuid_namespace/tests/tests_uuid_namespace.hpp MPT_FILES_SRC_OPENMPT = src/openmpt/all/BuildSettings.hpp \ src/openmpt/all/PlatformFixes.hpp src/openmpt/base/Endian.hpp \ src/openmpt/base/FlagSet.hpp src/openmpt/base/Int24.hpp \ src/openmpt/base/Types.hpp \ src/openmpt/fileformat_base/magic.hpp \ src/openmpt/logging/Logger.hpp src/openmpt/random/ModPlug.hpp \ src/openmpt/soundbase/Copy.hpp \ src/openmpt/soundbase/CopyMix.hpp \ src/openmpt/soundbase/Dither.hpp \ src/openmpt/soundbase/DitherModPlug.hpp \ src/openmpt/soundbase/DitherNone.hpp \ src/openmpt/soundbase/DitherSimple.hpp \ src/openmpt/soundbase/MixSample.hpp \ src/openmpt/soundbase/MixSampleConvert.hpp \ src/openmpt/soundbase/SampleClip.hpp \ src/openmpt/soundbase/SampleClipFixedPoint.hpp \ src/openmpt/soundbase/SampleConvert.hpp \ src/openmpt/soundbase/SampleConvertFixedPoint.hpp \ src/openmpt/soundbase/SampleDecode.hpp \ src/openmpt/soundbase/SampleEncode.hpp \ src/openmpt/soundbase/SampleFormat.hpp \ src/openmpt/soundfile_data/tags.hpp \ src/openmpt/soundfile_data/wav.hpp MPT_FILES_SRC_OPENMPT_SOUNDFILE_WRITE = \ src/openmpt/soundfile_write/wav_write.cpp \ src/openmpt/soundfile_write/wav_write.hpp MPT_FILES_COMMON = common/BuildSettings.h \ common/BuildSettingsCompiler.h common/ComponentManager.cpp \ common/ComponentManager.h common/FileReader.h \ common/FileReaderFwd.h common/GzipWriter.h common/Logging.cpp \ common/Logging.h common/misc_util.h common/mptAssert.h \ common/mptBaseMacros.h common/mptBaseTypes.h \ common/mptBaseUtils.h common/mptCPU.h common/mptFileIO.h \ common/mptFileTemporary.h common/mptFileType.cpp \ common/mptFileType.h common/mptPathString.cpp \ common/mptPathString.h common/mptRandom.cpp common/mptRandom.h \ common/mptString.h common/mptStringBuffer.cpp \ common/mptStringBuffer.h common/mptStringFormat.h \ common/mptTime.cpp common/mptTime.h common/Profiler.cpp \ common/Profiler.h common/serialization_utils.cpp \ common/serialization_utils.h common/stdafx.h \ common/version.cpp common/version.h common/versionNumber.h MPT_FILES_SOUNDLIB = soundlib/AudioCriticalSection.cpp \ soundlib/AudioCriticalSection.h soundlib/AudioReadTarget.h \ soundlib/BitReader.h soundlib/ContainerMMCMP.cpp \ soundlib/ContainerPP20.cpp soundlib/ContainerUMX.cpp \ soundlib/ContainerXPK.cpp soundlib/Container.h \ soundlib/Dlsbank.cpp soundlib/Dlsbank.h soundlib/Fastmix.cpp \ soundlib/FloatMixer.h soundlib/InstrumentExtensions.cpp \ soundlib/InstrumentSynth.cpp soundlib/InstrumentSynth.h \ soundlib/IntMixer.h soundlib/ITCompression.cpp \ soundlib/ITCompression.h soundlib/ITTools.cpp \ soundlib/ITTools.h soundlib/Load_667.cpp soundlib/Load_669.cpp \ soundlib/Load_amf.cpp soundlib/Load_ams.cpp \ soundlib/Load_c67.cpp soundlib/Load_cba.cpp \ soundlib/Load_dbm.cpp soundlib/Load_digi.cpp \ soundlib/Load_dmf.cpp soundlib/Load_dsm.cpp \ soundlib/Load_dsym.cpp soundlib/Load_dtm.cpp \ soundlib/Loaders.h soundlib/Load_etx.cpp soundlib/Load_far.cpp \ soundlib/Load_fc.cpp soundlib/Load_fmt.cpp \ soundlib/Load_ftm.cpp soundlib/Load_gdm.cpp \ soundlib/Load_gmc.cpp soundlib/Load_gt2.cpp \ soundlib/Load_ice.cpp soundlib/Load_imf.cpp \ soundlib/Load_ims.cpp soundlib/Load_it.cpp \ soundlib/Load_itp.cpp soundlib/load_j2b.cpp \ soundlib/Load_kris.cpp soundlib/Load_mdl.cpp \ soundlib/Load_med.cpp soundlib/Load_mid.cpp \ soundlib/Load_mo3.cpp soundlib/Load_mod.cpp \ soundlib/Load_mt2.cpp soundlib/Load_mtm.cpp \ soundlib/Load_mus_km.cpp soundlib/Load_okt.cpp \ soundlib/Load_plm.cpp soundlib/Load_psm.cpp \ soundlib/Load_pt36.cpp soundlib/Load_ptm.cpp \ soundlib/Load_puma.cpp soundlib/Load_rtm.cpp \ soundlib/Load_s3m.cpp soundlib/Load_sfx.cpp \ soundlib/Load_stk.cpp soundlib/Load_stm.cpp \ soundlib/Load_stp.cpp soundlib/Load_symmod.cpp \ soundlib/Load_tcb.cpp soundlib/Load_uax.cpp \ soundlib/Load_ult.cpp soundlib/Load_unic.cpp \ soundlib/Load_wav.cpp soundlib/Load_xm.cpp \ soundlib/Load_xmf.cpp soundlib/Message.cpp soundlib/Message.h \ soundlib/MIDIEvents.cpp soundlib/MIDIEvents.h \ soundlib/MIDIMacroParser.cpp soundlib/MIDIMacroParser.h \ soundlib/MIDIMacros.cpp soundlib/MIDIMacros.h soundlib/Mixer.h \ soundlib/MixerInterface.h soundlib/MixerLoops.cpp \ soundlib/MixerLoops.h soundlib/MixerSettings.cpp \ soundlib/MixerSettings.h soundlib/MixFuncTable.cpp \ soundlib/MixFuncTable.h soundlib/ModChannel.cpp \ soundlib/ModChannel.h soundlib/modcommand.cpp \ soundlib/modcommand.h soundlib/ModInstrument.cpp \ soundlib/ModInstrument.h soundlib/ModSample.cpp \ soundlib/ModSample.h soundlib/ModSampleCopy.h \ soundlib/ModSequence.cpp soundlib/ModSequence.h \ soundlib/modsmp_ctrl.cpp soundlib/modsmp_ctrl.h \ soundlib/mod_specifications.cpp soundlib/mod_specifications.h \ soundlib/MODTools.cpp soundlib/MODTools.h \ soundlib/MPEGFrame.cpp soundlib/MPEGFrame.h \ soundlib/OggStream.cpp soundlib/OggStream.h soundlib/opal.h \ soundlib/OPL.cpp soundlib/OPL.h soundlib/Paula.cpp \ soundlib/Paula.h soundlib/patternContainer.cpp \ soundlib/patternContainer.h soundlib/pattern.cpp \ soundlib/pattern.h soundlib/PlaybackTest.cpp \ soundlib/PlaybackTest.h soundlib/PlayState.cpp \ soundlib/PlayState.h soundlib/Resampler.h \ soundlib/RowVisitor.cpp soundlib/RowVisitor.h \ soundlib/S3MTools.cpp soundlib/S3MTools.h \ soundlib/SampleCopy.h soundlib/SampleFormats.cpp \ soundlib/SampleFormatBRR.cpp soundlib/SampleFormatFLAC.cpp \ soundlib/SampleFormatMediaFoundation.cpp \ soundlib/SampleFormatMP3.cpp soundlib/SampleFormatOpus.cpp \ soundlib/SampleFormatSFZ.cpp soundlib/SampleFormatVorbis.cpp \ soundlib/SampleIO.cpp soundlib/SampleIO.h \ soundlib/SampleNormalize.h soundlib/Snd_defs.h \ soundlib/Sndfile.cpp soundlib/Sndfile.h soundlib/Snd_flt.cpp \ soundlib/Snd_fx.cpp soundlib/Sndmix.cpp \ soundlib/SoundFilePlayConfig.cpp \ soundlib/SoundFilePlayConfig.h soundlib/Tables.cpp \ soundlib/Tables.h soundlib/Tagging.cpp soundlib/Tagging.h \ soundlib/TinyFFT.cpp soundlib/TinyFFT.h soundlib/tuningbase.h \ soundlib/tuningCollection.cpp soundlib/tuningcollection.h \ soundlib/tuning.cpp soundlib/tuning.h soundlib/UMXTools.cpp \ soundlib/UMXTools.h soundlib/UpgradeModule.cpp \ soundlib/WAVTools.cpp soundlib/WAVTools.h \ soundlib/WindowedFIR.cpp soundlib/WindowedFIR.h \ soundlib/XMTools.cpp soundlib/XMTools.h \ soundlib/plugins/dmo/DMOPlugin.cpp \ soundlib/plugins/dmo/DMOPlugin.h \ soundlib/plugins/dmo/DMOUtils.cpp \ soundlib/plugins/dmo/DMOUtils.h \ soundlib/plugins/dmo/Chorus.cpp soundlib/plugins/dmo/Chorus.h \ soundlib/plugins/dmo/Compressor.cpp \ soundlib/plugins/dmo/Compressor.h \ soundlib/plugins/dmo/Distortion.cpp \ soundlib/plugins/dmo/Distortion.h \ soundlib/plugins/dmo/Echo.cpp soundlib/plugins/dmo/Echo.h \ soundlib/plugins/dmo/Flanger.cpp \ soundlib/plugins/dmo/Flanger.h soundlib/plugins/dmo/Gargle.cpp \ soundlib/plugins/dmo/Gargle.h \ soundlib/plugins/dmo/I3DL2Reverb.cpp \ soundlib/plugins/dmo/I3DL2Reverb.h \ soundlib/plugins/dmo/ParamEq.cpp \ soundlib/plugins/dmo/ParamEq.h \ soundlib/plugins/dmo/WavesReverb.cpp \ soundlib/plugins/dmo/WavesReverb.h \ soundlib/plugins/DigiBoosterEcho.cpp \ soundlib/plugins/DigiBoosterEcho.h \ soundlib/plugins/LFOPlugin.cpp soundlib/plugins/LFOPlugin.h \ soundlib/plugins/PluginManager.cpp \ soundlib/plugins/PluginManager.h \ soundlib/plugins/PluginMixBuffer.h \ soundlib/plugins/PluginStructs.h \ soundlib/plugins/PlugInterface.cpp \ soundlib/plugins/PlugInterface.h \ soundlib/plugins/SymMODEcho.cpp soundlib/plugins/SymMODEcho.h MPT_FILES_SOUNDDSP = sounddsp/AGC.cpp sounddsp/AGC.h sounddsp/DSP.cpp \ sounddsp/DSP.h sounddsp/EQ.cpp sounddsp/EQ.h \ sounddsp/Reverb.cpp sounddsp/Reverb.h libopenmpt_la_LDFLAGS = -version-info $(LIBOPENMPT_LTVER_CURRENT):$(LIBOPENMPT_LTVER_REVISION):$(LIBOPENMPT_LTVER_AGE) -no-undefined libopenmpt_la_CPPFLAGS = $(GLOBAL_CPPFLAGS) $(WIN32_CPPFLAGS) \ -DLIBOPENMPT_BUILD -I$(srcdir)/ -I$(srcdir)/src \ -I$(srcdir)/common $(ZLIB_CFLAGS) $(MPG123_CFLAGS) \ $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) libopenmpt_la_CXXFLAGS = $(GLOBAL_CXXFLAGS) $(WIN32_CXXFLAGS) \ $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) \ $(VORBISFILE_CFLAGS) libopenmpt_la_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(ZLIB_CFLAGS) \ $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) \ $(VORBISFILE_CFLAGS) libopenmpt_la_LIBADD = $(ZLIB_LIBS) $(MPG123_LIBS) $(OGG_LIBS) \ $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(LIBOPENMPT_WIN32_LIBS) libopenmpt_la_SOURCES = build/svn_version/svn_version.h \ $(MPT_FILES_SRC_MPT) $(MPT_FILES_SRC_OPENMPT) \ $(MPT_FILES_COMMON) $(MPT_FILES_SOUNDBASE) \ $(MPT_FILES_SOUNDLIB) $(MPT_FILES_SOUNDDSP) \ libopenmpt/libopenmpt_c.cpp libopenmpt/libopenmpt_cxx.cpp \ libopenmpt/libopenmpt_ext_impl.cpp \ libopenmpt/libopenmpt_impl.cpp libopenmpt/libopenmpt_config.h \ libopenmpt/libopenmpt_ext.h libopenmpt/libopenmpt_ext.hpp \ libopenmpt/libopenmpt_ext_impl.hpp libopenmpt/libopenmpt.h \ libopenmpt/libopenmpt.hpp libopenmpt/libopenmpt_impl.hpp \ libopenmpt/libopenmpt_internal.h \ libopenmpt/libopenmpt_stream_callbacks_buffer.h \ libopenmpt/libopenmpt_stream_callbacks_fd.h \ libopenmpt/libopenmpt_stream_callbacks_file.h \ libopenmpt/libopenmpt_stream_callbacks_file_mingw.h \ libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h \ libopenmpt/libopenmpt_stream_callbacks_file_posix.h \ libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h \ libopenmpt/libopenmpt_version.h @ENABLE_TESTS_TRUE@libopenmpttest_CPPFLAGS = $(GLOBAL_CPPFLAGS) \ @ENABLE_TESTS_TRUE@ $(WIN32_CPPFLAGS) -DLIBOPENMPT_BUILD \ @ENABLE_TESTS_TRUE@ -DLIBOPENMPT_BUILD_TEST -I$(srcdir)/ \ @ENABLE_TESTS_TRUE@ -I$(srcdir)/src -I$(srcdir)/common \ @ENABLE_TESTS_TRUE@ $(ZLIB_CFLAGS) $(MPG123_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(OGG_CFLAGS) $(VORBIS_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(VORBISFILE_CFLAGS) @ENABLE_TESTS_TRUE@libopenmpttest_CXXFLAGS = $(GLOBAL_CXXFLAGS) \ @ENABLE_TESTS_TRUE@ $(WIN32_CXXFLAGS) $(ZLIB_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(MPG123_CFLAGS) $(OGG_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(WIN32_CONSOLE_CXXFLAGS) @ENABLE_TESTS_TRUE@libopenmpttest_CFLAGS = $(GLOBAL_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(WIN32_CFLAGS) $(ZLIB_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(MPG123_CFLAGS) $(OGG_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(WIN32_CONSOLE_CFLAGS) @ENABLE_TESTS_TRUE@libopenmpttest_LDADD = $(ZLIB_LIBS) $(MPG123_LIBS) \ @ENABLE_TESTS_TRUE@ $(OGG_LIBS) $(VORBIS_LIBS) \ @ENABLE_TESTS_TRUE@ $(VORBISFILE_LIBS) $(LIBOPENMPT_WIN32_LIBS) \ @ENABLE_TESTS_TRUE@ $(LIBOPENMPTTEST_WIN32_LIBS) #libopenmpttest_SOURCES += test/mpt_tests_crypto.cpp #libopenmpttest_SOURCES += test/mpt_tests_uuid_namespace.cpp @ENABLE_TESTS_TRUE@libopenmpttest_SOURCES = test/mpt_tests_base.cpp \ @ENABLE_TESTS_TRUE@ test/mpt_tests_binary.cpp \ @ENABLE_TESTS_TRUE@ test/mpt_tests_crc.cpp \ @ENABLE_TESTS_TRUE@ test/mpt_tests_endian.cpp \ @ENABLE_TESTS_TRUE@ test/mpt_tests_format.cpp \ @ENABLE_TESTS_TRUE@ test/mpt_tests_io.cpp \ @ENABLE_TESTS_TRUE@ test/mpt_tests_parse.cpp \ @ENABLE_TESTS_TRUE@ test/mpt_tests_random.cpp \ @ENABLE_TESTS_TRUE@ test/mpt_tests_string.cpp \ @ENABLE_TESTS_TRUE@ test/mpt_tests_string_transcode.cpp \ @ENABLE_TESTS_TRUE@ test/mpt_tests_uuid.cpp test/test.cpp \ @ENABLE_TESTS_TRUE@ test/test.h test/TestTools.h \ @ENABLE_TESTS_TRUE@ test/TestToolsLib.cpp test/TestToolsLib.h \ @ENABLE_TESTS_TRUE@ test/TestToolsTracker.h \ @ENABLE_TESTS_TRUE@ build/svn_version/svn_version.h \ @ENABLE_TESTS_TRUE@ $(MPT_FILES_SRC_MPT) \ @ENABLE_TESTS_TRUE@ $(MPT_FILES_SRC_OPENMPT) \ @ENABLE_TESTS_TRUE@ $(MPT_FILES_SRC_OPENMPT_SOUNDFILE_WRITE) \ @ENABLE_TESTS_TRUE@ $(MPT_FILES_COMMON) $(MPT_FILES_SOUNDBASE) \ @ENABLE_TESTS_TRUE@ $(MPT_FILES_SOUNDLIB) $(MPT_FILES_SOUNDDSP) \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_c.cpp \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_cxx.cpp \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_ext_impl.cpp \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_impl.cpp \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_config.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_ext.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_ext.hpp \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_ext_impl.hpp \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt.hpp \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_impl.hpp \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_internal.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_stream_callbacks_buffer.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_stream_callbacks_fd.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_stream_callbacks_file.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_stream_callbacks_file_mingw.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_stream_callbacks_file_posix.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_version.h \ @ENABLE_TESTS_TRUE@ libopenmpt/libopenmpt_test/libopenmpt_test.cpp @ENABLE_OPENMPT123_TRUE@bin_openmpt123_CPPFLAGS = $(GLOBAL_CPPFLAGS) \ @ENABLE_OPENMPT123_TRUE@ $(WIN32_CPPFLAGS) -I$(srcdir)/src \ @ENABLE_OPENMPT123_TRUE@ $(PORTAUDIO_CFLAGS) \ @ENABLE_OPENMPT123_TRUE@ $(PULSEAUDIO_CFLAGS) $(SDL2_CFLAGS) \ @ENABLE_OPENMPT123_TRUE@ $(SNDFILE_CFLAGS) $(FLAC_CFLAGS) @ENABLE_OPENMPT123_TRUE@bin_openmpt123_CXXFLAGS = $(GLOBAL_CXXFLAGS) \ @ENABLE_OPENMPT123_TRUE@ $(WIN32_CXXFLAGS) \ @ENABLE_OPENMPT123_TRUE@ $(WIN32_CONSOLE_CXXFLAGS) @ENABLE_OPENMPT123_TRUE@bin_openmpt123_LDADD = libopenmpt.la $(PORTAUDIO_LIBS) $(PULSEAUDIO_LIBS) $(SDL2_LIBS) $(SNDFILE_LIBS) $(FLAC_LIBS) $(OPENMPT123_WIN32_LIBS) @ENABLE_OPENMPT123_TRUE@bin_openmpt123_SOURCES = $(MPT_FILES_SRC_MPT) \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_allegro42.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_config.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123.cpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_exception.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_flac.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_mmio.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_portaudio.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_pulseaudio.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_raw.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_sdl2.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_sndfile.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_stdio.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_stdout.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_terminal.hpp \ @ENABLE_OPENMPT123_TRUE@ openmpt123/openmpt123_waveout.hpp @ENABLE_OPENMPT123_TRUE@man1_MANS = man/openmpt123.1 all: all-am .SUFFIXES: .SUFFIXES: .c .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): libopenmpt/libopenmpt.pc: $(top_builddir)/config.status $(top_srcdir)/libopenmpt/libopenmpt.pc.in cd $(top_builddir) && $(SHELL) ./config.status $@ Doxyfile: $(top_builddir)/config.status $(srcdir)/Doxyfile.in cd $(top_builddir) && $(SHELL) ./config.status $@ install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } common/$(am__dirstamp): @$(MKDIR_P) common @: > common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) common/$(DEPDIR) @: > common/$(DEPDIR)/$(am__dirstamp) common/libopenmpt_la-ComponentManager.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpt_la-Logging.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpt_la-mptFileType.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpt_la-mptPathString.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpt_la-mptRandom.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpt_la-mptStringBuffer.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpt_la-mptTime.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpt_la-Profiler.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpt_la-serialization_utils.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpt_la-version.lo: common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) soundlib/$(am__dirstamp): @$(MKDIR_P) soundlib @: > soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) soundlib/$(DEPDIR) @: > soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-AudioCriticalSection.lo: \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-ContainerMMCMP.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-ContainerPP20.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-ContainerUMX.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-ContainerXPK.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Dlsbank.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Fastmix.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-InstrumentExtensions.lo: \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-InstrumentSynth.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-ITCompression.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-ITTools.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_667.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_669.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_amf.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_ams.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_c67.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_cba.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_dbm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_digi.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_dmf.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_dsm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_dsym.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_dtm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_etx.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_far.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_fc.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_fmt.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_ftm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_gdm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_gmc.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_gt2.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_ice.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_imf.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_ims.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_it.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_itp.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-load_j2b.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_kris.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_mdl.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_med.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_mid.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_mo3.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_mod.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_mt2.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_mtm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_mus_km.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_okt.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_plm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_psm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_pt36.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_ptm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_puma.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_rtm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_s3m.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_sfx.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_stk.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_stm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_stp.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_symmod.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_tcb.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_uax.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_ult.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_unic.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_wav.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_xm.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Load_xmf.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Message.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-MIDIEvents.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-MIDIMacroParser.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-MIDIMacros.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-MixerLoops.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-MixerSettings.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-MixFuncTable.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-ModChannel.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-modcommand.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-ModInstrument.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-ModSample.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-ModSequence.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-modsmp_ctrl.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-mod_specifications.lo: \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-MODTools.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-MPEGFrame.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-OggStream.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-OPL.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Paula.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-patternContainer.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-pattern.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-PlaybackTest.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-PlayState.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-RowVisitor.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-S3MTools.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-SampleFormats.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-SampleFormatBRR.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-SampleFormatFLAC.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo: \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-SampleFormatMP3.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-SampleFormatOpus.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-SampleFormatSFZ.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-SampleFormatVorbis.lo: \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-SampleIO.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Sndfile.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Snd_flt.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Snd_fx.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Sndmix.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-SoundFilePlayConfig.lo: \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Tables.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-Tagging.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-TinyFFT.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-tuningCollection.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-tuning.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-UMXTools.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-UpgradeModule.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-WAVTools.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-WindowedFIR.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpt_la-XMTools.lo: soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/$(am__dirstamp): @$(MKDIR_P) soundlib/plugins/dmo @: > soundlib/plugins/dmo/$(am__dirstamp) soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) soundlib/plugins/dmo/$(DEPDIR) @: > soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpt_la-DMOPlugin.lo: \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpt_la-DMOUtils.lo: \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpt_la-Chorus.lo: \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpt_la-Compressor.lo: \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpt_la-Distortion.lo: \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpt_la-Echo.lo: \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpt_la-Flanger.lo: \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpt_la-Gargle.lo: \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo: \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo: \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpt_la-WavesReverb.lo: \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/$(am__dirstamp): @$(MKDIR_P) soundlib/plugins @: > soundlib/plugins/$(am__dirstamp) soundlib/plugins/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) soundlib/plugins/$(DEPDIR) @: > soundlib/plugins/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/libopenmpt_la-DigiBoosterEcho.lo: \ soundlib/plugins/$(am__dirstamp) \ soundlib/plugins/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/libopenmpt_la-LFOPlugin.lo: \ soundlib/plugins/$(am__dirstamp) \ soundlib/plugins/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/libopenmpt_la-PluginManager.lo: \ soundlib/plugins/$(am__dirstamp) \ soundlib/plugins/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/libopenmpt_la-PlugInterface.lo: \ soundlib/plugins/$(am__dirstamp) \ soundlib/plugins/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/libopenmpt_la-SymMODEcho.lo: \ soundlib/plugins/$(am__dirstamp) \ soundlib/plugins/$(DEPDIR)/$(am__dirstamp) sounddsp/$(am__dirstamp): @$(MKDIR_P) sounddsp @: > sounddsp/$(am__dirstamp) sounddsp/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) sounddsp/$(DEPDIR) @: > sounddsp/$(DEPDIR)/$(am__dirstamp) sounddsp/libopenmpt_la-AGC.lo: sounddsp/$(am__dirstamp) \ sounddsp/$(DEPDIR)/$(am__dirstamp) sounddsp/libopenmpt_la-DSP.lo: sounddsp/$(am__dirstamp) \ sounddsp/$(DEPDIR)/$(am__dirstamp) sounddsp/libopenmpt_la-EQ.lo: sounddsp/$(am__dirstamp) \ sounddsp/$(DEPDIR)/$(am__dirstamp) sounddsp/libopenmpt_la-Reverb.lo: sounddsp/$(am__dirstamp) \ sounddsp/$(DEPDIR)/$(am__dirstamp) libopenmpt/$(am__dirstamp): @$(MKDIR_P) libopenmpt @: > libopenmpt/$(am__dirstamp) libopenmpt/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) libopenmpt/$(DEPDIR) @: > libopenmpt/$(DEPDIR)/$(am__dirstamp) libopenmpt/la-libopenmpt_c.lo: libopenmpt/$(am__dirstamp) \ libopenmpt/$(DEPDIR)/$(am__dirstamp) libopenmpt/la-libopenmpt_cxx.lo: libopenmpt/$(am__dirstamp) \ libopenmpt/$(DEPDIR)/$(am__dirstamp) libopenmpt/la-libopenmpt_ext_impl.lo: libopenmpt/$(am__dirstamp) \ libopenmpt/$(DEPDIR)/$(am__dirstamp) libopenmpt/la-libopenmpt_impl.lo: libopenmpt/$(am__dirstamp) \ libopenmpt/$(DEPDIR)/$(am__dirstamp) libopenmpt.la: $(libopenmpt_la_OBJECTS) $(libopenmpt_la_DEPENDENCIES) $(EXTRA_libopenmpt_la_DEPENDENCIES) $(AM_V_CXXLD)$(libopenmpt_la_LINK) -rpath $(libdir) $(libopenmpt_la_OBJECTS) $(libopenmpt_la_LIBADD) $(LIBS) openmpt123/$(am__dirstamp): @$(MKDIR_P) openmpt123 @: > openmpt123/$(am__dirstamp) openmpt123/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) openmpt123/$(DEPDIR) @: > openmpt123/$(DEPDIR)/$(am__dirstamp) openmpt123/bin_openmpt123-openmpt123.$(OBJEXT): \ openmpt123/$(am__dirstamp) \ openmpt123/$(DEPDIR)/$(am__dirstamp) bin/$(am__dirstamp): @$(MKDIR_P) bin @: > bin/$(am__dirstamp) bin/openmpt123$(EXEEXT): $(bin_openmpt123_OBJECTS) $(bin_openmpt123_DEPENDENCIES) $(EXTRA_bin_openmpt123_DEPENDENCIES) bin/$(am__dirstamp) @rm -f bin/openmpt123$(EXEEXT) $(AM_V_CXXLD)$(bin_openmpt123_LINK) $(bin_openmpt123_OBJECTS) $(bin_openmpt123_LDADD) $(LIBS) examples/$(am__dirstamp): @$(MKDIR_P) examples @: > examples/$(am__dirstamp) examples/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) examples/$(DEPDIR) @: > examples/$(DEPDIR)/$(am__dirstamp) examples/libopenmpt_example_c-libopenmpt_example_c.$(OBJEXT): \ examples/$(am__dirstamp) examples/$(DEPDIR)/$(am__dirstamp) libopenmpt_example_c$(EXEEXT): $(libopenmpt_example_c_OBJECTS) $(libopenmpt_example_c_DEPENDENCIES) $(EXTRA_libopenmpt_example_c_DEPENDENCIES) @rm -f libopenmpt_example_c$(EXEEXT) $(AM_V_CCLD)$(libopenmpt_example_c_LINK) $(libopenmpt_example_c_OBJECTS) $(libopenmpt_example_c_LDADD) $(LIBS) examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.$(OBJEXT): \ examples/$(am__dirstamp) examples/$(DEPDIR)/$(am__dirstamp) libopenmpt_example_c_mem$(EXEEXT): $(libopenmpt_example_c_mem_OBJECTS) $(libopenmpt_example_c_mem_DEPENDENCIES) $(EXTRA_libopenmpt_example_c_mem_DEPENDENCIES) @rm -f libopenmpt_example_c_mem$(EXEEXT) $(AM_V_CCLD)$(libopenmpt_example_c_mem_LINK) $(libopenmpt_example_c_mem_OBJECTS) $(libopenmpt_example_c_mem_LDADD) $(LIBS) examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.$(OBJEXT): \ examples/$(am__dirstamp) examples/$(DEPDIR)/$(am__dirstamp) libopenmpt_example_c_pipe$(EXEEXT): $(libopenmpt_example_c_pipe_OBJECTS) $(libopenmpt_example_c_pipe_DEPENDENCIES) $(EXTRA_libopenmpt_example_c_pipe_DEPENDENCIES) @rm -f libopenmpt_example_c_pipe$(EXEEXT) $(AM_V_CCLD)$(libopenmpt_example_c_pipe_LINK) $(libopenmpt_example_c_pipe_OBJECTS) $(libopenmpt_example_c_pipe_LDADD) $(LIBS) examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.$(OBJEXT): \ examples/$(am__dirstamp) examples/$(DEPDIR)/$(am__dirstamp) libopenmpt_example_c_probe$(EXEEXT): $(libopenmpt_example_c_probe_OBJECTS) $(libopenmpt_example_c_probe_DEPENDENCIES) $(EXTRA_libopenmpt_example_c_probe_DEPENDENCIES) @rm -f libopenmpt_example_c_probe$(EXEEXT) $(AM_V_CCLD)$(libopenmpt_example_c_probe_LINK) $(libopenmpt_example_c_probe_OBJECTS) $(libopenmpt_example_c_probe_LDADD) $(LIBS) examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.$(OBJEXT): \ examples/$(am__dirstamp) examples/$(DEPDIR)/$(am__dirstamp) libopenmpt_example_c_stdout$(EXEEXT): $(libopenmpt_example_c_stdout_OBJECTS) $(libopenmpt_example_c_stdout_DEPENDENCIES) $(EXTRA_libopenmpt_example_c_stdout_DEPENDENCIES) @rm -f libopenmpt_example_c_stdout$(EXEEXT) $(AM_V_CCLD)$(libopenmpt_example_c_stdout_LINK) $(libopenmpt_example_c_stdout_OBJECTS) $(libopenmpt_example_c_stdout_LDADD) $(LIBS) examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.$(OBJEXT): \ examples/$(am__dirstamp) examples/$(DEPDIR)/$(am__dirstamp) libopenmpt_example_c_unsafe$(EXEEXT): $(libopenmpt_example_c_unsafe_OBJECTS) $(libopenmpt_example_c_unsafe_DEPENDENCIES) $(EXTRA_libopenmpt_example_c_unsafe_DEPENDENCIES) @rm -f libopenmpt_example_c_unsafe$(EXEEXT) $(AM_V_CCLD)$(libopenmpt_example_c_unsafe_LINK) $(libopenmpt_example_c_unsafe_OBJECTS) $(libopenmpt_example_c_unsafe_LDADD) $(LIBS) examples/libopenmpt_example_cxx-libopenmpt_example_cxx.$(OBJEXT): \ examples/$(am__dirstamp) examples/$(DEPDIR)/$(am__dirstamp) libopenmpt_example_cxx$(EXEEXT): $(libopenmpt_example_cxx_OBJECTS) $(libopenmpt_example_cxx_DEPENDENCIES) $(EXTRA_libopenmpt_example_cxx_DEPENDENCIES) @rm -f libopenmpt_example_cxx$(EXEEXT) $(AM_V_CXXLD)$(libopenmpt_example_cxx_LINK) $(libopenmpt_example_cxx_OBJECTS) $(libopenmpt_example_cxx_LDADD) $(LIBS) test/$(am__dirstamp): @$(MKDIR_P) test @: > test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/$(DEPDIR) @: > test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-mpt_tests_base.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-mpt_tests_binary.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-mpt_tests_crc.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-mpt_tests_endian.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-mpt_tests_format.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-mpt_tests_io.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-mpt_tests_parse.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-mpt_tests_random.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-mpt_tests_string.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-mpt_tests_string_transcode.$(OBJEXT): \ test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-mpt_tests_uuid.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-test.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/libopenmpttest-TestToolsLib.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) src/openmpt/soundfile_write/$(am__dirstamp): @$(MKDIR_P) src/openmpt/soundfile_write @: > src/openmpt/soundfile_write/$(am__dirstamp) src/openmpt/soundfile_write/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/openmpt/soundfile_write/$(DEPDIR) @: > src/openmpt/soundfile_write/$(DEPDIR)/$(am__dirstamp) src/openmpt/soundfile_write/libopenmpttest-wav_write.$(OBJEXT): \ src/openmpt/soundfile_write/$(am__dirstamp) \ src/openmpt/soundfile_write/$(DEPDIR)/$(am__dirstamp) common/libopenmpttest-ComponentManager.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/libopenmpttest-Logging.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpttest-mptFileType.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpttest-mptPathString.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpttest-mptRandom.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpttest-mptStringBuffer.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/libopenmpttest-mptTime.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpttest-Profiler.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) common/libopenmpttest-serialization_utils.$(OBJEXT): \ common/$(am__dirstamp) common/$(DEPDIR)/$(am__dirstamp) common/libopenmpttest-version.$(OBJEXT): common/$(am__dirstamp) \ common/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-AudioCriticalSection.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-ContainerMMCMP.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-ContainerPP20.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-ContainerUMX.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-ContainerXPK.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Dlsbank.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Fastmix.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-InstrumentExtensions.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-InstrumentSynth.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-ITCompression.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-ITTools.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_667.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_669.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_amf.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_ams.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_c67.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_cba.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_dbm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_digi.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_dmf.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_dsm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_dsym.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_dtm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_etx.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_far.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_fc.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_fmt.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_ftm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_gdm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_gmc.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_gt2.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_ice.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_imf.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_ims.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_it.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_itp.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-load_j2b.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_kris.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_mdl.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_med.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_mid.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_mo3.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_mod.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_mt2.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_mtm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_mus_km.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_okt.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_plm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_psm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_pt36.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_ptm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_puma.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_rtm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_s3m.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_sfx.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_stk.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_stm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_stp.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_symmod.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_tcb.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_uax.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_ult.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_unic.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_wav.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_xm.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Load_xmf.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Message.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-MIDIEvents.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-MIDIMacroParser.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-MIDIMacros.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-MixerLoops.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-MixerSettings.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-MixFuncTable.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-ModChannel.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-modcommand.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-ModInstrument.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-ModSample.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-ModSequence.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-modsmp_ctrl.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-mod_specifications.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-MODTools.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-MPEGFrame.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-OggStream.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-OPL.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Paula.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-patternContainer.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-pattern.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-PlaybackTest.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-PlayState.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-RowVisitor.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-S3MTools.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-SampleFormats.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-SampleFormatBRR.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-SampleFormatFLAC.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-SampleFormatMediaFoundation.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-SampleFormatMP3.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-SampleFormatOpus.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-SampleFormatSFZ.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-SampleFormatVorbis.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-SampleIO.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Sndfile.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Snd_flt.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Snd_fx.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Sndmix.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-SoundFilePlayConfig.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Tables.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-Tagging.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-TinyFFT.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-tuningCollection.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-tuning.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-UMXTools.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-UpgradeModule.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-WAVTools.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-WindowedFIR.$(OBJEXT): \ soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/libopenmpttest-XMTools.$(OBJEXT): soundlib/$(am__dirstamp) \ soundlib/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpttest-DMOPlugin.$(OBJEXT): \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpttest-DMOUtils.$(OBJEXT): \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpttest-Chorus.$(OBJEXT): \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpttest-Compressor.$(OBJEXT): \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpttest-Distortion.$(OBJEXT): \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpttest-Echo.$(OBJEXT): \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpttest-Flanger.$(OBJEXT): \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpttest-Gargle.$(OBJEXT): \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.$(OBJEXT): \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpttest-ParamEq.$(OBJEXT): \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/dmo/libopenmpttest-WavesReverb.$(OBJEXT): \ soundlib/plugins/dmo/$(am__dirstamp) \ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/libopenmpttest-DigiBoosterEcho.$(OBJEXT): \ soundlib/plugins/$(am__dirstamp) \ soundlib/plugins/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/libopenmpttest-LFOPlugin.$(OBJEXT): \ soundlib/plugins/$(am__dirstamp) \ soundlib/plugins/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/libopenmpttest-PluginManager.$(OBJEXT): \ soundlib/plugins/$(am__dirstamp) \ soundlib/plugins/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/libopenmpttest-PlugInterface.$(OBJEXT): \ soundlib/plugins/$(am__dirstamp) \ soundlib/plugins/$(DEPDIR)/$(am__dirstamp) soundlib/plugins/libopenmpttest-SymMODEcho.$(OBJEXT): \ soundlib/plugins/$(am__dirstamp) \ soundlib/plugins/$(DEPDIR)/$(am__dirstamp) sounddsp/libopenmpttest-AGC.$(OBJEXT): sounddsp/$(am__dirstamp) \ sounddsp/$(DEPDIR)/$(am__dirstamp) sounddsp/libopenmpttest-DSP.$(OBJEXT): sounddsp/$(am__dirstamp) \ sounddsp/$(DEPDIR)/$(am__dirstamp) sounddsp/libopenmpttest-EQ.$(OBJEXT): sounddsp/$(am__dirstamp) \ sounddsp/$(DEPDIR)/$(am__dirstamp) sounddsp/libopenmpttest-Reverb.$(OBJEXT): sounddsp/$(am__dirstamp) \ sounddsp/$(DEPDIR)/$(am__dirstamp) libopenmpt/libopenmpttest-libopenmpt_c.$(OBJEXT): \ libopenmpt/$(am__dirstamp) \ libopenmpt/$(DEPDIR)/$(am__dirstamp) libopenmpt/libopenmpttest-libopenmpt_cxx.$(OBJEXT): \ libopenmpt/$(am__dirstamp) \ libopenmpt/$(DEPDIR)/$(am__dirstamp) libopenmpt/libopenmpttest-libopenmpt_ext_impl.$(OBJEXT): \ libopenmpt/$(am__dirstamp) \ libopenmpt/$(DEPDIR)/$(am__dirstamp) libopenmpt/libopenmpttest-libopenmpt_impl.$(OBJEXT): \ libopenmpt/$(am__dirstamp) \ libopenmpt/$(DEPDIR)/$(am__dirstamp) libopenmpt/libopenmpt_test/$(am__dirstamp): @$(MKDIR_P) libopenmpt/libopenmpt_test @: > libopenmpt/libopenmpt_test/$(am__dirstamp) libopenmpt/libopenmpt_test/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) libopenmpt/libopenmpt_test/$(DEPDIR) @: > libopenmpt/libopenmpt_test/$(DEPDIR)/$(am__dirstamp) libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.$(OBJEXT): \ libopenmpt/libopenmpt_test/$(am__dirstamp) \ libopenmpt/libopenmpt_test/$(DEPDIR)/$(am__dirstamp) libopenmpttest$(EXEEXT): $(libopenmpttest_OBJECTS) $(libopenmpttest_DEPENDENCIES) $(EXTRA_libopenmpttest_DEPENDENCIES) @rm -f libopenmpttest$(EXEEXT) $(AM_V_CXXLD)$(libopenmpttest_LINK) $(libopenmpttest_OBJECTS) $(libopenmpttest_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f common/*.$(OBJEXT) -rm -f common/*.lo -rm -f examples/*.$(OBJEXT) -rm -f libopenmpt/*.$(OBJEXT) -rm -f libopenmpt/*.lo -rm -f libopenmpt/libopenmpt_test/*.$(OBJEXT) -rm -f openmpt123/*.$(OBJEXT) -rm -f sounddsp/*.$(OBJEXT) -rm -f sounddsp/*.lo -rm -f soundlib/*.$(OBJEXT) -rm -f soundlib/*.lo -rm -f soundlib/plugins/*.$(OBJEXT) -rm -f soundlib/plugins/*.lo -rm -f soundlib/plugins/dmo/*.$(OBJEXT) -rm -f soundlib/plugins/dmo/*.lo -rm -f src/openmpt/soundfile_write/*.$(OBJEXT) -rm -f test/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpt_la-ComponentManager.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpt_la-Logging.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpt_la-Profiler.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpt_la-mptFileType.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpt_la-mptPathString.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpt_la-mptRandom.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpt_la-mptStringBuffer.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpt_la-mptTime.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpt_la-serialization_utils.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpt_la-version.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpttest-ComponentManager.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpttest-Logging.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpttest-Profiler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpttest-mptFileType.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpttest-mptPathString.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpttest-mptRandom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpttest-mptStringBuffer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpttest-mptTime.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpttest-serialization_utils.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@common/$(DEPDIR)/libopenmpttest-version.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/libopenmpt_example_c-libopenmpt_example_c.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/libopenmpt_example_c_mem-libopenmpt_example_c_mem.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/libopenmpt_example_c_probe-libopenmpt_example_c_probe.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libopenmpt/$(DEPDIR)/la-libopenmpt_c.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libopenmpt/$(DEPDIR)/la-libopenmpt_cxx.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libopenmpt/$(DEPDIR)/la-libopenmpt_ext_impl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libopenmpt/$(DEPDIR)/la-libopenmpt_impl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_cxx.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libopenmpt/libopenmpt_test/$(DEPDIR)/libopenmpttest-libopenmpt_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sounddsp/$(DEPDIR)/libopenmpt_la-AGC.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sounddsp/$(DEPDIR)/libopenmpt_la-DSP.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sounddsp/$(DEPDIR)/libopenmpt_la-EQ.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sounddsp/$(DEPDIR)/libopenmpt_la-Reverb.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sounddsp/$(DEPDIR)/libopenmpttest-AGC.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sounddsp/$(DEPDIR)/libopenmpttest-DSP.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sounddsp/$(DEPDIR)/libopenmpttest-EQ.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-AudioCriticalSection.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-ContainerMMCMP.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-ContainerPP20.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-ContainerUMX.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-ContainerXPK.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Dlsbank.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Fastmix.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-ITCompression.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-ITTools.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-InstrumentExtensions.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-InstrumentSynth.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_667.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_669.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_amf.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_ams.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_c67.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_cba.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_dbm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_digi.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_dmf.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_dsm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_dsym.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_dtm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_etx.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_far.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_fc.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_fmt.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_ftm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_gdm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_gmc.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_gt2.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_ice.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_imf.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_ims.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_it.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_itp.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_kris.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_mdl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_med.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_mid.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_mo3.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_mod.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_mt2.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_mtm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_mus_km.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_okt.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_plm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_psm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_pt36.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_ptm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_puma.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_rtm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_s3m.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_sfx.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_stk.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_stm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_stp.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_symmod.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_tcb.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_uax.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_ult.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_unic.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_wav.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_xm.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Load_xmf.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-MIDIEvents.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacroParser.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacros.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-MODTools.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-MPEGFrame.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Message.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-MixFuncTable.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-MixerLoops.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-MixerSettings.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-ModChannel.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-ModInstrument.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-ModSample.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-ModSequence.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-OPL.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-OggStream.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Paula.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-PlayState.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-PlaybackTest.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-RowVisitor.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-S3MTools.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatBRR.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatFLAC.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMP3.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMediaFoundation.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatOpus.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatSFZ.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatVorbis.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-SampleFormats.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-SampleIO.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Snd_flt.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Snd_fx.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Sndfile.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Sndmix.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-SoundFilePlayConfig.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Tables.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-Tagging.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-TinyFFT.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-UMXTools.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-UpgradeModule.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-WAVTools.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-WindowedFIR.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-XMTools.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-load_j2b.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-mod_specifications.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-modcommand.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-modsmp_ctrl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-pattern.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-patternContainer.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-tuning.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpt_la-tuningCollection.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-AudioCriticalSection.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Dlsbank.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Fastmix.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-ITCompression.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-ITTools.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-InstrumentExtensions.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-InstrumentSynth.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_667.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_669.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_amf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_ams.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_c67.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_cba.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_dbm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_digi.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_dmf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_dsm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_dsym.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_etx.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_far.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_fc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_fmt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_ftm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_gdm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_gmc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_gt2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_ice.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_imf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_ims.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_it.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_itp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_kris.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_mdl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_med.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_mid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_mo3.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_mod.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_mt2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_mtm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_mus_km.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_okt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_plm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_psm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_pt36.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_ptm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_puma.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_rtm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_s3m.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_sfx.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_stk.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_stm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_symmod.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_tcb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_unic.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_xm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Load_xmf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-MIDIEvents.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-MIDIMacroParser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-MIDIMacros.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-MODTools.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-MPEGFrame.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Message.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-MixFuncTable.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-MixerLoops.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-MixerSettings.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-ModInstrument.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-ModSample.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-ModSequence.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-OPL.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-OggStream.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Paula.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-PlayState.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-PlaybackTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-RowVisitor.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-S3MTools.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-SampleFormatBRR.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-SampleFormatSFZ.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-SampleFormats.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Snd_flt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Snd_fx.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Sndfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Sndmix.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-SoundFilePlayConfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Tables.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-Tagging.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-TinyFFT.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-WAVTools.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-WindowedFIR.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-XMTools.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-load_j2b.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-mod_specifications.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-modcommand.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-modsmp_ctrl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-pattern.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-tuning.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/$(DEPDIR)/libopenmpttest-tuningCollection.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/$(DEPDIR)/libopenmpt_la-DigiBoosterEcho.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/$(DEPDIR)/libopenmpt_la-LFOPlugin.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/$(DEPDIR)/libopenmpt_la-PlugInterface.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/$(DEPDIR)/libopenmpt_la-PluginManager.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/$(DEPDIR)/libopenmpt_la-SymMODEcho.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/$(DEPDIR)/libopenmpttest-DigiBoosterEcho.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/$(DEPDIR)/libopenmpttest-PlugInterface.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/$(DEPDIR)/libopenmpttest-SymMODEcho.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Chorus.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Compressor.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOPlugin.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOUtils.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Distortion.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Echo.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Flanger.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Gargle.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-I3DL2Reverb.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-ParamEq.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-WavesReverb.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOPlugin.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOUtils.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Distortion.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Echo.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-WavesReverb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/openmpt/soundfile_write/$(DEPDIR)/libopenmpttest-wav_write.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-TestToolsLib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-mpt_tests_base.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-mpt_tests_binary.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-mpt_tests_crc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-mpt_tests_endian.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-mpt_tests_format.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-mpt_tests_io.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-mpt_tests_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-mpt_tests_random.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-mpt_tests_string.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-mpt_tests_string_transcode.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-mpt_tests_uuid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/libopenmpttest-test.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< examples/libopenmpt_example_c-libopenmpt_example_c.o: examples/libopenmpt_example_c.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c-libopenmpt_example_c.o -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c-libopenmpt_example_c.Tpo -c -o examples/libopenmpt_example_c-libopenmpt_example_c.o `test -f 'examples/libopenmpt_example_c.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c-libopenmpt_example_c.Tpo examples/$(DEPDIR)/libopenmpt_example_c-libopenmpt_example_c.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c.c' object='examples/libopenmpt_example_c-libopenmpt_example_c.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c-libopenmpt_example_c.o `test -f 'examples/libopenmpt_example_c.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c.c examples/libopenmpt_example_c-libopenmpt_example_c.obj: examples/libopenmpt_example_c.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c-libopenmpt_example_c.obj -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c-libopenmpt_example_c.Tpo -c -o examples/libopenmpt_example_c-libopenmpt_example_c.obj `if test -f 'examples/libopenmpt_example_c.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c-libopenmpt_example_c.Tpo examples/$(DEPDIR)/libopenmpt_example_c-libopenmpt_example_c.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c.c' object='examples/libopenmpt_example_c-libopenmpt_example_c.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c-libopenmpt_example_c.obj `if test -f 'examples/libopenmpt_example_c.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c.c'; fi` examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.o: examples/libopenmpt_example_c_mem.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_mem_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_mem_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.o -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c_mem-libopenmpt_example_c_mem.Tpo -c -o examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.o `test -f 'examples/libopenmpt_example_c_mem.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c_mem.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c_mem-libopenmpt_example_c_mem.Tpo examples/$(DEPDIR)/libopenmpt_example_c_mem-libopenmpt_example_c_mem.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c_mem.c' object='examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_mem_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_mem_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.o `test -f 'examples/libopenmpt_example_c_mem.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c_mem.c examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.obj: examples/libopenmpt_example_c_mem.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_mem_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_mem_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.obj -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c_mem-libopenmpt_example_c_mem.Tpo -c -o examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.obj `if test -f 'examples/libopenmpt_example_c_mem.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c_mem.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c_mem.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c_mem-libopenmpt_example_c_mem.Tpo examples/$(DEPDIR)/libopenmpt_example_c_mem-libopenmpt_example_c_mem.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c_mem.c' object='examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_mem_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_mem_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c_mem-libopenmpt_example_c_mem.obj `if test -f 'examples/libopenmpt_example_c_mem.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c_mem.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c_mem.c'; fi` examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.o: examples/libopenmpt_example_c_pipe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_pipe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_pipe_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.o -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.Tpo -c -o examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.o `test -f 'examples/libopenmpt_example_c_pipe.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c_pipe.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.Tpo examples/$(DEPDIR)/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c_pipe.c' object='examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_pipe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_pipe_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.o `test -f 'examples/libopenmpt_example_c_pipe.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c_pipe.c examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.obj: examples/libopenmpt_example_c_pipe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_pipe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_pipe_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.obj -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.Tpo -c -o examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.obj `if test -f 'examples/libopenmpt_example_c_pipe.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c_pipe.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c_pipe.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.Tpo examples/$(DEPDIR)/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c_pipe.c' object='examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_pipe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_pipe_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.obj `if test -f 'examples/libopenmpt_example_c_pipe.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c_pipe.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c_pipe.c'; fi` examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.o: examples/libopenmpt_example_c_probe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_probe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_probe_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.o -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c_probe-libopenmpt_example_c_probe.Tpo -c -o examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.o `test -f 'examples/libopenmpt_example_c_probe.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c_probe.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c_probe-libopenmpt_example_c_probe.Tpo examples/$(DEPDIR)/libopenmpt_example_c_probe-libopenmpt_example_c_probe.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c_probe.c' object='examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_probe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_probe_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.o `test -f 'examples/libopenmpt_example_c_probe.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c_probe.c examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.obj: examples/libopenmpt_example_c_probe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_probe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_probe_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.obj -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c_probe-libopenmpt_example_c_probe.Tpo -c -o examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.obj `if test -f 'examples/libopenmpt_example_c_probe.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c_probe.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c_probe.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c_probe-libopenmpt_example_c_probe.Tpo examples/$(DEPDIR)/libopenmpt_example_c_probe-libopenmpt_example_c_probe.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c_probe.c' object='examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_probe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_probe_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c_probe-libopenmpt_example_c_probe.obj `if test -f 'examples/libopenmpt_example_c_probe.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c_probe.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c_probe.c'; fi` examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.o: examples/libopenmpt_example_c_stdout.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_stdout_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_stdout_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.o -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.Tpo -c -o examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.o `test -f 'examples/libopenmpt_example_c_stdout.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c_stdout.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.Tpo examples/$(DEPDIR)/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c_stdout.c' object='examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_stdout_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_stdout_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.o `test -f 'examples/libopenmpt_example_c_stdout.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c_stdout.c examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.obj: examples/libopenmpt_example_c_stdout.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_stdout_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_stdout_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.obj -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.Tpo -c -o examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.obj `if test -f 'examples/libopenmpt_example_c_stdout.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c_stdout.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c_stdout.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.Tpo examples/$(DEPDIR)/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c_stdout.c' object='examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_stdout_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_stdout_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.obj `if test -f 'examples/libopenmpt_example_c_stdout.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c_stdout.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c_stdout.c'; fi` examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.o: examples/libopenmpt_example_c_unsafe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_unsafe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_unsafe_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.o -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.Tpo -c -o examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.o `test -f 'examples/libopenmpt_example_c_unsafe.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c_unsafe.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.Tpo examples/$(DEPDIR)/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c_unsafe.c' object='examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_unsafe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_unsafe_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.o `test -f 'examples/libopenmpt_example_c_unsafe.c' || echo '$(srcdir)/'`examples/libopenmpt_example_c_unsafe.c examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.obj: examples/libopenmpt_example_c_unsafe.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_unsafe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_unsafe_CFLAGS) $(CFLAGS) -MT examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.obj -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.Tpo -c -o examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.obj `if test -f 'examples/libopenmpt_example_c_unsafe.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c_unsafe.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c_unsafe.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.Tpo examples/$(DEPDIR)/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='examples/libopenmpt_example_c_unsafe.c' object='examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_c_unsafe_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_c_unsafe_CFLAGS) $(CFLAGS) -c -o examples/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.obj `if test -f 'examples/libopenmpt_example_c_unsafe.c'; then $(CYGPATH_W) 'examples/libopenmpt_example_c_unsafe.c'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_c_unsafe.c'; fi` .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< common/libopenmpt_la-ComponentManager.lo: common/ComponentManager.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-ComponentManager.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-ComponentManager.Tpo -c -o common/libopenmpt_la-ComponentManager.lo `test -f 'common/ComponentManager.cpp' || echo '$(srcdir)/'`common/ComponentManager.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-ComponentManager.Tpo common/$(DEPDIR)/libopenmpt_la-ComponentManager.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ComponentManager.cpp' object='common/libopenmpt_la-ComponentManager.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-ComponentManager.lo `test -f 'common/ComponentManager.cpp' || echo '$(srcdir)/'`common/ComponentManager.cpp common/libopenmpt_la-Logging.lo: common/Logging.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-Logging.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-Logging.Tpo -c -o common/libopenmpt_la-Logging.lo `test -f 'common/Logging.cpp' || echo '$(srcdir)/'`common/Logging.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-Logging.Tpo common/$(DEPDIR)/libopenmpt_la-Logging.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Logging.cpp' object='common/libopenmpt_la-Logging.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-Logging.lo `test -f 'common/Logging.cpp' || echo '$(srcdir)/'`common/Logging.cpp common/libopenmpt_la-mptFileType.lo: common/mptFileType.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-mptFileType.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-mptFileType.Tpo -c -o common/libopenmpt_la-mptFileType.lo `test -f 'common/mptFileType.cpp' || echo '$(srcdir)/'`common/mptFileType.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-mptFileType.Tpo common/$(DEPDIR)/libopenmpt_la-mptFileType.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptFileType.cpp' object='common/libopenmpt_la-mptFileType.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-mptFileType.lo `test -f 'common/mptFileType.cpp' || echo '$(srcdir)/'`common/mptFileType.cpp common/libopenmpt_la-mptPathString.lo: common/mptPathString.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-mptPathString.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-mptPathString.Tpo -c -o common/libopenmpt_la-mptPathString.lo `test -f 'common/mptPathString.cpp' || echo '$(srcdir)/'`common/mptPathString.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-mptPathString.Tpo common/$(DEPDIR)/libopenmpt_la-mptPathString.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptPathString.cpp' object='common/libopenmpt_la-mptPathString.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-mptPathString.lo `test -f 'common/mptPathString.cpp' || echo '$(srcdir)/'`common/mptPathString.cpp common/libopenmpt_la-mptRandom.lo: common/mptRandom.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-mptRandom.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-mptRandom.Tpo -c -o common/libopenmpt_la-mptRandom.lo `test -f 'common/mptRandom.cpp' || echo '$(srcdir)/'`common/mptRandom.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-mptRandom.Tpo common/$(DEPDIR)/libopenmpt_la-mptRandom.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptRandom.cpp' object='common/libopenmpt_la-mptRandom.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-mptRandom.lo `test -f 'common/mptRandom.cpp' || echo '$(srcdir)/'`common/mptRandom.cpp common/libopenmpt_la-mptStringBuffer.lo: common/mptStringBuffer.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-mptStringBuffer.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-mptStringBuffer.Tpo -c -o common/libopenmpt_la-mptStringBuffer.lo `test -f 'common/mptStringBuffer.cpp' || echo '$(srcdir)/'`common/mptStringBuffer.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-mptStringBuffer.Tpo common/$(DEPDIR)/libopenmpt_la-mptStringBuffer.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptStringBuffer.cpp' object='common/libopenmpt_la-mptStringBuffer.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-mptStringBuffer.lo `test -f 'common/mptStringBuffer.cpp' || echo '$(srcdir)/'`common/mptStringBuffer.cpp common/libopenmpt_la-mptTime.lo: common/mptTime.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-mptTime.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-mptTime.Tpo -c -o common/libopenmpt_la-mptTime.lo `test -f 'common/mptTime.cpp' || echo '$(srcdir)/'`common/mptTime.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-mptTime.Tpo common/$(DEPDIR)/libopenmpt_la-mptTime.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptTime.cpp' object='common/libopenmpt_la-mptTime.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-mptTime.lo `test -f 'common/mptTime.cpp' || echo '$(srcdir)/'`common/mptTime.cpp common/libopenmpt_la-Profiler.lo: common/Profiler.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-Profiler.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-Profiler.Tpo -c -o common/libopenmpt_la-Profiler.lo `test -f 'common/Profiler.cpp' || echo '$(srcdir)/'`common/Profiler.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-Profiler.Tpo common/$(DEPDIR)/libopenmpt_la-Profiler.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Profiler.cpp' object='common/libopenmpt_la-Profiler.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-Profiler.lo `test -f 'common/Profiler.cpp' || echo '$(srcdir)/'`common/Profiler.cpp common/libopenmpt_la-serialization_utils.lo: common/serialization_utils.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-serialization_utils.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-serialization_utils.Tpo -c -o common/libopenmpt_la-serialization_utils.lo `test -f 'common/serialization_utils.cpp' || echo '$(srcdir)/'`common/serialization_utils.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-serialization_utils.Tpo common/$(DEPDIR)/libopenmpt_la-serialization_utils.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/serialization_utils.cpp' object='common/libopenmpt_la-serialization_utils.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-serialization_utils.lo `test -f 'common/serialization_utils.cpp' || echo '$(srcdir)/'`common/serialization_utils.cpp common/libopenmpt_la-version.lo: common/version.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-version.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-version.Tpo -c -o common/libopenmpt_la-version.lo `test -f 'common/version.cpp' || echo '$(srcdir)/'`common/version.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-version.Tpo common/$(DEPDIR)/libopenmpt_la-version.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/version.cpp' object='common/libopenmpt_la-version.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-version.lo `test -f 'common/version.cpp' || echo '$(srcdir)/'`common/version.cpp soundlib/libopenmpt_la-AudioCriticalSection.lo: soundlib/AudioCriticalSection.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-AudioCriticalSection.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-AudioCriticalSection.Tpo -c -o soundlib/libopenmpt_la-AudioCriticalSection.lo `test -f 'soundlib/AudioCriticalSection.cpp' || echo '$(srcdir)/'`soundlib/AudioCriticalSection.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-AudioCriticalSection.Tpo soundlib/$(DEPDIR)/libopenmpt_la-AudioCriticalSection.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/AudioCriticalSection.cpp' object='soundlib/libopenmpt_la-AudioCriticalSection.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-AudioCriticalSection.lo `test -f 'soundlib/AudioCriticalSection.cpp' || echo '$(srcdir)/'`soundlib/AudioCriticalSection.cpp soundlib/libopenmpt_la-ContainerMMCMP.lo: soundlib/ContainerMMCMP.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ContainerMMCMP.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ContainerMMCMP.Tpo -c -o soundlib/libopenmpt_la-ContainerMMCMP.lo `test -f 'soundlib/ContainerMMCMP.cpp' || echo '$(srcdir)/'`soundlib/ContainerMMCMP.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ContainerMMCMP.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ContainerMMCMP.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerMMCMP.cpp' object='soundlib/libopenmpt_la-ContainerMMCMP.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ContainerMMCMP.lo `test -f 'soundlib/ContainerMMCMP.cpp' || echo '$(srcdir)/'`soundlib/ContainerMMCMP.cpp soundlib/libopenmpt_la-ContainerPP20.lo: soundlib/ContainerPP20.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ContainerPP20.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ContainerPP20.Tpo -c -o soundlib/libopenmpt_la-ContainerPP20.lo `test -f 'soundlib/ContainerPP20.cpp' || echo '$(srcdir)/'`soundlib/ContainerPP20.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ContainerPP20.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ContainerPP20.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerPP20.cpp' object='soundlib/libopenmpt_la-ContainerPP20.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ContainerPP20.lo `test -f 'soundlib/ContainerPP20.cpp' || echo '$(srcdir)/'`soundlib/ContainerPP20.cpp soundlib/libopenmpt_la-ContainerUMX.lo: soundlib/ContainerUMX.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ContainerUMX.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ContainerUMX.Tpo -c -o soundlib/libopenmpt_la-ContainerUMX.lo `test -f 'soundlib/ContainerUMX.cpp' || echo '$(srcdir)/'`soundlib/ContainerUMX.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ContainerUMX.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ContainerUMX.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerUMX.cpp' object='soundlib/libopenmpt_la-ContainerUMX.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ContainerUMX.lo `test -f 'soundlib/ContainerUMX.cpp' || echo '$(srcdir)/'`soundlib/ContainerUMX.cpp soundlib/libopenmpt_la-ContainerXPK.lo: soundlib/ContainerXPK.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ContainerXPK.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ContainerXPK.Tpo -c -o soundlib/libopenmpt_la-ContainerXPK.lo `test -f 'soundlib/ContainerXPK.cpp' || echo '$(srcdir)/'`soundlib/ContainerXPK.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ContainerXPK.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ContainerXPK.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerXPK.cpp' object='soundlib/libopenmpt_la-ContainerXPK.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ContainerXPK.lo `test -f 'soundlib/ContainerXPK.cpp' || echo '$(srcdir)/'`soundlib/ContainerXPK.cpp soundlib/libopenmpt_la-Dlsbank.lo: soundlib/Dlsbank.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Dlsbank.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Dlsbank.Tpo -c -o soundlib/libopenmpt_la-Dlsbank.lo `test -f 'soundlib/Dlsbank.cpp' || echo '$(srcdir)/'`soundlib/Dlsbank.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Dlsbank.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Dlsbank.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Dlsbank.cpp' object='soundlib/libopenmpt_la-Dlsbank.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Dlsbank.lo `test -f 'soundlib/Dlsbank.cpp' || echo '$(srcdir)/'`soundlib/Dlsbank.cpp soundlib/libopenmpt_la-Fastmix.lo: soundlib/Fastmix.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Fastmix.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Fastmix.Tpo -c -o soundlib/libopenmpt_la-Fastmix.lo `test -f 'soundlib/Fastmix.cpp' || echo '$(srcdir)/'`soundlib/Fastmix.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Fastmix.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Fastmix.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Fastmix.cpp' object='soundlib/libopenmpt_la-Fastmix.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Fastmix.lo `test -f 'soundlib/Fastmix.cpp' || echo '$(srcdir)/'`soundlib/Fastmix.cpp soundlib/libopenmpt_la-InstrumentExtensions.lo: soundlib/InstrumentExtensions.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-InstrumentExtensions.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-InstrumentExtensions.Tpo -c -o soundlib/libopenmpt_la-InstrumentExtensions.lo `test -f 'soundlib/InstrumentExtensions.cpp' || echo '$(srcdir)/'`soundlib/InstrumentExtensions.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-InstrumentExtensions.Tpo soundlib/$(DEPDIR)/libopenmpt_la-InstrumentExtensions.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/InstrumentExtensions.cpp' object='soundlib/libopenmpt_la-InstrumentExtensions.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-InstrumentExtensions.lo `test -f 'soundlib/InstrumentExtensions.cpp' || echo '$(srcdir)/'`soundlib/InstrumentExtensions.cpp soundlib/libopenmpt_la-InstrumentSynth.lo: soundlib/InstrumentSynth.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-InstrumentSynth.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-InstrumentSynth.Tpo -c -o soundlib/libopenmpt_la-InstrumentSynth.lo `test -f 'soundlib/InstrumentSynth.cpp' || echo '$(srcdir)/'`soundlib/InstrumentSynth.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-InstrumentSynth.Tpo soundlib/$(DEPDIR)/libopenmpt_la-InstrumentSynth.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/InstrumentSynth.cpp' object='soundlib/libopenmpt_la-InstrumentSynth.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-InstrumentSynth.lo `test -f 'soundlib/InstrumentSynth.cpp' || echo '$(srcdir)/'`soundlib/InstrumentSynth.cpp soundlib/libopenmpt_la-ITCompression.lo: soundlib/ITCompression.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ITCompression.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ITCompression.Tpo -c -o soundlib/libopenmpt_la-ITCompression.lo `test -f 'soundlib/ITCompression.cpp' || echo '$(srcdir)/'`soundlib/ITCompression.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ITCompression.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ITCompression.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ITCompression.cpp' object='soundlib/libopenmpt_la-ITCompression.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ITCompression.lo `test -f 'soundlib/ITCompression.cpp' || echo '$(srcdir)/'`soundlib/ITCompression.cpp soundlib/libopenmpt_la-ITTools.lo: soundlib/ITTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ITTools.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ITTools.Tpo -c -o soundlib/libopenmpt_la-ITTools.lo `test -f 'soundlib/ITTools.cpp' || echo '$(srcdir)/'`soundlib/ITTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ITTools.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ITTools.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ITTools.cpp' object='soundlib/libopenmpt_la-ITTools.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ITTools.lo `test -f 'soundlib/ITTools.cpp' || echo '$(srcdir)/'`soundlib/ITTools.cpp soundlib/libopenmpt_la-Load_667.lo: soundlib/Load_667.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_667.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_667.Tpo -c -o soundlib/libopenmpt_la-Load_667.lo `test -f 'soundlib/Load_667.cpp' || echo '$(srcdir)/'`soundlib/Load_667.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_667.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_667.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_667.cpp' object='soundlib/libopenmpt_la-Load_667.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_667.lo `test -f 'soundlib/Load_667.cpp' || echo '$(srcdir)/'`soundlib/Load_667.cpp soundlib/libopenmpt_la-Load_669.lo: soundlib/Load_669.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_669.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_669.Tpo -c -o soundlib/libopenmpt_la-Load_669.lo `test -f 'soundlib/Load_669.cpp' || echo '$(srcdir)/'`soundlib/Load_669.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_669.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_669.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_669.cpp' object='soundlib/libopenmpt_la-Load_669.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_669.lo `test -f 'soundlib/Load_669.cpp' || echo '$(srcdir)/'`soundlib/Load_669.cpp soundlib/libopenmpt_la-Load_amf.lo: soundlib/Load_amf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_amf.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_amf.Tpo -c -o soundlib/libopenmpt_la-Load_amf.lo `test -f 'soundlib/Load_amf.cpp' || echo '$(srcdir)/'`soundlib/Load_amf.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_amf.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_amf.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_amf.cpp' object='soundlib/libopenmpt_la-Load_amf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_amf.lo `test -f 'soundlib/Load_amf.cpp' || echo '$(srcdir)/'`soundlib/Load_amf.cpp soundlib/libopenmpt_la-Load_ams.lo: soundlib/Load_ams.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_ams.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_ams.Tpo -c -o soundlib/libopenmpt_la-Load_ams.lo `test -f 'soundlib/Load_ams.cpp' || echo '$(srcdir)/'`soundlib/Load_ams.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_ams.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_ams.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ams.cpp' object='soundlib/libopenmpt_la-Load_ams.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_ams.lo `test -f 'soundlib/Load_ams.cpp' || echo '$(srcdir)/'`soundlib/Load_ams.cpp soundlib/libopenmpt_la-Load_c67.lo: soundlib/Load_c67.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_c67.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_c67.Tpo -c -o soundlib/libopenmpt_la-Load_c67.lo `test -f 'soundlib/Load_c67.cpp' || echo '$(srcdir)/'`soundlib/Load_c67.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_c67.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_c67.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_c67.cpp' object='soundlib/libopenmpt_la-Load_c67.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_c67.lo `test -f 'soundlib/Load_c67.cpp' || echo '$(srcdir)/'`soundlib/Load_c67.cpp soundlib/libopenmpt_la-Load_cba.lo: soundlib/Load_cba.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_cba.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_cba.Tpo -c -o soundlib/libopenmpt_la-Load_cba.lo `test -f 'soundlib/Load_cba.cpp' || echo '$(srcdir)/'`soundlib/Load_cba.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_cba.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_cba.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_cba.cpp' object='soundlib/libopenmpt_la-Load_cba.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_cba.lo `test -f 'soundlib/Load_cba.cpp' || echo '$(srcdir)/'`soundlib/Load_cba.cpp soundlib/libopenmpt_la-Load_dbm.lo: soundlib/Load_dbm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_dbm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_dbm.Tpo -c -o soundlib/libopenmpt_la-Load_dbm.lo `test -f 'soundlib/Load_dbm.cpp' || echo '$(srcdir)/'`soundlib/Load_dbm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_dbm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_dbm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dbm.cpp' object='soundlib/libopenmpt_la-Load_dbm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_dbm.lo `test -f 'soundlib/Load_dbm.cpp' || echo '$(srcdir)/'`soundlib/Load_dbm.cpp soundlib/libopenmpt_la-Load_digi.lo: soundlib/Load_digi.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_digi.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_digi.Tpo -c -o soundlib/libopenmpt_la-Load_digi.lo `test -f 'soundlib/Load_digi.cpp' || echo '$(srcdir)/'`soundlib/Load_digi.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_digi.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_digi.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_digi.cpp' object='soundlib/libopenmpt_la-Load_digi.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_digi.lo `test -f 'soundlib/Load_digi.cpp' || echo '$(srcdir)/'`soundlib/Load_digi.cpp soundlib/libopenmpt_la-Load_dmf.lo: soundlib/Load_dmf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_dmf.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_dmf.Tpo -c -o soundlib/libopenmpt_la-Load_dmf.lo `test -f 'soundlib/Load_dmf.cpp' || echo '$(srcdir)/'`soundlib/Load_dmf.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_dmf.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_dmf.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dmf.cpp' object='soundlib/libopenmpt_la-Load_dmf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_dmf.lo `test -f 'soundlib/Load_dmf.cpp' || echo '$(srcdir)/'`soundlib/Load_dmf.cpp soundlib/libopenmpt_la-Load_dsm.lo: soundlib/Load_dsm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_dsm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_dsm.Tpo -c -o soundlib/libopenmpt_la-Load_dsm.lo `test -f 'soundlib/Load_dsm.cpp' || echo '$(srcdir)/'`soundlib/Load_dsm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_dsm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_dsm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dsm.cpp' object='soundlib/libopenmpt_la-Load_dsm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_dsm.lo `test -f 'soundlib/Load_dsm.cpp' || echo '$(srcdir)/'`soundlib/Load_dsm.cpp soundlib/libopenmpt_la-Load_dsym.lo: soundlib/Load_dsym.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_dsym.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_dsym.Tpo -c -o soundlib/libopenmpt_la-Load_dsym.lo `test -f 'soundlib/Load_dsym.cpp' || echo '$(srcdir)/'`soundlib/Load_dsym.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_dsym.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_dsym.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dsym.cpp' object='soundlib/libopenmpt_la-Load_dsym.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_dsym.lo `test -f 'soundlib/Load_dsym.cpp' || echo '$(srcdir)/'`soundlib/Load_dsym.cpp soundlib/libopenmpt_la-Load_dtm.lo: soundlib/Load_dtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_dtm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_dtm.Tpo -c -o soundlib/libopenmpt_la-Load_dtm.lo `test -f 'soundlib/Load_dtm.cpp' || echo '$(srcdir)/'`soundlib/Load_dtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_dtm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_dtm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dtm.cpp' object='soundlib/libopenmpt_la-Load_dtm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_dtm.lo `test -f 'soundlib/Load_dtm.cpp' || echo '$(srcdir)/'`soundlib/Load_dtm.cpp soundlib/libopenmpt_la-Load_etx.lo: soundlib/Load_etx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_etx.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_etx.Tpo -c -o soundlib/libopenmpt_la-Load_etx.lo `test -f 'soundlib/Load_etx.cpp' || echo '$(srcdir)/'`soundlib/Load_etx.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_etx.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_etx.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_etx.cpp' object='soundlib/libopenmpt_la-Load_etx.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_etx.lo `test -f 'soundlib/Load_etx.cpp' || echo '$(srcdir)/'`soundlib/Load_etx.cpp soundlib/libopenmpt_la-Load_far.lo: soundlib/Load_far.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_far.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_far.Tpo -c -o soundlib/libopenmpt_la-Load_far.lo `test -f 'soundlib/Load_far.cpp' || echo '$(srcdir)/'`soundlib/Load_far.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_far.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_far.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_far.cpp' object='soundlib/libopenmpt_la-Load_far.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_far.lo `test -f 'soundlib/Load_far.cpp' || echo '$(srcdir)/'`soundlib/Load_far.cpp soundlib/libopenmpt_la-Load_fc.lo: soundlib/Load_fc.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_fc.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_fc.Tpo -c -o soundlib/libopenmpt_la-Load_fc.lo `test -f 'soundlib/Load_fc.cpp' || echo '$(srcdir)/'`soundlib/Load_fc.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_fc.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_fc.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_fc.cpp' object='soundlib/libopenmpt_la-Load_fc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_fc.lo `test -f 'soundlib/Load_fc.cpp' || echo '$(srcdir)/'`soundlib/Load_fc.cpp soundlib/libopenmpt_la-Load_fmt.lo: soundlib/Load_fmt.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_fmt.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_fmt.Tpo -c -o soundlib/libopenmpt_la-Load_fmt.lo `test -f 'soundlib/Load_fmt.cpp' || echo '$(srcdir)/'`soundlib/Load_fmt.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_fmt.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_fmt.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_fmt.cpp' object='soundlib/libopenmpt_la-Load_fmt.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_fmt.lo `test -f 'soundlib/Load_fmt.cpp' || echo '$(srcdir)/'`soundlib/Load_fmt.cpp soundlib/libopenmpt_la-Load_ftm.lo: soundlib/Load_ftm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_ftm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_ftm.Tpo -c -o soundlib/libopenmpt_la-Load_ftm.lo `test -f 'soundlib/Load_ftm.cpp' || echo '$(srcdir)/'`soundlib/Load_ftm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_ftm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_ftm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ftm.cpp' object='soundlib/libopenmpt_la-Load_ftm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_ftm.lo `test -f 'soundlib/Load_ftm.cpp' || echo '$(srcdir)/'`soundlib/Load_ftm.cpp soundlib/libopenmpt_la-Load_gdm.lo: soundlib/Load_gdm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_gdm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_gdm.Tpo -c -o soundlib/libopenmpt_la-Load_gdm.lo `test -f 'soundlib/Load_gdm.cpp' || echo '$(srcdir)/'`soundlib/Load_gdm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_gdm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_gdm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_gdm.cpp' object='soundlib/libopenmpt_la-Load_gdm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_gdm.lo `test -f 'soundlib/Load_gdm.cpp' || echo '$(srcdir)/'`soundlib/Load_gdm.cpp soundlib/libopenmpt_la-Load_gmc.lo: soundlib/Load_gmc.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_gmc.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_gmc.Tpo -c -o soundlib/libopenmpt_la-Load_gmc.lo `test -f 'soundlib/Load_gmc.cpp' || echo '$(srcdir)/'`soundlib/Load_gmc.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_gmc.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_gmc.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_gmc.cpp' object='soundlib/libopenmpt_la-Load_gmc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_gmc.lo `test -f 'soundlib/Load_gmc.cpp' || echo '$(srcdir)/'`soundlib/Load_gmc.cpp soundlib/libopenmpt_la-Load_gt2.lo: soundlib/Load_gt2.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_gt2.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_gt2.Tpo -c -o soundlib/libopenmpt_la-Load_gt2.lo `test -f 'soundlib/Load_gt2.cpp' || echo '$(srcdir)/'`soundlib/Load_gt2.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_gt2.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_gt2.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_gt2.cpp' object='soundlib/libopenmpt_la-Load_gt2.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_gt2.lo `test -f 'soundlib/Load_gt2.cpp' || echo '$(srcdir)/'`soundlib/Load_gt2.cpp soundlib/libopenmpt_la-Load_ice.lo: soundlib/Load_ice.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_ice.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_ice.Tpo -c -o soundlib/libopenmpt_la-Load_ice.lo `test -f 'soundlib/Load_ice.cpp' || echo '$(srcdir)/'`soundlib/Load_ice.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_ice.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_ice.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ice.cpp' object='soundlib/libopenmpt_la-Load_ice.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_ice.lo `test -f 'soundlib/Load_ice.cpp' || echo '$(srcdir)/'`soundlib/Load_ice.cpp soundlib/libopenmpt_la-Load_imf.lo: soundlib/Load_imf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_imf.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_imf.Tpo -c -o soundlib/libopenmpt_la-Load_imf.lo `test -f 'soundlib/Load_imf.cpp' || echo '$(srcdir)/'`soundlib/Load_imf.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_imf.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_imf.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_imf.cpp' object='soundlib/libopenmpt_la-Load_imf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_imf.lo `test -f 'soundlib/Load_imf.cpp' || echo '$(srcdir)/'`soundlib/Load_imf.cpp soundlib/libopenmpt_la-Load_ims.lo: soundlib/Load_ims.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_ims.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_ims.Tpo -c -o soundlib/libopenmpt_la-Load_ims.lo `test -f 'soundlib/Load_ims.cpp' || echo '$(srcdir)/'`soundlib/Load_ims.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_ims.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_ims.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ims.cpp' object='soundlib/libopenmpt_la-Load_ims.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_ims.lo `test -f 'soundlib/Load_ims.cpp' || echo '$(srcdir)/'`soundlib/Load_ims.cpp soundlib/libopenmpt_la-Load_it.lo: soundlib/Load_it.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_it.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_it.Tpo -c -o soundlib/libopenmpt_la-Load_it.lo `test -f 'soundlib/Load_it.cpp' || echo '$(srcdir)/'`soundlib/Load_it.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_it.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_it.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_it.cpp' object='soundlib/libopenmpt_la-Load_it.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_it.lo `test -f 'soundlib/Load_it.cpp' || echo '$(srcdir)/'`soundlib/Load_it.cpp soundlib/libopenmpt_la-Load_itp.lo: soundlib/Load_itp.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_itp.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_itp.Tpo -c -o soundlib/libopenmpt_la-Load_itp.lo `test -f 'soundlib/Load_itp.cpp' || echo '$(srcdir)/'`soundlib/Load_itp.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_itp.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_itp.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_itp.cpp' object='soundlib/libopenmpt_la-Load_itp.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_itp.lo `test -f 'soundlib/Load_itp.cpp' || echo '$(srcdir)/'`soundlib/Load_itp.cpp soundlib/libopenmpt_la-load_j2b.lo: soundlib/load_j2b.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-load_j2b.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-load_j2b.Tpo -c -o soundlib/libopenmpt_la-load_j2b.lo `test -f 'soundlib/load_j2b.cpp' || echo '$(srcdir)/'`soundlib/load_j2b.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-load_j2b.Tpo soundlib/$(DEPDIR)/libopenmpt_la-load_j2b.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/load_j2b.cpp' object='soundlib/libopenmpt_la-load_j2b.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-load_j2b.lo `test -f 'soundlib/load_j2b.cpp' || echo '$(srcdir)/'`soundlib/load_j2b.cpp soundlib/libopenmpt_la-Load_kris.lo: soundlib/Load_kris.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_kris.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_kris.Tpo -c -o soundlib/libopenmpt_la-Load_kris.lo `test -f 'soundlib/Load_kris.cpp' || echo '$(srcdir)/'`soundlib/Load_kris.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_kris.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_kris.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_kris.cpp' object='soundlib/libopenmpt_la-Load_kris.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_kris.lo `test -f 'soundlib/Load_kris.cpp' || echo '$(srcdir)/'`soundlib/Load_kris.cpp soundlib/libopenmpt_la-Load_mdl.lo: soundlib/Load_mdl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_mdl.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_mdl.Tpo -c -o soundlib/libopenmpt_la-Load_mdl.lo `test -f 'soundlib/Load_mdl.cpp' || echo '$(srcdir)/'`soundlib/Load_mdl.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_mdl.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_mdl.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mdl.cpp' object='soundlib/libopenmpt_la-Load_mdl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_mdl.lo `test -f 'soundlib/Load_mdl.cpp' || echo '$(srcdir)/'`soundlib/Load_mdl.cpp soundlib/libopenmpt_la-Load_med.lo: soundlib/Load_med.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_med.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_med.Tpo -c -o soundlib/libopenmpt_la-Load_med.lo `test -f 'soundlib/Load_med.cpp' || echo '$(srcdir)/'`soundlib/Load_med.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_med.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_med.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_med.cpp' object='soundlib/libopenmpt_la-Load_med.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_med.lo `test -f 'soundlib/Load_med.cpp' || echo '$(srcdir)/'`soundlib/Load_med.cpp soundlib/libopenmpt_la-Load_mid.lo: soundlib/Load_mid.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_mid.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_mid.Tpo -c -o soundlib/libopenmpt_la-Load_mid.lo `test -f 'soundlib/Load_mid.cpp' || echo '$(srcdir)/'`soundlib/Load_mid.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_mid.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_mid.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mid.cpp' object='soundlib/libopenmpt_la-Load_mid.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_mid.lo `test -f 'soundlib/Load_mid.cpp' || echo '$(srcdir)/'`soundlib/Load_mid.cpp soundlib/libopenmpt_la-Load_mo3.lo: soundlib/Load_mo3.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_mo3.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_mo3.Tpo -c -o soundlib/libopenmpt_la-Load_mo3.lo `test -f 'soundlib/Load_mo3.cpp' || echo '$(srcdir)/'`soundlib/Load_mo3.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_mo3.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_mo3.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mo3.cpp' object='soundlib/libopenmpt_la-Load_mo3.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_mo3.lo `test -f 'soundlib/Load_mo3.cpp' || echo '$(srcdir)/'`soundlib/Load_mo3.cpp soundlib/libopenmpt_la-Load_mod.lo: soundlib/Load_mod.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_mod.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_mod.Tpo -c -o soundlib/libopenmpt_la-Load_mod.lo `test -f 'soundlib/Load_mod.cpp' || echo '$(srcdir)/'`soundlib/Load_mod.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_mod.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_mod.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mod.cpp' object='soundlib/libopenmpt_la-Load_mod.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_mod.lo `test -f 'soundlib/Load_mod.cpp' || echo '$(srcdir)/'`soundlib/Load_mod.cpp soundlib/libopenmpt_la-Load_mt2.lo: soundlib/Load_mt2.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_mt2.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_mt2.Tpo -c -o soundlib/libopenmpt_la-Load_mt2.lo `test -f 'soundlib/Load_mt2.cpp' || echo '$(srcdir)/'`soundlib/Load_mt2.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_mt2.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_mt2.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mt2.cpp' object='soundlib/libopenmpt_la-Load_mt2.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_mt2.lo `test -f 'soundlib/Load_mt2.cpp' || echo '$(srcdir)/'`soundlib/Load_mt2.cpp soundlib/libopenmpt_la-Load_mtm.lo: soundlib/Load_mtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_mtm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_mtm.Tpo -c -o soundlib/libopenmpt_la-Load_mtm.lo `test -f 'soundlib/Load_mtm.cpp' || echo '$(srcdir)/'`soundlib/Load_mtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_mtm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_mtm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mtm.cpp' object='soundlib/libopenmpt_la-Load_mtm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_mtm.lo `test -f 'soundlib/Load_mtm.cpp' || echo '$(srcdir)/'`soundlib/Load_mtm.cpp soundlib/libopenmpt_la-Load_mus_km.lo: soundlib/Load_mus_km.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_mus_km.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_mus_km.Tpo -c -o soundlib/libopenmpt_la-Load_mus_km.lo `test -f 'soundlib/Load_mus_km.cpp' || echo '$(srcdir)/'`soundlib/Load_mus_km.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_mus_km.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_mus_km.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mus_km.cpp' object='soundlib/libopenmpt_la-Load_mus_km.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_mus_km.lo `test -f 'soundlib/Load_mus_km.cpp' || echo '$(srcdir)/'`soundlib/Load_mus_km.cpp soundlib/libopenmpt_la-Load_okt.lo: soundlib/Load_okt.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_okt.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_okt.Tpo -c -o soundlib/libopenmpt_la-Load_okt.lo `test -f 'soundlib/Load_okt.cpp' || echo '$(srcdir)/'`soundlib/Load_okt.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_okt.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_okt.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_okt.cpp' object='soundlib/libopenmpt_la-Load_okt.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_okt.lo `test -f 'soundlib/Load_okt.cpp' || echo '$(srcdir)/'`soundlib/Load_okt.cpp soundlib/libopenmpt_la-Load_plm.lo: soundlib/Load_plm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_plm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_plm.Tpo -c -o soundlib/libopenmpt_la-Load_plm.lo `test -f 'soundlib/Load_plm.cpp' || echo '$(srcdir)/'`soundlib/Load_plm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_plm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_plm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_plm.cpp' object='soundlib/libopenmpt_la-Load_plm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_plm.lo `test -f 'soundlib/Load_plm.cpp' || echo '$(srcdir)/'`soundlib/Load_plm.cpp soundlib/libopenmpt_la-Load_psm.lo: soundlib/Load_psm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_psm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_psm.Tpo -c -o soundlib/libopenmpt_la-Load_psm.lo `test -f 'soundlib/Load_psm.cpp' || echo '$(srcdir)/'`soundlib/Load_psm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_psm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_psm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_psm.cpp' object='soundlib/libopenmpt_la-Load_psm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_psm.lo `test -f 'soundlib/Load_psm.cpp' || echo '$(srcdir)/'`soundlib/Load_psm.cpp soundlib/libopenmpt_la-Load_pt36.lo: soundlib/Load_pt36.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_pt36.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_pt36.Tpo -c -o soundlib/libopenmpt_la-Load_pt36.lo `test -f 'soundlib/Load_pt36.cpp' || echo '$(srcdir)/'`soundlib/Load_pt36.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_pt36.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_pt36.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_pt36.cpp' object='soundlib/libopenmpt_la-Load_pt36.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_pt36.lo `test -f 'soundlib/Load_pt36.cpp' || echo '$(srcdir)/'`soundlib/Load_pt36.cpp soundlib/libopenmpt_la-Load_ptm.lo: soundlib/Load_ptm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_ptm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_ptm.Tpo -c -o soundlib/libopenmpt_la-Load_ptm.lo `test -f 'soundlib/Load_ptm.cpp' || echo '$(srcdir)/'`soundlib/Load_ptm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_ptm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_ptm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ptm.cpp' object='soundlib/libopenmpt_la-Load_ptm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_ptm.lo `test -f 'soundlib/Load_ptm.cpp' || echo '$(srcdir)/'`soundlib/Load_ptm.cpp soundlib/libopenmpt_la-Load_puma.lo: soundlib/Load_puma.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_puma.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_puma.Tpo -c -o soundlib/libopenmpt_la-Load_puma.lo `test -f 'soundlib/Load_puma.cpp' || echo '$(srcdir)/'`soundlib/Load_puma.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_puma.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_puma.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_puma.cpp' object='soundlib/libopenmpt_la-Load_puma.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_puma.lo `test -f 'soundlib/Load_puma.cpp' || echo '$(srcdir)/'`soundlib/Load_puma.cpp soundlib/libopenmpt_la-Load_rtm.lo: soundlib/Load_rtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_rtm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_rtm.Tpo -c -o soundlib/libopenmpt_la-Load_rtm.lo `test -f 'soundlib/Load_rtm.cpp' || echo '$(srcdir)/'`soundlib/Load_rtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_rtm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_rtm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_rtm.cpp' object='soundlib/libopenmpt_la-Load_rtm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_rtm.lo `test -f 'soundlib/Load_rtm.cpp' || echo '$(srcdir)/'`soundlib/Load_rtm.cpp soundlib/libopenmpt_la-Load_s3m.lo: soundlib/Load_s3m.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_s3m.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_s3m.Tpo -c -o soundlib/libopenmpt_la-Load_s3m.lo `test -f 'soundlib/Load_s3m.cpp' || echo '$(srcdir)/'`soundlib/Load_s3m.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_s3m.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_s3m.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_s3m.cpp' object='soundlib/libopenmpt_la-Load_s3m.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_s3m.lo `test -f 'soundlib/Load_s3m.cpp' || echo '$(srcdir)/'`soundlib/Load_s3m.cpp soundlib/libopenmpt_la-Load_sfx.lo: soundlib/Load_sfx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_sfx.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_sfx.Tpo -c -o soundlib/libopenmpt_la-Load_sfx.lo `test -f 'soundlib/Load_sfx.cpp' || echo '$(srcdir)/'`soundlib/Load_sfx.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_sfx.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_sfx.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_sfx.cpp' object='soundlib/libopenmpt_la-Load_sfx.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_sfx.lo `test -f 'soundlib/Load_sfx.cpp' || echo '$(srcdir)/'`soundlib/Load_sfx.cpp soundlib/libopenmpt_la-Load_stk.lo: soundlib/Load_stk.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_stk.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_stk.Tpo -c -o soundlib/libopenmpt_la-Load_stk.lo `test -f 'soundlib/Load_stk.cpp' || echo '$(srcdir)/'`soundlib/Load_stk.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_stk.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_stk.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_stk.cpp' object='soundlib/libopenmpt_la-Load_stk.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_stk.lo `test -f 'soundlib/Load_stk.cpp' || echo '$(srcdir)/'`soundlib/Load_stk.cpp soundlib/libopenmpt_la-Load_stm.lo: soundlib/Load_stm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_stm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_stm.Tpo -c -o soundlib/libopenmpt_la-Load_stm.lo `test -f 'soundlib/Load_stm.cpp' || echo '$(srcdir)/'`soundlib/Load_stm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_stm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_stm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_stm.cpp' object='soundlib/libopenmpt_la-Load_stm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_stm.lo `test -f 'soundlib/Load_stm.cpp' || echo '$(srcdir)/'`soundlib/Load_stm.cpp soundlib/libopenmpt_la-Load_stp.lo: soundlib/Load_stp.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_stp.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_stp.Tpo -c -o soundlib/libopenmpt_la-Load_stp.lo `test -f 'soundlib/Load_stp.cpp' || echo '$(srcdir)/'`soundlib/Load_stp.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_stp.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_stp.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_stp.cpp' object='soundlib/libopenmpt_la-Load_stp.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_stp.lo `test -f 'soundlib/Load_stp.cpp' || echo '$(srcdir)/'`soundlib/Load_stp.cpp soundlib/libopenmpt_la-Load_symmod.lo: soundlib/Load_symmod.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_symmod.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_symmod.Tpo -c -o soundlib/libopenmpt_la-Load_symmod.lo `test -f 'soundlib/Load_symmod.cpp' || echo '$(srcdir)/'`soundlib/Load_symmod.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_symmod.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_symmod.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_symmod.cpp' object='soundlib/libopenmpt_la-Load_symmod.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_symmod.lo `test -f 'soundlib/Load_symmod.cpp' || echo '$(srcdir)/'`soundlib/Load_symmod.cpp soundlib/libopenmpt_la-Load_tcb.lo: soundlib/Load_tcb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_tcb.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_tcb.Tpo -c -o soundlib/libopenmpt_la-Load_tcb.lo `test -f 'soundlib/Load_tcb.cpp' || echo '$(srcdir)/'`soundlib/Load_tcb.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_tcb.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_tcb.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_tcb.cpp' object='soundlib/libopenmpt_la-Load_tcb.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_tcb.lo `test -f 'soundlib/Load_tcb.cpp' || echo '$(srcdir)/'`soundlib/Load_tcb.cpp soundlib/libopenmpt_la-Load_uax.lo: soundlib/Load_uax.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_uax.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_uax.Tpo -c -o soundlib/libopenmpt_la-Load_uax.lo `test -f 'soundlib/Load_uax.cpp' || echo '$(srcdir)/'`soundlib/Load_uax.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_uax.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_uax.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_uax.cpp' object='soundlib/libopenmpt_la-Load_uax.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_uax.lo `test -f 'soundlib/Load_uax.cpp' || echo '$(srcdir)/'`soundlib/Load_uax.cpp soundlib/libopenmpt_la-Load_ult.lo: soundlib/Load_ult.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_ult.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_ult.Tpo -c -o soundlib/libopenmpt_la-Load_ult.lo `test -f 'soundlib/Load_ult.cpp' || echo '$(srcdir)/'`soundlib/Load_ult.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_ult.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_ult.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ult.cpp' object='soundlib/libopenmpt_la-Load_ult.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_ult.lo `test -f 'soundlib/Load_ult.cpp' || echo '$(srcdir)/'`soundlib/Load_ult.cpp soundlib/libopenmpt_la-Load_unic.lo: soundlib/Load_unic.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_unic.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_unic.Tpo -c -o soundlib/libopenmpt_la-Load_unic.lo `test -f 'soundlib/Load_unic.cpp' || echo '$(srcdir)/'`soundlib/Load_unic.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_unic.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_unic.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_unic.cpp' object='soundlib/libopenmpt_la-Load_unic.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_unic.lo `test -f 'soundlib/Load_unic.cpp' || echo '$(srcdir)/'`soundlib/Load_unic.cpp soundlib/libopenmpt_la-Load_wav.lo: soundlib/Load_wav.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_wav.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_wav.Tpo -c -o soundlib/libopenmpt_la-Load_wav.lo `test -f 'soundlib/Load_wav.cpp' || echo '$(srcdir)/'`soundlib/Load_wav.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_wav.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_wav.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_wav.cpp' object='soundlib/libopenmpt_la-Load_wav.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_wav.lo `test -f 'soundlib/Load_wav.cpp' || echo '$(srcdir)/'`soundlib/Load_wav.cpp soundlib/libopenmpt_la-Load_xm.lo: soundlib/Load_xm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_xm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_xm.Tpo -c -o soundlib/libopenmpt_la-Load_xm.lo `test -f 'soundlib/Load_xm.cpp' || echo '$(srcdir)/'`soundlib/Load_xm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_xm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_xm.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_xm.cpp' object='soundlib/libopenmpt_la-Load_xm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_xm.lo `test -f 'soundlib/Load_xm.cpp' || echo '$(srcdir)/'`soundlib/Load_xm.cpp soundlib/libopenmpt_la-Load_xmf.lo: soundlib/Load_xmf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_xmf.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_xmf.Tpo -c -o soundlib/libopenmpt_la-Load_xmf.lo `test -f 'soundlib/Load_xmf.cpp' || echo '$(srcdir)/'`soundlib/Load_xmf.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_xmf.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_xmf.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_xmf.cpp' object='soundlib/libopenmpt_la-Load_xmf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_xmf.lo `test -f 'soundlib/Load_xmf.cpp' || echo '$(srcdir)/'`soundlib/Load_xmf.cpp soundlib/libopenmpt_la-Message.lo: soundlib/Message.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Message.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Message.Tpo -c -o soundlib/libopenmpt_la-Message.lo `test -f 'soundlib/Message.cpp' || echo '$(srcdir)/'`soundlib/Message.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Message.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Message.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Message.cpp' object='soundlib/libopenmpt_la-Message.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Message.lo `test -f 'soundlib/Message.cpp' || echo '$(srcdir)/'`soundlib/Message.cpp soundlib/libopenmpt_la-MIDIEvents.lo: soundlib/MIDIEvents.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-MIDIEvents.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-MIDIEvents.Tpo -c -o soundlib/libopenmpt_la-MIDIEvents.lo `test -f 'soundlib/MIDIEvents.cpp' || echo '$(srcdir)/'`soundlib/MIDIEvents.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-MIDIEvents.Tpo soundlib/$(DEPDIR)/libopenmpt_la-MIDIEvents.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MIDIEvents.cpp' object='soundlib/libopenmpt_la-MIDIEvents.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-MIDIEvents.lo `test -f 'soundlib/MIDIEvents.cpp' || echo '$(srcdir)/'`soundlib/MIDIEvents.cpp soundlib/libopenmpt_la-MIDIMacroParser.lo: soundlib/MIDIMacroParser.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-MIDIMacroParser.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacroParser.Tpo -c -o soundlib/libopenmpt_la-MIDIMacroParser.lo `test -f 'soundlib/MIDIMacroParser.cpp' || echo '$(srcdir)/'`soundlib/MIDIMacroParser.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacroParser.Tpo soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacroParser.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MIDIMacroParser.cpp' object='soundlib/libopenmpt_la-MIDIMacroParser.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-MIDIMacroParser.lo `test -f 'soundlib/MIDIMacroParser.cpp' || echo '$(srcdir)/'`soundlib/MIDIMacroParser.cpp soundlib/libopenmpt_la-MIDIMacros.lo: soundlib/MIDIMacros.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-MIDIMacros.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacros.Tpo -c -o soundlib/libopenmpt_la-MIDIMacros.lo `test -f 'soundlib/MIDIMacros.cpp' || echo '$(srcdir)/'`soundlib/MIDIMacros.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacros.Tpo soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacros.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MIDIMacros.cpp' object='soundlib/libopenmpt_la-MIDIMacros.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-MIDIMacros.lo `test -f 'soundlib/MIDIMacros.cpp' || echo '$(srcdir)/'`soundlib/MIDIMacros.cpp soundlib/libopenmpt_la-MixerLoops.lo: soundlib/MixerLoops.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-MixerLoops.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-MixerLoops.Tpo -c -o soundlib/libopenmpt_la-MixerLoops.lo `test -f 'soundlib/MixerLoops.cpp' || echo '$(srcdir)/'`soundlib/MixerLoops.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-MixerLoops.Tpo soundlib/$(DEPDIR)/libopenmpt_la-MixerLoops.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MixerLoops.cpp' object='soundlib/libopenmpt_la-MixerLoops.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-MixerLoops.lo `test -f 'soundlib/MixerLoops.cpp' || echo '$(srcdir)/'`soundlib/MixerLoops.cpp soundlib/libopenmpt_la-MixerSettings.lo: soundlib/MixerSettings.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-MixerSettings.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-MixerSettings.Tpo -c -o soundlib/libopenmpt_la-MixerSettings.lo `test -f 'soundlib/MixerSettings.cpp' || echo '$(srcdir)/'`soundlib/MixerSettings.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-MixerSettings.Tpo soundlib/$(DEPDIR)/libopenmpt_la-MixerSettings.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MixerSettings.cpp' object='soundlib/libopenmpt_la-MixerSettings.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-MixerSettings.lo `test -f 'soundlib/MixerSettings.cpp' || echo '$(srcdir)/'`soundlib/MixerSettings.cpp soundlib/libopenmpt_la-MixFuncTable.lo: soundlib/MixFuncTable.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-MixFuncTable.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-MixFuncTable.Tpo -c -o soundlib/libopenmpt_la-MixFuncTable.lo `test -f 'soundlib/MixFuncTable.cpp' || echo '$(srcdir)/'`soundlib/MixFuncTable.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-MixFuncTable.Tpo soundlib/$(DEPDIR)/libopenmpt_la-MixFuncTable.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MixFuncTable.cpp' object='soundlib/libopenmpt_la-MixFuncTable.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-MixFuncTable.lo `test -f 'soundlib/MixFuncTable.cpp' || echo '$(srcdir)/'`soundlib/MixFuncTable.cpp soundlib/libopenmpt_la-ModChannel.lo: soundlib/ModChannel.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ModChannel.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ModChannel.Tpo -c -o soundlib/libopenmpt_la-ModChannel.lo `test -f 'soundlib/ModChannel.cpp' || echo '$(srcdir)/'`soundlib/ModChannel.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ModChannel.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ModChannel.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModChannel.cpp' object='soundlib/libopenmpt_la-ModChannel.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ModChannel.lo `test -f 'soundlib/ModChannel.cpp' || echo '$(srcdir)/'`soundlib/ModChannel.cpp soundlib/libopenmpt_la-modcommand.lo: soundlib/modcommand.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-modcommand.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-modcommand.Tpo -c -o soundlib/libopenmpt_la-modcommand.lo `test -f 'soundlib/modcommand.cpp' || echo '$(srcdir)/'`soundlib/modcommand.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-modcommand.Tpo soundlib/$(DEPDIR)/libopenmpt_la-modcommand.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/modcommand.cpp' object='soundlib/libopenmpt_la-modcommand.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-modcommand.lo `test -f 'soundlib/modcommand.cpp' || echo '$(srcdir)/'`soundlib/modcommand.cpp soundlib/libopenmpt_la-ModInstrument.lo: soundlib/ModInstrument.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ModInstrument.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ModInstrument.Tpo -c -o soundlib/libopenmpt_la-ModInstrument.lo `test -f 'soundlib/ModInstrument.cpp' || echo '$(srcdir)/'`soundlib/ModInstrument.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ModInstrument.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ModInstrument.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModInstrument.cpp' object='soundlib/libopenmpt_la-ModInstrument.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ModInstrument.lo `test -f 'soundlib/ModInstrument.cpp' || echo '$(srcdir)/'`soundlib/ModInstrument.cpp soundlib/libopenmpt_la-ModSample.lo: soundlib/ModSample.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ModSample.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ModSample.Tpo -c -o soundlib/libopenmpt_la-ModSample.lo `test -f 'soundlib/ModSample.cpp' || echo '$(srcdir)/'`soundlib/ModSample.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ModSample.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ModSample.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModSample.cpp' object='soundlib/libopenmpt_la-ModSample.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ModSample.lo `test -f 'soundlib/ModSample.cpp' || echo '$(srcdir)/'`soundlib/ModSample.cpp soundlib/libopenmpt_la-ModSequence.lo: soundlib/ModSequence.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ModSequence.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ModSequence.Tpo -c -o soundlib/libopenmpt_la-ModSequence.lo `test -f 'soundlib/ModSequence.cpp' || echo '$(srcdir)/'`soundlib/ModSequence.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ModSequence.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ModSequence.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModSequence.cpp' object='soundlib/libopenmpt_la-ModSequence.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ModSequence.lo `test -f 'soundlib/ModSequence.cpp' || echo '$(srcdir)/'`soundlib/ModSequence.cpp soundlib/libopenmpt_la-modsmp_ctrl.lo: soundlib/modsmp_ctrl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-modsmp_ctrl.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-modsmp_ctrl.Tpo -c -o soundlib/libopenmpt_la-modsmp_ctrl.lo `test -f 'soundlib/modsmp_ctrl.cpp' || echo '$(srcdir)/'`soundlib/modsmp_ctrl.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-modsmp_ctrl.Tpo soundlib/$(DEPDIR)/libopenmpt_la-modsmp_ctrl.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/modsmp_ctrl.cpp' object='soundlib/libopenmpt_la-modsmp_ctrl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-modsmp_ctrl.lo `test -f 'soundlib/modsmp_ctrl.cpp' || echo '$(srcdir)/'`soundlib/modsmp_ctrl.cpp soundlib/libopenmpt_la-mod_specifications.lo: soundlib/mod_specifications.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-mod_specifications.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-mod_specifications.Tpo -c -o soundlib/libopenmpt_la-mod_specifications.lo `test -f 'soundlib/mod_specifications.cpp' || echo '$(srcdir)/'`soundlib/mod_specifications.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-mod_specifications.Tpo soundlib/$(DEPDIR)/libopenmpt_la-mod_specifications.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/mod_specifications.cpp' object='soundlib/libopenmpt_la-mod_specifications.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-mod_specifications.lo `test -f 'soundlib/mod_specifications.cpp' || echo '$(srcdir)/'`soundlib/mod_specifications.cpp soundlib/libopenmpt_la-MODTools.lo: soundlib/MODTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-MODTools.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-MODTools.Tpo -c -o soundlib/libopenmpt_la-MODTools.lo `test -f 'soundlib/MODTools.cpp' || echo '$(srcdir)/'`soundlib/MODTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-MODTools.Tpo soundlib/$(DEPDIR)/libopenmpt_la-MODTools.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MODTools.cpp' object='soundlib/libopenmpt_la-MODTools.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-MODTools.lo `test -f 'soundlib/MODTools.cpp' || echo '$(srcdir)/'`soundlib/MODTools.cpp soundlib/libopenmpt_la-MPEGFrame.lo: soundlib/MPEGFrame.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-MPEGFrame.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-MPEGFrame.Tpo -c -o soundlib/libopenmpt_la-MPEGFrame.lo `test -f 'soundlib/MPEGFrame.cpp' || echo '$(srcdir)/'`soundlib/MPEGFrame.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-MPEGFrame.Tpo soundlib/$(DEPDIR)/libopenmpt_la-MPEGFrame.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MPEGFrame.cpp' object='soundlib/libopenmpt_la-MPEGFrame.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-MPEGFrame.lo `test -f 'soundlib/MPEGFrame.cpp' || echo '$(srcdir)/'`soundlib/MPEGFrame.cpp soundlib/libopenmpt_la-OggStream.lo: soundlib/OggStream.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-OggStream.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-OggStream.Tpo -c -o soundlib/libopenmpt_la-OggStream.lo `test -f 'soundlib/OggStream.cpp' || echo '$(srcdir)/'`soundlib/OggStream.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-OggStream.Tpo soundlib/$(DEPDIR)/libopenmpt_la-OggStream.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/OggStream.cpp' object='soundlib/libopenmpt_la-OggStream.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-OggStream.lo `test -f 'soundlib/OggStream.cpp' || echo '$(srcdir)/'`soundlib/OggStream.cpp soundlib/libopenmpt_la-OPL.lo: soundlib/OPL.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-OPL.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-OPL.Tpo -c -o soundlib/libopenmpt_la-OPL.lo `test -f 'soundlib/OPL.cpp' || echo '$(srcdir)/'`soundlib/OPL.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-OPL.Tpo soundlib/$(DEPDIR)/libopenmpt_la-OPL.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/OPL.cpp' object='soundlib/libopenmpt_la-OPL.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-OPL.lo `test -f 'soundlib/OPL.cpp' || echo '$(srcdir)/'`soundlib/OPL.cpp soundlib/libopenmpt_la-Paula.lo: soundlib/Paula.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Paula.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Paula.Tpo -c -o soundlib/libopenmpt_la-Paula.lo `test -f 'soundlib/Paula.cpp' || echo '$(srcdir)/'`soundlib/Paula.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Paula.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Paula.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Paula.cpp' object='soundlib/libopenmpt_la-Paula.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Paula.lo `test -f 'soundlib/Paula.cpp' || echo '$(srcdir)/'`soundlib/Paula.cpp soundlib/libopenmpt_la-patternContainer.lo: soundlib/patternContainer.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-patternContainer.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-patternContainer.Tpo -c -o soundlib/libopenmpt_la-patternContainer.lo `test -f 'soundlib/patternContainer.cpp' || echo '$(srcdir)/'`soundlib/patternContainer.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-patternContainer.Tpo soundlib/$(DEPDIR)/libopenmpt_la-patternContainer.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/patternContainer.cpp' object='soundlib/libopenmpt_la-patternContainer.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-patternContainer.lo `test -f 'soundlib/patternContainer.cpp' || echo '$(srcdir)/'`soundlib/patternContainer.cpp soundlib/libopenmpt_la-pattern.lo: soundlib/pattern.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-pattern.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-pattern.Tpo -c -o soundlib/libopenmpt_la-pattern.lo `test -f 'soundlib/pattern.cpp' || echo '$(srcdir)/'`soundlib/pattern.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-pattern.Tpo soundlib/$(DEPDIR)/libopenmpt_la-pattern.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/pattern.cpp' object='soundlib/libopenmpt_la-pattern.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-pattern.lo `test -f 'soundlib/pattern.cpp' || echo '$(srcdir)/'`soundlib/pattern.cpp soundlib/libopenmpt_la-PlaybackTest.lo: soundlib/PlaybackTest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-PlaybackTest.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-PlaybackTest.Tpo -c -o soundlib/libopenmpt_la-PlaybackTest.lo `test -f 'soundlib/PlaybackTest.cpp' || echo '$(srcdir)/'`soundlib/PlaybackTest.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-PlaybackTest.Tpo soundlib/$(DEPDIR)/libopenmpt_la-PlaybackTest.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/PlaybackTest.cpp' object='soundlib/libopenmpt_la-PlaybackTest.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-PlaybackTest.lo `test -f 'soundlib/PlaybackTest.cpp' || echo '$(srcdir)/'`soundlib/PlaybackTest.cpp soundlib/libopenmpt_la-PlayState.lo: soundlib/PlayState.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-PlayState.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-PlayState.Tpo -c -o soundlib/libopenmpt_la-PlayState.lo `test -f 'soundlib/PlayState.cpp' || echo '$(srcdir)/'`soundlib/PlayState.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-PlayState.Tpo soundlib/$(DEPDIR)/libopenmpt_la-PlayState.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/PlayState.cpp' object='soundlib/libopenmpt_la-PlayState.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-PlayState.lo `test -f 'soundlib/PlayState.cpp' || echo '$(srcdir)/'`soundlib/PlayState.cpp soundlib/libopenmpt_la-RowVisitor.lo: soundlib/RowVisitor.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-RowVisitor.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-RowVisitor.Tpo -c -o soundlib/libopenmpt_la-RowVisitor.lo `test -f 'soundlib/RowVisitor.cpp' || echo '$(srcdir)/'`soundlib/RowVisitor.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-RowVisitor.Tpo soundlib/$(DEPDIR)/libopenmpt_la-RowVisitor.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/RowVisitor.cpp' object='soundlib/libopenmpt_la-RowVisitor.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-RowVisitor.lo `test -f 'soundlib/RowVisitor.cpp' || echo '$(srcdir)/'`soundlib/RowVisitor.cpp soundlib/libopenmpt_la-S3MTools.lo: soundlib/S3MTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-S3MTools.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-S3MTools.Tpo -c -o soundlib/libopenmpt_la-S3MTools.lo `test -f 'soundlib/S3MTools.cpp' || echo '$(srcdir)/'`soundlib/S3MTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-S3MTools.Tpo soundlib/$(DEPDIR)/libopenmpt_la-S3MTools.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/S3MTools.cpp' object='soundlib/libopenmpt_la-S3MTools.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-S3MTools.lo `test -f 'soundlib/S3MTools.cpp' || echo '$(srcdir)/'`soundlib/S3MTools.cpp soundlib/libopenmpt_la-SampleFormats.lo: soundlib/SampleFormats.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormats.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormats.Tpo -c -o soundlib/libopenmpt_la-SampleFormats.lo `test -f 'soundlib/SampleFormats.cpp' || echo '$(srcdir)/'`soundlib/SampleFormats.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormats.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormats.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormats.cpp' object='soundlib/libopenmpt_la-SampleFormats.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormats.lo `test -f 'soundlib/SampleFormats.cpp' || echo '$(srcdir)/'`soundlib/SampleFormats.cpp soundlib/libopenmpt_la-SampleFormatBRR.lo: soundlib/SampleFormatBRR.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatBRR.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatBRR.Tpo -c -o soundlib/libopenmpt_la-SampleFormatBRR.lo `test -f 'soundlib/SampleFormatBRR.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatBRR.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatBRR.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatBRR.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatBRR.cpp' object='soundlib/libopenmpt_la-SampleFormatBRR.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatBRR.lo `test -f 'soundlib/SampleFormatBRR.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatBRR.cpp soundlib/libopenmpt_la-SampleFormatFLAC.lo: soundlib/SampleFormatFLAC.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatFLAC.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatFLAC.Tpo -c -o soundlib/libopenmpt_la-SampleFormatFLAC.lo `test -f 'soundlib/SampleFormatFLAC.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatFLAC.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatFLAC.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatFLAC.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatFLAC.cpp' object='soundlib/libopenmpt_la-SampleFormatFLAC.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatFLAC.lo `test -f 'soundlib/SampleFormatFLAC.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatFLAC.cpp soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo: soundlib/SampleFormatMediaFoundation.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMediaFoundation.Tpo -c -o soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo `test -f 'soundlib/SampleFormatMediaFoundation.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMediaFoundation.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMediaFoundation.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMediaFoundation.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatMediaFoundation.cpp' object='soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo `test -f 'soundlib/SampleFormatMediaFoundation.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMediaFoundation.cpp soundlib/libopenmpt_la-SampleFormatMP3.lo: soundlib/SampleFormatMP3.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatMP3.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMP3.Tpo -c -o soundlib/libopenmpt_la-SampleFormatMP3.lo `test -f 'soundlib/SampleFormatMP3.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMP3.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMP3.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMP3.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatMP3.cpp' object='soundlib/libopenmpt_la-SampleFormatMP3.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatMP3.lo `test -f 'soundlib/SampleFormatMP3.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMP3.cpp soundlib/libopenmpt_la-SampleFormatOpus.lo: soundlib/SampleFormatOpus.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatOpus.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatOpus.Tpo -c -o soundlib/libopenmpt_la-SampleFormatOpus.lo `test -f 'soundlib/SampleFormatOpus.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatOpus.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatOpus.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatOpus.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatOpus.cpp' object='soundlib/libopenmpt_la-SampleFormatOpus.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatOpus.lo `test -f 'soundlib/SampleFormatOpus.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatOpus.cpp soundlib/libopenmpt_la-SampleFormatSFZ.lo: soundlib/SampleFormatSFZ.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatSFZ.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatSFZ.Tpo -c -o soundlib/libopenmpt_la-SampleFormatSFZ.lo `test -f 'soundlib/SampleFormatSFZ.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatSFZ.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatSFZ.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatSFZ.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatSFZ.cpp' object='soundlib/libopenmpt_la-SampleFormatSFZ.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatSFZ.lo `test -f 'soundlib/SampleFormatSFZ.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatSFZ.cpp soundlib/libopenmpt_la-SampleFormatVorbis.lo: soundlib/SampleFormatVorbis.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatVorbis.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatVorbis.Tpo -c -o soundlib/libopenmpt_la-SampleFormatVorbis.lo `test -f 'soundlib/SampleFormatVorbis.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatVorbis.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatVorbis.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatVorbis.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatVorbis.cpp' object='soundlib/libopenmpt_la-SampleFormatVorbis.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatVorbis.lo `test -f 'soundlib/SampleFormatVorbis.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatVorbis.cpp soundlib/libopenmpt_la-SampleIO.lo: soundlib/SampleIO.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleIO.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleIO.Tpo -c -o soundlib/libopenmpt_la-SampleIO.lo `test -f 'soundlib/SampleIO.cpp' || echo '$(srcdir)/'`soundlib/SampleIO.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleIO.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleIO.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleIO.cpp' object='soundlib/libopenmpt_la-SampleIO.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleIO.lo `test -f 'soundlib/SampleIO.cpp' || echo '$(srcdir)/'`soundlib/SampleIO.cpp soundlib/libopenmpt_la-Sndfile.lo: soundlib/Sndfile.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Sndfile.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Sndfile.Tpo -c -o soundlib/libopenmpt_la-Sndfile.lo `test -f 'soundlib/Sndfile.cpp' || echo '$(srcdir)/'`soundlib/Sndfile.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Sndfile.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Sndfile.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Sndfile.cpp' object='soundlib/libopenmpt_la-Sndfile.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Sndfile.lo `test -f 'soundlib/Sndfile.cpp' || echo '$(srcdir)/'`soundlib/Sndfile.cpp soundlib/libopenmpt_la-Snd_flt.lo: soundlib/Snd_flt.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Snd_flt.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Snd_flt.Tpo -c -o soundlib/libopenmpt_la-Snd_flt.lo `test -f 'soundlib/Snd_flt.cpp' || echo '$(srcdir)/'`soundlib/Snd_flt.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Snd_flt.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Snd_flt.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Snd_flt.cpp' object='soundlib/libopenmpt_la-Snd_flt.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Snd_flt.lo `test -f 'soundlib/Snd_flt.cpp' || echo '$(srcdir)/'`soundlib/Snd_flt.cpp soundlib/libopenmpt_la-Snd_fx.lo: soundlib/Snd_fx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Snd_fx.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Snd_fx.Tpo -c -o soundlib/libopenmpt_la-Snd_fx.lo `test -f 'soundlib/Snd_fx.cpp' || echo '$(srcdir)/'`soundlib/Snd_fx.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Snd_fx.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Snd_fx.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Snd_fx.cpp' object='soundlib/libopenmpt_la-Snd_fx.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Snd_fx.lo `test -f 'soundlib/Snd_fx.cpp' || echo '$(srcdir)/'`soundlib/Snd_fx.cpp soundlib/libopenmpt_la-Sndmix.lo: soundlib/Sndmix.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Sndmix.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Sndmix.Tpo -c -o soundlib/libopenmpt_la-Sndmix.lo `test -f 'soundlib/Sndmix.cpp' || echo '$(srcdir)/'`soundlib/Sndmix.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Sndmix.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Sndmix.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Sndmix.cpp' object='soundlib/libopenmpt_la-Sndmix.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Sndmix.lo `test -f 'soundlib/Sndmix.cpp' || echo '$(srcdir)/'`soundlib/Sndmix.cpp soundlib/libopenmpt_la-SoundFilePlayConfig.lo: soundlib/SoundFilePlayConfig.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SoundFilePlayConfig.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SoundFilePlayConfig.Tpo -c -o soundlib/libopenmpt_la-SoundFilePlayConfig.lo `test -f 'soundlib/SoundFilePlayConfig.cpp' || echo '$(srcdir)/'`soundlib/SoundFilePlayConfig.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SoundFilePlayConfig.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SoundFilePlayConfig.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SoundFilePlayConfig.cpp' object='soundlib/libopenmpt_la-SoundFilePlayConfig.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SoundFilePlayConfig.lo `test -f 'soundlib/SoundFilePlayConfig.cpp' || echo '$(srcdir)/'`soundlib/SoundFilePlayConfig.cpp soundlib/libopenmpt_la-Tables.lo: soundlib/Tables.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Tables.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Tables.Tpo -c -o soundlib/libopenmpt_la-Tables.lo `test -f 'soundlib/Tables.cpp' || echo '$(srcdir)/'`soundlib/Tables.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Tables.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Tables.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Tables.cpp' object='soundlib/libopenmpt_la-Tables.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Tables.lo `test -f 'soundlib/Tables.cpp' || echo '$(srcdir)/'`soundlib/Tables.cpp soundlib/libopenmpt_la-Tagging.lo: soundlib/Tagging.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Tagging.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Tagging.Tpo -c -o soundlib/libopenmpt_la-Tagging.lo `test -f 'soundlib/Tagging.cpp' || echo '$(srcdir)/'`soundlib/Tagging.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Tagging.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Tagging.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Tagging.cpp' object='soundlib/libopenmpt_la-Tagging.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Tagging.lo `test -f 'soundlib/Tagging.cpp' || echo '$(srcdir)/'`soundlib/Tagging.cpp soundlib/libopenmpt_la-TinyFFT.lo: soundlib/TinyFFT.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-TinyFFT.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-TinyFFT.Tpo -c -o soundlib/libopenmpt_la-TinyFFT.lo `test -f 'soundlib/TinyFFT.cpp' || echo '$(srcdir)/'`soundlib/TinyFFT.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-TinyFFT.Tpo soundlib/$(DEPDIR)/libopenmpt_la-TinyFFT.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/TinyFFT.cpp' object='soundlib/libopenmpt_la-TinyFFT.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-TinyFFT.lo `test -f 'soundlib/TinyFFT.cpp' || echo '$(srcdir)/'`soundlib/TinyFFT.cpp soundlib/libopenmpt_la-tuningCollection.lo: soundlib/tuningCollection.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-tuningCollection.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-tuningCollection.Tpo -c -o soundlib/libopenmpt_la-tuningCollection.lo `test -f 'soundlib/tuningCollection.cpp' || echo '$(srcdir)/'`soundlib/tuningCollection.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-tuningCollection.Tpo soundlib/$(DEPDIR)/libopenmpt_la-tuningCollection.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/tuningCollection.cpp' object='soundlib/libopenmpt_la-tuningCollection.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-tuningCollection.lo `test -f 'soundlib/tuningCollection.cpp' || echo '$(srcdir)/'`soundlib/tuningCollection.cpp soundlib/libopenmpt_la-tuning.lo: soundlib/tuning.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-tuning.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-tuning.Tpo -c -o soundlib/libopenmpt_la-tuning.lo `test -f 'soundlib/tuning.cpp' || echo '$(srcdir)/'`soundlib/tuning.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-tuning.Tpo soundlib/$(DEPDIR)/libopenmpt_la-tuning.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/tuning.cpp' object='soundlib/libopenmpt_la-tuning.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-tuning.lo `test -f 'soundlib/tuning.cpp' || echo '$(srcdir)/'`soundlib/tuning.cpp soundlib/libopenmpt_la-UMXTools.lo: soundlib/UMXTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-UMXTools.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-UMXTools.Tpo -c -o soundlib/libopenmpt_la-UMXTools.lo `test -f 'soundlib/UMXTools.cpp' || echo '$(srcdir)/'`soundlib/UMXTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-UMXTools.Tpo soundlib/$(DEPDIR)/libopenmpt_la-UMXTools.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/UMXTools.cpp' object='soundlib/libopenmpt_la-UMXTools.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-UMXTools.lo `test -f 'soundlib/UMXTools.cpp' || echo '$(srcdir)/'`soundlib/UMXTools.cpp soundlib/libopenmpt_la-UpgradeModule.lo: soundlib/UpgradeModule.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-UpgradeModule.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-UpgradeModule.Tpo -c -o soundlib/libopenmpt_la-UpgradeModule.lo `test -f 'soundlib/UpgradeModule.cpp' || echo '$(srcdir)/'`soundlib/UpgradeModule.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-UpgradeModule.Tpo soundlib/$(DEPDIR)/libopenmpt_la-UpgradeModule.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/UpgradeModule.cpp' object='soundlib/libopenmpt_la-UpgradeModule.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-UpgradeModule.lo `test -f 'soundlib/UpgradeModule.cpp' || echo '$(srcdir)/'`soundlib/UpgradeModule.cpp soundlib/libopenmpt_la-WAVTools.lo: soundlib/WAVTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-WAVTools.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-WAVTools.Tpo -c -o soundlib/libopenmpt_la-WAVTools.lo `test -f 'soundlib/WAVTools.cpp' || echo '$(srcdir)/'`soundlib/WAVTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-WAVTools.Tpo soundlib/$(DEPDIR)/libopenmpt_la-WAVTools.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/WAVTools.cpp' object='soundlib/libopenmpt_la-WAVTools.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-WAVTools.lo `test -f 'soundlib/WAVTools.cpp' || echo '$(srcdir)/'`soundlib/WAVTools.cpp soundlib/libopenmpt_la-WindowedFIR.lo: soundlib/WindowedFIR.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-WindowedFIR.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-WindowedFIR.Tpo -c -o soundlib/libopenmpt_la-WindowedFIR.lo `test -f 'soundlib/WindowedFIR.cpp' || echo '$(srcdir)/'`soundlib/WindowedFIR.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-WindowedFIR.Tpo soundlib/$(DEPDIR)/libopenmpt_la-WindowedFIR.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/WindowedFIR.cpp' object='soundlib/libopenmpt_la-WindowedFIR.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-WindowedFIR.lo `test -f 'soundlib/WindowedFIR.cpp' || echo '$(srcdir)/'`soundlib/WindowedFIR.cpp soundlib/libopenmpt_la-XMTools.lo: soundlib/XMTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-XMTools.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-XMTools.Tpo -c -o soundlib/libopenmpt_la-XMTools.lo `test -f 'soundlib/XMTools.cpp' || echo '$(srcdir)/'`soundlib/XMTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-XMTools.Tpo soundlib/$(DEPDIR)/libopenmpt_la-XMTools.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/XMTools.cpp' object='soundlib/libopenmpt_la-XMTools.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-XMTools.lo `test -f 'soundlib/XMTools.cpp' || echo '$(srcdir)/'`soundlib/XMTools.cpp soundlib/plugins/dmo/libopenmpt_la-DMOPlugin.lo: soundlib/plugins/dmo/DMOPlugin.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-DMOPlugin.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOPlugin.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-DMOPlugin.lo `test -f 'soundlib/plugins/dmo/DMOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/DMOPlugin.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOPlugin.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOPlugin.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/DMOPlugin.cpp' object='soundlib/plugins/dmo/libopenmpt_la-DMOPlugin.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-DMOPlugin.lo `test -f 'soundlib/plugins/dmo/DMOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/DMOPlugin.cpp soundlib/plugins/dmo/libopenmpt_la-DMOUtils.lo: soundlib/plugins/dmo/DMOUtils.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-DMOUtils.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOUtils.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-DMOUtils.lo `test -f 'soundlib/plugins/dmo/DMOUtils.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/DMOUtils.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOUtils.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOUtils.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/DMOUtils.cpp' object='soundlib/plugins/dmo/libopenmpt_la-DMOUtils.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-DMOUtils.lo `test -f 'soundlib/plugins/dmo/DMOUtils.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/DMOUtils.cpp soundlib/plugins/dmo/libopenmpt_la-Chorus.lo: soundlib/plugins/dmo/Chorus.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-Chorus.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Chorus.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-Chorus.lo `test -f 'soundlib/plugins/dmo/Chorus.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Chorus.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Chorus.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Chorus.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Chorus.cpp' object='soundlib/plugins/dmo/libopenmpt_la-Chorus.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-Chorus.lo `test -f 'soundlib/plugins/dmo/Chorus.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Chorus.cpp soundlib/plugins/dmo/libopenmpt_la-Compressor.lo: soundlib/plugins/dmo/Compressor.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-Compressor.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Compressor.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-Compressor.lo `test -f 'soundlib/plugins/dmo/Compressor.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Compressor.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Compressor.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Compressor.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Compressor.cpp' object='soundlib/plugins/dmo/libopenmpt_la-Compressor.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-Compressor.lo `test -f 'soundlib/plugins/dmo/Compressor.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Compressor.cpp soundlib/plugins/dmo/libopenmpt_la-Distortion.lo: soundlib/plugins/dmo/Distortion.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-Distortion.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Distortion.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-Distortion.lo `test -f 'soundlib/plugins/dmo/Distortion.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Distortion.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Distortion.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Distortion.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Distortion.cpp' object='soundlib/plugins/dmo/libopenmpt_la-Distortion.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-Distortion.lo `test -f 'soundlib/plugins/dmo/Distortion.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Distortion.cpp soundlib/plugins/dmo/libopenmpt_la-Echo.lo: soundlib/plugins/dmo/Echo.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-Echo.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Echo.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-Echo.lo `test -f 'soundlib/plugins/dmo/Echo.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Echo.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Echo.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Echo.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Echo.cpp' object='soundlib/plugins/dmo/libopenmpt_la-Echo.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-Echo.lo `test -f 'soundlib/plugins/dmo/Echo.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Echo.cpp soundlib/plugins/dmo/libopenmpt_la-Flanger.lo: soundlib/plugins/dmo/Flanger.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-Flanger.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Flanger.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-Flanger.lo `test -f 'soundlib/plugins/dmo/Flanger.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Flanger.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Flanger.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Flanger.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Flanger.cpp' object='soundlib/plugins/dmo/libopenmpt_la-Flanger.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-Flanger.lo `test -f 'soundlib/plugins/dmo/Flanger.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Flanger.cpp soundlib/plugins/dmo/libopenmpt_la-Gargle.lo: soundlib/plugins/dmo/Gargle.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-Gargle.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Gargle.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-Gargle.lo `test -f 'soundlib/plugins/dmo/Gargle.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Gargle.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Gargle.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Gargle.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Gargle.cpp' object='soundlib/plugins/dmo/libopenmpt_la-Gargle.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-Gargle.lo `test -f 'soundlib/plugins/dmo/Gargle.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Gargle.cpp soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo: soundlib/plugins/dmo/I3DL2Reverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-I3DL2Reverb.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo `test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/I3DL2Reverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-I3DL2Reverb.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-I3DL2Reverb.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/I3DL2Reverb.cpp' object='soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo `test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/I3DL2Reverb.cpp soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo: soundlib/plugins/dmo/ParamEq.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-ParamEq.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo `test -f 'soundlib/plugins/dmo/ParamEq.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/ParamEq.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-ParamEq.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-ParamEq.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/ParamEq.cpp' object='soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo `test -f 'soundlib/plugins/dmo/ParamEq.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/ParamEq.cpp soundlib/plugins/dmo/libopenmpt_la-WavesReverb.lo: soundlib/plugins/dmo/WavesReverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-WavesReverb.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-WavesReverb.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-WavesReverb.lo `test -f 'soundlib/plugins/dmo/WavesReverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/WavesReverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-WavesReverb.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-WavesReverb.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/WavesReverb.cpp' object='soundlib/plugins/dmo/libopenmpt_la-WavesReverb.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-WavesReverb.lo `test -f 'soundlib/plugins/dmo/WavesReverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/WavesReverb.cpp soundlib/plugins/libopenmpt_la-DigiBoosterEcho.lo: soundlib/plugins/DigiBoosterEcho.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpt_la-DigiBoosterEcho.lo -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpt_la-DigiBoosterEcho.Tpo -c -o soundlib/plugins/libopenmpt_la-DigiBoosterEcho.lo `test -f 'soundlib/plugins/DigiBoosterEcho.cpp' || echo '$(srcdir)/'`soundlib/plugins/DigiBoosterEcho.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpt_la-DigiBoosterEcho.Tpo soundlib/plugins/$(DEPDIR)/libopenmpt_la-DigiBoosterEcho.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/DigiBoosterEcho.cpp' object='soundlib/plugins/libopenmpt_la-DigiBoosterEcho.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpt_la-DigiBoosterEcho.lo `test -f 'soundlib/plugins/DigiBoosterEcho.cpp' || echo '$(srcdir)/'`soundlib/plugins/DigiBoosterEcho.cpp soundlib/plugins/libopenmpt_la-LFOPlugin.lo: soundlib/plugins/LFOPlugin.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpt_la-LFOPlugin.lo -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpt_la-LFOPlugin.Tpo -c -o soundlib/plugins/libopenmpt_la-LFOPlugin.lo `test -f 'soundlib/plugins/LFOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/LFOPlugin.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpt_la-LFOPlugin.Tpo soundlib/plugins/$(DEPDIR)/libopenmpt_la-LFOPlugin.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/LFOPlugin.cpp' object='soundlib/plugins/libopenmpt_la-LFOPlugin.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpt_la-LFOPlugin.lo `test -f 'soundlib/plugins/LFOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/LFOPlugin.cpp soundlib/plugins/libopenmpt_la-PluginManager.lo: soundlib/plugins/PluginManager.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpt_la-PluginManager.lo -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpt_la-PluginManager.Tpo -c -o soundlib/plugins/libopenmpt_la-PluginManager.lo `test -f 'soundlib/plugins/PluginManager.cpp' || echo '$(srcdir)/'`soundlib/plugins/PluginManager.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpt_la-PluginManager.Tpo soundlib/plugins/$(DEPDIR)/libopenmpt_la-PluginManager.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/PluginManager.cpp' object='soundlib/plugins/libopenmpt_la-PluginManager.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpt_la-PluginManager.lo `test -f 'soundlib/plugins/PluginManager.cpp' || echo '$(srcdir)/'`soundlib/plugins/PluginManager.cpp soundlib/plugins/libopenmpt_la-PlugInterface.lo: soundlib/plugins/PlugInterface.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpt_la-PlugInterface.lo -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpt_la-PlugInterface.Tpo -c -o soundlib/plugins/libopenmpt_la-PlugInterface.lo `test -f 'soundlib/plugins/PlugInterface.cpp' || echo '$(srcdir)/'`soundlib/plugins/PlugInterface.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpt_la-PlugInterface.Tpo soundlib/plugins/$(DEPDIR)/libopenmpt_la-PlugInterface.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/PlugInterface.cpp' object='soundlib/plugins/libopenmpt_la-PlugInterface.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpt_la-PlugInterface.lo `test -f 'soundlib/plugins/PlugInterface.cpp' || echo '$(srcdir)/'`soundlib/plugins/PlugInterface.cpp soundlib/plugins/libopenmpt_la-SymMODEcho.lo: soundlib/plugins/SymMODEcho.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpt_la-SymMODEcho.lo -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpt_la-SymMODEcho.Tpo -c -o soundlib/plugins/libopenmpt_la-SymMODEcho.lo `test -f 'soundlib/plugins/SymMODEcho.cpp' || echo '$(srcdir)/'`soundlib/plugins/SymMODEcho.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpt_la-SymMODEcho.Tpo soundlib/plugins/$(DEPDIR)/libopenmpt_la-SymMODEcho.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/SymMODEcho.cpp' object='soundlib/plugins/libopenmpt_la-SymMODEcho.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpt_la-SymMODEcho.lo `test -f 'soundlib/plugins/SymMODEcho.cpp' || echo '$(srcdir)/'`soundlib/plugins/SymMODEcho.cpp sounddsp/libopenmpt_la-AGC.lo: sounddsp/AGC.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpt_la-AGC.lo -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpt_la-AGC.Tpo -c -o sounddsp/libopenmpt_la-AGC.lo `test -f 'sounddsp/AGC.cpp' || echo '$(srcdir)/'`sounddsp/AGC.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpt_la-AGC.Tpo sounddsp/$(DEPDIR)/libopenmpt_la-AGC.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/AGC.cpp' object='sounddsp/libopenmpt_la-AGC.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpt_la-AGC.lo `test -f 'sounddsp/AGC.cpp' || echo '$(srcdir)/'`sounddsp/AGC.cpp sounddsp/libopenmpt_la-DSP.lo: sounddsp/DSP.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpt_la-DSP.lo -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpt_la-DSP.Tpo -c -o sounddsp/libopenmpt_la-DSP.lo `test -f 'sounddsp/DSP.cpp' || echo '$(srcdir)/'`sounddsp/DSP.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpt_la-DSP.Tpo sounddsp/$(DEPDIR)/libopenmpt_la-DSP.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/DSP.cpp' object='sounddsp/libopenmpt_la-DSP.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpt_la-DSP.lo `test -f 'sounddsp/DSP.cpp' || echo '$(srcdir)/'`sounddsp/DSP.cpp sounddsp/libopenmpt_la-EQ.lo: sounddsp/EQ.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpt_la-EQ.lo -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpt_la-EQ.Tpo -c -o sounddsp/libopenmpt_la-EQ.lo `test -f 'sounddsp/EQ.cpp' || echo '$(srcdir)/'`sounddsp/EQ.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpt_la-EQ.Tpo sounddsp/$(DEPDIR)/libopenmpt_la-EQ.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/EQ.cpp' object='sounddsp/libopenmpt_la-EQ.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpt_la-EQ.lo `test -f 'sounddsp/EQ.cpp' || echo '$(srcdir)/'`sounddsp/EQ.cpp sounddsp/libopenmpt_la-Reverb.lo: sounddsp/Reverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpt_la-Reverb.lo -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpt_la-Reverb.Tpo -c -o sounddsp/libopenmpt_la-Reverb.lo `test -f 'sounddsp/Reverb.cpp' || echo '$(srcdir)/'`sounddsp/Reverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpt_la-Reverb.Tpo sounddsp/$(DEPDIR)/libopenmpt_la-Reverb.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/Reverb.cpp' object='sounddsp/libopenmpt_la-Reverb.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpt_la-Reverb.lo `test -f 'sounddsp/Reverb.cpp' || echo '$(srcdir)/'`sounddsp/Reverb.cpp libopenmpt/la-libopenmpt_c.lo: libopenmpt/libopenmpt_c.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/la-libopenmpt_c.lo -MD -MP -MF libopenmpt/$(DEPDIR)/la-libopenmpt_c.Tpo -c -o libopenmpt/la-libopenmpt_c.lo `test -f 'libopenmpt/libopenmpt_c.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_c.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/la-libopenmpt_c.Tpo libopenmpt/$(DEPDIR)/la-libopenmpt_c.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_c.cpp' object='libopenmpt/la-libopenmpt_c.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/la-libopenmpt_c.lo `test -f 'libopenmpt/libopenmpt_c.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_c.cpp libopenmpt/la-libopenmpt_cxx.lo: libopenmpt/libopenmpt_cxx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/la-libopenmpt_cxx.lo -MD -MP -MF libopenmpt/$(DEPDIR)/la-libopenmpt_cxx.Tpo -c -o libopenmpt/la-libopenmpt_cxx.lo `test -f 'libopenmpt/libopenmpt_cxx.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_cxx.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/la-libopenmpt_cxx.Tpo libopenmpt/$(DEPDIR)/la-libopenmpt_cxx.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_cxx.cpp' object='libopenmpt/la-libopenmpt_cxx.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/la-libopenmpt_cxx.lo `test -f 'libopenmpt/libopenmpt_cxx.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_cxx.cpp libopenmpt/la-libopenmpt_ext_impl.lo: libopenmpt/libopenmpt_ext_impl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/la-libopenmpt_ext_impl.lo -MD -MP -MF libopenmpt/$(DEPDIR)/la-libopenmpt_ext_impl.Tpo -c -o libopenmpt/la-libopenmpt_ext_impl.lo `test -f 'libopenmpt/libopenmpt_ext_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext_impl.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/la-libopenmpt_ext_impl.Tpo libopenmpt/$(DEPDIR)/la-libopenmpt_ext_impl.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_ext_impl.cpp' object='libopenmpt/la-libopenmpt_ext_impl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/la-libopenmpt_ext_impl.lo `test -f 'libopenmpt/libopenmpt_ext_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext_impl.cpp libopenmpt/la-libopenmpt_impl.lo: libopenmpt/libopenmpt_impl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/la-libopenmpt_impl.lo -MD -MP -MF libopenmpt/$(DEPDIR)/la-libopenmpt_impl.Tpo -c -o libopenmpt/la-libopenmpt_impl.lo `test -f 'libopenmpt/libopenmpt_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_impl.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/la-libopenmpt_impl.Tpo libopenmpt/$(DEPDIR)/la-libopenmpt_impl.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_impl.cpp' object='libopenmpt/la-libopenmpt_impl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/la-libopenmpt_impl.lo `test -f 'libopenmpt/libopenmpt_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_impl.cpp openmpt123/bin_openmpt123-openmpt123.o: openmpt123/openmpt123.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_openmpt123_CPPFLAGS) $(CPPFLAGS) $(bin_openmpt123_CXXFLAGS) $(CXXFLAGS) -MT openmpt123/bin_openmpt123-openmpt123.o -MD -MP -MF openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Tpo -c -o openmpt123/bin_openmpt123-openmpt123.o `test -f 'openmpt123/openmpt123.cpp' || echo '$(srcdir)/'`openmpt123/openmpt123.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Tpo openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='openmpt123/openmpt123.cpp' object='openmpt123/bin_openmpt123-openmpt123.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_openmpt123_CPPFLAGS) $(CPPFLAGS) $(bin_openmpt123_CXXFLAGS) $(CXXFLAGS) -c -o openmpt123/bin_openmpt123-openmpt123.o `test -f 'openmpt123/openmpt123.cpp' || echo '$(srcdir)/'`openmpt123/openmpt123.cpp openmpt123/bin_openmpt123-openmpt123.obj: openmpt123/openmpt123.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_openmpt123_CPPFLAGS) $(CPPFLAGS) $(bin_openmpt123_CXXFLAGS) $(CXXFLAGS) -MT openmpt123/bin_openmpt123-openmpt123.obj -MD -MP -MF openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Tpo -c -o openmpt123/bin_openmpt123-openmpt123.obj `if test -f 'openmpt123/openmpt123.cpp'; then $(CYGPATH_W) 'openmpt123/openmpt123.cpp'; else $(CYGPATH_W) '$(srcdir)/openmpt123/openmpt123.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Tpo openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='openmpt123/openmpt123.cpp' object='openmpt123/bin_openmpt123-openmpt123.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_openmpt123_CPPFLAGS) $(CPPFLAGS) $(bin_openmpt123_CXXFLAGS) $(CXXFLAGS) -c -o openmpt123/bin_openmpt123-openmpt123.obj `if test -f 'openmpt123/openmpt123.cpp'; then $(CYGPATH_W) 'openmpt123/openmpt123.cpp'; else $(CYGPATH_W) '$(srcdir)/openmpt123/openmpt123.cpp'; fi` examples/libopenmpt_example_cxx-libopenmpt_example_cxx.o: examples/libopenmpt_example_cxx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_cxx_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_cxx_CXXFLAGS) $(CXXFLAGS) -MT examples/libopenmpt_example_cxx-libopenmpt_example_cxx.o -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Tpo -c -o examples/libopenmpt_example_cxx-libopenmpt_example_cxx.o `test -f 'examples/libopenmpt_example_cxx.cpp' || echo '$(srcdir)/'`examples/libopenmpt_example_cxx.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Tpo examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='examples/libopenmpt_example_cxx.cpp' object='examples/libopenmpt_example_cxx-libopenmpt_example_cxx.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_cxx_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_cxx_CXXFLAGS) $(CXXFLAGS) -c -o examples/libopenmpt_example_cxx-libopenmpt_example_cxx.o `test -f 'examples/libopenmpt_example_cxx.cpp' || echo '$(srcdir)/'`examples/libopenmpt_example_cxx.cpp examples/libopenmpt_example_cxx-libopenmpt_example_cxx.obj: examples/libopenmpt_example_cxx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_cxx_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_cxx_CXXFLAGS) $(CXXFLAGS) -MT examples/libopenmpt_example_cxx-libopenmpt_example_cxx.obj -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Tpo -c -o examples/libopenmpt_example_cxx-libopenmpt_example_cxx.obj `if test -f 'examples/libopenmpt_example_cxx.cpp'; then $(CYGPATH_W) 'examples/libopenmpt_example_cxx.cpp'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_cxx.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Tpo examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='examples/libopenmpt_example_cxx.cpp' object='examples/libopenmpt_example_cxx-libopenmpt_example_cxx.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_cxx_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_cxx_CXXFLAGS) $(CXXFLAGS) -c -o examples/libopenmpt_example_cxx-libopenmpt_example_cxx.obj `if test -f 'examples/libopenmpt_example_cxx.cpp'; then $(CYGPATH_W) 'examples/libopenmpt_example_cxx.cpp'; else $(CYGPATH_W) '$(srcdir)/examples/libopenmpt_example_cxx.cpp'; fi` test/libopenmpttest-mpt_tests_base.o: test/mpt_tests_base.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_base.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_base.Tpo -c -o test/libopenmpttest-mpt_tests_base.o `test -f 'test/mpt_tests_base.cpp' || echo '$(srcdir)/'`test/mpt_tests_base.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_base.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_base.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_base.cpp' object='test/libopenmpttest-mpt_tests_base.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_base.o `test -f 'test/mpt_tests_base.cpp' || echo '$(srcdir)/'`test/mpt_tests_base.cpp test/libopenmpttest-mpt_tests_base.obj: test/mpt_tests_base.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_base.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_base.Tpo -c -o test/libopenmpttest-mpt_tests_base.obj `if test -f 'test/mpt_tests_base.cpp'; then $(CYGPATH_W) 'test/mpt_tests_base.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_base.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_base.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_base.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_base.cpp' object='test/libopenmpttest-mpt_tests_base.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_base.obj `if test -f 'test/mpt_tests_base.cpp'; then $(CYGPATH_W) 'test/mpt_tests_base.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_base.cpp'; fi` test/libopenmpttest-mpt_tests_binary.o: test/mpt_tests_binary.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_binary.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_binary.Tpo -c -o test/libopenmpttest-mpt_tests_binary.o `test -f 'test/mpt_tests_binary.cpp' || echo '$(srcdir)/'`test/mpt_tests_binary.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_binary.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_binary.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_binary.cpp' object='test/libopenmpttest-mpt_tests_binary.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_binary.o `test -f 'test/mpt_tests_binary.cpp' || echo '$(srcdir)/'`test/mpt_tests_binary.cpp test/libopenmpttest-mpt_tests_binary.obj: test/mpt_tests_binary.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_binary.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_binary.Tpo -c -o test/libopenmpttest-mpt_tests_binary.obj `if test -f 'test/mpt_tests_binary.cpp'; then $(CYGPATH_W) 'test/mpt_tests_binary.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_binary.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_binary.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_binary.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_binary.cpp' object='test/libopenmpttest-mpt_tests_binary.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_binary.obj `if test -f 'test/mpt_tests_binary.cpp'; then $(CYGPATH_W) 'test/mpt_tests_binary.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_binary.cpp'; fi` test/libopenmpttest-mpt_tests_crc.o: test/mpt_tests_crc.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_crc.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_crc.Tpo -c -o test/libopenmpttest-mpt_tests_crc.o `test -f 'test/mpt_tests_crc.cpp' || echo '$(srcdir)/'`test/mpt_tests_crc.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_crc.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_crc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_crc.cpp' object='test/libopenmpttest-mpt_tests_crc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_crc.o `test -f 'test/mpt_tests_crc.cpp' || echo '$(srcdir)/'`test/mpt_tests_crc.cpp test/libopenmpttest-mpt_tests_crc.obj: test/mpt_tests_crc.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_crc.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_crc.Tpo -c -o test/libopenmpttest-mpt_tests_crc.obj `if test -f 'test/mpt_tests_crc.cpp'; then $(CYGPATH_W) 'test/mpt_tests_crc.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_crc.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_crc.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_crc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_crc.cpp' object='test/libopenmpttest-mpt_tests_crc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_crc.obj `if test -f 'test/mpt_tests_crc.cpp'; then $(CYGPATH_W) 'test/mpt_tests_crc.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_crc.cpp'; fi` test/libopenmpttest-mpt_tests_endian.o: test/mpt_tests_endian.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_endian.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_endian.Tpo -c -o test/libopenmpttest-mpt_tests_endian.o `test -f 'test/mpt_tests_endian.cpp' || echo '$(srcdir)/'`test/mpt_tests_endian.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_endian.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_endian.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_endian.cpp' object='test/libopenmpttest-mpt_tests_endian.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_endian.o `test -f 'test/mpt_tests_endian.cpp' || echo '$(srcdir)/'`test/mpt_tests_endian.cpp test/libopenmpttest-mpt_tests_endian.obj: test/mpt_tests_endian.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_endian.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_endian.Tpo -c -o test/libopenmpttest-mpt_tests_endian.obj `if test -f 'test/mpt_tests_endian.cpp'; then $(CYGPATH_W) 'test/mpt_tests_endian.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_endian.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_endian.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_endian.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_endian.cpp' object='test/libopenmpttest-mpt_tests_endian.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_endian.obj `if test -f 'test/mpt_tests_endian.cpp'; then $(CYGPATH_W) 'test/mpt_tests_endian.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_endian.cpp'; fi` test/libopenmpttest-mpt_tests_format.o: test/mpt_tests_format.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_format.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_format.Tpo -c -o test/libopenmpttest-mpt_tests_format.o `test -f 'test/mpt_tests_format.cpp' || echo '$(srcdir)/'`test/mpt_tests_format.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_format.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_format.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_format.cpp' object='test/libopenmpttest-mpt_tests_format.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_format.o `test -f 'test/mpt_tests_format.cpp' || echo '$(srcdir)/'`test/mpt_tests_format.cpp test/libopenmpttest-mpt_tests_format.obj: test/mpt_tests_format.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_format.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_format.Tpo -c -o test/libopenmpttest-mpt_tests_format.obj `if test -f 'test/mpt_tests_format.cpp'; then $(CYGPATH_W) 'test/mpt_tests_format.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_format.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_format.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_format.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_format.cpp' object='test/libopenmpttest-mpt_tests_format.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_format.obj `if test -f 'test/mpt_tests_format.cpp'; then $(CYGPATH_W) 'test/mpt_tests_format.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_format.cpp'; fi` test/libopenmpttest-mpt_tests_io.o: test/mpt_tests_io.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_io.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_io.Tpo -c -o test/libopenmpttest-mpt_tests_io.o `test -f 'test/mpt_tests_io.cpp' || echo '$(srcdir)/'`test/mpt_tests_io.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_io.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_io.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_io.cpp' object='test/libopenmpttest-mpt_tests_io.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_io.o `test -f 'test/mpt_tests_io.cpp' || echo '$(srcdir)/'`test/mpt_tests_io.cpp test/libopenmpttest-mpt_tests_io.obj: test/mpt_tests_io.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_io.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_io.Tpo -c -o test/libopenmpttest-mpt_tests_io.obj `if test -f 'test/mpt_tests_io.cpp'; then $(CYGPATH_W) 'test/mpt_tests_io.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_io.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_io.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_io.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_io.cpp' object='test/libopenmpttest-mpt_tests_io.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_io.obj `if test -f 'test/mpt_tests_io.cpp'; then $(CYGPATH_W) 'test/mpt_tests_io.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_io.cpp'; fi` test/libopenmpttest-mpt_tests_parse.o: test/mpt_tests_parse.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_parse.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_parse.Tpo -c -o test/libopenmpttest-mpt_tests_parse.o `test -f 'test/mpt_tests_parse.cpp' || echo '$(srcdir)/'`test/mpt_tests_parse.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_parse.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_parse.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_parse.cpp' object='test/libopenmpttest-mpt_tests_parse.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_parse.o `test -f 'test/mpt_tests_parse.cpp' || echo '$(srcdir)/'`test/mpt_tests_parse.cpp test/libopenmpttest-mpt_tests_parse.obj: test/mpt_tests_parse.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_parse.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_parse.Tpo -c -o test/libopenmpttest-mpt_tests_parse.obj `if test -f 'test/mpt_tests_parse.cpp'; then $(CYGPATH_W) 'test/mpt_tests_parse.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_parse.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_parse.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_parse.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_parse.cpp' object='test/libopenmpttest-mpt_tests_parse.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_parse.obj `if test -f 'test/mpt_tests_parse.cpp'; then $(CYGPATH_W) 'test/mpt_tests_parse.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_parse.cpp'; fi` test/libopenmpttest-mpt_tests_random.o: test/mpt_tests_random.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_random.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_random.Tpo -c -o test/libopenmpttest-mpt_tests_random.o `test -f 'test/mpt_tests_random.cpp' || echo '$(srcdir)/'`test/mpt_tests_random.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_random.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_random.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_random.cpp' object='test/libopenmpttest-mpt_tests_random.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_random.o `test -f 'test/mpt_tests_random.cpp' || echo '$(srcdir)/'`test/mpt_tests_random.cpp test/libopenmpttest-mpt_tests_random.obj: test/mpt_tests_random.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_random.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_random.Tpo -c -o test/libopenmpttest-mpt_tests_random.obj `if test -f 'test/mpt_tests_random.cpp'; then $(CYGPATH_W) 'test/mpt_tests_random.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_random.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_random.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_random.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_random.cpp' object='test/libopenmpttest-mpt_tests_random.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_random.obj `if test -f 'test/mpt_tests_random.cpp'; then $(CYGPATH_W) 'test/mpt_tests_random.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_random.cpp'; fi` test/libopenmpttest-mpt_tests_string.o: test/mpt_tests_string.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_string.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_string.Tpo -c -o test/libopenmpttest-mpt_tests_string.o `test -f 'test/mpt_tests_string.cpp' || echo '$(srcdir)/'`test/mpt_tests_string.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_string.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_string.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_string.cpp' object='test/libopenmpttest-mpt_tests_string.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_string.o `test -f 'test/mpt_tests_string.cpp' || echo '$(srcdir)/'`test/mpt_tests_string.cpp test/libopenmpttest-mpt_tests_string.obj: test/mpt_tests_string.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_string.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_string.Tpo -c -o test/libopenmpttest-mpt_tests_string.obj `if test -f 'test/mpt_tests_string.cpp'; then $(CYGPATH_W) 'test/mpt_tests_string.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_string.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_string.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_string.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_string.cpp' object='test/libopenmpttest-mpt_tests_string.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_string.obj `if test -f 'test/mpt_tests_string.cpp'; then $(CYGPATH_W) 'test/mpt_tests_string.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_string.cpp'; fi` test/libopenmpttest-mpt_tests_string_transcode.o: test/mpt_tests_string_transcode.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_string_transcode.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_string_transcode.Tpo -c -o test/libopenmpttest-mpt_tests_string_transcode.o `test -f 'test/mpt_tests_string_transcode.cpp' || echo '$(srcdir)/'`test/mpt_tests_string_transcode.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_string_transcode.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_string_transcode.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_string_transcode.cpp' object='test/libopenmpttest-mpt_tests_string_transcode.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_string_transcode.o `test -f 'test/mpt_tests_string_transcode.cpp' || echo '$(srcdir)/'`test/mpt_tests_string_transcode.cpp test/libopenmpttest-mpt_tests_string_transcode.obj: test/mpt_tests_string_transcode.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_string_transcode.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_string_transcode.Tpo -c -o test/libopenmpttest-mpt_tests_string_transcode.obj `if test -f 'test/mpt_tests_string_transcode.cpp'; then $(CYGPATH_W) 'test/mpt_tests_string_transcode.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_string_transcode.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_string_transcode.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_string_transcode.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_string_transcode.cpp' object='test/libopenmpttest-mpt_tests_string_transcode.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_string_transcode.obj `if test -f 'test/mpt_tests_string_transcode.cpp'; then $(CYGPATH_W) 'test/mpt_tests_string_transcode.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_string_transcode.cpp'; fi` test/libopenmpttest-mpt_tests_uuid.o: test/mpt_tests_uuid.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_uuid.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_uuid.Tpo -c -o test/libopenmpttest-mpt_tests_uuid.o `test -f 'test/mpt_tests_uuid.cpp' || echo '$(srcdir)/'`test/mpt_tests_uuid.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_uuid.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_uuid.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_uuid.cpp' object='test/libopenmpttest-mpt_tests_uuid.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_uuid.o `test -f 'test/mpt_tests_uuid.cpp' || echo '$(srcdir)/'`test/mpt_tests_uuid.cpp test/libopenmpttest-mpt_tests_uuid.obj: test/mpt_tests_uuid.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-mpt_tests_uuid.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-mpt_tests_uuid.Tpo -c -o test/libopenmpttest-mpt_tests_uuid.obj `if test -f 'test/mpt_tests_uuid.cpp'; then $(CYGPATH_W) 'test/mpt_tests_uuid.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_uuid.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-mpt_tests_uuid.Tpo test/$(DEPDIR)/libopenmpttest-mpt_tests_uuid.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/mpt_tests_uuid.cpp' object='test/libopenmpttest-mpt_tests_uuid.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-mpt_tests_uuid.obj `if test -f 'test/mpt_tests_uuid.cpp'; then $(CYGPATH_W) 'test/mpt_tests_uuid.cpp'; else $(CYGPATH_W) '$(srcdir)/test/mpt_tests_uuid.cpp'; fi` test/libopenmpttest-test.o: test/test.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-test.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-test.Tpo -c -o test/libopenmpttest-test.o `test -f 'test/test.cpp' || echo '$(srcdir)/'`test/test.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-test.Tpo test/$(DEPDIR)/libopenmpttest-test.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test.cpp' object='test/libopenmpttest-test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-test.o `test -f 'test/test.cpp' || echo '$(srcdir)/'`test/test.cpp test/libopenmpttest-test.obj: test/test.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-test.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-test.Tpo -c -o test/libopenmpttest-test.obj `if test -f 'test/test.cpp'; then $(CYGPATH_W) 'test/test.cpp'; else $(CYGPATH_W) '$(srcdir)/test/test.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-test.Tpo test/$(DEPDIR)/libopenmpttest-test.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/test.cpp' object='test/libopenmpttest-test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-test.obj `if test -f 'test/test.cpp'; then $(CYGPATH_W) 'test/test.cpp'; else $(CYGPATH_W) '$(srcdir)/test/test.cpp'; fi` test/libopenmpttest-TestToolsLib.o: test/TestToolsLib.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-TestToolsLib.o -MD -MP -MF test/$(DEPDIR)/libopenmpttest-TestToolsLib.Tpo -c -o test/libopenmpttest-TestToolsLib.o `test -f 'test/TestToolsLib.cpp' || echo '$(srcdir)/'`test/TestToolsLib.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-TestToolsLib.Tpo test/$(DEPDIR)/libopenmpttest-TestToolsLib.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/TestToolsLib.cpp' object='test/libopenmpttest-TestToolsLib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-TestToolsLib.o `test -f 'test/TestToolsLib.cpp' || echo '$(srcdir)/'`test/TestToolsLib.cpp test/libopenmpttest-TestToolsLib.obj: test/TestToolsLib.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT test/libopenmpttest-TestToolsLib.obj -MD -MP -MF test/$(DEPDIR)/libopenmpttest-TestToolsLib.Tpo -c -o test/libopenmpttest-TestToolsLib.obj `if test -f 'test/TestToolsLib.cpp'; then $(CYGPATH_W) 'test/TestToolsLib.cpp'; else $(CYGPATH_W) '$(srcdir)/test/TestToolsLib.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/libopenmpttest-TestToolsLib.Tpo test/$(DEPDIR)/libopenmpttest-TestToolsLib.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test/TestToolsLib.cpp' object='test/libopenmpttest-TestToolsLib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o test/libopenmpttest-TestToolsLib.obj `if test -f 'test/TestToolsLib.cpp'; then $(CYGPATH_W) 'test/TestToolsLib.cpp'; else $(CYGPATH_W) '$(srcdir)/test/TestToolsLib.cpp'; fi` src/openmpt/soundfile_write/libopenmpttest-wav_write.o: src/openmpt/soundfile_write/wav_write.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT src/openmpt/soundfile_write/libopenmpttest-wav_write.o -MD -MP -MF src/openmpt/soundfile_write/$(DEPDIR)/libopenmpttest-wav_write.Tpo -c -o src/openmpt/soundfile_write/libopenmpttest-wav_write.o `test -f 'src/openmpt/soundfile_write/wav_write.cpp' || echo '$(srcdir)/'`src/openmpt/soundfile_write/wav_write.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/openmpt/soundfile_write/$(DEPDIR)/libopenmpttest-wav_write.Tpo src/openmpt/soundfile_write/$(DEPDIR)/libopenmpttest-wav_write.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/openmpt/soundfile_write/wav_write.cpp' object='src/openmpt/soundfile_write/libopenmpttest-wav_write.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o src/openmpt/soundfile_write/libopenmpttest-wav_write.o `test -f 'src/openmpt/soundfile_write/wav_write.cpp' || echo '$(srcdir)/'`src/openmpt/soundfile_write/wav_write.cpp src/openmpt/soundfile_write/libopenmpttest-wav_write.obj: src/openmpt/soundfile_write/wav_write.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT src/openmpt/soundfile_write/libopenmpttest-wav_write.obj -MD -MP -MF src/openmpt/soundfile_write/$(DEPDIR)/libopenmpttest-wav_write.Tpo -c -o src/openmpt/soundfile_write/libopenmpttest-wav_write.obj `if test -f 'src/openmpt/soundfile_write/wav_write.cpp'; then $(CYGPATH_W) 'src/openmpt/soundfile_write/wav_write.cpp'; else $(CYGPATH_W) '$(srcdir)/src/openmpt/soundfile_write/wav_write.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/openmpt/soundfile_write/$(DEPDIR)/libopenmpttest-wav_write.Tpo src/openmpt/soundfile_write/$(DEPDIR)/libopenmpttest-wav_write.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/openmpt/soundfile_write/wav_write.cpp' object='src/openmpt/soundfile_write/libopenmpttest-wav_write.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o src/openmpt/soundfile_write/libopenmpttest-wav_write.obj `if test -f 'src/openmpt/soundfile_write/wav_write.cpp'; then $(CYGPATH_W) 'src/openmpt/soundfile_write/wav_write.cpp'; else $(CYGPATH_W) '$(srcdir)/src/openmpt/soundfile_write/wav_write.cpp'; fi` common/libopenmpttest-ComponentManager.o: common/ComponentManager.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-ComponentManager.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-ComponentManager.Tpo -c -o common/libopenmpttest-ComponentManager.o `test -f 'common/ComponentManager.cpp' || echo '$(srcdir)/'`common/ComponentManager.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-ComponentManager.Tpo common/$(DEPDIR)/libopenmpttest-ComponentManager.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ComponentManager.cpp' object='common/libopenmpttest-ComponentManager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-ComponentManager.o `test -f 'common/ComponentManager.cpp' || echo '$(srcdir)/'`common/ComponentManager.cpp common/libopenmpttest-ComponentManager.obj: common/ComponentManager.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-ComponentManager.obj -MD -MP -MF common/$(DEPDIR)/libopenmpttest-ComponentManager.Tpo -c -o common/libopenmpttest-ComponentManager.obj `if test -f 'common/ComponentManager.cpp'; then $(CYGPATH_W) 'common/ComponentManager.cpp'; else $(CYGPATH_W) '$(srcdir)/common/ComponentManager.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-ComponentManager.Tpo common/$(DEPDIR)/libopenmpttest-ComponentManager.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/ComponentManager.cpp' object='common/libopenmpttest-ComponentManager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-ComponentManager.obj `if test -f 'common/ComponentManager.cpp'; then $(CYGPATH_W) 'common/ComponentManager.cpp'; else $(CYGPATH_W) '$(srcdir)/common/ComponentManager.cpp'; fi` common/libopenmpttest-Logging.o: common/Logging.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-Logging.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-Logging.Tpo -c -o common/libopenmpttest-Logging.o `test -f 'common/Logging.cpp' || echo '$(srcdir)/'`common/Logging.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-Logging.Tpo common/$(DEPDIR)/libopenmpttest-Logging.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Logging.cpp' object='common/libopenmpttest-Logging.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-Logging.o `test -f 'common/Logging.cpp' || echo '$(srcdir)/'`common/Logging.cpp common/libopenmpttest-Logging.obj: common/Logging.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-Logging.obj -MD -MP -MF common/$(DEPDIR)/libopenmpttest-Logging.Tpo -c -o common/libopenmpttest-Logging.obj `if test -f 'common/Logging.cpp'; then $(CYGPATH_W) 'common/Logging.cpp'; else $(CYGPATH_W) '$(srcdir)/common/Logging.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-Logging.Tpo common/$(DEPDIR)/libopenmpttest-Logging.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Logging.cpp' object='common/libopenmpttest-Logging.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-Logging.obj `if test -f 'common/Logging.cpp'; then $(CYGPATH_W) 'common/Logging.cpp'; else $(CYGPATH_W) '$(srcdir)/common/Logging.cpp'; fi` common/libopenmpttest-mptFileType.o: common/mptFileType.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptFileType.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptFileType.Tpo -c -o common/libopenmpttest-mptFileType.o `test -f 'common/mptFileType.cpp' || echo '$(srcdir)/'`common/mptFileType.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptFileType.Tpo common/$(DEPDIR)/libopenmpttest-mptFileType.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptFileType.cpp' object='common/libopenmpttest-mptFileType.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptFileType.o `test -f 'common/mptFileType.cpp' || echo '$(srcdir)/'`common/mptFileType.cpp common/libopenmpttest-mptFileType.obj: common/mptFileType.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptFileType.obj -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptFileType.Tpo -c -o common/libopenmpttest-mptFileType.obj `if test -f 'common/mptFileType.cpp'; then $(CYGPATH_W) 'common/mptFileType.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptFileType.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptFileType.Tpo common/$(DEPDIR)/libopenmpttest-mptFileType.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptFileType.cpp' object='common/libopenmpttest-mptFileType.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptFileType.obj `if test -f 'common/mptFileType.cpp'; then $(CYGPATH_W) 'common/mptFileType.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptFileType.cpp'; fi` common/libopenmpttest-mptPathString.o: common/mptPathString.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptPathString.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptPathString.Tpo -c -o common/libopenmpttest-mptPathString.o `test -f 'common/mptPathString.cpp' || echo '$(srcdir)/'`common/mptPathString.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptPathString.Tpo common/$(DEPDIR)/libopenmpttest-mptPathString.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptPathString.cpp' object='common/libopenmpttest-mptPathString.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptPathString.o `test -f 'common/mptPathString.cpp' || echo '$(srcdir)/'`common/mptPathString.cpp common/libopenmpttest-mptPathString.obj: common/mptPathString.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptPathString.obj -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptPathString.Tpo -c -o common/libopenmpttest-mptPathString.obj `if test -f 'common/mptPathString.cpp'; then $(CYGPATH_W) 'common/mptPathString.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptPathString.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptPathString.Tpo common/$(DEPDIR)/libopenmpttest-mptPathString.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptPathString.cpp' object='common/libopenmpttest-mptPathString.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptPathString.obj `if test -f 'common/mptPathString.cpp'; then $(CYGPATH_W) 'common/mptPathString.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptPathString.cpp'; fi` common/libopenmpttest-mptRandom.o: common/mptRandom.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptRandom.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptRandom.Tpo -c -o common/libopenmpttest-mptRandom.o `test -f 'common/mptRandom.cpp' || echo '$(srcdir)/'`common/mptRandom.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptRandom.Tpo common/$(DEPDIR)/libopenmpttest-mptRandom.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptRandom.cpp' object='common/libopenmpttest-mptRandom.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptRandom.o `test -f 'common/mptRandom.cpp' || echo '$(srcdir)/'`common/mptRandom.cpp common/libopenmpttest-mptRandom.obj: common/mptRandom.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptRandom.obj -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptRandom.Tpo -c -o common/libopenmpttest-mptRandom.obj `if test -f 'common/mptRandom.cpp'; then $(CYGPATH_W) 'common/mptRandom.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptRandom.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptRandom.Tpo common/$(DEPDIR)/libopenmpttest-mptRandom.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptRandom.cpp' object='common/libopenmpttest-mptRandom.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptRandom.obj `if test -f 'common/mptRandom.cpp'; then $(CYGPATH_W) 'common/mptRandom.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptRandom.cpp'; fi` common/libopenmpttest-mptStringBuffer.o: common/mptStringBuffer.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptStringBuffer.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptStringBuffer.Tpo -c -o common/libopenmpttest-mptStringBuffer.o `test -f 'common/mptStringBuffer.cpp' || echo '$(srcdir)/'`common/mptStringBuffer.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptStringBuffer.Tpo common/$(DEPDIR)/libopenmpttest-mptStringBuffer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptStringBuffer.cpp' object='common/libopenmpttest-mptStringBuffer.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptStringBuffer.o `test -f 'common/mptStringBuffer.cpp' || echo '$(srcdir)/'`common/mptStringBuffer.cpp common/libopenmpttest-mptStringBuffer.obj: common/mptStringBuffer.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptStringBuffer.obj -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptStringBuffer.Tpo -c -o common/libopenmpttest-mptStringBuffer.obj `if test -f 'common/mptStringBuffer.cpp'; then $(CYGPATH_W) 'common/mptStringBuffer.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptStringBuffer.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptStringBuffer.Tpo common/$(DEPDIR)/libopenmpttest-mptStringBuffer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptStringBuffer.cpp' object='common/libopenmpttest-mptStringBuffer.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptStringBuffer.obj `if test -f 'common/mptStringBuffer.cpp'; then $(CYGPATH_W) 'common/mptStringBuffer.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptStringBuffer.cpp'; fi` common/libopenmpttest-mptTime.o: common/mptTime.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptTime.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptTime.Tpo -c -o common/libopenmpttest-mptTime.o `test -f 'common/mptTime.cpp' || echo '$(srcdir)/'`common/mptTime.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptTime.Tpo common/$(DEPDIR)/libopenmpttest-mptTime.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptTime.cpp' object='common/libopenmpttest-mptTime.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptTime.o `test -f 'common/mptTime.cpp' || echo '$(srcdir)/'`common/mptTime.cpp common/libopenmpttest-mptTime.obj: common/mptTime.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptTime.obj -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptTime.Tpo -c -o common/libopenmpttest-mptTime.obj `if test -f 'common/mptTime.cpp'; then $(CYGPATH_W) 'common/mptTime.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptTime.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptTime.Tpo common/$(DEPDIR)/libopenmpttest-mptTime.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/mptTime.cpp' object='common/libopenmpttest-mptTime.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptTime.obj `if test -f 'common/mptTime.cpp'; then $(CYGPATH_W) 'common/mptTime.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptTime.cpp'; fi` common/libopenmpttest-Profiler.o: common/Profiler.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-Profiler.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-Profiler.Tpo -c -o common/libopenmpttest-Profiler.o `test -f 'common/Profiler.cpp' || echo '$(srcdir)/'`common/Profiler.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-Profiler.Tpo common/$(DEPDIR)/libopenmpttest-Profiler.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Profiler.cpp' object='common/libopenmpttest-Profiler.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-Profiler.o `test -f 'common/Profiler.cpp' || echo '$(srcdir)/'`common/Profiler.cpp common/libopenmpttest-Profiler.obj: common/Profiler.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-Profiler.obj -MD -MP -MF common/$(DEPDIR)/libopenmpttest-Profiler.Tpo -c -o common/libopenmpttest-Profiler.obj `if test -f 'common/Profiler.cpp'; then $(CYGPATH_W) 'common/Profiler.cpp'; else $(CYGPATH_W) '$(srcdir)/common/Profiler.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-Profiler.Tpo common/$(DEPDIR)/libopenmpttest-Profiler.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/Profiler.cpp' object='common/libopenmpttest-Profiler.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-Profiler.obj `if test -f 'common/Profiler.cpp'; then $(CYGPATH_W) 'common/Profiler.cpp'; else $(CYGPATH_W) '$(srcdir)/common/Profiler.cpp'; fi` common/libopenmpttest-serialization_utils.o: common/serialization_utils.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-serialization_utils.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-serialization_utils.Tpo -c -o common/libopenmpttest-serialization_utils.o `test -f 'common/serialization_utils.cpp' || echo '$(srcdir)/'`common/serialization_utils.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-serialization_utils.Tpo common/$(DEPDIR)/libopenmpttest-serialization_utils.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/serialization_utils.cpp' object='common/libopenmpttest-serialization_utils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-serialization_utils.o `test -f 'common/serialization_utils.cpp' || echo '$(srcdir)/'`common/serialization_utils.cpp common/libopenmpttest-serialization_utils.obj: common/serialization_utils.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-serialization_utils.obj -MD -MP -MF common/$(DEPDIR)/libopenmpttest-serialization_utils.Tpo -c -o common/libopenmpttest-serialization_utils.obj `if test -f 'common/serialization_utils.cpp'; then $(CYGPATH_W) 'common/serialization_utils.cpp'; else $(CYGPATH_W) '$(srcdir)/common/serialization_utils.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-serialization_utils.Tpo common/$(DEPDIR)/libopenmpttest-serialization_utils.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/serialization_utils.cpp' object='common/libopenmpttest-serialization_utils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-serialization_utils.obj `if test -f 'common/serialization_utils.cpp'; then $(CYGPATH_W) 'common/serialization_utils.cpp'; else $(CYGPATH_W) '$(srcdir)/common/serialization_utils.cpp'; fi` common/libopenmpttest-version.o: common/version.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-version.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-version.Tpo -c -o common/libopenmpttest-version.o `test -f 'common/version.cpp' || echo '$(srcdir)/'`common/version.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-version.Tpo common/$(DEPDIR)/libopenmpttest-version.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/version.cpp' object='common/libopenmpttest-version.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-version.o `test -f 'common/version.cpp' || echo '$(srcdir)/'`common/version.cpp common/libopenmpttest-version.obj: common/version.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-version.obj -MD -MP -MF common/$(DEPDIR)/libopenmpttest-version.Tpo -c -o common/libopenmpttest-version.obj `if test -f 'common/version.cpp'; then $(CYGPATH_W) 'common/version.cpp'; else $(CYGPATH_W) '$(srcdir)/common/version.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-version.Tpo common/$(DEPDIR)/libopenmpttest-version.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='common/version.cpp' object='common/libopenmpttest-version.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-version.obj `if test -f 'common/version.cpp'; then $(CYGPATH_W) 'common/version.cpp'; else $(CYGPATH_W) '$(srcdir)/common/version.cpp'; fi` soundlib/libopenmpttest-AudioCriticalSection.o: soundlib/AudioCriticalSection.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-AudioCriticalSection.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-AudioCriticalSection.Tpo -c -o soundlib/libopenmpttest-AudioCriticalSection.o `test -f 'soundlib/AudioCriticalSection.cpp' || echo '$(srcdir)/'`soundlib/AudioCriticalSection.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-AudioCriticalSection.Tpo soundlib/$(DEPDIR)/libopenmpttest-AudioCriticalSection.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/AudioCriticalSection.cpp' object='soundlib/libopenmpttest-AudioCriticalSection.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-AudioCriticalSection.o `test -f 'soundlib/AudioCriticalSection.cpp' || echo '$(srcdir)/'`soundlib/AudioCriticalSection.cpp soundlib/libopenmpttest-AudioCriticalSection.obj: soundlib/AudioCriticalSection.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-AudioCriticalSection.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-AudioCriticalSection.Tpo -c -o soundlib/libopenmpttest-AudioCriticalSection.obj `if test -f 'soundlib/AudioCriticalSection.cpp'; then $(CYGPATH_W) 'soundlib/AudioCriticalSection.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/AudioCriticalSection.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-AudioCriticalSection.Tpo soundlib/$(DEPDIR)/libopenmpttest-AudioCriticalSection.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/AudioCriticalSection.cpp' object='soundlib/libopenmpttest-AudioCriticalSection.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-AudioCriticalSection.obj `if test -f 'soundlib/AudioCriticalSection.cpp'; then $(CYGPATH_W) 'soundlib/AudioCriticalSection.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/AudioCriticalSection.cpp'; fi` soundlib/libopenmpttest-ContainerMMCMP.o: soundlib/ContainerMMCMP.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerMMCMP.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Tpo -c -o soundlib/libopenmpttest-ContainerMMCMP.o `test -f 'soundlib/ContainerMMCMP.cpp' || echo '$(srcdir)/'`soundlib/ContainerMMCMP.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerMMCMP.cpp' object='soundlib/libopenmpttest-ContainerMMCMP.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerMMCMP.o `test -f 'soundlib/ContainerMMCMP.cpp' || echo '$(srcdir)/'`soundlib/ContainerMMCMP.cpp soundlib/libopenmpttest-ContainerMMCMP.obj: soundlib/ContainerMMCMP.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerMMCMP.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Tpo -c -o soundlib/libopenmpttest-ContainerMMCMP.obj `if test -f 'soundlib/ContainerMMCMP.cpp'; then $(CYGPATH_W) 'soundlib/ContainerMMCMP.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerMMCMP.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerMMCMP.cpp' object='soundlib/libopenmpttest-ContainerMMCMP.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerMMCMP.obj `if test -f 'soundlib/ContainerMMCMP.cpp'; then $(CYGPATH_W) 'soundlib/ContainerMMCMP.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerMMCMP.cpp'; fi` soundlib/libopenmpttest-ContainerPP20.o: soundlib/ContainerPP20.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerPP20.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Tpo -c -o soundlib/libopenmpttest-ContainerPP20.o `test -f 'soundlib/ContainerPP20.cpp' || echo '$(srcdir)/'`soundlib/ContainerPP20.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerPP20.cpp' object='soundlib/libopenmpttest-ContainerPP20.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerPP20.o `test -f 'soundlib/ContainerPP20.cpp' || echo '$(srcdir)/'`soundlib/ContainerPP20.cpp soundlib/libopenmpttest-ContainerPP20.obj: soundlib/ContainerPP20.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerPP20.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Tpo -c -o soundlib/libopenmpttest-ContainerPP20.obj `if test -f 'soundlib/ContainerPP20.cpp'; then $(CYGPATH_W) 'soundlib/ContainerPP20.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerPP20.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerPP20.cpp' object='soundlib/libopenmpttest-ContainerPP20.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerPP20.obj `if test -f 'soundlib/ContainerPP20.cpp'; then $(CYGPATH_W) 'soundlib/ContainerPP20.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerPP20.cpp'; fi` soundlib/libopenmpttest-ContainerUMX.o: soundlib/ContainerUMX.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerUMX.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Tpo -c -o soundlib/libopenmpttest-ContainerUMX.o `test -f 'soundlib/ContainerUMX.cpp' || echo '$(srcdir)/'`soundlib/ContainerUMX.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerUMX.cpp' object='soundlib/libopenmpttest-ContainerUMX.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerUMX.o `test -f 'soundlib/ContainerUMX.cpp' || echo '$(srcdir)/'`soundlib/ContainerUMX.cpp soundlib/libopenmpttest-ContainerUMX.obj: soundlib/ContainerUMX.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerUMX.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Tpo -c -o soundlib/libopenmpttest-ContainerUMX.obj `if test -f 'soundlib/ContainerUMX.cpp'; then $(CYGPATH_W) 'soundlib/ContainerUMX.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerUMX.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerUMX.cpp' object='soundlib/libopenmpttest-ContainerUMX.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerUMX.obj `if test -f 'soundlib/ContainerUMX.cpp'; then $(CYGPATH_W) 'soundlib/ContainerUMX.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerUMX.cpp'; fi` soundlib/libopenmpttest-ContainerXPK.o: soundlib/ContainerXPK.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerXPK.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Tpo -c -o soundlib/libopenmpttest-ContainerXPK.o `test -f 'soundlib/ContainerXPK.cpp' || echo '$(srcdir)/'`soundlib/ContainerXPK.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerXPK.cpp' object='soundlib/libopenmpttest-ContainerXPK.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerXPK.o `test -f 'soundlib/ContainerXPK.cpp' || echo '$(srcdir)/'`soundlib/ContainerXPK.cpp soundlib/libopenmpttest-ContainerXPK.obj: soundlib/ContainerXPK.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerXPK.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Tpo -c -o soundlib/libopenmpttest-ContainerXPK.obj `if test -f 'soundlib/ContainerXPK.cpp'; then $(CYGPATH_W) 'soundlib/ContainerXPK.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerXPK.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ContainerXPK.cpp' object='soundlib/libopenmpttest-ContainerXPK.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerXPK.obj `if test -f 'soundlib/ContainerXPK.cpp'; then $(CYGPATH_W) 'soundlib/ContainerXPK.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerXPK.cpp'; fi` soundlib/libopenmpttest-Dlsbank.o: soundlib/Dlsbank.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Dlsbank.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Dlsbank.Tpo -c -o soundlib/libopenmpttest-Dlsbank.o `test -f 'soundlib/Dlsbank.cpp' || echo '$(srcdir)/'`soundlib/Dlsbank.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Dlsbank.Tpo soundlib/$(DEPDIR)/libopenmpttest-Dlsbank.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Dlsbank.cpp' object='soundlib/libopenmpttest-Dlsbank.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Dlsbank.o `test -f 'soundlib/Dlsbank.cpp' || echo '$(srcdir)/'`soundlib/Dlsbank.cpp soundlib/libopenmpttest-Dlsbank.obj: soundlib/Dlsbank.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Dlsbank.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Dlsbank.Tpo -c -o soundlib/libopenmpttest-Dlsbank.obj `if test -f 'soundlib/Dlsbank.cpp'; then $(CYGPATH_W) 'soundlib/Dlsbank.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Dlsbank.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Dlsbank.Tpo soundlib/$(DEPDIR)/libopenmpttest-Dlsbank.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Dlsbank.cpp' object='soundlib/libopenmpttest-Dlsbank.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Dlsbank.obj `if test -f 'soundlib/Dlsbank.cpp'; then $(CYGPATH_W) 'soundlib/Dlsbank.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Dlsbank.cpp'; fi` soundlib/libopenmpttest-Fastmix.o: soundlib/Fastmix.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Fastmix.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Fastmix.Tpo -c -o soundlib/libopenmpttest-Fastmix.o `test -f 'soundlib/Fastmix.cpp' || echo '$(srcdir)/'`soundlib/Fastmix.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Fastmix.Tpo soundlib/$(DEPDIR)/libopenmpttest-Fastmix.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Fastmix.cpp' object='soundlib/libopenmpttest-Fastmix.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Fastmix.o `test -f 'soundlib/Fastmix.cpp' || echo '$(srcdir)/'`soundlib/Fastmix.cpp soundlib/libopenmpttest-Fastmix.obj: soundlib/Fastmix.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Fastmix.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Fastmix.Tpo -c -o soundlib/libopenmpttest-Fastmix.obj `if test -f 'soundlib/Fastmix.cpp'; then $(CYGPATH_W) 'soundlib/Fastmix.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Fastmix.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Fastmix.Tpo soundlib/$(DEPDIR)/libopenmpttest-Fastmix.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Fastmix.cpp' object='soundlib/libopenmpttest-Fastmix.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Fastmix.obj `if test -f 'soundlib/Fastmix.cpp'; then $(CYGPATH_W) 'soundlib/Fastmix.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Fastmix.cpp'; fi` soundlib/libopenmpttest-InstrumentExtensions.o: soundlib/InstrumentExtensions.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-InstrumentExtensions.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-InstrumentExtensions.Tpo -c -o soundlib/libopenmpttest-InstrumentExtensions.o `test -f 'soundlib/InstrumentExtensions.cpp' || echo '$(srcdir)/'`soundlib/InstrumentExtensions.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-InstrumentExtensions.Tpo soundlib/$(DEPDIR)/libopenmpttest-InstrumentExtensions.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/InstrumentExtensions.cpp' object='soundlib/libopenmpttest-InstrumentExtensions.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-InstrumentExtensions.o `test -f 'soundlib/InstrumentExtensions.cpp' || echo '$(srcdir)/'`soundlib/InstrumentExtensions.cpp soundlib/libopenmpttest-InstrumentExtensions.obj: soundlib/InstrumentExtensions.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-InstrumentExtensions.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-InstrumentExtensions.Tpo -c -o soundlib/libopenmpttest-InstrumentExtensions.obj `if test -f 'soundlib/InstrumentExtensions.cpp'; then $(CYGPATH_W) 'soundlib/InstrumentExtensions.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/InstrumentExtensions.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-InstrumentExtensions.Tpo soundlib/$(DEPDIR)/libopenmpttest-InstrumentExtensions.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/InstrumentExtensions.cpp' object='soundlib/libopenmpttest-InstrumentExtensions.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-InstrumentExtensions.obj `if test -f 'soundlib/InstrumentExtensions.cpp'; then $(CYGPATH_W) 'soundlib/InstrumentExtensions.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/InstrumentExtensions.cpp'; fi` soundlib/libopenmpttest-InstrumentSynth.o: soundlib/InstrumentSynth.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-InstrumentSynth.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-InstrumentSynth.Tpo -c -o soundlib/libopenmpttest-InstrumentSynth.o `test -f 'soundlib/InstrumentSynth.cpp' || echo '$(srcdir)/'`soundlib/InstrumentSynth.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-InstrumentSynth.Tpo soundlib/$(DEPDIR)/libopenmpttest-InstrumentSynth.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/InstrumentSynth.cpp' object='soundlib/libopenmpttest-InstrumentSynth.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-InstrumentSynth.o `test -f 'soundlib/InstrumentSynth.cpp' || echo '$(srcdir)/'`soundlib/InstrumentSynth.cpp soundlib/libopenmpttest-InstrumentSynth.obj: soundlib/InstrumentSynth.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-InstrumentSynth.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-InstrumentSynth.Tpo -c -o soundlib/libopenmpttest-InstrumentSynth.obj `if test -f 'soundlib/InstrumentSynth.cpp'; then $(CYGPATH_W) 'soundlib/InstrumentSynth.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/InstrumentSynth.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-InstrumentSynth.Tpo soundlib/$(DEPDIR)/libopenmpttest-InstrumentSynth.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/InstrumentSynth.cpp' object='soundlib/libopenmpttest-InstrumentSynth.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-InstrumentSynth.obj `if test -f 'soundlib/InstrumentSynth.cpp'; then $(CYGPATH_W) 'soundlib/InstrumentSynth.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/InstrumentSynth.cpp'; fi` soundlib/libopenmpttest-ITCompression.o: soundlib/ITCompression.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ITCompression.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ITCompression.Tpo -c -o soundlib/libopenmpttest-ITCompression.o `test -f 'soundlib/ITCompression.cpp' || echo '$(srcdir)/'`soundlib/ITCompression.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ITCompression.Tpo soundlib/$(DEPDIR)/libopenmpttest-ITCompression.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ITCompression.cpp' object='soundlib/libopenmpttest-ITCompression.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ITCompression.o `test -f 'soundlib/ITCompression.cpp' || echo '$(srcdir)/'`soundlib/ITCompression.cpp soundlib/libopenmpttest-ITCompression.obj: soundlib/ITCompression.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ITCompression.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ITCompression.Tpo -c -o soundlib/libopenmpttest-ITCompression.obj `if test -f 'soundlib/ITCompression.cpp'; then $(CYGPATH_W) 'soundlib/ITCompression.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ITCompression.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ITCompression.Tpo soundlib/$(DEPDIR)/libopenmpttest-ITCompression.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ITCompression.cpp' object='soundlib/libopenmpttest-ITCompression.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ITCompression.obj `if test -f 'soundlib/ITCompression.cpp'; then $(CYGPATH_W) 'soundlib/ITCompression.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ITCompression.cpp'; fi` soundlib/libopenmpttest-ITTools.o: soundlib/ITTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ITTools.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ITTools.Tpo -c -o soundlib/libopenmpttest-ITTools.o `test -f 'soundlib/ITTools.cpp' || echo '$(srcdir)/'`soundlib/ITTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ITTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-ITTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ITTools.cpp' object='soundlib/libopenmpttest-ITTools.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ITTools.o `test -f 'soundlib/ITTools.cpp' || echo '$(srcdir)/'`soundlib/ITTools.cpp soundlib/libopenmpttest-ITTools.obj: soundlib/ITTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ITTools.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ITTools.Tpo -c -o soundlib/libopenmpttest-ITTools.obj `if test -f 'soundlib/ITTools.cpp'; then $(CYGPATH_W) 'soundlib/ITTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ITTools.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ITTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-ITTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ITTools.cpp' object='soundlib/libopenmpttest-ITTools.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ITTools.obj `if test -f 'soundlib/ITTools.cpp'; then $(CYGPATH_W) 'soundlib/ITTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ITTools.cpp'; fi` soundlib/libopenmpttest-Load_667.o: soundlib/Load_667.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_667.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_667.Tpo -c -o soundlib/libopenmpttest-Load_667.o `test -f 'soundlib/Load_667.cpp' || echo '$(srcdir)/'`soundlib/Load_667.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_667.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_667.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_667.cpp' object='soundlib/libopenmpttest-Load_667.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_667.o `test -f 'soundlib/Load_667.cpp' || echo '$(srcdir)/'`soundlib/Load_667.cpp soundlib/libopenmpttest-Load_667.obj: soundlib/Load_667.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_667.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_667.Tpo -c -o soundlib/libopenmpttest-Load_667.obj `if test -f 'soundlib/Load_667.cpp'; then $(CYGPATH_W) 'soundlib/Load_667.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_667.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_667.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_667.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_667.cpp' object='soundlib/libopenmpttest-Load_667.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_667.obj `if test -f 'soundlib/Load_667.cpp'; then $(CYGPATH_W) 'soundlib/Load_667.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_667.cpp'; fi` soundlib/libopenmpttest-Load_669.o: soundlib/Load_669.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_669.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_669.Tpo -c -o soundlib/libopenmpttest-Load_669.o `test -f 'soundlib/Load_669.cpp' || echo '$(srcdir)/'`soundlib/Load_669.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_669.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_669.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_669.cpp' object='soundlib/libopenmpttest-Load_669.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_669.o `test -f 'soundlib/Load_669.cpp' || echo '$(srcdir)/'`soundlib/Load_669.cpp soundlib/libopenmpttest-Load_669.obj: soundlib/Load_669.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_669.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_669.Tpo -c -o soundlib/libopenmpttest-Load_669.obj `if test -f 'soundlib/Load_669.cpp'; then $(CYGPATH_W) 'soundlib/Load_669.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_669.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_669.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_669.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_669.cpp' object='soundlib/libopenmpttest-Load_669.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_669.obj `if test -f 'soundlib/Load_669.cpp'; then $(CYGPATH_W) 'soundlib/Load_669.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_669.cpp'; fi` soundlib/libopenmpttest-Load_amf.o: soundlib/Load_amf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_amf.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_amf.Tpo -c -o soundlib/libopenmpttest-Load_amf.o `test -f 'soundlib/Load_amf.cpp' || echo '$(srcdir)/'`soundlib/Load_amf.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_amf.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_amf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_amf.cpp' object='soundlib/libopenmpttest-Load_amf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_amf.o `test -f 'soundlib/Load_amf.cpp' || echo '$(srcdir)/'`soundlib/Load_amf.cpp soundlib/libopenmpttest-Load_amf.obj: soundlib/Load_amf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_amf.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_amf.Tpo -c -o soundlib/libopenmpttest-Load_amf.obj `if test -f 'soundlib/Load_amf.cpp'; then $(CYGPATH_W) 'soundlib/Load_amf.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_amf.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_amf.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_amf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_amf.cpp' object='soundlib/libopenmpttest-Load_amf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_amf.obj `if test -f 'soundlib/Load_amf.cpp'; then $(CYGPATH_W) 'soundlib/Load_amf.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_amf.cpp'; fi` soundlib/libopenmpttest-Load_ams.o: soundlib/Load_ams.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ams.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ams.Tpo -c -o soundlib/libopenmpttest-Load_ams.o `test -f 'soundlib/Load_ams.cpp' || echo '$(srcdir)/'`soundlib/Load_ams.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ams.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ams.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ams.cpp' object='soundlib/libopenmpttest-Load_ams.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ams.o `test -f 'soundlib/Load_ams.cpp' || echo '$(srcdir)/'`soundlib/Load_ams.cpp soundlib/libopenmpttest-Load_ams.obj: soundlib/Load_ams.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ams.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ams.Tpo -c -o soundlib/libopenmpttest-Load_ams.obj `if test -f 'soundlib/Load_ams.cpp'; then $(CYGPATH_W) 'soundlib/Load_ams.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ams.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ams.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ams.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ams.cpp' object='soundlib/libopenmpttest-Load_ams.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ams.obj `if test -f 'soundlib/Load_ams.cpp'; then $(CYGPATH_W) 'soundlib/Load_ams.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ams.cpp'; fi` soundlib/libopenmpttest-Load_c67.o: soundlib/Load_c67.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_c67.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_c67.Tpo -c -o soundlib/libopenmpttest-Load_c67.o `test -f 'soundlib/Load_c67.cpp' || echo '$(srcdir)/'`soundlib/Load_c67.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_c67.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_c67.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_c67.cpp' object='soundlib/libopenmpttest-Load_c67.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_c67.o `test -f 'soundlib/Load_c67.cpp' || echo '$(srcdir)/'`soundlib/Load_c67.cpp soundlib/libopenmpttest-Load_c67.obj: soundlib/Load_c67.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_c67.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_c67.Tpo -c -o soundlib/libopenmpttest-Load_c67.obj `if test -f 'soundlib/Load_c67.cpp'; then $(CYGPATH_W) 'soundlib/Load_c67.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_c67.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_c67.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_c67.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_c67.cpp' object='soundlib/libopenmpttest-Load_c67.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_c67.obj `if test -f 'soundlib/Load_c67.cpp'; then $(CYGPATH_W) 'soundlib/Load_c67.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_c67.cpp'; fi` soundlib/libopenmpttest-Load_cba.o: soundlib/Load_cba.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_cba.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_cba.Tpo -c -o soundlib/libopenmpttest-Load_cba.o `test -f 'soundlib/Load_cba.cpp' || echo '$(srcdir)/'`soundlib/Load_cba.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_cba.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_cba.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_cba.cpp' object='soundlib/libopenmpttest-Load_cba.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_cba.o `test -f 'soundlib/Load_cba.cpp' || echo '$(srcdir)/'`soundlib/Load_cba.cpp soundlib/libopenmpttest-Load_cba.obj: soundlib/Load_cba.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_cba.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_cba.Tpo -c -o soundlib/libopenmpttest-Load_cba.obj `if test -f 'soundlib/Load_cba.cpp'; then $(CYGPATH_W) 'soundlib/Load_cba.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_cba.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_cba.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_cba.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_cba.cpp' object='soundlib/libopenmpttest-Load_cba.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_cba.obj `if test -f 'soundlib/Load_cba.cpp'; then $(CYGPATH_W) 'soundlib/Load_cba.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_cba.cpp'; fi` soundlib/libopenmpttest-Load_dbm.o: soundlib/Load_dbm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dbm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dbm.Tpo -c -o soundlib/libopenmpttest-Load_dbm.o `test -f 'soundlib/Load_dbm.cpp' || echo '$(srcdir)/'`soundlib/Load_dbm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dbm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dbm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dbm.cpp' object='soundlib/libopenmpttest-Load_dbm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dbm.o `test -f 'soundlib/Load_dbm.cpp' || echo '$(srcdir)/'`soundlib/Load_dbm.cpp soundlib/libopenmpttest-Load_dbm.obj: soundlib/Load_dbm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dbm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dbm.Tpo -c -o soundlib/libopenmpttest-Load_dbm.obj `if test -f 'soundlib/Load_dbm.cpp'; then $(CYGPATH_W) 'soundlib/Load_dbm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dbm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dbm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dbm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dbm.cpp' object='soundlib/libopenmpttest-Load_dbm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dbm.obj `if test -f 'soundlib/Load_dbm.cpp'; then $(CYGPATH_W) 'soundlib/Load_dbm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dbm.cpp'; fi` soundlib/libopenmpttest-Load_digi.o: soundlib/Load_digi.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_digi.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_digi.Tpo -c -o soundlib/libopenmpttest-Load_digi.o `test -f 'soundlib/Load_digi.cpp' || echo '$(srcdir)/'`soundlib/Load_digi.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_digi.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_digi.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_digi.cpp' object='soundlib/libopenmpttest-Load_digi.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_digi.o `test -f 'soundlib/Load_digi.cpp' || echo '$(srcdir)/'`soundlib/Load_digi.cpp soundlib/libopenmpttest-Load_digi.obj: soundlib/Load_digi.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_digi.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_digi.Tpo -c -o soundlib/libopenmpttest-Load_digi.obj `if test -f 'soundlib/Load_digi.cpp'; then $(CYGPATH_W) 'soundlib/Load_digi.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_digi.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_digi.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_digi.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_digi.cpp' object='soundlib/libopenmpttest-Load_digi.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_digi.obj `if test -f 'soundlib/Load_digi.cpp'; then $(CYGPATH_W) 'soundlib/Load_digi.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_digi.cpp'; fi` soundlib/libopenmpttest-Load_dmf.o: soundlib/Load_dmf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dmf.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dmf.Tpo -c -o soundlib/libopenmpttest-Load_dmf.o `test -f 'soundlib/Load_dmf.cpp' || echo '$(srcdir)/'`soundlib/Load_dmf.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dmf.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dmf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dmf.cpp' object='soundlib/libopenmpttest-Load_dmf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dmf.o `test -f 'soundlib/Load_dmf.cpp' || echo '$(srcdir)/'`soundlib/Load_dmf.cpp soundlib/libopenmpttest-Load_dmf.obj: soundlib/Load_dmf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dmf.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dmf.Tpo -c -o soundlib/libopenmpttest-Load_dmf.obj `if test -f 'soundlib/Load_dmf.cpp'; then $(CYGPATH_W) 'soundlib/Load_dmf.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dmf.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dmf.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dmf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dmf.cpp' object='soundlib/libopenmpttest-Load_dmf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dmf.obj `if test -f 'soundlib/Load_dmf.cpp'; then $(CYGPATH_W) 'soundlib/Load_dmf.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dmf.cpp'; fi` soundlib/libopenmpttest-Load_dsm.o: soundlib/Load_dsm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dsm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dsm.Tpo -c -o soundlib/libopenmpttest-Load_dsm.o `test -f 'soundlib/Load_dsm.cpp' || echo '$(srcdir)/'`soundlib/Load_dsm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dsm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dsm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dsm.cpp' object='soundlib/libopenmpttest-Load_dsm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dsm.o `test -f 'soundlib/Load_dsm.cpp' || echo '$(srcdir)/'`soundlib/Load_dsm.cpp soundlib/libopenmpttest-Load_dsm.obj: soundlib/Load_dsm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dsm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dsm.Tpo -c -o soundlib/libopenmpttest-Load_dsm.obj `if test -f 'soundlib/Load_dsm.cpp'; then $(CYGPATH_W) 'soundlib/Load_dsm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dsm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dsm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dsm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dsm.cpp' object='soundlib/libopenmpttest-Load_dsm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dsm.obj `if test -f 'soundlib/Load_dsm.cpp'; then $(CYGPATH_W) 'soundlib/Load_dsm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dsm.cpp'; fi` soundlib/libopenmpttest-Load_dsym.o: soundlib/Load_dsym.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dsym.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dsym.Tpo -c -o soundlib/libopenmpttest-Load_dsym.o `test -f 'soundlib/Load_dsym.cpp' || echo '$(srcdir)/'`soundlib/Load_dsym.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dsym.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dsym.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dsym.cpp' object='soundlib/libopenmpttest-Load_dsym.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dsym.o `test -f 'soundlib/Load_dsym.cpp' || echo '$(srcdir)/'`soundlib/Load_dsym.cpp soundlib/libopenmpttest-Load_dsym.obj: soundlib/Load_dsym.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dsym.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dsym.Tpo -c -o soundlib/libopenmpttest-Load_dsym.obj `if test -f 'soundlib/Load_dsym.cpp'; then $(CYGPATH_W) 'soundlib/Load_dsym.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dsym.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dsym.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dsym.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dsym.cpp' object='soundlib/libopenmpttest-Load_dsym.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dsym.obj `if test -f 'soundlib/Load_dsym.cpp'; then $(CYGPATH_W) 'soundlib/Load_dsym.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dsym.cpp'; fi` soundlib/libopenmpttest-Load_dtm.o: soundlib/Load_dtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dtm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Tpo -c -o soundlib/libopenmpttest-Load_dtm.o `test -f 'soundlib/Load_dtm.cpp' || echo '$(srcdir)/'`soundlib/Load_dtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dtm.cpp' object='soundlib/libopenmpttest-Load_dtm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dtm.o `test -f 'soundlib/Load_dtm.cpp' || echo '$(srcdir)/'`soundlib/Load_dtm.cpp soundlib/libopenmpttest-Load_dtm.obj: soundlib/Load_dtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dtm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Tpo -c -o soundlib/libopenmpttest-Load_dtm.obj `if test -f 'soundlib/Load_dtm.cpp'; then $(CYGPATH_W) 'soundlib/Load_dtm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dtm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_dtm.cpp' object='soundlib/libopenmpttest-Load_dtm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dtm.obj `if test -f 'soundlib/Load_dtm.cpp'; then $(CYGPATH_W) 'soundlib/Load_dtm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dtm.cpp'; fi` soundlib/libopenmpttest-Load_etx.o: soundlib/Load_etx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_etx.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_etx.Tpo -c -o soundlib/libopenmpttest-Load_etx.o `test -f 'soundlib/Load_etx.cpp' || echo '$(srcdir)/'`soundlib/Load_etx.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_etx.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_etx.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_etx.cpp' object='soundlib/libopenmpttest-Load_etx.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_etx.o `test -f 'soundlib/Load_etx.cpp' || echo '$(srcdir)/'`soundlib/Load_etx.cpp soundlib/libopenmpttest-Load_etx.obj: soundlib/Load_etx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_etx.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_etx.Tpo -c -o soundlib/libopenmpttest-Load_etx.obj `if test -f 'soundlib/Load_etx.cpp'; then $(CYGPATH_W) 'soundlib/Load_etx.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_etx.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_etx.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_etx.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_etx.cpp' object='soundlib/libopenmpttest-Load_etx.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_etx.obj `if test -f 'soundlib/Load_etx.cpp'; then $(CYGPATH_W) 'soundlib/Load_etx.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_etx.cpp'; fi` soundlib/libopenmpttest-Load_far.o: soundlib/Load_far.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_far.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_far.Tpo -c -o soundlib/libopenmpttest-Load_far.o `test -f 'soundlib/Load_far.cpp' || echo '$(srcdir)/'`soundlib/Load_far.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_far.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_far.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_far.cpp' object='soundlib/libopenmpttest-Load_far.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_far.o `test -f 'soundlib/Load_far.cpp' || echo '$(srcdir)/'`soundlib/Load_far.cpp soundlib/libopenmpttest-Load_far.obj: soundlib/Load_far.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_far.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_far.Tpo -c -o soundlib/libopenmpttest-Load_far.obj `if test -f 'soundlib/Load_far.cpp'; then $(CYGPATH_W) 'soundlib/Load_far.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_far.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_far.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_far.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_far.cpp' object='soundlib/libopenmpttest-Load_far.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_far.obj `if test -f 'soundlib/Load_far.cpp'; then $(CYGPATH_W) 'soundlib/Load_far.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_far.cpp'; fi` soundlib/libopenmpttest-Load_fc.o: soundlib/Load_fc.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_fc.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_fc.Tpo -c -o soundlib/libopenmpttest-Load_fc.o `test -f 'soundlib/Load_fc.cpp' || echo '$(srcdir)/'`soundlib/Load_fc.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_fc.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_fc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_fc.cpp' object='soundlib/libopenmpttest-Load_fc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_fc.o `test -f 'soundlib/Load_fc.cpp' || echo '$(srcdir)/'`soundlib/Load_fc.cpp soundlib/libopenmpttest-Load_fc.obj: soundlib/Load_fc.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_fc.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_fc.Tpo -c -o soundlib/libopenmpttest-Load_fc.obj `if test -f 'soundlib/Load_fc.cpp'; then $(CYGPATH_W) 'soundlib/Load_fc.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_fc.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_fc.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_fc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_fc.cpp' object='soundlib/libopenmpttest-Load_fc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_fc.obj `if test -f 'soundlib/Load_fc.cpp'; then $(CYGPATH_W) 'soundlib/Load_fc.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_fc.cpp'; fi` soundlib/libopenmpttest-Load_fmt.o: soundlib/Load_fmt.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_fmt.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_fmt.Tpo -c -o soundlib/libopenmpttest-Load_fmt.o `test -f 'soundlib/Load_fmt.cpp' || echo '$(srcdir)/'`soundlib/Load_fmt.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_fmt.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_fmt.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_fmt.cpp' object='soundlib/libopenmpttest-Load_fmt.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_fmt.o `test -f 'soundlib/Load_fmt.cpp' || echo '$(srcdir)/'`soundlib/Load_fmt.cpp soundlib/libopenmpttest-Load_fmt.obj: soundlib/Load_fmt.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_fmt.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_fmt.Tpo -c -o soundlib/libopenmpttest-Load_fmt.obj `if test -f 'soundlib/Load_fmt.cpp'; then $(CYGPATH_W) 'soundlib/Load_fmt.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_fmt.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_fmt.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_fmt.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_fmt.cpp' object='soundlib/libopenmpttest-Load_fmt.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_fmt.obj `if test -f 'soundlib/Load_fmt.cpp'; then $(CYGPATH_W) 'soundlib/Load_fmt.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_fmt.cpp'; fi` soundlib/libopenmpttest-Load_ftm.o: soundlib/Load_ftm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ftm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ftm.Tpo -c -o soundlib/libopenmpttest-Load_ftm.o `test -f 'soundlib/Load_ftm.cpp' || echo '$(srcdir)/'`soundlib/Load_ftm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ftm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ftm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ftm.cpp' object='soundlib/libopenmpttest-Load_ftm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ftm.o `test -f 'soundlib/Load_ftm.cpp' || echo '$(srcdir)/'`soundlib/Load_ftm.cpp soundlib/libopenmpttest-Load_ftm.obj: soundlib/Load_ftm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ftm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ftm.Tpo -c -o soundlib/libopenmpttest-Load_ftm.obj `if test -f 'soundlib/Load_ftm.cpp'; then $(CYGPATH_W) 'soundlib/Load_ftm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ftm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ftm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ftm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ftm.cpp' object='soundlib/libopenmpttest-Load_ftm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ftm.obj `if test -f 'soundlib/Load_ftm.cpp'; then $(CYGPATH_W) 'soundlib/Load_ftm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ftm.cpp'; fi` soundlib/libopenmpttest-Load_gdm.o: soundlib/Load_gdm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_gdm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_gdm.Tpo -c -o soundlib/libopenmpttest-Load_gdm.o `test -f 'soundlib/Load_gdm.cpp' || echo '$(srcdir)/'`soundlib/Load_gdm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_gdm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_gdm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_gdm.cpp' object='soundlib/libopenmpttest-Load_gdm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_gdm.o `test -f 'soundlib/Load_gdm.cpp' || echo '$(srcdir)/'`soundlib/Load_gdm.cpp soundlib/libopenmpttest-Load_gdm.obj: soundlib/Load_gdm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_gdm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_gdm.Tpo -c -o soundlib/libopenmpttest-Load_gdm.obj `if test -f 'soundlib/Load_gdm.cpp'; then $(CYGPATH_W) 'soundlib/Load_gdm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_gdm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_gdm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_gdm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_gdm.cpp' object='soundlib/libopenmpttest-Load_gdm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_gdm.obj `if test -f 'soundlib/Load_gdm.cpp'; then $(CYGPATH_W) 'soundlib/Load_gdm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_gdm.cpp'; fi` soundlib/libopenmpttest-Load_gmc.o: soundlib/Load_gmc.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_gmc.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_gmc.Tpo -c -o soundlib/libopenmpttest-Load_gmc.o `test -f 'soundlib/Load_gmc.cpp' || echo '$(srcdir)/'`soundlib/Load_gmc.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_gmc.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_gmc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_gmc.cpp' object='soundlib/libopenmpttest-Load_gmc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_gmc.o `test -f 'soundlib/Load_gmc.cpp' || echo '$(srcdir)/'`soundlib/Load_gmc.cpp soundlib/libopenmpttest-Load_gmc.obj: soundlib/Load_gmc.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_gmc.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_gmc.Tpo -c -o soundlib/libopenmpttest-Load_gmc.obj `if test -f 'soundlib/Load_gmc.cpp'; then $(CYGPATH_W) 'soundlib/Load_gmc.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_gmc.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_gmc.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_gmc.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_gmc.cpp' object='soundlib/libopenmpttest-Load_gmc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_gmc.obj `if test -f 'soundlib/Load_gmc.cpp'; then $(CYGPATH_W) 'soundlib/Load_gmc.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_gmc.cpp'; fi` soundlib/libopenmpttest-Load_gt2.o: soundlib/Load_gt2.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_gt2.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_gt2.Tpo -c -o soundlib/libopenmpttest-Load_gt2.o `test -f 'soundlib/Load_gt2.cpp' || echo '$(srcdir)/'`soundlib/Load_gt2.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_gt2.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_gt2.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_gt2.cpp' object='soundlib/libopenmpttest-Load_gt2.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_gt2.o `test -f 'soundlib/Load_gt2.cpp' || echo '$(srcdir)/'`soundlib/Load_gt2.cpp soundlib/libopenmpttest-Load_gt2.obj: soundlib/Load_gt2.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_gt2.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_gt2.Tpo -c -o soundlib/libopenmpttest-Load_gt2.obj `if test -f 'soundlib/Load_gt2.cpp'; then $(CYGPATH_W) 'soundlib/Load_gt2.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_gt2.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_gt2.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_gt2.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_gt2.cpp' object='soundlib/libopenmpttest-Load_gt2.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_gt2.obj `if test -f 'soundlib/Load_gt2.cpp'; then $(CYGPATH_W) 'soundlib/Load_gt2.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_gt2.cpp'; fi` soundlib/libopenmpttest-Load_ice.o: soundlib/Load_ice.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ice.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ice.Tpo -c -o soundlib/libopenmpttest-Load_ice.o `test -f 'soundlib/Load_ice.cpp' || echo '$(srcdir)/'`soundlib/Load_ice.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ice.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ice.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ice.cpp' object='soundlib/libopenmpttest-Load_ice.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ice.o `test -f 'soundlib/Load_ice.cpp' || echo '$(srcdir)/'`soundlib/Load_ice.cpp soundlib/libopenmpttest-Load_ice.obj: soundlib/Load_ice.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ice.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ice.Tpo -c -o soundlib/libopenmpttest-Load_ice.obj `if test -f 'soundlib/Load_ice.cpp'; then $(CYGPATH_W) 'soundlib/Load_ice.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ice.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ice.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ice.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ice.cpp' object='soundlib/libopenmpttest-Load_ice.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ice.obj `if test -f 'soundlib/Load_ice.cpp'; then $(CYGPATH_W) 'soundlib/Load_ice.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ice.cpp'; fi` soundlib/libopenmpttest-Load_imf.o: soundlib/Load_imf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_imf.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_imf.Tpo -c -o soundlib/libopenmpttest-Load_imf.o `test -f 'soundlib/Load_imf.cpp' || echo '$(srcdir)/'`soundlib/Load_imf.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_imf.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_imf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_imf.cpp' object='soundlib/libopenmpttest-Load_imf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_imf.o `test -f 'soundlib/Load_imf.cpp' || echo '$(srcdir)/'`soundlib/Load_imf.cpp soundlib/libopenmpttest-Load_imf.obj: soundlib/Load_imf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_imf.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_imf.Tpo -c -o soundlib/libopenmpttest-Load_imf.obj `if test -f 'soundlib/Load_imf.cpp'; then $(CYGPATH_W) 'soundlib/Load_imf.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_imf.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_imf.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_imf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_imf.cpp' object='soundlib/libopenmpttest-Load_imf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_imf.obj `if test -f 'soundlib/Load_imf.cpp'; then $(CYGPATH_W) 'soundlib/Load_imf.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_imf.cpp'; fi` soundlib/libopenmpttest-Load_ims.o: soundlib/Load_ims.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ims.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ims.Tpo -c -o soundlib/libopenmpttest-Load_ims.o `test -f 'soundlib/Load_ims.cpp' || echo '$(srcdir)/'`soundlib/Load_ims.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ims.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ims.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ims.cpp' object='soundlib/libopenmpttest-Load_ims.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ims.o `test -f 'soundlib/Load_ims.cpp' || echo '$(srcdir)/'`soundlib/Load_ims.cpp soundlib/libopenmpttest-Load_ims.obj: soundlib/Load_ims.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ims.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ims.Tpo -c -o soundlib/libopenmpttest-Load_ims.obj `if test -f 'soundlib/Load_ims.cpp'; then $(CYGPATH_W) 'soundlib/Load_ims.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ims.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ims.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ims.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ims.cpp' object='soundlib/libopenmpttest-Load_ims.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ims.obj `if test -f 'soundlib/Load_ims.cpp'; then $(CYGPATH_W) 'soundlib/Load_ims.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ims.cpp'; fi` soundlib/libopenmpttest-Load_it.o: soundlib/Load_it.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_it.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_it.Tpo -c -o soundlib/libopenmpttest-Load_it.o `test -f 'soundlib/Load_it.cpp' || echo '$(srcdir)/'`soundlib/Load_it.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_it.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_it.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_it.cpp' object='soundlib/libopenmpttest-Load_it.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_it.o `test -f 'soundlib/Load_it.cpp' || echo '$(srcdir)/'`soundlib/Load_it.cpp soundlib/libopenmpttest-Load_it.obj: soundlib/Load_it.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_it.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_it.Tpo -c -o soundlib/libopenmpttest-Load_it.obj `if test -f 'soundlib/Load_it.cpp'; then $(CYGPATH_W) 'soundlib/Load_it.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_it.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_it.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_it.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_it.cpp' object='soundlib/libopenmpttest-Load_it.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_it.obj `if test -f 'soundlib/Load_it.cpp'; then $(CYGPATH_W) 'soundlib/Load_it.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_it.cpp'; fi` soundlib/libopenmpttest-Load_itp.o: soundlib/Load_itp.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_itp.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_itp.Tpo -c -o soundlib/libopenmpttest-Load_itp.o `test -f 'soundlib/Load_itp.cpp' || echo '$(srcdir)/'`soundlib/Load_itp.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_itp.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_itp.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_itp.cpp' object='soundlib/libopenmpttest-Load_itp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_itp.o `test -f 'soundlib/Load_itp.cpp' || echo '$(srcdir)/'`soundlib/Load_itp.cpp soundlib/libopenmpttest-Load_itp.obj: soundlib/Load_itp.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_itp.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_itp.Tpo -c -o soundlib/libopenmpttest-Load_itp.obj `if test -f 'soundlib/Load_itp.cpp'; then $(CYGPATH_W) 'soundlib/Load_itp.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_itp.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_itp.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_itp.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_itp.cpp' object='soundlib/libopenmpttest-Load_itp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_itp.obj `if test -f 'soundlib/Load_itp.cpp'; then $(CYGPATH_W) 'soundlib/Load_itp.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_itp.cpp'; fi` soundlib/libopenmpttest-load_j2b.o: soundlib/load_j2b.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-load_j2b.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-load_j2b.Tpo -c -o soundlib/libopenmpttest-load_j2b.o `test -f 'soundlib/load_j2b.cpp' || echo '$(srcdir)/'`soundlib/load_j2b.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-load_j2b.Tpo soundlib/$(DEPDIR)/libopenmpttest-load_j2b.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/load_j2b.cpp' object='soundlib/libopenmpttest-load_j2b.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-load_j2b.o `test -f 'soundlib/load_j2b.cpp' || echo '$(srcdir)/'`soundlib/load_j2b.cpp soundlib/libopenmpttest-load_j2b.obj: soundlib/load_j2b.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-load_j2b.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-load_j2b.Tpo -c -o soundlib/libopenmpttest-load_j2b.obj `if test -f 'soundlib/load_j2b.cpp'; then $(CYGPATH_W) 'soundlib/load_j2b.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/load_j2b.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-load_j2b.Tpo soundlib/$(DEPDIR)/libopenmpttest-load_j2b.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/load_j2b.cpp' object='soundlib/libopenmpttest-load_j2b.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-load_j2b.obj `if test -f 'soundlib/load_j2b.cpp'; then $(CYGPATH_W) 'soundlib/load_j2b.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/load_j2b.cpp'; fi` soundlib/libopenmpttest-Load_kris.o: soundlib/Load_kris.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_kris.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_kris.Tpo -c -o soundlib/libopenmpttest-Load_kris.o `test -f 'soundlib/Load_kris.cpp' || echo '$(srcdir)/'`soundlib/Load_kris.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_kris.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_kris.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_kris.cpp' object='soundlib/libopenmpttest-Load_kris.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_kris.o `test -f 'soundlib/Load_kris.cpp' || echo '$(srcdir)/'`soundlib/Load_kris.cpp soundlib/libopenmpttest-Load_kris.obj: soundlib/Load_kris.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_kris.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_kris.Tpo -c -o soundlib/libopenmpttest-Load_kris.obj `if test -f 'soundlib/Load_kris.cpp'; then $(CYGPATH_W) 'soundlib/Load_kris.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_kris.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_kris.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_kris.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_kris.cpp' object='soundlib/libopenmpttest-Load_kris.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_kris.obj `if test -f 'soundlib/Load_kris.cpp'; then $(CYGPATH_W) 'soundlib/Load_kris.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_kris.cpp'; fi` soundlib/libopenmpttest-Load_mdl.o: soundlib/Load_mdl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mdl.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mdl.Tpo -c -o soundlib/libopenmpttest-Load_mdl.o `test -f 'soundlib/Load_mdl.cpp' || echo '$(srcdir)/'`soundlib/Load_mdl.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mdl.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mdl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mdl.cpp' object='soundlib/libopenmpttest-Load_mdl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mdl.o `test -f 'soundlib/Load_mdl.cpp' || echo '$(srcdir)/'`soundlib/Load_mdl.cpp soundlib/libopenmpttest-Load_mdl.obj: soundlib/Load_mdl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mdl.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mdl.Tpo -c -o soundlib/libopenmpttest-Load_mdl.obj `if test -f 'soundlib/Load_mdl.cpp'; then $(CYGPATH_W) 'soundlib/Load_mdl.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mdl.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mdl.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mdl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mdl.cpp' object='soundlib/libopenmpttest-Load_mdl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mdl.obj `if test -f 'soundlib/Load_mdl.cpp'; then $(CYGPATH_W) 'soundlib/Load_mdl.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mdl.cpp'; fi` soundlib/libopenmpttest-Load_med.o: soundlib/Load_med.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_med.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_med.Tpo -c -o soundlib/libopenmpttest-Load_med.o `test -f 'soundlib/Load_med.cpp' || echo '$(srcdir)/'`soundlib/Load_med.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_med.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_med.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_med.cpp' object='soundlib/libopenmpttest-Load_med.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_med.o `test -f 'soundlib/Load_med.cpp' || echo '$(srcdir)/'`soundlib/Load_med.cpp soundlib/libopenmpttest-Load_med.obj: soundlib/Load_med.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_med.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_med.Tpo -c -o soundlib/libopenmpttest-Load_med.obj `if test -f 'soundlib/Load_med.cpp'; then $(CYGPATH_W) 'soundlib/Load_med.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_med.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_med.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_med.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_med.cpp' object='soundlib/libopenmpttest-Load_med.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_med.obj `if test -f 'soundlib/Load_med.cpp'; then $(CYGPATH_W) 'soundlib/Load_med.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_med.cpp'; fi` soundlib/libopenmpttest-Load_mid.o: soundlib/Load_mid.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mid.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mid.Tpo -c -o soundlib/libopenmpttest-Load_mid.o `test -f 'soundlib/Load_mid.cpp' || echo '$(srcdir)/'`soundlib/Load_mid.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mid.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mid.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mid.cpp' object='soundlib/libopenmpttest-Load_mid.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mid.o `test -f 'soundlib/Load_mid.cpp' || echo '$(srcdir)/'`soundlib/Load_mid.cpp soundlib/libopenmpttest-Load_mid.obj: soundlib/Load_mid.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mid.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mid.Tpo -c -o soundlib/libopenmpttest-Load_mid.obj `if test -f 'soundlib/Load_mid.cpp'; then $(CYGPATH_W) 'soundlib/Load_mid.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mid.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mid.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mid.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mid.cpp' object='soundlib/libopenmpttest-Load_mid.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mid.obj `if test -f 'soundlib/Load_mid.cpp'; then $(CYGPATH_W) 'soundlib/Load_mid.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mid.cpp'; fi` soundlib/libopenmpttest-Load_mo3.o: soundlib/Load_mo3.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mo3.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mo3.Tpo -c -o soundlib/libopenmpttest-Load_mo3.o `test -f 'soundlib/Load_mo3.cpp' || echo '$(srcdir)/'`soundlib/Load_mo3.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mo3.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mo3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mo3.cpp' object='soundlib/libopenmpttest-Load_mo3.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mo3.o `test -f 'soundlib/Load_mo3.cpp' || echo '$(srcdir)/'`soundlib/Load_mo3.cpp soundlib/libopenmpttest-Load_mo3.obj: soundlib/Load_mo3.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mo3.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mo3.Tpo -c -o soundlib/libopenmpttest-Load_mo3.obj `if test -f 'soundlib/Load_mo3.cpp'; then $(CYGPATH_W) 'soundlib/Load_mo3.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mo3.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mo3.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mo3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mo3.cpp' object='soundlib/libopenmpttest-Load_mo3.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mo3.obj `if test -f 'soundlib/Load_mo3.cpp'; then $(CYGPATH_W) 'soundlib/Load_mo3.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mo3.cpp'; fi` soundlib/libopenmpttest-Load_mod.o: soundlib/Load_mod.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mod.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mod.Tpo -c -o soundlib/libopenmpttest-Load_mod.o `test -f 'soundlib/Load_mod.cpp' || echo '$(srcdir)/'`soundlib/Load_mod.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mod.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mod.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mod.cpp' object='soundlib/libopenmpttest-Load_mod.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mod.o `test -f 'soundlib/Load_mod.cpp' || echo '$(srcdir)/'`soundlib/Load_mod.cpp soundlib/libopenmpttest-Load_mod.obj: soundlib/Load_mod.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mod.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mod.Tpo -c -o soundlib/libopenmpttest-Load_mod.obj `if test -f 'soundlib/Load_mod.cpp'; then $(CYGPATH_W) 'soundlib/Load_mod.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mod.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mod.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mod.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mod.cpp' object='soundlib/libopenmpttest-Load_mod.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mod.obj `if test -f 'soundlib/Load_mod.cpp'; then $(CYGPATH_W) 'soundlib/Load_mod.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mod.cpp'; fi` soundlib/libopenmpttest-Load_mt2.o: soundlib/Load_mt2.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mt2.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mt2.Tpo -c -o soundlib/libopenmpttest-Load_mt2.o `test -f 'soundlib/Load_mt2.cpp' || echo '$(srcdir)/'`soundlib/Load_mt2.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mt2.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mt2.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mt2.cpp' object='soundlib/libopenmpttest-Load_mt2.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mt2.o `test -f 'soundlib/Load_mt2.cpp' || echo '$(srcdir)/'`soundlib/Load_mt2.cpp soundlib/libopenmpttest-Load_mt2.obj: soundlib/Load_mt2.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mt2.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mt2.Tpo -c -o soundlib/libopenmpttest-Load_mt2.obj `if test -f 'soundlib/Load_mt2.cpp'; then $(CYGPATH_W) 'soundlib/Load_mt2.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mt2.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mt2.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mt2.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mt2.cpp' object='soundlib/libopenmpttest-Load_mt2.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mt2.obj `if test -f 'soundlib/Load_mt2.cpp'; then $(CYGPATH_W) 'soundlib/Load_mt2.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mt2.cpp'; fi` soundlib/libopenmpttest-Load_mtm.o: soundlib/Load_mtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mtm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mtm.Tpo -c -o soundlib/libopenmpttest-Load_mtm.o `test -f 'soundlib/Load_mtm.cpp' || echo '$(srcdir)/'`soundlib/Load_mtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mtm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mtm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mtm.cpp' object='soundlib/libopenmpttest-Load_mtm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mtm.o `test -f 'soundlib/Load_mtm.cpp' || echo '$(srcdir)/'`soundlib/Load_mtm.cpp soundlib/libopenmpttest-Load_mtm.obj: soundlib/Load_mtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mtm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mtm.Tpo -c -o soundlib/libopenmpttest-Load_mtm.obj `if test -f 'soundlib/Load_mtm.cpp'; then $(CYGPATH_W) 'soundlib/Load_mtm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mtm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mtm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mtm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mtm.cpp' object='soundlib/libopenmpttest-Load_mtm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mtm.obj `if test -f 'soundlib/Load_mtm.cpp'; then $(CYGPATH_W) 'soundlib/Load_mtm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mtm.cpp'; fi` soundlib/libopenmpttest-Load_mus_km.o: soundlib/Load_mus_km.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mus_km.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mus_km.Tpo -c -o soundlib/libopenmpttest-Load_mus_km.o `test -f 'soundlib/Load_mus_km.cpp' || echo '$(srcdir)/'`soundlib/Load_mus_km.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mus_km.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mus_km.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mus_km.cpp' object='soundlib/libopenmpttest-Load_mus_km.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mus_km.o `test -f 'soundlib/Load_mus_km.cpp' || echo '$(srcdir)/'`soundlib/Load_mus_km.cpp soundlib/libopenmpttest-Load_mus_km.obj: soundlib/Load_mus_km.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_mus_km.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_mus_km.Tpo -c -o soundlib/libopenmpttest-Load_mus_km.obj `if test -f 'soundlib/Load_mus_km.cpp'; then $(CYGPATH_W) 'soundlib/Load_mus_km.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mus_km.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_mus_km.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_mus_km.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_mus_km.cpp' object='soundlib/libopenmpttest-Load_mus_km.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_mus_km.obj `if test -f 'soundlib/Load_mus_km.cpp'; then $(CYGPATH_W) 'soundlib/Load_mus_km.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_mus_km.cpp'; fi` soundlib/libopenmpttest-Load_okt.o: soundlib/Load_okt.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_okt.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_okt.Tpo -c -o soundlib/libopenmpttest-Load_okt.o `test -f 'soundlib/Load_okt.cpp' || echo '$(srcdir)/'`soundlib/Load_okt.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_okt.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_okt.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_okt.cpp' object='soundlib/libopenmpttest-Load_okt.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_okt.o `test -f 'soundlib/Load_okt.cpp' || echo '$(srcdir)/'`soundlib/Load_okt.cpp soundlib/libopenmpttest-Load_okt.obj: soundlib/Load_okt.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_okt.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_okt.Tpo -c -o soundlib/libopenmpttest-Load_okt.obj `if test -f 'soundlib/Load_okt.cpp'; then $(CYGPATH_W) 'soundlib/Load_okt.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_okt.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_okt.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_okt.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_okt.cpp' object='soundlib/libopenmpttest-Load_okt.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_okt.obj `if test -f 'soundlib/Load_okt.cpp'; then $(CYGPATH_W) 'soundlib/Load_okt.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_okt.cpp'; fi` soundlib/libopenmpttest-Load_plm.o: soundlib/Load_plm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_plm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_plm.Tpo -c -o soundlib/libopenmpttest-Load_plm.o `test -f 'soundlib/Load_plm.cpp' || echo '$(srcdir)/'`soundlib/Load_plm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_plm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_plm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_plm.cpp' object='soundlib/libopenmpttest-Load_plm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_plm.o `test -f 'soundlib/Load_plm.cpp' || echo '$(srcdir)/'`soundlib/Load_plm.cpp soundlib/libopenmpttest-Load_plm.obj: soundlib/Load_plm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_plm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_plm.Tpo -c -o soundlib/libopenmpttest-Load_plm.obj `if test -f 'soundlib/Load_plm.cpp'; then $(CYGPATH_W) 'soundlib/Load_plm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_plm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_plm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_plm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_plm.cpp' object='soundlib/libopenmpttest-Load_plm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_plm.obj `if test -f 'soundlib/Load_plm.cpp'; then $(CYGPATH_W) 'soundlib/Load_plm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_plm.cpp'; fi` soundlib/libopenmpttest-Load_psm.o: soundlib/Load_psm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_psm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_psm.Tpo -c -o soundlib/libopenmpttest-Load_psm.o `test -f 'soundlib/Load_psm.cpp' || echo '$(srcdir)/'`soundlib/Load_psm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_psm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_psm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_psm.cpp' object='soundlib/libopenmpttest-Load_psm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_psm.o `test -f 'soundlib/Load_psm.cpp' || echo '$(srcdir)/'`soundlib/Load_psm.cpp soundlib/libopenmpttest-Load_psm.obj: soundlib/Load_psm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_psm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_psm.Tpo -c -o soundlib/libopenmpttest-Load_psm.obj `if test -f 'soundlib/Load_psm.cpp'; then $(CYGPATH_W) 'soundlib/Load_psm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_psm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_psm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_psm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_psm.cpp' object='soundlib/libopenmpttest-Load_psm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_psm.obj `if test -f 'soundlib/Load_psm.cpp'; then $(CYGPATH_W) 'soundlib/Load_psm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_psm.cpp'; fi` soundlib/libopenmpttest-Load_pt36.o: soundlib/Load_pt36.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_pt36.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_pt36.Tpo -c -o soundlib/libopenmpttest-Load_pt36.o `test -f 'soundlib/Load_pt36.cpp' || echo '$(srcdir)/'`soundlib/Load_pt36.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_pt36.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_pt36.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_pt36.cpp' object='soundlib/libopenmpttest-Load_pt36.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_pt36.o `test -f 'soundlib/Load_pt36.cpp' || echo '$(srcdir)/'`soundlib/Load_pt36.cpp soundlib/libopenmpttest-Load_pt36.obj: soundlib/Load_pt36.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_pt36.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_pt36.Tpo -c -o soundlib/libopenmpttest-Load_pt36.obj `if test -f 'soundlib/Load_pt36.cpp'; then $(CYGPATH_W) 'soundlib/Load_pt36.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_pt36.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_pt36.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_pt36.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_pt36.cpp' object='soundlib/libopenmpttest-Load_pt36.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_pt36.obj `if test -f 'soundlib/Load_pt36.cpp'; then $(CYGPATH_W) 'soundlib/Load_pt36.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_pt36.cpp'; fi` soundlib/libopenmpttest-Load_ptm.o: soundlib/Load_ptm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ptm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ptm.Tpo -c -o soundlib/libopenmpttest-Load_ptm.o `test -f 'soundlib/Load_ptm.cpp' || echo '$(srcdir)/'`soundlib/Load_ptm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ptm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ptm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ptm.cpp' object='soundlib/libopenmpttest-Load_ptm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ptm.o `test -f 'soundlib/Load_ptm.cpp' || echo '$(srcdir)/'`soundlib/Load_ptm.cpp soundlib/libopenmpttest-Load_ptm.obj: soundlib/Load_ptm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ptm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ptm.Tpo -c -o soundlib/libopenmpttest-Load_ptm.obj `if test -f 'soundlib/Load_ptm.cpp'; then $(CYGPATH_W) 'soundlib/Load_ptm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ptm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ptm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ptm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ptm.cpp' object='soundlib/libopenmpttest-Load_ptm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ptm.obj `if test -f 'soundlib/Load_ptm.cpp'; then $(CYGPATH_W) 'soundlib/Load_ptm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ptm.cpp'; fi` soundlib/libopenmpttest-Load_puma.o: soundlib/Load_puma.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_puma.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_puma.Tpo -c -o soundlib/libopenmpttest-Load_puma.o `test -f 'soundlib/Load_puma.cpp' || echo '$(srcdir)/'`soundlib/Load_puma.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_puma.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_puma.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_puma.cpp' object='soundlib/libopenmpttest-Load_puma.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_puma.o `test -f 'soundlib/Load_puma.cpp' || echo '$(srcdir)/'`soundlib/Load_puma.cpp soundlib/libopenmpttest-Load_puma.obj: soundlib/Load_puma.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_puma.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_puma.Tpo -c -o soundlib/libopenmpttest-Load_puma.obj `if test -f 'soundlib/Load_puma.cpp'; then $(CYGPATH_W) 'soundlib/Load_puma.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_puma.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_puma.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_puma.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_puma.cpp' object='soundlib/libopenmpttest-Load_puma.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_puma.obj `if test -f 'soundlib/Load_puma.cpp'; then $(CYGPATH_W) 'soundlib/Load_puma.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_puma.cpp'; fi` soundlib/libopenmpttest-Load_rtm.o: soundlib/Load_rtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_rtm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_rtm.Tpo -c -o soundlib/libopenmpttest-Load_rtm.o `test -f 'soundlib/Load_rtm.cpp' || echo '$(srcdir)/'`soundlib/Load_rtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_rtm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_rtm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_rtm.cpp' object='soundlib/libopenmpttest-Load_rtm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_rtm.o `test -f 'soundlib/Load_rtm.cpp' || echo '$(srcdir)/'`soundlib/Load_rtm.cpp soundlib/libopenmpttest-Load_rtm.obj: soundlib/Load_rtm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_rtm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_rtm.Tpo -c -o soundlib/libopenmpttest-Load_rtm.obj `if test -f 'soundlib/Load_rtm.cpp'; then $(CYGPATH_W) 'soundlib/Load_rtm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_rtm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_rtm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_rtm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_rtm.cpp' object='soundlib/libopenmpttest-Load_rtm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_rtm.obj `if test -f 'soundlib/Load_rtm.cpp'; then $(CYGPATH_W) 'soundlib/Load_rtm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_rtm.cpp'; fi` soundlib/libopenmpttest-Load_s3m.o: soundlib/Load_s3m.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_s3m.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_s3m.Tpo -c -o soundlib/libopenmpttest-Load_s3m.o `test -f 'soundlib/Load_s3m.cpp' || echo '$(srcdir)/'`soundlib/Load_s3m.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_s3m.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_s3m.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_s3m.cpp' object='soundlib/libopenmpttest-Load_s3m.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_s3m.o `test -f 'soundlib/Load_s3m.cpp' || echo '$(srcdir)/'`soundlib/Load_s3m.cpp soundlib/libopenmpttest-Load_s3m.obj: soundlib/Load_s3m.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_s3m.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_s3m.Tpo -c -o soundlib/libopenmpttest-Load_s3m.obj `if test -f 'soundlib/Load_s3m.cpp'; then $(CYGPATH_W) 'soundlib/Load_s3m.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_s3m.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_s3m.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_s3m.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_s3m.cpp' object='soundlib/libopenmpttest-Load_s3m.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_s3m.obj `if test -f 'soundlib/Load_s3m.cpp'; then $(CYGPATH_W) 'soundlib/Load_s3m.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_s3m.cpp'; fi` soundlib/libopenmpttest-Load_sfx.o: soundlib/Load_sfx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_sfx.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_sfx.Tpo -c -o soundlib/libopenmpttest-Load_sfx.o `test -f 'soundlib/Load_sfx.cpp' || echo '$(srcdir)/'`soundlib/Load_sfx.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_sfx.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_sfx.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_sfx.cpp' object='soundlib/libopenmpttest-Load_sfx.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_sfx.o `test -f 'soundlib/Load_sfx.cpp' || echo '$(srcdir)/'`soundlib/Load_sfx.cpp soundlib/libopenmpttest-Load_sfx.obj: soundlib/Load_sfx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_sfx.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_sfx.Tpo -c -o soundlib/libopenmpttest-Load_sfx.obj `if test -f 'soundlib/Load_sfx.cpp'; then $(CYGPATH_W) 'soundlib/Load_sfx.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_sfx.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_sfx.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_sfx.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_sfx.cpp' object='soundlib/libopenmpttest-Load_sfx.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_sfx.obj `if test -f 'soundlib/Load_sfx.cpp'; then $(CYGPATH_W) 'soundlib/Load_sfx.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_sfx.cpp'; fi` soundlib/libopenmpttest-Load_stk.o: soundlib/Load_stk.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_stk.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_stk.Tpo -c -o soundlib/libopenmpttest-Load_stk.o `test -f 'soundlib/Load_stk.cpp' || echo '$(srcdir)/'`soundlib/Load_stk.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_stk.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_stk.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_stk.cpp' object='soundlib/libopenmpttest-Load_stk.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_stk.o `test -f 'soundlib/Load_stk.cpp' || echo '$(srcdir)/'`soundlib/Load_stk.cpp soundlib/libopenmpttest-Load_stk.obj: soundlib/Load_stk.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_stk.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_stk.Tpo -c -o soundlib/libopenmpttest-Load_stk.obj `if test -f 'soundlib/Load_stk.cpp'; then $(CYGPATH_W) 'soundlib/Load_stk.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_stk.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_stk.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_stk.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_stk.cpp' object='soundlib/libopenmpttest-Load_stk.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_stk.obj `if test -f 'soundlib/Load_stk.cpp'; then $(CYGPATH_W) 'soundlib/Load_stk.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_stk.cpp'; fi` soundlib/libopenmpttest-Load_stm.o: soundlib/Load_stm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_stm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_stm.Tpo -c -o soundlib/libopenmpttest-Load_stm.o `test -f 'soundlib/Load_stm.cpp' || echo '$(srcdir)/'`soundlib/Load_stm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_stm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_stm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_stm.cpp' object='soundlib/libopenmpttest-Load_stm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_stm.o `test -f 'soundlib/Load_stm.cpp' || echo '$(srcdir)/'`soundlib/Load_stm.cpp soundlib/libopenmpttest-Load_stm.obj: soundlib/Load_stm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_stm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_stm.Tpo -c -o soundlib/libopenmpttest-Load_stm.obj `if test -f 'soundlib/Load_stm.cpp'; then $(CYGPATH_W) 'soundlib/Load_stm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_stm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_stm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_stm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_stm.cpp' object='soundlib/libopenmpttest-Load_stm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_stm.obj `if test -f 'soundlib/Load_stm.cpp'; then $(CYGPATH_W) 'soundlib/Load_stm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_stm.cpp'; fi` soundlib/libopenmpttest-Load_stp.o: soundlib/Load_stp.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_stp.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Tpo -c -o soundlib/libopenmpttest-Load_stp.o `test -f 'soundlib/Load_stp.cpp' || echo '$(srcdir)/'`soundlib/Load_stp.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_stp.cpp' object='soundlib/libopenmpttest-Load_stp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_stp.o `test -f 'soundlib/Load_stp.cpp' || echo '$(srcdir)/'`soundlib/Load_stp.cpp soundlib/libopenmpttest-Load_stp.obj: soundlib/Load_stp.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_stp.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Tpo -c -o soundlib/libopenmpttest-Load_stp.obj `if test -f 'soundlib/Load_stp.cpp'; then $(CYGPATH_W) 'soundlib/Load_stp.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_stp.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_stp.cpp' object='soundlib/libopenmpttest-Load_stp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_stp.obj `if test -f 'soundlib/Load_stp.cpp'; then $(CYGPATH_W) 'soundlib/Load_stp.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_stp.cpp'; fi` soundlib/libopenmpttest-Load_symmod.o: soundlib/Load_symmod.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_symmod.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_symmod.Tpo -c -o soundlib/libopenmpttest-Load_symmod.o `test -f 'soundlib/Load_symmod.cpp' || echo '$(srcdir)/'`soundlib/Load_symmod.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_symmod.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_symmod.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_symmod.cpp' object='soundlib/libopenmpttest-Load_symmod.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_symmod.o `test -f 'soundlib/Load_symmod.cpp' || echo '$(srcdir)/'`soundlib/Load_symmod.cpp soundlib/libopenmpttest-Load_symmod.obj: soundlib/Load_symmod.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_symmod.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_symmod.Tpo -c -o soundlib/libopenmpttest-Load_symmod.obj `if test -f 'soundlib/Load_symmod.cpp'; then $(CYGPATH_W) 'soundlib/Load_symmod.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_symmod.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_symmod.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_symmod.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_symmod.cpp' object='soundlib/libopenmpttest-Load_symmod.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_symmod.obj `if test -f 'soundlib/Load_symmod.cpp'; then $(CYGPATH_W) 'soundlib/Load_symmod.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_symmod.cpp'; fi` soundlib/libopenmpttest-Load_tcb.o: soundlib/Load_tcb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_tcb.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_tcb.Tpo -c -o soundlib/libopenmpttest-Load_tcb.o `test -f 'soundlib/Load_tcb.cpp' || echo '$(srcdir)/'`soundlib/Load_tcb.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_tcb.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_tcb.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_tcb.cpp' object='soundlib/libopenmpttest-Load_tcb.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_tcb.o `test -f 'soundlib/Load_tcb.cpp' || echo '$(srcdir)/'`soundlib/Load_tcb.cpp soundlib/libopenmpttest-Load_tcb.obj: soundlib/Load_tcb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_tcb.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_tcb.Tpo -c -o soundlib/libopenmpttest-Load_tcb.obj `if test -f 'soundlib/Load_tcb.cpp'; then $(CYGPATH_W) 'soundlib/Load_tcb.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_tcb.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_tcb.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_tcb.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_tcb.cpp' object='soundlib/libopenmpttest-Load_tcb.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_tcb.obj `if test -f 'soundlib/Load_tcb.cpp'; then $(CYGPATH_W) 'soundlib/Load_tcb.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_tcb.cpp'; fi` soundlib/libopenmpttest-Load_uax.o: soundlib/Load_uax.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_uax.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Tpo -c -o soundlib/libopenmpttest-Load_uax.o `test -f 'soundlib/Load_uax.cpp' || echo '$(srcdir)/'`soundlib/Load_uax.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_uax.cpp' object='soundlib/libopenmpttest-Load_uax.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_uax.o `test -f 'soundlib/Load_uax.cpp' || echo '$(srcdir)/'`soundlib/Load_uax.cpp soundlib/libopenmpttest-Load_uax.obj: soundlib/Load_uax.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_uax.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Tpo -c -o soundlib/libopenmpttest-Load_uax.obj `if test -f 'soundlib/Load_uax.cpp'; then $(CYGPATH_W) 'soundlib/Load_uax.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_uax.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_uax.cpp' object='soundlib/libopenmpttest-Load_uax.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_uax.obj `if test -f 'soundlib/Load_uax.cpp'; then $(CYGPATH_W) 'soundlib/Load_uax.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_uax.cpp'; fi` soundlib/libopenmpttest-Load_ult.o: soundlib/Load_ult.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ult.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Tpo -c -o soundlib/libopenmpttest-Load_ult.o `test -f 'soundlib/Load_ult.cpp' || echo '$(srcdir)/'`soundlib/Load_ult.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ult.cpp' object='soundlib/libopenmpttest-Load_ult.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ult.o `test -f 'soundlib/Load_ult.cpp' || echo '$(srcdir)/'`soundlib/Load_ult.cpp soundlib/libopenmpttest-Load_ult.obj: soundlib/Load_ult.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ult.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Tpo -c -o soundlib/libopenmpttest-Load_ult.obj `if test -f 'soundlib/Load_ult.cpp'; then $(CYGPATH_W) 'soundlib/Load_ult.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ult.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_ult.cpp' object='soundlib/libopenmpttest-Load_ult.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ult.obj `if test -f 'soundlib/Load_ult.cpp'; then $(CYGPATH_W) 'soundlib/Load_ult.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ult.cpp'; fi` soundlib/libopenmpttest-Load_unic.o: soundlib/Load_unic.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_unic.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_unic.Tpo -c -o soundlib/libopenmpttest-Load_unic.o `test -f 'soundlib/Load_unic.cpp' || echo '$(srcdir)/'`soundlib/Load_unic.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_unic.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_unic.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_unic.cpp' object='soundlib/libopenmpttest-Load_unic.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_unic.o `test -f 'soundlib/Load_unic.cpp' || echo '$(srcdir)/'`soundlib/Load_unic.cpp soundlib/libopenmpttest-Load_unic.obj: soundlib/Load_unic.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_unic.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_unic.Tpo -c -o soundlib/libopenmpttest-Load_unic.obj `if test -f 'soundlib/Load_unic.cpp'; then $(CYGPATH_W) 'soundlib/Load_unic.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_unic.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_unic.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_unic.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_unic.cpp' object='soundlib/libopenmpttest-Load_unic.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_unic.obj `if test -f 'soundlib/Load_unic.cpp'; then $(CYGPATH_W) 'soundlib/Load_unic.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_unic.cpp'; fi` soundlib/libopenmpttest-Load_wav.o: soundlib/Load_wav.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_wav.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Tpo -c -o soundlib/libopenmpttest-Load_wav.o `test -f 'soundlib/Load_wav.cpp' || echo '$(srcdir)/'`soundlib/Load_wav.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_wav.cpp' object='soundlib/libopenmpttest-Load_wav.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_wav.o `test -f 'soundlib/Load_wav.cpp' || echo '$(srcdir)/'`soundlib/Load_wav.cpp soundlib/libopenmpttest-Load_wav.obj: soundlib/Load_wav.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_wav.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Tpo -c -o soundlib/libopenmpttest-Load_wav.obj `if test -f 'soundlib/Load_wav.cpp'; then $(CYGPATH_W) 'soundlib/Load_wav.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_wav.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_wav.cpp' object='soundlib/libopenmpttest-Load_wav.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_wav.obj `if test -f 'soundlib/Load_wav.cpp'; then $(CYGPATH_W) 'soundlib/Load_wav.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_wav.cpp'; fi` soundlib/libopenmpttest-Load_xm.o: soundlib/Load_xm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_xm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_xm.Tpo -c -o soundlib/libopenmpttest-Load_xm.o `test -f 'soundlib/Load_xm.cpp' || echo '$(srcdir)/'`soundlib/Load_xm.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_xm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_xm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_xm.cpp' object='soundlib/libopenmpttest-Load_xm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_xm.o `test -f 'soundlib/Load_xm.cpp' || echo '$(srcdir)/'`soundlib/Load_xm.cpp soundlib/libopenmpttest-Load_xm.obj: soundlib/Load_xm.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_xm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_xm.Tpo -c -o soundlib/libopenmpttest-Load_xm.obj `if test -f 'soundlib/Load_xm.cpp'; then $(CYGPATH_W) 'soundlib/Load_xm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_xm.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_xm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_xm.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_xm.cpp' object='soundlib/libopenmpttest-Load_xm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_xm.obj `if test -f 'soundlib/Load_xm.cpp'; then $(CYGPATH_W) 'soundlib/Load_xm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_xm.cpp'; fi` soundlib/libopenmpttest-Load_xmf.o: soundlib/Load_xmf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_xmf.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_xmf.Tpo -c -o soundlib/libopenmpttest-Load_xmf.o `test -f 'soundlib/Load_xmf.cpp' || echo '$(srcdir)/'`soundlib/Load_xmf.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_xmf.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_xmf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_xmf.cpp' object='soundlib/libopenmpttest-Load_xmf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_xmf.o `test -f 'soundlib/Load_xmf.cpp' || echo '$(srcdir)/'`soundlib/Load_xmf.cpp soundlib/libopenmpttest-Load_xmf.obj: soundlib/Load_xmf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_xmf.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_xmf.Tpo -c -o soundlib/libopenmpttest-Load_xmf.obj `if test -f 'soundlib/Load_xmf.cpp'; then $(CYGPATH_W) 'soundlib/Load_xmf.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_xmf.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_xmf.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_xmf.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Load_xmf.cpp' object='soundlib/libopenmpttest-Load_xmf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_xmf.obj `if test -f 'soundlib/Load_xmf.cpp'; then $(CYGPATH_W) 'soundlib/Load_xmf.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_xmf.cpp'; fi` soundlib/libopenmpttest-Message.o: soundlib/Message.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Message.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Message.Tpo -c -o soundlib/libopenmpttest-Message.o `test -f 'soundlib/Message.cpp' || echo '$(srcdir)/'`soundlib/Message.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Message.Tpo soundlib/$(DEPDIR)/libopenmpttest-Message.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Message.cpp' object='soundlib/libopenmpttest-Message.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Message.o `test -f 'soundlib/Message.cpp' || echo '$(srcdir)/'`soundlib/Message.cpp soundlib/libopenmpttest-Message.obj: soundlib/Message.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Message.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Message.Tpo -c -o soundlib/libopenmpttest-Message.obj `if test -f 'soundlib/Message.cpp'; then $(CYGPATH_W) 'soundlib/Message.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Message.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Message.Tpo soundlib/$(DEPDIR)/libopenmpttest-Message.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Message.cpp' object='soundlib/libopenmpttest-Message.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Message.obj `if test -f 'soundlib/Message.cpp'; then $(CYGPATH_W) 'soundlib/Message.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Message.cpp'; fi` soundlib/libopenmpttest-MIDIEvents.o: soundlib/MIDIEvents.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MIDIEvents.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MIDIEvents.Tpo -c -o soundlib/libopenmpttest-MIDIEvents.o `test -f 'soundlib/MIDIEvents.cpp' || echo '$(srcdir)/'`soundlib/MIDIEvents.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MIDIEvents.Tpo soundlib/$(DEPDIR)/libopenmpttest-MIDIEvents.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MIDIEvents.cpp' object='soundlib/libopenmpttest-MIDIEvents.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MIDIEvents.o `test -f 'soundlib/MIDIEvents.cpp' || echo '$(srcdir)/'`soundlib/MIDIEvents.cpp soundlib/libopenmpttest-MIDIEvents.obj: soundlib/MIDIEvents.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MIDIEvents.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MIDIEvents.Tpo -c -o soundlib/libopenmpttest-MIDIEvents.obj `if test -f 'soundlib/MIDIEvents.cpp'; then $(CYGPATH_W) 'soundlib/MIDIEvents.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MIDIEvents.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MIDIEvents.Tpo soundlib/$(DEPDIR)/libopenmpttest-MIDIEvents.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MIDIEvents.cpp' object='soundlib/libopenmpttest-MIDIEvents.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MIDIEvents.obj `if test -f 'soundlib/MIDIEvents.cpp'; then $(CYGPATH_W) 'soundlib/MIDIEvents.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MIDIEvents.cpp'; fi` soundlib/libopenmpttest-MIDIMacroParser.o: soundlib/MIDIMacroParser.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MIDIMacroParser.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MIDIMacroParser.Tpo -c -o soundlib/libopenmpttest-MIDIMacroParser.o `test -f 'soundlib/MIDIMacroParser.cpp' || echo '$(srcdir)/'`soundlib/MIDIMacroParser.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MIDIMacroParser.Tpo soundlib/$(DEPDIR)/libopenmpttest-MIDIMacroParser.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MIDIMacroParser.cpp' object='soundlib/libopenmpttest-MIDIMacroParser.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MIDIMacroParser.o `test -f 'soundlib/MIDIMacroParser.cpp' || echo '$(srcdir)/'`soundlib/MIDIMacroParser.cpp soundlib/libopenmpttest-MIDIMacroParser.obj: soundlib/MIDIMacroParser.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MIDIMacroParser.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MIDIMacroParser.Tpo -c -o soundlib/libopenmpttest-MIDIMacroParser.obj `if test -f 'soundlib/MIDIMacroParser.cpp'; then $(CYGPATH_W) 'soundlib/MIDIMacroParser.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MIDIMacroParser.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MIDIMacroParser.Tpo soundlib/$(DEPDIR)/libopenmpttest-MIDIMacroParser.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MIDIMacroParser.cpp' object='soundlib/libopenmpttest-MIDIMacroParser.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MIDIMacroParser.obj `if test -f 'soundlib/MIDIMacroParser.cpp'; then $(CYGPATH_W) 'soundlib/MIDIMacroParser.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MIDIMacroParser.cpp'; fi` soundlib/libopenmpttest-MIDIMacros.o: soundlib/MIDIMacros.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MIDIMacros.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MIDIMacros.Tpo -c -o soundlib/libopenmpttest-MIDIMacros.o `test -f 'soundlib/MIDIMacros.cpp' || echo '$(srcdir)/'`soundlib/MIDIMacros.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MIDIMacros.Tpo soundlib/$(DEPDIR)/libopenmpttest-MIDIMacros.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MIDIMacros.cpp' object='soundlib/libopenmpttest-MIDIMacros.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MIDIMacros.o `test -f 'soundlib/MIDIMacros.cpp' || echo '$(srcdir)/'`soundlib/MIDIMacros.cpp soundlib/libopenmpttest-MIDIMacros.obj: soundlib/MIDIMacros.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MIDIMacros.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MIDIMacros.Tpo -c -o soundlib/libopenmpttest-MIDIMacros.obj `if test -f 'soundlib/MIDIMacros.cpp'; then $(CYGPATH_W) 'soundlib/MIDIMacros.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MIDIMacros.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MIDIMacros.Tpo soundlib/$(DEPDIR)/libopenmpttest-MIDIMacros.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MIDIMacros.cpp' object='soundlib/libopenmpttest-MIDIMacros.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MIDIMacros.obj `if test -f 'soundlib/MIDIMacros.cpp'; then $(CYGPATH_W) 'soundlib/MIDIMacros.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MIDIMacros.cpp'; fi` soundlib/libopenmpttest-MixerLoops.o: soundlib/MixerLoops.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MixerLoops.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MixerLoops.Tpo -c -o soundlib/libopenmpttest-MixerLoops.o `test -f 'soundlib/MixerLoops.cpp' || echo '$(srcdir)/'`soundlib/MixerLoops.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MixerLoops.Tpo soundlib/$(DEPDIR)/libopenmpttest-MixerLoops.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MixerLoops.cpp' object='soundlib/libopenmpttest-MixerLoops.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MixerLoops.o `test -f 'soundlib/MixerLoops.cpp' || echo '$(srcdir)/'`soundlib/MixerLoops.cpp soundlib/libopenmpttest-MixerLoops.obj: soundlib/MixerLoops.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MixerLoops.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MixerLoops.Tpo -c -o soundlib/libopenmpttest-MixerLoops.obj `if test -f 'soundlib/MixerLoops.cpp'; then $(CYGPATH_W) 'soundlib/MixerLoops.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MixerLoops.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MixerLoops.Tpo soundlib/$(DEPDIR)/libopenmpttest-MixerLoops.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MixerLoops.cpp' object='soundlib/libopenmpttest-MixerLoops.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MixerLoops.obj `if test -f 'soundlib/MixerLoops.cpp'; then $(CYGPATH_W) 'soundlib/MixerLoops.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MixerLoops.cpp'; fi` soundlib/libopenmpttest-MixerSettings.o: soundlib/MixerSettings.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MixerSettings.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MixerSettings.Tpo -c -o soundlib/libopenmpttest-MixerSettings.o `test -f 'soundlib/MixerSettings.cpp' || echo '$(srcdir)/'`soundlib/MixerSettings.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MixerSettings.Tpo soundlib/$(DEPDIR)/libopenmpttest-MixerSettings.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MixerSettings.cpp' object='soundlib/libopenmpttest-MixerSettings.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MixerSettings.o `test -f 'soundlib/MixerSettings.cpp' || echo '$(srcdir)/'`soundlib/MixerSettings.cpp soundlib/libopenmpttest-MixerSettings.obj: soundlib/MixerSettings.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MixerSettings.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MixerSettings.Tpo -c -o soundlib/libopenmpttest-MixerSettings.obj `if test -f 'soundlib/MixerSettings.cpp'; then $(CYGPATH_W) 'soundlib/MixerSettings.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MixerSettings.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MixerSettings.Tpo soundlib/$(DEPDIR)/libopenmpttest-MixerSettings.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MixerSettings.cpp' object='soundlib/libopenmpttest-MixerSettings.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MixerSettings.obj `if test -f 'soundlib/MixerSettings.cpp'; then $(CYGPATH_W) 'soundlib/MixerSettings.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MixerSettings.cpp'; fi` soundlib/libopenmpttest-MixFuncTable.o: soundlib/MixFuncTable.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MixFuncTable.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MixFuncTable.Tpo -c -o soundlib/libopenmpttest-MixFuncTable.o `test -f 'soundlib/MixFuncTable.cpp' || echo '$(srcdir)/'`soundlib/MixFuncTable.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MixFuncTable.Tpo soundlib/$(DEPDIR)/libopenmpttest-MixFuncTable.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MixFuncTable.cpp' object='soundlib/libopenmpttest-MixFuncTable.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MixFuncTable.o `test -f 'soundlib/MixFuncTable.cpp' || echo '$(srcdir)/'`soundlib/MixFuncTable.cpp soundlib/libopenmpttest-MixFuncTable.obj: soundlib/MixFuncTable.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MixFuncTable.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MixFuncTable.Tpo -c -o soundlib/libopenmpttest-MixFuncTable.obj `if test -f 'soundlib/MixFuncTable.cpp'; then $(CYGPATH_W) 'soundlib/MixFuncTable.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MixFuncTable.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MixFuncTable.Tpo soundlib/$(DEPDIR)/libopenmpttest-MixFuncTable.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MixFuncTable.cpp' object='soundlib/libopenmpttest-MixFuncTable.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MixFuncTable.obj `if test -f 'soundlib/MixFuncTable.cpp'; then $(CYGPATH_W) 'soundlib/MixFuncTable.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MixFuncTable.cpp'; fi` soundlib/libopenmpttest-ModChannel.o: soundlib/ModChannel.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ModChannel.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Tpo -c -o soundlib/libopenmpttest-ModChannel.o `test -f 'soundlib/ModChannel.cpp' || echo '$(srcdir)/'`soundlib/ModChannel.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Tpo soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModChannel.cpp' object='soundlib/libopenmpttest-ModChannel.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ModChannel.o `test -f 'soundlib/ModChannel.cpp' || echo '$(srcdir)/'`soundlib/ModChannel.cpp soundlib/libopenmpttest-ModChannel.obj: soundlib/ModChannel.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ModChannel.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Tpo -c -o soundlib/libopenmpttest-ModChannel.obj `if test -f 'soundlib/ModChannel.cpp'; then $(CYGPATH_W) 'soundlib/ModChannel.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ModChannel.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Tpo soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModChannel.cpp' object='soundlib/libopenmpttest-ModChannel.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ModChannel.obj `if test -f 'soundlib/ModChannel.cpp'; then $(CYGPATH_W) 'soundlib/ModChannel.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ModChannel.cpp'; fi` soundlib/libopenmpttest-modcommand.o: soundlib/modcommand.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-modcommand.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-modcommand.Tpo -c -o soundlib/libopenmpttest-modcommand.o `test -f 'soundlib/modcommand.cpp' || echo '$(srcdir)/'`soundlib/modcommand.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-modcommand.Tpo soundlib/$(DEPDIR)/libopenmpttest-modcommand.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/modcommand.cpp' object='soundlib/libopenmpttest-modcommand.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-modcommand.o `test -f 'soundlib/modcommand.cpp' || echo '$(srcdir)/'`soundlib/modcommand.cpp soundlib/libopenmpttest-modcommand.obj: soundlib/modcommand.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-modcommand.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-modcommand.Tpo -c -o soundlib/libopenmpttest-modcommand.obj `if test -f 'soundlib/modcommand.cpp'; then $(CYGPATH_W) 'soundlib/modcommand.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/modcommand.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-modcommand.Tpo soundlib/$(DEPDIR)/libopenmpttest-modcommand.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/modcommand.cpp' object='soundlib/libopenmpttest-modcommand.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-modcommand.obj `if test -f 'soundlib/modcommand.cpp'; then $(CYGPATH_W) 'soundlib/modcommand.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/modcommand.cpp'; fi` soundlib/libopenmpttest-ModInstrument.o: soundlib/ModInstrument.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ModInstrument.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ModInstrument.Tpo -c -o soundlib/libopenmpttest-ModInstrument.o `test -f 'soundlib/ModInstrument.cpp' || echo '$(srcdir)/'`soundlib/ModInstrument.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ModInstrument.Tpo soundlib/$(DEPDIR)/libopenmpttest-ModInstrument.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModInstrument.cpp' object='soundlib/libopenmpttest-ModInstrument.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ModInstrument.o `test -f 'soundlib/ModInstrument.cpp' || echo '$(srcdir)/'`soundlib/ModInstrument.cpp soundlib/libopenmpttest-ModInstrument.obj: soundlib/ModInstrument.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ModInstrument.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ModInstrument.Tpo -c -o soundlib/libopenmpttest-ModInstrument.obj `if test -f 'soundlib/ModInstrument.cpp'; then $(CYGPATH_W) 'soundlib/ModInstrument.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ModInstrument.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ModInstrument.Tpo soundlib/$(DEPDIR)/libopenmpttest-ModInstrument.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModInstrument.cpp' object='soundlib/libopenmpttest-ModInstrument.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ModInstrument.obj `if test -f 'soundlib/ModInstrument.cpp'; then $(CYGPATH_W) 'soundlib/ModInstrument.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ModInstrument.cpp'; fi` soundlib/libopenmpttest-ModSample.o: soundlib/ModSample.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ModSample.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ModSample.Tpo -c -o soundlib/libopenmpttest-ModSample.o `test -f 'soundlib/ModSample.cpp' || echo '$(srcdir)/'`soundlib/ModSample.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ModSample.Tpo soundlib/$(DEPDIR)/libopenmpttest-ModSample.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModSample.cpp' object='soundlib/libopenmpttest-ModSample.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ModSample.o `test -f 'soundlib/ModSample.cpp' || echo '$(srcdir)/'`soundlib/ModSample.cpp soundlib/libopenmpttest-ModSample.obj: soundlib/ModSample.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ModSample.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ModSample.Tpo -c -o soundlib/libopenmpttest-ModSample.obj `if test -f 'soundlib/ModSample.cpp'; then $(CYGPATH_W) 'soundlib/ModSample.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ModSample.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ModSample.Tpo soundlib/$(DEPDIR)/libopenmpttest-ModSample.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModSample.cpp' object='soundlib/libopenmpttest-ModSample.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ModSample.obj `if test -f 'soundlib/ModSample.cpp'; then $(CYGPATH_W) 'soundlib/ModSample.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ModSample.cpp'; fi` soundlib/libopenmpttest-ModSequence.o: soundlib/ModSequence.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ModSequence.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ModSequence.Tpo -c -o soundlib/libopenmpttest-ModSequence.o `test -f 'soundlib/ModSequence.cpp' || echo '$(srcdir)/'`soundlib/ModSequence.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ModSequence.Tpo soundlib/$(DEPDIR)/libopenmpttest-ModSequence.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModSequence.cpp' object='soundlib/libopenmpttest-ModSequence.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ModSequence.o `test -f 'soundlib/ModSequence.cpp' || echo '$(srcdir)/'`soundlib/ModSequence.cpp soundlib/libopenmpttest-ModSequence.obj: soundlib/ModSequence.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ModSequence.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ModSequence.Tpo -c -o soundlib/libopenmpttest-ModSequence.obj `if test -f 'soundlib/ModSequence.cpp'; then $(CYGPATH_W) 'soundlib/ModSequence.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ModSequence.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ModSequence.Tpo soundlib/$(DEPDIR)/libopenmpttest-ModSequence.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/ModSequence.cpp' object='soundlib/libopenmpttest-ModSequence.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ModSequence.obj `if test -f 'soundlib/ModSequence.cpp'; then $(CYGPATH_W) 'soundlib/ModSequence.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ModSequence.cpp'; fi` soundlib/libopenmpttest-modsmp_ctrl.o: soundlib/modsmp_ctrl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-modsmp_ctrl.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-modsmp_ctrl.Tpo -c -o soundlib/libopenmpttest-modsmp_ctrl.o `test -f 'soundlib/modsmp_ctrl.cpp' || echo '$(srcdir)/'`soundlib/modsmp_ctrl.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-modsmp_ctrl.Tpo soundlib/$(DEPDIR)/libopenmpttest-modsmp_ctrl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/modsmp_ctrl.cpp' object='soundlib/libopenmpttest-modsmp_ctrl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-modsmp_ctrl.o `test -f 'soundlib/modsmp_ctrl.cpp' || echo '$(srcdir)/'`soundlib/modsmp_ctrl.cpp soundlib/libopenmpttest-modsmp_ctrl.obj: soundlib/modsmp_ctrl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-modsmp_ctrl.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-modsmp_ctrl.Tpo -c -o soundlib/libopenmpttest-modsmp_ctrl.obj `if test -f 'soundlib/modsmp_ctrl.cpp'; then $(CYGPATH_W) 'soundlib/modsmp_ctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/modsmp_ctrl.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-modsmp_ctrl.Tpo soundlib/$(DEPDIR)/libopenmpttest-modsmp_ctrl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/modsmp_ctrl.cpp' object='soundlib/libopenmpttest-modsmp_ctrl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-modsmp_ctrl.obj `if test -f 'soundlib/modsmp_ctrl.cpp'; then $(CYGPATH_W) 'soundlib/modsmp_ctrl.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/modsmp_ctrl.cpp'; fi` soundlib/libopenmpttest-mod_specifications.o: soundlib/mod_specifications.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-mod_specifications.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-mod_specifications.Tpo -c -o soundlib/libopenmpttest-mod_specifications.o `test -f 'soundlib/mod_specifications.cpp' || echo '$(srcdir)/'`soundlib/mod_specifications.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-mod_specifications.Tpo soundlib/$(DEPDIR)/libopenmpttest-mod_specifications.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/mod_specifications.cpp' object='soundlib/libopenmpttest-mod_specifications.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-mod_specifications.o `test -f 'soundlib/mod_specifications.cpp' || echo '$(srcdir)/'`soundlib/mod_specifications.cpp soundlib/libopenmpttest-mod_specifications.obj: soundlib/mod_specifications.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-mod_specifications.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-mod_specifications.Tpo -c -o soundlib/libopenmpttest-mod_specifications.obj `if test -f 'soundlib/mod_specifications.cpp'; then $(CYGPATH_W) 'soundlib/mod_specifications.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/mod_specifications.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-mod_specifications.Tpo soundlib/$(DEPDIR)/libopenmpttest-mod_specifications.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/mod_specifications.cpp' object='soundlib/libopenmpttest-mod_specifications.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-mod_specifications.obj `if test -f 'soundlib/mod_specifications.cpp'; then $(CYGPATH_W) 'soundlib/mod_specifications.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/mod_specifications.cpp'; fi` soundlib/libopenmpttest-MODTools.o: soundlib/MODTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MODTools.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MODTools.Tpo -c -o soundlib/libopenmpttest-MODTools.o `test -f 'soundlib/MODTools.cpp' || echo '$(srcdir)/'`soundlib/MODTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MODTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-MODTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MODTools.cpp' object='soundlib/libopenmpttest-MODTools.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MODTools.o `test -f 'soundlib/MODTools.cpp' || echo '$(srcdir)/'`soundlib/MODTools.cpp soundlib/libopenmpttest-MODTools.obj: soundlib/MODTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MODTools.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MODTools.Tpo -c -o soundlib/libopenmpttest-MODTools.obj `if test -f 'soundlib/MODTools.cpp'; then $(CYGPATH_W) 'soundlib/MODTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MODTools.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MODTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-MODTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MODTools.cpp' object='soundlib/libopenmpttest-MODTools.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MODTools.obj `if test -f 'soundlib/MODTools.cpp'; then $(CYGPATH_W) 'soundlib/MODTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MODTools.cpp'; fi` soundlib/libopenmpttest-MPEGFrame.o: soundlib/MPEGFrame.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MPEGFrame.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MPEGFrame.Tpo -c -o soundlib/libopenmpttest-MPEGFrame.o `test -f 'soundlib/MPEGFrame.cpp' || echo '$(srcdir)/'`soundlib/MPEGFrame.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MPEGFrame.Tpo soundlib/$(DEPDIR)/libopenmpttest-MPEGFrame.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MPEGFrame.cpp' object='soundlib/libopenmpttest-MPEGFrame.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MPEGFrame.o `test -f 'soundlib/MPEGFrame.cpp' || echo '$(srcdir)/'`soundlib/MPEGFrame.cpp soundlib/libopenmpttest-MPEGFrame.obj: soundlib/MPEGFrame.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-MPEGFrame.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-MPEGFrame.Tpo -c -o soundlib/libopenmpttest-MPEGFrame.obj `if test -f 'soundlib/MPEGFrame.cpp'; then $(CYGPATH_W) 'soundlib/MPEGFrame.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MPEGFrame.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-MPEGFrame.Tpo soundlib/$(DEPDIR)/libopenmpttest-MPEGFrame.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/MPEGFrame.cpp' object='soundlib/libopenmpttest-MPEGFrame.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MPEGFrame.obj `if test -f 'soundlib/MPEGFrame.cpp'; then $(CYGPATH_W) 'soundlib/MPEGFrame.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MPEGFrame.cpp'; fi` soundlib/libopenmpttest-OggStream.o: soundlib/OggStream.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-OggStream.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-OggStream.Tpo -c -o soundlib/libopenmpttest-OggStream.o `test -f 'soundlib/OggStream.cpp' || echo '$(srcdir)/'`soundlib/OggStream.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-OggStream.Tpo soundlib/$(DEPDIR)/libopenmpttest-OggStream.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/OggStream.cpp' object='soundlib/libopenmpttest-OggStream.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-OggStream.o `test -f 'soundlib/OggStream.cpp' || echo '$(srcdir)/'`soundlib/OggStream.cpp soundlib/libopenmpttest-OggStream.obj: soundlib/OggStream.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-OggStream.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-OggStream.Tpo -c -o soundlib/libopenmpttest-OggStream.obj `if test -f 'soundlib/OggStream.cpp'; then $(CYGPATH_W) 'soundlib/OggStream.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/OggStream.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-OggStream.Tpo soundlib/$(DEPDIR)/libopenmpttest-OggStream.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/OggStream.cpp' object='soundlib/libopenmpttest-OggStream.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-OggStream.obj `if test -f 'soundlib/OggStream.cpp'; then $(CYGPATH_W) 'soundlib/OggStream.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/OggStream.cpp'; fi` soundlib/libopenmpttest-OPL.o: soundlib/OPL.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-OPL.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-OPL.Tpo -c -o soundlib/libopenmpttest-OPL.o `test -f 'soundlib/OPL.cpp' || echo '$(srcdir)/'`soundlib/OPL.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-OPL.Tpo soundlib/$(DEPDIR)/libopenmpttest-OPL.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/OPL.cpp' object='soundlib/libopenmpttest-OPL.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-OPL.o `test -f 'soundlib/OPL.cpp' || echo '$(srcdir)/'`soundlib/OPL.cpp soundlib/libopenmpttest-OPL.obj: soundlib/OPL.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-OPL.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-OPL.Tpo -c -o soundlib/libopenmpttest-OPL.obj `if test -f 'soundlib/OPL.cpp'; then $(CYGPATH_W) 'soundlib/OPL.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/OPL.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-OPL.Tpo soundlib/$(DEPDIR)/libopenmpttest-OPL.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/OPL.cpp' object='soundlib/libopenmpttest-OPL.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-OPL.obj `if test -f 'soundlib/OPL.cpp'; then $(CYGPATH_W) 'soundlib/OPL.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/OPL.cpp'; fi` soundlib/libopenmpttest-Paula.o: soundlib/Paula.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Paula.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Paula.Tpo -c -o soundlib/libopenmpttest-Paula.o `test -f 'soundlib/Paula.cpp' || echo '$(srcdir)/'`soundlib/Paula.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Paula.Tpo soundlib/$(DEPDIR)/libopenmpttest-Paula.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Paula.cpp' object='soundlib/libopenmpttest-Paula.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Paula.o `test -f 'soundlib/Paula.cpp' || echo '$(srcdir)/'`soundlib/Paula.cpp soundlib/libopenmpttest-Paula.obj: soundlib/Paula.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Paula.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Paula.Tpo -c -o soundlib/libopenmpttest-Paula.obj `if test -f 'soundlib/Paula.cpp'; then $(CYGPATH_W) 'soundlib/Paula.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Paula.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Paula.Tpo soundlib/$(DEPDIR)/libopenmpttest-Paula.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Paula.cpp' object='soundlib/libopenmpttest-Paula.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Paula.obj `if test -f 'soundlib/Paula.cpp'; then $(CYGPATH_W) 'soundlib/Paula.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Paula.cpp'; fi` soundlib/libopenmpttest-patternContainer.o: soundlib/patternContainer.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-patternContainer.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Tpo -c -o soundlib/libopenmpttest-patternContainer.o `test -f 'soundlib/patternContainer.cpp' || echo '$(srcdir)/'`soundlib/patternContainer.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Tpo soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/patternContainer.cpp' object='soundlib/libopenmpttest-patternContainer.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-patternContainer.o `test -f 'soundlib/patternContainer.cpp' || echo '$(srcdir)/'`soundlib/patternContainer.cpp soundlib/libopenmpttest-patternContainer.obj: soundlib/patternContainer.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-patternContainer.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Tpo -c -o soundlib/libopenmpttest-patternContainer.obj `if test -f 'soundlib/patternContainer.cpp'; then $(CYGPATH_W) 'soundlib/patternContainer.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/patternContainer.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Tpo soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/patternContainer.cpp' object='soundlib/libopenmpttest-patternContainer.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-patternContainer.obj `if test -f 'soundlib/patternContainer.cpp'; then $(CYGPATH_W) 'soundlib/patternContainer.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/patternContainer.cpp'; fi` soundlib/libopenmpttest-pattern.o: soundlib/pattern.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-pattern.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-pattern.Tpo -c -o soundlib/libopenmpttest-pattern.o `test -f 'soundlib/pattern.cpp' || echo '$(srcdir)/'`soundlib/pattern.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-pattern.Tpo soundlib/$(DEPDIR)/libopenmpttest-pattern.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/pattern.cpp' object='soundlib/libopenmpttest-pattern.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-pattern.o `test -f 'soundlib/pattern.cpp' || echo '$(srcdir)/'`soundlib/pattern.cpp soundlib/libopenmpttest-pattern.obj: soundlib/pattern.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-pattern.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-pattern.Tpo -c -o soundlib/libopenmpttest-pattern.obj `if test -f 'soundlib/pattern.cpp'; then $(CYGPATH_W) 'soundlib/pattern.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/pattern.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-pattern.Tpo soundlib/$(DEPDIR)/libopenmpttest-pattern.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/pattern.cpp' object='soundlib/libopenmpttest-pattern.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-pattern.obj `if test -f 'soundlib/pattern.cpp'; then $(CYGPATH_W) 'soundlib/pattern.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/pattern.cpp'; fi` soundlib/libopenmpttest-PlaybackTest.o: soundlib/PlaybackTest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-PlaybackTest.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-PlaybackTest.Tpo -c -o soundlib/libopenmpttest-PlaybackTest.o `test -f 'soundlib/PlaybackTest.cpp' || echo '$(srcdir)/'`soundlib/PlaybackTest.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-PlaybackTest.Tpo soundlib/$(DEPDIR)/libopenmpttest-PlaybackTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/PlaybackTest.cpp' object='soundlib/libopenmpttest-PlaybackTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-PlaybackTest.o `test -f 'soundlib/PlaybackTest.cpp' || echo '$(srcdir)/'`soundlib/PlaybackTest.cpp soundlib/libopenmpttest-PlaybackTest.obj: soundlib/PlaybackTest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-PlaybackTest.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-PlaybackTest.Tpo -c -o soundlib/libopenmpttest-PlaybackTest.obj `if test -f 'soundlib/PlaybackTest.cpp'; then $(CYGPATH_W) 'soundlib/PlaybackTest.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/PlaybackTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-PlaybackTest.Tpo soundlib/$(DEPDIR)/libopenmpttest-PlaybackTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/PlaybackTest.cpp' object='soundlib/libopenmpttest-PlaybackTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-PlaybackTest.obj `if test -f 'soundlib/PlaybackTest.cpp'; then $(CYGPATH_W) 'soundlib/PlaybackTest.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/PlaybackTest.cpp'; fi` soundlib/libopenmpttest-PlayState.o: soundlib/PlayState.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-PlayState.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-PlayState.Tpo -c -o soundlib/libopenmpttest-PlayState.o `test -f 'soundlib/PlayState.cpp' || echo '$(srcdir)/'`soundlib/PlayState.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-PlayState.Tpo soundlib/$(DEPDIR)/libopenmpttest-PlayState.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/PlayState.cpp' object='soundlib/libopenmpttest-PlayState.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-PlayState.o `test -f 'soundlib/PlayState.cpp' || echo '$(srcdir)/'`soundlib/PlayState.cpp soundlib/libopenmpttest-PlayState.obj: soundlib/PlayState.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-PlayState.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-PlayState.Tpo -c -o soundlib/libopenmpttest-PlayState.obj `if test -f 'soundlib/PlayState.cpp'; then $(CYGPATH_W) 'soundlib/PlayState.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/PlayState.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-PlayState.Tpo soundlib/$(DEPDIR)/libopenmpttest-PlayState.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/PlayState.cpp' object='soundlib/libopenmpttest-PlayState.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-PlayState.obj `if test -f 'soundlib/PlayState.cpp'; then $(CYGPATH_W) 'soundlib/PlayState.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/PlayState.cpp'; fi` soundlib/libopenmpttest-RowVisitor.o: soundlib/RowVisitor.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-RowVisitor.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-RowVisitor.Tpo -c -o soundlib/libopenmpttest-RowVisitor.o `test -f 'soundlib/RowVisitor.cpp' || echo '$(srcdir)/'`soundlib/RowVisitor.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-RowVisitor.Tpo soundlib/$(DEPDIR)/libopenmpttest-RowVisitor.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/RowVisitor.cpp' object='soundlib/libopenmpttest-RowVisitor.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-RowVisitor.o `test -f 'soundlib/RowVisitor.cpp' || echo '$(srcdir)/'`soundlib/RowVisitor.cpp soundlib/libopenmpttest-RowVisitor.obj: soundlib/RowVisitor.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-RowVisitor.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-RowVisitor.Tpo -c -o soundlib/libopenmpttest-RowVisitor.obj `if test -f 'soundlib/RowVisitor.cpp'; then $(CYGPATH_W) 'soundlib/RowVisitor.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/RowVisitor.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-RowVisitor.Tpo soundlib/$(DEPDIR)/libopenmpttest-RowVisitor.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/RowVisitor.cpp' object='soundlib/libopenmpttest-RowVisitor.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-RowVisitor.obj `if test -f 'soundlib/RowVisitor.cpp'; then $(CYGPATH_W) 'soundlib/RowVisitor.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/RowVisitor.cpp'; fi` soundlib/libopenmpttest-S3MTools.o: soundlib/S3MTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-S3MTools.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-S3MTools.Tpo -c -o soundlib/libopenmpttest-S3MTools.o `test -f 'soundlib/S3MTools.cpp' || echo '$(srcdir)/'`soundlib/S3MTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-S3MTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-S3MTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/S3MTools.cpp' object='soundlib/libopenmpttest-S3MTools.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-S3MTools.o `test -f 'soundlib/S3MTools.cpp' || echo '$(srcdir)/'`soundlib/S3MTools.cpp soundlib/libopenmpttest-S3MTools.obj: soundlib/S3MTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-S3MTools.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-S3MTools.Tpo -c -o soundlib/libopenmpttest-S3MTools.obj `if test -f 'soundlib/S3MTools.cpp'; then $(CYGPATH_W) 'soundlib/S3MTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/S3MTools.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-S3MTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-S3MTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/S3MTools.cpp' object='soundlib/libopenmpttest-S3MTools.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-S3MTools.obj `if test -f 'soundlib/S3MTools.cpp'; then $(CYGPATH_W) 'soundlib/S3MTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/S3MTools.cpp'; fi` soundlib/libopenmpttest-SampleFormats.o: soundlib/SampleFormats.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormats.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormats.Tpo -c -o soundlib/libopenmpttest-SampleFormats.o `test -f 'soundlib/SampleFormats.cpp' || echo '$(srcdir)/'`soundlib/SampleFormats.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormats.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormats.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormats.cpp' object='soundlib/libopenmpttest-SampleFormats.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormats.o `test -f 'soundlib/SampleFormats.cpp' || echo '$(srcdir)/'`soundlib/SampleFormats.cpp soundlib/libopenmpttest-SampleFormats.obj: soundlib/SampleFormats.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormats.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormats.Tpo -c -o soundlib/libopenmpttest-SampleFormats.obj `if test -f 'soundlib/SampleFormats.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormats.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormats.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormats.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormats.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormats.cpp' object='soundlib/libopenmpttest-SampleFormats.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormats.obj `if test -f 'soundlib/SampleFormats.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormats.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormats.cpp'; fi` soundlib/libopenmpttest-SampleFormatBRR.o: soundlib/SampleFormatBRR.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatBRR.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatBRR.Tpo -c -o soundlib/libopenmpttest-SampleFormatBRR.o `test -f 'soundlib/SampleFormatBRR.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatBRR.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatBRR.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatBRR.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatBRR.cpp' object='soundlib/libopenmpttest-SampleFormatBRR.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatBRR.o `test -f 'soundlib/SampleFormatBRR.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatBRR.cpp soundlib/libopenmpttest-SampleFormatBRR.obj: soundlib/SampleFormatBRR.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatBRR.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatBRR.Tpo -c -o soundlib/libopenmpttest-SampleFormatBRR.obj `if test -f 'soundlib/SampleFormatBRR.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatBRR.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatBRR.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatBRR.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatBRR.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatBRR.cpp' object='soundlib/libopenmpttest-SampleFormatBRR.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatBRR.obj `if test -f 'soundlib/SampleFormatBRR.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatBRR.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatBRR.cpp'; fi` soundlib/libopenmpttest-SampleFormatFLAC.o: soundlib/SampleFormatFLAC.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatFLAC.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Tpo -c -o soundlib/libopenmpttest-SampleFormatFLAC.o `test -f 'soundlib/SampleFormatFLAC.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatFLAC.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatFLAC.cpp' object='soundlib/libopenmpttest-SampleFormatFLAC.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatFLAC.o `test -f 'soundlib/SampleFormatFLAC.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatFLAC.cpp soundlib/libopenmpttest-SampleFormatFLAC.obj: soundlib/SampleFormatFLAC.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatFLAC.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Tpo -c -o soundlib/libopenmpttest-SampleFormatFLAC.obj `if test -f 'soundlib/SampleFormatFLAC.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatFLAC.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatFLAC.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatFLAC.cpp' object='soundlib/libopenmpttest-SampleFormatFLAC.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatFLAC.obj `if test -f 'soundlib/SampleFormatFLAC.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatFLAC.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatFLAC.cpp'; fi` soundlib/libopenmpttest-SampleFormatMediaFoundation.o: soundlib/SampleFormatMediaFoundation.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatMediaFoundation.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Tpo -c -o soundlib/libopenmpttest-SampleFormatMediaFoundation.o `test -f 'soundlib/SampleFormatMediaFoundation.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMediaFoundation.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatMediaFoundation.cpp' object='soundlib/libopenmpttest-SampleFormatMediaFoundation.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatMediaFoundation.o `test -f 'soundlib/SampleFormatMediaFoundation.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMediaFoundation.cpp soundlib/libopenmpttest-SampleFormatMediaFoundation.obj: soundlib/SampleFormatMediaFoundation.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatMediaFoundation.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Tpo -c -o soundlib/libopenmpttest-SampleFormatMediaFoundation.obj `if test -f 'soundlib/SampleFormatMediaFoundation.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatMediaFoundation.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatMediaFoundation.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatMediaFoundation.cpp' object='soundlib/libopenmpttest-SampleFormatMediaFoundation.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatMediaFoundation.obj `if test -f 'soundlib/SampleFormatMediaFoundation.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatMediaFoundation.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatMediaFoundation.cpp'; fi` soundlib/libopenmpttest-SampleFormatMP3.o: soundlib/SampleFormatMP3.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatMP3.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Tpo -c -o soundlib/libopenmpttest-SampleFormatMP3.o `test -f 'soundlib/SampleFormatMP3.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMP3.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatMP3.cpp' object='soundlib/libopenmpttest-SampleFormatMP3.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatMP3.o `test -f 'soundlib/SampleFormatMP3.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMP3.cpp soundlib/libopenmpttest-SampleFormatMP3.obj: soundlib/SampleFormatMP3.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatMP3.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Tpo -c -o soundlib/libopenmpttest-SampleFormatMP3.obj `if test -f 'soundlib/SampleFormatMP3.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatMP3.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatMP3.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatMP3.cpp' object='soundlib/libopenmpttest-SampleFormatMP3.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatMP3.obj `if test -f 'soundlib/SampleFormatMP3.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatMP3.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatMP3.cpp'; fi` soundlib/libopenmpttest-SampleFormatOpus.o: soundlib/SampleFormatOpus.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatOpus.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Tpo -c -o soundlib/libopenmpttest-SampleFormatOpus.o `test -f 'soundlib/SampleFormatOpus.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatOpus.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatOpus.cpp' object='soundlib/libopenmpttest-SampleFormatOpus.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatOpus.o `test -f 'soundlib/SampleFormatOpus.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatOpus.cpp soundlib/libopenmpttest-SampleFormatOpus.obj: soundlib/SampleFormatOpus.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatOpus.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Tpo -c -o soundlib/libopenmpttest-SampleFormatOpus.obj `if test -f 'soundlib/SampleFormatOpus.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatOpus.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatOpus.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatOpus.cpp' object='soundlib/libopenmpttest-SampleFormatOpus.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatOpus.obj `if test -f 'soundlib/SampleFormatOpus.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatOpus.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatOpus.cpp'; fi` soundlib/libopenmpttest-SampleFormatSFZ.o: soundlib/SampleFormatSFZ.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatSFZ.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatSFZ.Tpo -c -o soundlib/libopenmpttest-SampleFormatSFZ.o `test -f 'soundlib/SampleFormatSFZ.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatSFZ.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatSFZ.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatSFZ.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatSFZ.cpp' object='soundlib/libopenmpttest-SampleFormatSFZ.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatSFZ.o `test -f 'soundlib/SampleFormatSFZ.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatSFZ.cpp soundlib/libopenmpttest-SampleFormatSFZ.obj: soundlib/SampleFormatSFZ.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatSFZ.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatSFZ.Tpo -c -o soundlib/libopenmpttest-SampleFormatSFZ.obj `if test -f 'soundlib/SampleFormatSFZ.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatSFZ.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatSFZ.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatSFZ.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatSFZ.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatSFZ.cpp' object='soundlib/libopenmpttest-SampleFormatSFZ.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatSFZ.obj `if test -f 'soundlib/SampleFormatSFZ.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatSFZ.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatSFZ.cpp'; fi` soundlib/libopenmpttest-SampleFormatVorbis.o: soundlib/SampleFormatVorbis.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatVorbis.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Tpo -c -o soundlib/libopenmpttest-SampleFormatVorbis.o `test -f 'soundlib/SampleFormatVorbis.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatVorbis.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatVorbis.cpp' object='soundlib/libopenmpttest-SampleFormatVorbis.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatVorbis.o `test -f 'soundlib/SampleFormatVorbis.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatVorbis.cpp soundlib/libopenmpttest-SampleFormatVorbis.obj: soundlib/SampleFormatVorbis.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatVorbis.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Tpo -c -o soundlib/libopenmpttest-SampleFormatVorbis.obj `if test -f 'soundlib/SampleFormatVorbis.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatVorbis.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatVorbis.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleFormatVorbis.cpp' object='soundlib/libopenmpttest-SampleFormatVorbis.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatVorbis.obj `if test -f 'soundlib/SampleFormatVorbis.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatVorbis.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatVorbis.cpp'; fi` soundlib/libopenmpttest-SampleIO.o: soundlib/SampleIO.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleIO.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Tpo -c -o soundlib/libopenmpttest-SampleIO.o `test -f 'soundlib/SampleIO.cpp' || echo '$(srcdir)/'`soundlib/SampleIO.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleIO.cpp' object='soundlib/libopenmpttest-SampleIO.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleIO.o `test -f 'soundlib/SampleIO.cpp' || echo '$(srcdir)/'`soundlib/SampleIO.cpp soundlib/libopenmpttest-SampleIO.obj: soundlib/SampleIO.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleIO.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Tpo -c -o soundlib/libopenmpttest-SampleIO.obj `if test -f 'soundlib/SampleIO.cpp'; then $(CYGPATH_W) 'soundlib/SampleIO.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleIO.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SampleIO.cpp' object='soundlib/libopenmpttest-SampleIO.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleIO.obj `if test -f 'soundlib/SampleIO.cpp'; then $(CYGPATH_W) 'soundlib/SampleIO.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleIO.cpp'; fi` soundlib/libopenmpttest-Sndfile.o: soundlib/Sndfile.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Sndfile.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Sndfile.Tpo -c -o soundlib/libopenmpttest-Sndfile.o `test -f 'soundlib/Sndfile.cpp' || echo '$(srcdir)/'`soundlib/Sndfile.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Sndfile.Tpo soundlib/$(DEPDIR)/libopenmpttest-Sndfile.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Sndfile.cpp' object='soundlib/libopenmpttest-Sndfile.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Sndfile.o `test -f 'soundlib/Sndfile.cpp' || echo '$(srcdir)/'`soundlib/Sndfile.cpp soundlib/libopenmpttest-Sndfile.obj: soundlib/Sndfile.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Sndfile.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Sndfile.Tpo -c -o soundlib/libopenmpttest-Sndfile.obj `if test -f 'soundlib/Sndfile.cpp'; then $(CYGPATH_W) 'soundlib/Sndfile.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Sndfile.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Sndfile.Tpo soundlib/$(DEPDIR)/libopenmpttest-Sndfile.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Sndfile.cpp' object='soundlib/libopenmpttest-Sndfile.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Sndfile.obj `if test -f 'soundlib/Sndfile.cpp'; then $(CYGPATH_W) 'soundlib/Sndfile.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Sndfile.cpp'; fi` soundlib/libopenmpttest-Snd_flt.o: soundlib/Snd_flt.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Snd_flt.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Snd_flt.Tpo -c -o soundlib/libopenmpttest-Snd_flt.o `test -f 'soundlib/Snd_flt.cpp' || echo '$(srcdir)/'`soundlib/Snd_flt.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Snd_flt.Tpo soundlib/$(DEPDIR)/libopenmpttest-Snd_flt.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Snd_flt.cpp' object='soundlib/libopenmpttest-Snd_flt.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Snd_flt.o `test -f 'soundlib/Snd_flt.cpp' || echo '$(srcdir)/'`soundlib/Snd_flt.cpp soundlib/libopenmpttest-Snd_flt.obj: soundlib/Snd_flt.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Snd_flt.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Snd_flt.Tpo -c -o soundlib/libopenmpttest-Snd_flt.obj `if test -f 'soundlib/Snd_flt.cpp'; then $(CYGPATH_W) 'soundlib/Snd_flt.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Snd_flt.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Snd_flt.Tpo soundlib/$(DEPDIR)/libopenmpttest-Snd_flt.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Snd_flt.cpp' object='soundlib/libopenmpttest-Snd_flt.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Snd_flt.obj `if test -f 'soundlib/Snd_flt.cpp'; then $(CYGPATH_W) 'soundlib/Snd_flt.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Snd_flt.cpp'; fi` soundlib/libopenmpttest-Snd_fx.o: soundlib/Snd_fx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Snd_fx.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Snd_fx.Tpo -c -o soundlib/libopenmpttest-Snd_fx.o `test -f 'soundlib/Snd_fx.cpp' || echo '$(srcdir)/'`soundlib/Snd_fx.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Snd_fx.Tpo soundlib/$(DEPDIR)/libopenmpttest-Snd_fx.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Snd_fx.cpp' object='soundlib/libopenmpttest-Snd_fx.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Snd_fx.o `test -f 'soundlib/Snd_fx.cpp' || echo '$(srcdir)/'`soundlib/Snd_fx.cpp soundlib/libopenmpttest-Snd_fx.obj: soundlib/Snd_fx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Snd_fx.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Snd_fx.Tpo -c -o soundlib/libopenmpttest-Snd_fx.obj `if test -f 'soundlib/Snd_fx.cpp'; then $(CYGPATH_W) 'soundlib/Snd_fx.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Snd_fx.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Snd_fx.Tpo soundlib/$(DEPDIR)/libopenmpttest-Snd_fx.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Snd_fx.cpp' object='soundlib/libopenmpttest-Snd_fx.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Snd_fx.obj `if test -f 'soundlib/Snd_fx.cpp'; then $(CYGPATH_W) 'soundlib/Snd_fx.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Snd_fx.cpp'; fi` soundlib/libopenmpttest-Sndmix.o: soundlib/Sndmix.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Sndmix.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Sndmix.Tpo -c -o soundlib/libopenmpttest-Sndmix.o `test -f 'soundlib/Sndmix.cpp' || echo '$(srcdir)/'`soundlib/Sndmix.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Sndmix.Tpo soundlib/$(DEPDIR)/libopenmpttest-Sndmix.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Sndmix.cpp' object='soundlib/libopenmpttest-Sndmix.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Sndmix.o `test -f 'soundlib/Sndmix.cpp' || echo '$(srcdir)/'`soundlib/Sndmix.cpp soundlib/libopenmpttest-Sndmix.obj: soundlib/Sndmix.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Sndmix.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Sndmix.Tpo -c -o soundlib/libopenmpttest-Sndmix.obj `if test -f 'soundlib/Sndmix.cpp'; then $(CYGPATH_W) 'soundlib/Sndmix.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Sndmix.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Sndmix.Tpo soundlib/$(DEPDIR)/libopenmpttest-Sndmix.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Sndmix.cpp' object='soundlib/libopenmpttest-Sndmix.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Sndmix.obj `if test -f 'soundlib/Sndmix.cpp'; then $(CYGPATH_W) 'soundlib/Sndmix.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Sndmix.cpp'; fi` soundlib/libopenmpttest-SoundFilePlayConfig.o: soundlib/SoundFilePlayConfig.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SoundFilePlayConfig.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SoundFilePlayConfig.Tpo -c -o soundlib/libopenmpttest-SoundFilePlayConfig.o `test -f 'soundlib/SoundFilePlayConfig.cpp' || echo '$(srcdir)/'`soundlib/SoundFilePlayConfig.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SoundFilePlayConfig.Tpo soundlib/$(DEPDIR)/libopenmpttest-SoundFilePlayConfig.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SoundFilePlayConfig.cpp' object='soundlib/libopenmpttest-SoundFilePlayConfig.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SoundFilePlayConfig.o `test -f 'soundlib/SoundFilePlayConfig.cpp' || echo '$(srcdir)/'`soundlib/SoundFilePlayConfig.cpp soundlib/libopenmpttest-SoundFilePlayConfig.obj: soundlib/SoundFilePlayConfig.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SoundFilePlayConfig.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SoundFilePlayConfig.Tpo -c -o soundlib/libopenmpttest-SoundFilePlayConfig.obj `if test -f 'soundlib/SoundFilePlayConfig.cpp'; then $(CYGPATH_W) 'soundlib/SoundFilePlayConfig.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SoundFilePlayConfig.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SoundFilePlayConfig.Tpo soundlib/$(DEPDIR)/libopenmpttest-SoundFilePlayConfig.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/SoundFilePlayConfig.cpp' object='soundlib/libopenmpttest-SoundFilePlayConfig.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SoundFilePlayConfig.obj `if test -f 'soundlib/SoundFilePlayConfig.cpp'; then $(CYGPATH_W) 'soundlib/SoundFilePlayConfig.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SoundFilePlayConfig.cpp'; fi` soundlib/libopenmpttest-Tables.o: soundlib/Tables.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Tables.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Tables.Tpo -c -o soundlib/libopenmpttest-Tables.o `test -f 'soundlib/Tables.cpp' || echo '$(srcdir)/'`soundlib/Tables.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Tables.Tpo soundlib/$(DEPDIR)/libopenmpttest-Tables.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Tables.cpp' object='soundlib/libopenmpttest-Tables.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Tables.o `test -f 'soundlib/Tables.cpp' || echo '$(srcdir)/'`soundlib/Tables.cpp soundlib/libopenmpttest-Tables.obj: soundlib/Tables.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Tables.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Tables.Tpo -c -o soundlib/libopenmpttest-Tables.obj `if test -f 'soundlib/Tables.cpp'; then $(CYGPATH_W) 'soundlib/Tables.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Tables.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Tables.Tpo soundlib/$(DEPDIR)/libopenmpttest-Tables.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Tables.cpp' object='soundlib/libopenmpttest-Tables.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Tables.obj `if test -f 'soundlib/Tables.cpp'; then $(CYGPATH_W) 'soundlib/Tables.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Tables.cpp'; fi` soundlib/libopenmpttest-Tagging.o: soundlib/Tagging.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Tagging.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Tagging.Tpo -c -o soundlib/libopenmpttest-Tagging.o `test -f 'soundlib/Tagging.cpp' || echo '$(srcdir)/'`soundlib/Tagging.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Tagging.Tpo soundlib/$(DEPDIR)/libopenmpttest-Tagging.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Tagging.cpp' object='soundlib/libopenmpttest-Tagging.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Tagging.o `test -f 'soundlib/Tagging.cpp' || echo '$(srcdir)/'`soundlib/Tagging.cpp soundlib/libopenmpttest-Tagging.obj: soundlib/Tagging.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Tagging.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Tagging.Tpo -c -o soundlib/libopenmpttest-Tagging.obj `if test -f 'soundlib/Tagging.cpp'; then $(CYGPATH_W) 'soundlib/Tagging.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Tagging.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Tagging.Tpo soundlib/$(DEPDIR)/libopenmpttest-Tagging.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/Tagging.cpp' object='soundlib/libopenmpttest-Tagging.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Tagging.obj `if test -f 'soundlib/Tagging.cpp'; then $(CYGPATH_W) 'soundlib/Tagging.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Tagging.cpp'; fi` soundlib/libopenmpttest-TinyFFT.o: soundlib/TinyFFT.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-TinyFFT.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-TinyFFT.Tpo -c -o soundlib/libopenmpttest-TinyFFT.o `test -f 'soundlib/TinyFFT.cpp' || echo '$(srcdir)/'`soundlib/TinyFFT.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-TinyFFT.Tpo soundlib/$(DEPDIR)/libopenmpttest-TinyFFT.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/TinyFFT.cpp' object='soundlib/libopenmpttest-TinyFFT.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-TinyFFT.o `test -f 'soundlib/TinyFFT.cpp' || echo '$(srcdir)/'`soundlib/TinyFFT.cpp soundlib/libopenmpttest-TinyFFT.obj: soundlib/TinyFFT.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-TinyFFT.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-TinyFFT.Tpo -c -o soundlib/libopenmpttest-TinyFFT.obj `if test -f 'soundlib/TinyFFT.cpp'; then $(CYGPATH_W) 'soundlib/TinyFFT.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/TinyFFT.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-TinyFFT.Tpo soundlib/$(DEPDIR)/libopenmpttest-TinyFFT.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/TinyFFT.cpp' object='soundlib/libopenmpttest-TinyFFT.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-TinyFFT.obj `if test -f 'soundlib/TinyFFT.cpp'; then $(CYGPATH_W) 'soundlib/TinyFFT.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/TinyFFT.cpp'; fi` soundlib/libopenmpttest-tuningCollection.o: soundlib/tuningCollection.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-tuningCollection.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-tuningCollection.Tpo -c -o soundlib/libopenmpttest-tuningCollection.o `test -f 'soundlib/tuningCollection.cpp' || echo '$(srcdir)/'`soundlib/tuningCollection.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-tuningCollection.Tpo soundlib/$(DEPDIR)/libopenmpttest-tuningCollection.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/tuningCollection.cpp' object='soundlib/libopenmpttest-tuningCollection.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-tuningCollection.o `test -f 'soundlib/tuningCollection.cpp' || echo '$(srcdir)/'`soundlib/tuningCollection.cpp soundlib/libopenmpttest-tuningCollection.obj: soundlib/tuningCollection.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-tuningCollection.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-tuningCollection.Tpo -c -o soundlib/libopenmpttest-tuningCollection.obj `if test -f 'soundlib/tuningCollection.cpp'; then $(CYGPATH_W) 'soundlib/tuningCollection.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/tuningCollection.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-tuningCollection.Tpo soundlib/$(DEPDIR)/libopenmpttest-tuningCollection.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/tuningCollection.cpp' object='soundlib/libopenmpttest-tuningCollection.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-tuningCollection.obj `if test -f 'soundlib/tuningCollection.cpp'; then $(CYGPATH_W) 'soundlib/tuningCollection.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/tuningCollection.cpp'; fi` soundlib/libopenmpttest-tuning.o: soundlib/tuning.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-tuning.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-tuning.Tpo -c -o soundlib/libopenmpttest-tuning.o `test -f 'soundlib/tuning.cpp' || echo '$(srcdir)/'`soundlib/tuning.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-tuning.Tpo soundlib/$(DEPDIR)/libopenmpttest-tuning.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/tuning.cpp' object='soundlib/libopenmpttest-tuning.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-tuning.o `test -f 'soundlib/tuning.cpp' || echo '$(srcdir)/'`soundlib/tuning.cpp soundlib/libopenmpttest-tuning.obj: soundlib/tuning.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-tuning.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-tuning.Tpo -c -o soundlib/libopenmpttest-tuning.obj `if test -f 'soundlib/tuning.cpp'; then $(CYGPATH_W) 'soundlib/tuning.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/tuning.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-tuning.Tpo soundlib/$(DEPDIR)/libopenmpttest-tuning.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/tuning.cpp' object='soundlib/libopenmpttest-tuning.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-tuning.obj `if test -f 'soundlib/tuning.cpp'; then $(CYGPATH_W) 'soundlib/tuning.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/tuning.cpp'; fi` soundlib/libopenmpttest-UMXTools.o: soundlib/UMXTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-UMXTools.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Tpo -c -o soundlib/libopenmpttest-UMXTools.o `test -f 'soundlib/UMXTools.cpp' || echo '$(srcdir)/'`soundlib/UMXTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/UMXTools.cpp' object='soundlib/libopenmpttest-UMXTools.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-UMXTools.o `test -f 'soundlib/UMXTools.cpp' || echo '$(srcdir)/'`soundlib/UMXTools.cpp soundlib/libopenmpttest-UMXTools.obj: soundlib/UMXTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-UMXTools.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Tpo -c -o soundlib/libopenmpttest-UMXTools.obj `if test -f 'soundlib/UMXTools.cpp'; then $(CYGPATH_W) 'soundlib/UMXTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/UMXTools.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/UMXTools.cpp' object='soundlib/libopenmpttest-UMXTools.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-UMXTools.obj `if test -f 'soundlib/UMXTools.cpp'; then $(CYGPATH_W) 'soundlib/UMXTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/UMXTools.cpp'; fi` soundlib/libopenmpttest-UpgradeModule.o: soundlib/UpgradeModule.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-UpgradeModule.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Tpo -c -o soundlib/libopenmpttest-UpgradeModule.o `test -f 'soundlib/UpgradeModule.cpp' || echo '$(srcdir)/'`soundlib/UpgradeModule.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Tpo soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/UpgradeModule.cpp' object='soundlib/libopenmpttest-UpgradeModule.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-UpgradeModule.o `test -f 'soundlib/UpgradeModule.cpp' || echo '$(srcdir)/'`soundlib/UpgradeModule.cpp soundlib/libopenmpttest-UpgradeModule.obj: soundlib/UpgradeModule.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-UpgradeModule.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Tpo -c -o soundlib/libopenmpttest-UpgradeModule.obj `if test -f 'soundlib/UpgradeModule.cpp'; then $(CYGPATH_W) 'soundlib/UpgradeModule.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/UpgradeModule.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Tpo soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/UpgradeModule.cpp' object='soundlib/libopenmpttest-UpgradeModule.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-UpgradeModule.obj `if test -f 'soundlib/UpgradeModule.cpp'; then $(CYGPATH_W) 'soundlib/UpgradeModule.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/UpgradeModule.cpp'; fi` soundlib/libopenmpttest-WAVTools.o: soundlib/WAVTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-WAVTools.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-WAVTools.Tpo -c -o soundlib/libopenmpttest-WAVTools.o `test -f 'soundlib/WAVTools.cpp' || echo '$(srcdir)/'`soundlib/WAVTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-WAVTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-WAVTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/WAVTools.cpp' object='soundlib/libopenmpttest-WAVTools.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-WAVTools.o `test -f 'soundlib/WAVTools.cpp' || echo '$(srcdir)/'`soundlib/WAVTools.cpp soundlib/libopenmpttest-WAVTools.obj: soundlib/WAVTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-WAVTools.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-WAVTools.Tpo -c -o soundlib/libopenmpttest-WAVTools.obj `if test -f 'soundlib/WAVTools.cpp'; then $(CYGPATH_W) 'soundlib/WAVTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/WAVTools.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-WAVTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-WAVTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/WAVTools.cpp' object='soundlib/libopenmpttest-WAVTools.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-WAVTools.obj `if test -f 'soundlib/WAVTools.cpp'; then $(CYGPATH_W) 'soundlib/WAVTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/WAVTools.cpp'; fi` soundlib/libopenmpttest-WindowedFIR.o: soundlib/WindowedFIR.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-WindowedFIR.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-WindowedFIR.Tpo -c -o soundlib/libopenmpttest-WindowedFIR.o `test -f 'soundlib/WindowedFIR.cpp' || echo '$(srcdir)/'`soundlib/WindowedFIR.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-WindowedFIR.Tpo soundlib/$(DEPDIR)/libopenmpttest-WindowedFIR.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/WindowedFIR.cpp' object='soundlib/libopenmpttest-WindowedFIR.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-WindowedFIR.o `test -f 'soundlib/WindowedFIR.cpp' || echo '$(srcdir)/'`soundlib/WindowedFIR.cpp soundlib/libopenmpttest-WindowedFIR.obj: soundlib/WindowedFIR.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-WindowedFIR.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-WindowedFIR.Tpo -c -o soundlib/libopenmpttest-WindowedFIR.obj `if test -f 'soundlib/WindowedFIR.cpp'; then $(CYGPATH_W) 'soundlib/WindowedFIR.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/WindowedFIR.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-WindowedFIR.Tpo soundlib/$(DEPDIR)/libopenmpttest-WindowedFIR.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/WindowedFIR.cpp' object='soundlib/libopenmpttest-WindowedFIR.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-WindowedFIR.obj `if test -f 'soundlib/WindowedFIR.cpp'; then $(CYGPATH_W) 'soundlib/WindowedFIR.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/WindowedFIR.cpp'; fi` soundlib/libopenmpttest-XMTools.o: soundlib/XMTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-XMTools.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-XMTools.Tpo -c -o soundlib/libopenmpttest-XMTools.o `test -f 'soundlib/XMTools.cpp' || echo '$(srcdir)/'`soundlib/XMTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-XMTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-XMTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/XMTools.cpp' object='soundlib/libopenmpttest-XMTools.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-XMTools.o `test -f 'soundlib/XMTools.cpp' || echo '$(srcdir)/'`soundlib/XMTools.cpp soundlib/libopenmpttest-XMTools.obj: soundlib/XMTools.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-XMTools.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-XMTools.Tpo -c -o soundlib/libopenmpttest-XMTools.obj `if test -f 'soundlib/XMTools.cpp'; then $(CYGPATH_W) 'soundlib/XMTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/XMTools.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-XMTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-XMTools.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/XMTools.cpp' object='soundlib/libopenmpttest-XMTools.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-XMTools.obj `if test -f 'soundlib/XMTools.cpp'; then $(CYGPATH_W) 'soundlib/XMTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/XMTools.cpp'; fi` soundlib/plugins/dmo/libopenmpttest-DMOPlugin.o: soundlib/plugins/dmo/DMOPlugin.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-DMOPlugin.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOPlugin.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-DMOPlugin.o `test -f 'soundlib/plugins/dmo/DMOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/DMOPlugin.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOPlugin.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOPlugin.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/DMOPlugin.cpp' object='soundlib/plugins/dmo/libopenmpttest-DMOPlugin.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-DMOPlugin.o `test -f 'soundlib/plugins/dmo/DMOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/DMOPlugin.cpp soundlib/plugins/dmo/libopenmpttest-DMOPlugin.obj: soundlib/plugins/dmo/DMOPlugin.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-DMOPlugin.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOPlugin.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-DMOPlugin.obj `if test -f 'soundlib/plugins/dmo/DMOPlugin.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/DMOPlugin.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/DMOPlugin.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOPlugin.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOPlugin.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/DMOPlugin.cpp' object='soundlib/plugins/dmo/libopenmpttest-DMOPlugin.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-DMOPlugin.obj `if test -f 'soundlib/plugins/dmo/DMOPlugin.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/DMOPlugin.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/DMOPlugin.cpp'; fi` soundlib/plugins/dmo/libopenmpttest-DMOUtils.o: soundlib/plugins/dmo/DMOUtils.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-DMOUtils.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOUtils.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-DMOUtils.o `test -f 'soundlib/plugins/dmo/DMOUtils.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/DMOUtils.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOUtils.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOUtils.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/DMOUtils.cpp' object='soundlib/plugins/dmo/libopenmpttest-DMOUtils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-DMOUtils.o `test -f 'soundlib/plugins/dmo/DMOUtils.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/DMOUtils.cpp soundlib/plugins/dmo/libopenmpttest-DMOUtils.obj: soundlib/plugins/dmo/DMOUtils.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-DMOUtils.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOUtils.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-DMOUtils.obj `if test -f 'soundlib/plugins/dmo/DMOUtils.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/DMOUtils.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/DMOUtils.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOUtils.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOUtils.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/DMOUtils.cpp' object='soundlib/plugins/dmo/libopenmpttest-DMOUtils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-DMOUtils.obj `if test -f 'soundlib/plugins/dmo/DMOUtils.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/DMOUtils.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/DMOUtils.cpp'; fi` soundlib/plugins/dmo/libopenmpttest-Chorus.o: soundlib/plugins/dmo/Chorus.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Chorus.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Chorus.o `test -f 'soundlib/plugins/dmo/Chorus.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Chorus.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Chorus.cpp' object='soundlib/plugins/dmo/libopenmpttest-Chorus.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Chorus.o `test -f 'soundlib/plugins/dmo/Chorus.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Chorus.cpp soundlib/plugins/dmo/libopenmpttest-Chorus.obj: soundlib/plugins/dmo/Chorus.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Chorus.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Chorus.obj `if test -f 'soundlib/plugins/dmo/Chorus.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Chorus.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Chorus.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Chorus.cpp' object='soundlib/plugins/dmo/libopenmpttest-Chorus.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Chorus.obj `if test -f 'soundlib/plugins/dmo/Chorus.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Chorus.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Chorus.cpp'; fi` soundlib/plugins/dmo/libopenmpttest-Compressor.o: soundlib/plugins/dmo/Compressor.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Compressor.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Compressor.o `test -f 'soundlib/plugins/dmo/Compressor.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Compressor.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Compressor.cpp' object='soundlib/plugins/dmo/libopenmpttest-Compressor.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Compressor.o `test -f 'soundlib/plugins/dmo/Compressor.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Compressor.cpp soundlib/plugins/dmo/libopenmpttest-Compressor.obj: soundlib/plugins/dmo/Compressor.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Compressor.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Compressor.obj `if test -f 'soundlib/plugins/dmo/Compressor.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Compressor.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Compressor.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Compressor.cpp' object='soundlib/plugins/dmo/libopenmpttest-Compressor.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Compressor.obj `if test -f 'soundlib/plugins/dmo/Compressor.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Compressor.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Compressor.cpp'; fi` soundlib/plugins/dmo/libopenmpttest-Distortion.o: soundlib/plugins/dmo/Distortion.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Distortion.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Distortion.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Distortion.o `test -f 'soundlib/plugins/dmo/Distortion.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Distortion.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Distortion.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Distortion.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Distortion.cpp' object='soundlib/plugins/dmo/libopenmpttest-Distortion.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Distortion.o `test -f 'soundlib/plugins/dmo/Distortion.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Distortion.cpp soundlib/plugins/dmo/libopenmpttest-Distortion.obj: soundlib/plugins/dmo/Distortion.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Distortion.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Distortion.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Distortion.obj `if test -f 'soundlib/plugins/dmo/Distortion.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Distortion.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Distortion.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Distortion.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Distortion.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Distortion.cpp' object='soundlib/plugins/dmo/libopenmpttest-Distortion.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Distortion.obj `if test -f 'soundlib/plugins/dmo/Distortion.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Distortion.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Distortion.cpp'; fi` soundlib/plugins/dmo/libopenmpttest-Echo.o: soundlib/plugins/dmo/Echo.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Echo.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Echo.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Echo.o `test -f 'soundlib/plugins/dmo/Echo.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Echo.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Echo.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Echo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Echo.cpp' object='soundlib/plugins/dmo/libopenmpttest-Echo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Echo.o `test -f 'soundlib/plugins/dmo/Echo.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Echo.cpp soundlib/plugins/dmo/libopenmpttest-Echo.obj: soundlib/plugins/dmo/Echo.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Echo.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Echo.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Echo.obj `if test -f 'soundlib/plugins/dmo/Echo.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Echo.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Echo.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Echo.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Echo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Echo.cpp' object='soundlib/plugins/dmo/libopenmpttest-Echo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Echo.obj `if test -f 'soundlib/plugins/dmo/Echo.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Echo.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Echo.cpp'; fi` soundlib/plugins/dmo/libopenmpttest-Flanger.o: soundlib/plugins/dmo/Flanger.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Flanger.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Flanger.o `test -f 'soundlib/plugins/dmo/Flanger.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Flanger.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Flanger.cpp' object='soundlib/plugins/dmo/libopenmpttest-Flanger.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Flanger.o `test -f 'soundlib/plugins/dmo/Flanger.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Flanger.cpp soundlib/plugins/dmo/libopenmpttest-Flanger.obj: soundlib/plugins/dmo/Flanger.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Flanger.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Flanger.obj `if test -f 'soundlib/plugins/dmo/Flanger.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Flanger.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Flanger.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Flanger.cpp' object='soundlib/plugins/dmo/libopenmpttest-Flanger.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Flanger.obj `if test -f 'soundlib/plugins/dmo/Flanger.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Flanger.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Flanger.cpp'; fi` soundlib/plugins/dmo/libopenmpttest-Gargle.o: soundlib/plugins/dmo/Gargle.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Gargle.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Gargle.o `test -f 'soundlib/plugins/dmo/Gargle.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Gargle.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Gargle.cpp' object='soundlib/plugins/dmo/libopenmpttest-Gargle.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Gargle.o `test -f 'soundlib/plugins/dmo/Gargle.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Gargle.cpp soundlib/plugins/dmo/libopenmpttest-Gargle.obj: soundlib/plugins/dmo/Gargle.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Gargle.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Gargle.obj `if test -f 'soundlib/plugins/dmo/Gargle.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Gargle.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Gargle.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/Gargle.cpp' object='soundlib/plugins/dmo/libopenmpttest-Gargle.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Gargle.obj `if test -f 'soundlib/plugins/dmo/Gargle.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Gargle.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Gargle.cpp'; fi` soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.o: soundlib/plugins/dmo/I3DL2Reverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.o `test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/I3DL2Reverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/I3DL2Reverb.cpp' object='soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.o `test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/I3DL2Reverb.cpp soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.obj: soundlib/plugins/dmo/I3DL2Reverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.obj `if test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/I3DL2Reverb.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/I3DL2Reverb.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/I3DL2Reverb.cpp' object='soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.obj `if test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/I3DL2Reverb.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/I3DL2Reverb.cpp'; fi` soundlib/plugins/dmo/libopenmpttest-ParamEq.o: soundlib/plugins/dmo/ParamEq.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-ParamEq.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-ParamEq.o `test -f 'soundlib/plugins/dmo/ParamEq.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/ParamEq.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/ParamEq.cpp' object='soundlib/plugins/dmo/libopenmpttest-ParamEq.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-ParamEq.o `test -f 'soundlib/plugins/dmo/ParamEq.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/ParamEq.cpp soundlib/plugins/dmo/libopenmpttest-ParamEq.obj: soundlib/plugins/dmo/ParamEq.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-ParamEq.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-ParamEq.obj `if test -f 'soundlib/plugins/dmo/ParamEq.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/ParamEq.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/ParamEq.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/ParamEq.cpp' object='soundlib/plugins/dmo/libopenmpttest-ParamEq.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-ParamEq.obj `if test -f 'soundlib/plugins/dmo/ParamEq.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/ParamEq.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/ParamEq.cpp'; fi` soundlib/plugins/dmo/libopenmpttest-WavesReverb.o: soundlib/plugins/dmo/WavesReverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-WavesReverb.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-WavesReverb.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-WavesReverb.o `test -f 'soundlib/plugins/dmo/WavesReverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/WavesReverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-WavesReverb.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-WavesReverb.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/WavesReverb.cpp' object='soundlib/plugins/dmo/libopenmpttest-WavesReverb.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-WavesReverb.o `test -f 'soundlib/plugins/dmo/WavesReverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/WavesReverb.cpp soundlib/plugins/dmo/libopenmpttest-WavesReverb.obj: soundlib/plugins/dmo/WavesReverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-WavesReverb.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-WavesReverb.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-WavesReverb.obj `if test -f 'soundlib/plugins/dmo/WavesReverb.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/WavesReverb.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/WavesReverb.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-WavesReverb.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-WavesReverb.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/dmo/WavesReverb.cpp' object='soundlib/plugins/dmo/libopenmpttest-WavesReverb.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-WavesReverb.obj `if test -f 'soundlib/plugins/dmo/WavesReverb.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/WavesReverb.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/WavesReverb.cpp'; fi` soundlib/plugins/libopenmpttest-DigiBoosterEcho.o: soundlib/plugins/DigiBoosterEcho.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-DigiBoosterEcho.o -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-DigiBoosterEcho.Tpo -c -o soundlib/plugins/libopenmpttest-DigiBoosterEcho.o `test -f 'soundlib/plugins/DigiBoosterEcho.cpp' || echo '$(srcdir)/'`soundlib/plugins/DigiBoosterEcho.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-DigiBoosterEcho.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-DigiBoosterEcho.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/DigiBoosterEcho.cpp' object='soundlib/plugins/libopenmpttest-DigiBoosterEcho.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-DigiBoosterEcho.o `test -f 'soundlib/plugins/DigiBoosterEcho.cpp' || echo '$(srcdir)/'`soundlib/plugins/DigiBoosterEcho.cpp soundlib/plugins/libopenmpttest-DigiBoosterEcho.obj: soundlib/plugins/DigiBoosterEcho.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-DigiBoosterEcho.obj -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-DigiBoosterEcho.Tpo -c -o soundlib/plugins/libopenmpttest-DigiBoosterEcho.obj `if test -f 'soundlib/plugins/DigiBoosterEcho.cpp'; then $(CYGPATH_W) 'soundlib/plugins/DigiBoosterEcho.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/DigiBoosterEcho.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-DigiBoosterEcho.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-DigiBoosterEcho.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/DigiBoosterEcho.cpp' object='soundlib/plugins/libopenmpttest-DigiBoosterEcho.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-DigiBoosterEcho.obj `if test -f 'soundlib/plugins/DigiBoosterEcho.cpp'; then $(CYGPATH_W) 'soundlib/plugins/DigiBoosterEcho.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/DigiBoosterEcho.cpp'; fi` soundlib/plugins/libopenmpttest-LFOPlugin.o: soundlib/plugins/LFOPlugin.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-LFOPlugin.o -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Tpo -c -o soundlib/plugins/libopenmpttest-LFOPlugin.o `test -f 'soundlib/plugins/LFOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/LFOPlugin.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/LFOPlugin.cpp' object='soundlib/plugins/libopenmpttest-LFOPlugin.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-LFOPlugin.o `test -f 'soundlib/plugins/LFOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/LFOPlugin.cpp soundlib/plugins/libopenmpttest-LFOPlugin.obj: soundlib/plugins/LFOPlugin.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-LFOPlugin.obj -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Tpo -c -o soundlib/plugins/libopenmpttest-LFOPlugin.obj `if test -f 'soundlib/plugins/LFOPlugin.cpp'; then $(CYGPATH_W) 'soundlib/plugins/LFOPlugin.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/LFOPlugin.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/LFOPlugin.cpp' object='soundlib/plugins/libopenmpttest-LFOPlugin.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-LFOPlugin.obj `if test -f 'soundlib/plugins/LFOPlugin.cpp'; then $(CYGPATH_W) 'soundlib/plugins/LFOPlugin.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/LFOPlugin.cpp'; fi` soundlib/plugins/libopenmpttest-PluginManager.o: soundlib/plugins/PluginManager.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-PluginManager.o -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Tpo -c -o soundlib/plugins/libopenmpttest-PluginManager.o `test -f 'soundlib/plugins/PluginManager.cpp' || echo '$(srcdir)/'`soundlib/plugins/PluginManager.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/PluginManager.cpp' object='soundlib/plugins/libopenmpttest-PluginManager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-PluginManager.o `test -f 'soundlib/plugins/PluginManager.cpp' || echo '$(srcdir)/'`soundlib/plugins/PluginManager.cpp soundlib/plugins/libopenmpttest-PluginManager.obj: soundlib/plugins/PluginManager.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-PluginManager.obj -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Tpo -c -o soundlib/plugins/libopenmpttest-PluginManager.obj `if test -f 'soundlib/plugins/PluginManager.cpp'; then $(CYGPATH_W) 'soundlib/plugins/PluginManager.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/PluginManager.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/PluginManager.cpp' object='soundlib/plugins/libopenmpttest-PluginManager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-PluginManager.obj `if test -f 'soundlib/plugins/PluginManager.cpp'; then $(CYGPATH_W) 'soundlib/plugins/PluginManager.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/PluginManager.cpp'; fi` soundlib/plugins/libopenmpttest-PlugInterface.o: soundlib/plugins/PlugInterface.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-PlugInterface.o -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-PlugInterface.Tpo -c -o soundlib/plugins/libopenmpttest-PlugInterface.o `test -f 'soundlib/plugins/PlugInterface.cpp' || echo '$(srcdir)/'`soundlib/plugins/PlugInterface.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-PlugInterface.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-PlugInterface.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/PlugInterface.cpp' object='soundlib/plugins/libopenmpttest-PlugInterface.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-PlugInterface.o `test -f 'soundlib/plugins/PlugInterface.cpp' || echo '$(srcdir)/'`soundlib/plugins/PlugInterface.cpp soundlib/plugins/libopenmpttest-PlugInterface.obj: soundlib/plugins/PlugInterface.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-PlugInterface.obj -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-PlugInterface.Tpo -c -o soundlib/plugins/libopenmpttest-PlugInterface.obj `if test -f 'soundlib/plugins/PlugInterface.cpp'; then $(CYGPATH_W) 'soundlib/plugins/PlugInterface.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/PlugInterface.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-PlugInterface.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-PlugInterface.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/PlugInterface.cpp' object='soundlib/plugins/libopenmpttest-PlugInterface.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-PlugInterface.obj `if test -f 'soundlib/plugins/PlugInterface.cpp'; then $(CYGPATH_W) 'soundlib/plugins/PlugInterface.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/PlugInterface.cpp'; fi` soundlib/plugins/libopenmpttest-SymMODEcho.o: soundlib/plugins/SymMODEcho.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-SymMODEcho.o -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-SymMODEcho.Tpo -c -o soundlib/plugins/libopenmpttest-SymMODEcho.o `test -f 'soundlib/plugins/SymMODEcho.cpp' || echo '$(srcdir)/'`soundlib/plugins/SymMODEcho.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-SymMODEcho.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-SymMODEcho.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/SymMODEcho.cpp' object='soundlib/plugins/libopenmpttest-SymMODEcho.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-SymMODEcho.o `test -f 'soundlib/plugins/SymMODEcho.cpp' || echo '$(srcdir)/'`soundlib/plugins/SymMODEcho.cpp soundlib/plugins/libopenmpttest-SymMODEcho.obj: soundlib/plugins/SymMODEcho.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-SymMODEcho.obj -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-SymMODEcho.Tpo -c -o soundlib/plugins/libopenmpttest-SymMODEcho.obj `if test -f 'soundlib/plugins/SymMODEcho.cpp'; then $(CYGPATH_W) 'soundlib/plugins/SymMODEcho.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/SymMODEcho.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-SymMODEcho.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-SymMODEcho.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='soundlib/plugins/SymMODEcho.cpp' object='soundlib/plugins/libopenmpttest-SymMODEcho.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-SymMODEcho.obj `if test -f 'soundlib/plugins/SymMODEcho.cpp'; then $(CYGPATH_W) 'soundlib/plugins/SymMODEcho.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/SymMODEcho.cpp'; fi` sounddsp/libopenmpttest-AGC.o: sounddsp/AGC.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-AGC.o -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-AGC.Tpo -c -o sounddsp/libopenmpttest-AGC.o `test -f 'sounddsp/AGC.cpp' || echo '$(srcdir)/'`sounddsp/AGC.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-AGC.Tpo sounddsp/$(DEPDIR)/libopenmpttest-AGC.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/AGC.cpp' object='sounddsp/libopenmpttest-AGC.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-AGC.o `test -f 'sounddsp/AGC.cpp' || echo '$(srcdir)/'`sounddsp/AGC.cpp sounddsp/libopenmpttest-AGC.obj: sounddsp/AGC.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-AGC.obj -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-AGC.Tpo -c -o sounddsp/libopenmpttest-AGC.obj `if test -f 'sounddsp/AGC.cpp'; then $(CYGPATH_W) 'sounddsp/AGC.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/AGC.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-AGC.Tpo sounddsp/$(DEPDIR)/libopenmpttest-AGC.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/AGC.cpp' object='sounddsp/libopenmpttest-AGC.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-AGC.obj `if test -f 'sounddsp/AGC.cpp'; then $(CYGPATH_W) 'sounddsp/AGC.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/AGC.cpp'; fi` sounddsp/libopenmpttest-DSP.o: sounddsp/DSP.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-DSP.o -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-DSP.Tpo -c -o sounddsp/libopenmpttest-DSP.o `test -f 'sounddsp/DSP.cpp' || echo '$(srcdir)/'`sounddsp/DSP.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-DSP.Tpo sounddsp/$(DEPDIR)/libopenmpttest-DSP.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/DSP.cpp' object='sounddsp/libopenmpttest-DSP.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-DSP.o `test -f 'sounddsp/DSP.cpp' || echo '$(srcdir)/'`sounddsp/DSP.cpp sounddsp/libopenmpttest-DSP.obj: sounddsp/DSP.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-DSP.obj -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-DSP.Tpo -c -o sounddsp/libopenmpttest-DSP.obj `if test -f 'sounddsp/DSP.cpp'; then $(CYGPATH_W) 'sounddsp/DSP.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/DSP.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-DSP.Tpo sounddsp/$(DEPDIR)/libopenmpttest-DSP.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/DSP.cpp' object='sounddsp/libopenmpttest-DSP.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-DSP.obj `if test -f 'sounddsp/DSP.cpp'; then $(CYGPATH_W) 'sounddsp/DSP.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/DSP.cpp'; fi` sounddsp/libopenmpttest-EQ.o: sounddsp/EQ.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-EQ.o -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-EQ.Tpo -c -o sounddsp/libopenmpttest-EQ.o `test -f 'sounddsp/EQ.cpp' || echo '$(srcdir)/'`sounddsp/EQ.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-EQ.Tpo sounddsp/$(DEPDIR)/libopenmpttest-EQ.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/EQ.cpp' object='sounddsp/libopenmpttest-EQ.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-EQ.o `test -f 'sounddsp/EQ.cpp' || echo '$(srcdir)/'`sounddsp/EQ.cpp sounddsp/libopenmpttest-EQ.obj: sounddsp/EQ.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-EQ.obj -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-EQ.Tpo -c -o sounddsp/libopenmpttest-EQ.obj `if test -f 'sounddsp/EQ.cpp'; then $(CYGPATH_W) 'sounddsp/EQ.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/EQ.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-EQ.Tpo sounddsp/$(DEPDIR)/libopenmpttest-EQ.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/EQ.cpp' object='sounddsp/libopenmpttest-EQ.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-EQ.obj `if test -f 'sounddsp/EQ.cpp'; then $(CYGPATH_W) 'sounddsp/EQ.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/EQ.cpp'; fi` sounddsp/libopenmpttest-Reverb.o: sounddsp/Reverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-Reverb.o -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Tpo -c -o sounddsp/libopenmpttest-Reverb.o `test -f 'sounddsp/Reverb.cpp' || echo '$(srcdir)/'`sounddsp/Reverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Tpo sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/Reverb.cpp' object='sounddsp/libopenmpttest-Reverb.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-Reverb.o `test -f 'sounddsp/Reverb.cpp' || echo '$(srcdir)/'`sounddsp/Reverb.cpp sounddsp/libopenmpttest-Reverb.obj: sounddsp/Reverb.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-Reverb.obj -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Tpo -c -o sounddsp/libopenmpttest-Reverb.obj `if test -f 'sounddsp/Reverb.cpp'; then $(CYGPATH_W) 'sounddsp/Reverb.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/Reverb.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Tpo sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sounddsp/Reverb.cpp' object='sounddsp/libopenmpttest-Reverb.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-Reverb.obj `if test -f 'sounddsp/Reverb.cpp'; then $(CYGPATH_W) 'sounddsp/Reverb.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/Reverb.cpp'; fi` libopenmpt/libopenmpttest-libopenmpt_c.o: libopenmpt/libopenmpt_c.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_c.o -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_c.o `test -f 'libopenmpt/libopenmpt_c.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_c.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_c.cpp' object='libopenmpt/libopenmpttest-libopenmpt_c.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_c.o `test -f 'libopenmpt/libopenmpt_c.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_c.cpp libopenmpt/libopenmpttest-libopenmpt_c.obj: libopenmpt/libopenmpt_c.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_c.obj -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_c.obj `if test -f 'libopenmpt/libopenmpt_c.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_c.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_c.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_c.cpp' object='libopenmpt/libopenmpttest-libopenmpt_c.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_c.obj `if test -f 'libopenmpt/libopenmpt_c.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_c.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_c.cpp'; fi` libopenmpt/libopenmpttest-libopenmpt_cxx.o: libopenmpt/libopenmpt_cxx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_cxx.o -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_cxx.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_cxx.o `test -f 'libopenmpt/libopenmpt_cxx.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_cxx.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_cxx.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_cxx.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_cxx.cpp' object='libopenmpt/libopenmpttest-libopenmpt_cxx.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_cxx.o `test -f 'libopenmpt/libopenmpt_cxx.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_cxx.cpp libopenmpt/libopenmpttest-libopenmpt_cxx.obj: libopenmpt/libopenmpt_cxx.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_cxx.obj -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_cxx.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_cxx.obj `if test -f 'libopenmpt/libopenmpt_cxx.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_cxx.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_cxx.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_cxx.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_cxx.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_cxx.cpp' object='libopenmpt/libopenmpttest-libopenmpt_cxx.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_cxx.obj `if test -f 'libopenmpt/libopenmpt_cxx.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_cxx.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_cxx.cpp'; fi` libopenmpt/libopenmpttest-libopenmpt_ext_impl.o: libopenmpt/libopenmpt_ext_impl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_ext_impl.o -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_ext_impl.o `test -f 'libopenmpt/libopenmpt_ext_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext_impl.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_ext_impl.cpp' object='libopenmpt/libopenmpttest-libopenmpt_ext_impl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_ext_impl.o `test -f 'libopenmpt/libopenmpt_ext_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext_impl.cpp libopenmpt/libopenmpttest-libopenmpt_ext_impl.obj: libopenmpt/libopenmpt_ext_impl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_ext_impl.obj -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_ext_impl.obj `if test -f 'libopenmpt/libopenmpt_ext_impl.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_ext_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_ext_impl.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_ext_impl.cpp' object='libopenmpt/libopenmpttest-libopenmpt_ext_impl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_ext_impl.obj `if test -f 'libopenmpt/libopenmpt_ext_impl.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_ext_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_ext_impl.cpp'; fi` libopenmpt/libopenmpttest-libopenmpt_impl.o: libopenmpt/libopenmpt_impl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_impl.o -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_impl.o `test -f 'libopenmpt/libopenmpt_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_impl.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_impl.cpp' object='libopenmpt/libopenmpttest-libopenmpt_impl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_impl.o `test -f 'libopenmpt/libopenmpt_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_impl.cpp libopenmpt/libopenmpttest-libopenmpt_impl.obj: libopenmpt/libopenmpt_impl.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_impl.obj -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_impl.obj `if test -f 'libopenmpt/libopenmpt_impl.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_impl.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_impl.cpp' object='libopenmpt/libopenmpttest-libopenmpt_impl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_impl.obj `if test -f 'libopenmpt/libopenmpt_impl.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_impl.cpp'; fi` libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.o: libopenmpt/libopenmpt_test/libopenmpt_test.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.o -MD -MP -MF libopenmpt/libopenmpt_test/$(DEPDIR)/libopenmpttest-libopenmpt_test.Tpo -c -o libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.o `test -f 'libopenmpt/libopenmpt_test/libopenmpt_test.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_test/libopenmpt_test.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/libopenmpt_test/$(DEPDIR)/libopenmpttest-libopenmpt_test.Tpo libopenmpt/libopenmpt_test/$(DEPDIR)/libopenmpttest-libopenmpt_test.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_test/libopenmpt_test.cpp' object='libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.o `test -f 'libopenmpt/libopenmpt_test/libopenmpt_test.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_test/libopenmpt_test.cpp libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.obj: libopenmpt/libopenmpt_test/libopenmpt_test.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.obj -MD -MP -MF libopenmpt/libopenmpt_test/$(DEPDIR)/libopenmpttest-libopenmpt_test.Tpo -c -o libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.obj `if test -f 'libopenmpt/libopenmpt_test/libopenmpt_test.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_test/libopenmpt_test.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_test/libopenmpt_test.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libopenmpt/libopenmpt_test/$(DEPDIR)/libopenmpttest-libopenmpt_test.Tpo libopenmpt/libopenmpt_test/$(DEPDIR)/libopenmpttest-libopenmpt_test.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libopenmpt/libopenmpt_test/libopenmpt_test.cpp' object='libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpt_test/libopenmpttest-libopenmpt_test.obj `if test -f 'libopenmpt/libopenmpt_test/libopenmpt_test.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_test/libopenmpt_test.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_test/libopenmpt_test.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs -rm -rf bin/.libs bin/_libs -rm -rf common/.libs common/_libs -rm -rf libopenmpt/.libs libopenmpt/_libs -rm -rf sounddsp/.libs sounddsp/_libs -rm -rf soundlib/.libs soundlib/_libs -rm -rf soundlib/plugins/.libs soundlib/plugins/_libs -rm -rf soundlib/plugins/dmo/.libs soundlib/plugins/dmo/_libs distclean-libtool: -rm -f libtool config.lt install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-dist_docDATA: $(dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) install-nobase_dist_docDATA: $(nobase_dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(nobase_dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ $(am__nobase_list) | while read dir files; do \ xfiles=; for file in $$files; do \ if test -f "$$file"; then xfiles="$$xfiles $$file"; \ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ test -z "$$xfiles" || { \ test "x$$dir" = x. || { \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)/$$dir"; }; \ echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(docdir)/$$dir'"; \ $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(docdir)/$$dir" || exit $$?; }; \ done uninstall-nobase_dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(nobase_dist_doc_DATA)'; test -n "$(docdir)" || list=; \ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) install-includelibopenmptHEADERS: $(includelibopenmpt_HEADERS) @$(NORMAL_INSTALL) @list='$(includelibopenmpt_HEADERS)'; test -n "$(includelibopenmptdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(includelibopenmptdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(includelibopenmptdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includelibopenmptdir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includelibopenmptdir)" || exit $$?; \ done uninstall-includelibopenmptHEADERS: @$(NORMAL_UNINSTALL) @list='$(includelibopenmpt_HEADERS)'; test -n "$(includelibopenmptdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(includelibopenmptdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ elif test -n "$$redo_logs"; then \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: $(check_PROGRAMS) @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all $(check_PROGRAMS) @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? libopenmpttest.log: libopenmpttest$(EXEEXT) @p='libopenmpttest$(EXEEXT)'; \ b='libopenmpttest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) .test.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) @am__EXEEXT_TRUE@.test$(EXEEXT).log: @am__EXEEXT_TRUE@ @p='$<'; \ @am__EXEEXT_TRUE@ $(am__set_b); \ @am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-zstd: distdir tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(MANS) $(DATA) $(HEADERS) install-binPROGRAMS: install-libLTLIBRARIES install-checkPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includelibopenmptdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f bin/$(am__dirstamp) -rm -f common/$(DEPDIR)/$(am__dirstamp) -rm -f common/$(am__dirstamp) -rm -f examples/$(DEPDIR)/$(am__dirstamp) -rm -f examples/$(am__dirstamp) -rm -f libopenmpt/$(DEPDIR)/$(am__dirstamp) -rm -f libopenmpt/$(am__dirstamp) -rm -f libopenmpt/libopenmpt_test/$(DEPDIR)/$(am__dirstamp) -rm -f libopenmpt/libopenmpt_test/$(am__dirstamp) -rm -f openmpt123/$(DEPDIR)/$(am__dirstamp) -rm -f openmpt123/$(am__dirstamp) -rm -f sounddsp/$(DEPDIR)/$(am__dirstamp) -rm -f sounddsp/$(am__dirstamp) -rm -f soundlib/$(DEPDIR)/$(am__dirstamp) -rm -f soundlib/$(am__dirstamp) -rm -f soundlib/plugins/$(DEPDIR)/$(am__dirstamp) -rm -f soundlib/plugins/$(am__dirstamp) -rm -f soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp) -rm -f soundlib/plugins/dmo/$(am__dirstamp) -rm -f src/openmpt/soundfile_write/$(DEPDIR)/$(am__dirstamp) -rm -f src/openmpt/soundfile_write/$(am__dirstamp) -rm -f test/$(DEPDIR)/$(am__dirstamp) -rm -f test/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f common/$(DEPDIR)/libopenmpt_la-ComponentManager.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-Logging.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-Profiler.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-mptFileType.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-mptPathString.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-mptRandom.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-mptStringBuffer.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-mptTime.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-serialization_utils.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-version.Plo -rm -f common/$(DEPDIR)/libopenmpttest-ComponentManager.Po -rm -f common/$(DEPDIR)/libopenmpttest-Logging.Po -rm -f common/$(DEPDIR)/libopenmpttest-Profiler.Po -rm -f common/$(DEPDIR)/libopenmpttest-mptFileType.Po -rm -f common/$(DEPDIR)/libopenmpttest-mptPathString.Po -rm -f common/$(DEPDIR)/libopenmpttest-mptRandom.Po -rm -f common/$(DEPDIR)/libopenmpttest-mptStringBuffer.Po -rm -f common/$(DEPDIR)/libopenmpttest-mptTime.Po -rm -f common/$(DEPDIR)/libopenmpttest-serialization_utils.Po -rm -f common/$(DEPDIR)/libopenmpttest-version.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c-libopenmpt_example_c.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c_mem-libopenmpt_example_c_mem.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c_probe-libopenmpt_example_c_probe.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Po -rm -f libopenmpt/$(DEPDIR)/la-libopenmpt_c.Plo -rm -f libopenmpt/$(DEPDIR)/la-libopenmpt_cxx.Plo -rm -f libopenmpt/$(DEPDIR)/la-libopenmpt_ext_impl.Plo -rm -f libopenmpt/$(DEPDIR)/la-libopenmpt_impl.Plo -rm -f libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Po -rm -f libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_cxx.Po -rm -f libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Po -rm -f libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Po -rm -f libopenmpt/libopenmpt_test/$(DEPDIR)/libopenmpttest-libopenmpt_test.Po -rm -f openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Po -rm -f sounddsp/$(DEPDIR)/libopenmpt_la-AGC.Plo -rm -f sounddsp/$(DEPDIR)/libopenmpt_la-DSP.Plo -rm -f sounddsp/$(DEPDIR)/libopenmpt_la-EQ.Plo -rm -f sounddsp/$(DEPDIR)/libopenmpt_la-Reverb.Plo -rm -f sounddsp/$(DEPDIR)/libopenmpttest-AGC.Po -rm -f sounddsp/$(DEPDIR)/libopenmpttest-DSP.Po -rm -f sounddsp/$(DEPDIR)/libopenmpttest-EQ.Po -rm -f sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Po -rm -f soundlib/$(DEPDIR)/libopenmpt_la-AudioCriticalSection.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ContainerMMCMP.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ContainerPP20.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ContainerUMX.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ContainerXPK.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Dlsbank.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Fastmix.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ITCompression.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ITTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-InstrumentExtensions.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-InstrumentSynth.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_667.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_669.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_amf.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ams.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_c67.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_cba.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_dbm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_digi.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_dmf.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_dsm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_dsym.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_dtm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_etx.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_far.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_fc.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_fmt.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ftm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_gdm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_gmc.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_gt2.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ice.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_imf.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ims.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_it.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_itp.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_kris.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mdl.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_med.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mid.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mo3.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mod.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mt2.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mtm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mus_km.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_okt.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_plm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_psm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_pt36.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ptm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_puma.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_rtm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_s3m.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_sfx.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_stk.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_stm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_stp.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_symmod.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_tcb.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_uax.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ult.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_unic.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_wav.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_xm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_xmf.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MIDIEvents.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacroParser.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacros.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MODTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MPEGFrame.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Message.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MixFuncTable.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MixerLoops.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MixerSettings.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ModChannel.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ModInstrument.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ModSample.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ModSequence.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-OPL.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-OggStream.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Paula.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-PlayState.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-PlaybackTest.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-RowVisitor.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-S3MTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatBRR.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatFLAC.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMP3.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMediaFoundation.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatOpus.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatSFZ.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatVorbis.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormats.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleIO.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Snd_flt.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Snd_fx.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Sndfile.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Sndmix.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SoundFilePlayConfig.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Tables.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Tagging.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-TinyFFT.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-UMXTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-UpgradeModule.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-WAVTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-WindowedFIR.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-XMTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-load_j2b.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-mod_specifications.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-modcommand.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-modsmp_ctrl.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-pattern.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-patternContainer.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-tuning.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-tuningCollection.Plo -rm -f soundlib/$(DEPDIR)/libopenmpttest-AudioCriticalSection.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Dlsbank.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Fastmix.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ITCompression.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ITTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-InstrumentExtensions.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-InstrumentSynth.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_667.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_669.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_amf.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ams.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_c67.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_cba.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_dbm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_digi.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_dmf.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_dsm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_dsym.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_etx.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_far.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_fc.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_fmt.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ftm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_gdm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_gmc.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_gt2.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ice.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_imf.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ims.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_it.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_itp.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_kris.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mdl.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_med.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mid.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mo3.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mod.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mt2.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mtm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mus_km.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_okt.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_plm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_psm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_pt36.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ptm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_puma.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_rtm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_s3m.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_sfx.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_stk.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_stm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_symmod.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_tcb.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_unic.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_xm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_xmf.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MIDIEvents.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MIDIMacroParser.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MIDIMacros.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MODTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MPEGFrame.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Message.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MixFuncTable.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MixerLoops.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MixerSettings.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ModInstrument.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ModSample.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ModSequence.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-OPL.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-OggStream.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Paula.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-PlayState.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-PlaybackTest.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-RowVisitor.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-S3MTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatBRR.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatSFZ.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormats.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Snd_flt.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Snd_fx.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Sndfile.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Sndmix.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SoundFilePlayConfig.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Tables.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Tagging.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-TinyFFT.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-WAVTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-WindowedFIR.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-XMTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-load_j2b.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-mod_specifications.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-modcommand.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-modsmp_ctrl.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-pattern.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-tuning.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-tuningCollection.Po -rm -f soundlib/plugins/$(DEPDIR)/libopenmpt_la-DigiBoosterEcho.Plo -rm -f soundlib/plugins/$(DEPDIR)/libopenmpt_la-LFOPlugin.Plo -rm -f soundlib/plugins/$(DEPDIR)/libopenmpt_la-PlugInterface.Plo -rm -f soundlib/plugins/$(DEPDIR)/libopenmpt_la-PluginManager.Plo -rm -f soundlib/plugins/$(DEPDIR)/libopenmpt_la-SymMODEcho.Plo -rm -f soundlib/plugins/$(DEPDIR)/libopenmpttest-DigiBoosterEcho.Po -rm -f soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Po -rm -f soundlib/plugins/$(DEPDIR)/libopenmpttest-PlugInterface.Po -rm -f soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Po -rm -f soundlib/plugins/$(DEPDIR)/libopenmpttest-SymMODEcho.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Chorus.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Compressor.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOPlugin.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOUtils.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Distortion.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Echo.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Flanger.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Gargle.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-I3DL2Reverb.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-ParamEq.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-WavesReverb.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOPlugin.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOUtils.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Distortion.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Echo.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-WavesReverb.Po -rm -f src/openmpt/soundfile_write/$(DEPDIR)/libopenmpttest-wav_write.Po -rm -f test/$(DEPDIR)/libopenmpttest-TestToolsLib.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_base.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_binary.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_crc.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_endian.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_format.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_io.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_parse.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_random.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_string.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_string_transcode.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_uuid.Po -rm -f test/$(DEPDIR)/libopenmpttest-test.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_docDATA install-includelibopenmptHEADERS \ install-man install-nobase_dist_docDATA install-pkgconfigDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f common/$(DEPDIR)/libopenmpt_la-ComponentManager.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-Logging.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-Profiler.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-mptFileType.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-mptPathString.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-mptRandom.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-mptStringBuffer.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-mptTime.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-serialization_utils.Plo -rm -f common/$(DEPDIR)/libopenmpt_la-version.Plo -rm -f common/$(DEPDIR)/libopenmpttest-ComponentManager.Po -rm -f common/$(DEPDIR)/libopenmpttest-Logging.Po -rm -f common/$(DEPDIR)/libopenmpttest-Profiler.Po -rm -f common/$(DEPDIR)/libopenmpttest-mptFileType.Po -rm -f common/$(DEPDIR)/libopenmpttest-mptPathString.Po -rm -f common/$(DEPDIR)/libopenmpttest-mptRandom.Po -rm -f common/$(DEPDIR)/libopenmpttest-mptStringBuffer.Po -rm -f common/$(DEPDIR)/libopenmpttest-mptTime.Po -rm -f common/$(DEPDIR)/libopenmpttest-serialization_utils.Po -rm -f common/$(DEPDIR)/libopenmpttest-version.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c-libopenmpt_example_c.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c_mem-libopenmpt_example_c_mem.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c_pipe-libopenmpt_example_c_pipe.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c_probe-libopenmpt_example_c_probe.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c_stdout-libopenmpt_example_c_stdout.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_c_unsafe-libopenmpt_example_c_unsafe.Po -rm -f examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Po -rm -f libopenmpt/$(DEPDIR)/la-libopenmpt_c.Plo -rm -f libopenmpt/$(DEPDIR)/la-libopenmpt_cxx.Plo -rm -f libopenmpt/$(DEPDIR)/la-libopenmpt_ext_impl.Plo -rm -f libopenmpt/$(DEPDIR)/la-libopenmpt_impl.Plo -rm -f libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Po -rm -f libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_cxx.Po -rm -f libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Po -rm -f libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Po -rm -f libopenmpt/libopenmpt_test/$(DEPDIR)/libopenmpttest-libopenmpt_test.Po -rm -f openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Po -rm -f sounddsp/$(DEPDIR)/libopenmpt_la-AGC.Plo -rm -f sounddsp/$(DEPDIR)/libopenmpt_la-DSP.Plo -rm -f sounddsp/$(DEPDIR)/libopenmpt_la-EQ.Plo -rm -f sounddsp/$(DEPDIR)/libopenmpt_la-Reverb.Plo -rm -f sounddsp/$(DEPDIR)/libopenmpttest-AGC.Po -rm -f sounddsp/$(DEPDIR)/libopenmpttest-DSP.Po -rm -f sounddsp/$(DEPDIR)/libopenmpttest-EQ.Po -rm -f sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Po -rm -f soundlib/$(DEPDIR)/libopenmpt_la-AudioCriticalSection.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ContainerMMCMP.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ContainerPP20.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ContainerUMX.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ContainerXPK.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Dlsbank.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Fastmix.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ITCompression.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ITTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-InstrumentExtensions.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-InstrumentSynth.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_667.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_669.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_amf.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ams.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_c67.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_cba.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_dbm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_digi.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_dmf.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_dsm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_dsym.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_dtm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_etx.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_far.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_fc.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_fmt.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ftm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_gdm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_gmc.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_gt2.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ice.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_imf.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ims.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_it.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_itp.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_kris.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mdl.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_med.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mid.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mo3.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mod.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mt2.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mtm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_mus_km.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_okt.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_plm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_psm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_pt36.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ptm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_puma.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_rtm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_s3m.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_sfx.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_stk.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_stm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_stp.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_symmod.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_tcb.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_uax.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_ult.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_unic.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_wav.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_xm.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Load_xmf.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MIDIEvents.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacroParser.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MIDIMacros.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MODTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MPEGFrame.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Message.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MixFuncTable.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MixerLoops.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-MixerSettings.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ModChannel.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ModInstrument.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ModSample.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-ModSequence.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-OPL.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-OggStream.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Paula.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-PlayState.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-PlaybackTest.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-RowVisitor.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-S3MTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatBRR.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatFLAC.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMP3.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMediaFoundation.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatOpus.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatSFZ.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatVorbis.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleFormats.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SampleIO.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Snd_flt.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Snd_fx.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Sndfile.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Sndmix.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-SoundFilePlayConfig.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Tables.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-Tagging.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-TinyFFT.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-UMXTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-UpgradeModule.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-WAVTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-WindowedFIR.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-XMTools.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-load_j2b.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-mod_specifications.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-modcommand.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-modsmp_ctrl.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-pattern.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-patternContainer.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-tuning.Plo -rm -f soundlib/$(DEPDIR)/libopenmpt_la-tuningCollection.Plo -rm -f soundlib/$(DEPDIR)/libopenmpttest-AudioCriticalSection.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Dlsbank.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Fastmix.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ITCompression.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ITTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-InstrumentExtensions.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-InstrumentSynth.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_667.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_669.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_amf.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ams.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_c67.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_cba.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_dbm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_digi.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_dmf.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_dsm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_dsym.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_etx.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_far.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_fc.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_fmt.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ftm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_gdm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_gmc.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_gt2.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ice.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_imf.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ims.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_it.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_itp.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_kris.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mdl.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_med.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mid.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mo3.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mod.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mt2.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mtm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_mus_km.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_okt.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_plm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_psm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_pt36.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ptm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_puma.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_rtm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_s3m.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_sfx.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_stk.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_stm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_symmod.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_tcb.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_unic.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_xm.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Load_xmf.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MIDIEvents.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MIDIMacroParser.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MIDIMacros.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MODTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MPEGFrame.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Message.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MixFuncTable.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MixerLoops.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-MixerSettings.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ModInstrument.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ModSample.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-ModSequence.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-OPL.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-OggStream.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Paula.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-PlayState.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-PlaybackTest.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-RowVisitor.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-S3MTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatBRR.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatSFZ.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleFormats.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Snd_flt.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Snd_fx.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Sndfile.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Sndmix.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-SoundFilePlayConfig.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Tables.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-Tagging.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-TinyFFT.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-WAVTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-WindowedFIR.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-XMTools.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-load_j2b.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-mod_specifications.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-modcommand.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-modsmp_ctrl.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-pattern.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-tuning.Po -rm -f soundlib/$(DEPDIR)/libopenmpttest-tuningCollection.Po -rm -f soundlib/plugins/$(DEPDIR)/libopenmpt_la-DigiBoosterEcho.Plo -rm -f soundlib/plugins/$(DEPDIR)/libopenmpt_la-LFOPlugin.Plo -rm -f soundlib/plugins/$(DEPDIR)/libopenmpt_la-PlugInterface.Plo -rm -f soundlib/plugins/$(DEPDIR)/libopenmpt_la-PluginManager.Plo -rm -f soundlib/plugins/$(DEPDIR)/libopenmpt_la-SymMODEcho.Plo -rm -f soundlib/plugins/$(DEPDIR)/libopenmpttest-DigiBoosterEcho.Po -rm -f soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Po -rm -f soundlib/plugins/$(DEPDIR)/libopenmpttest-PlugInterface.Po -rm -f soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Po -rm -f soundlib/plugins/$(DEPDIR)/libopenmpttest-SymMODEcho.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Chorus.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Compressor.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOPlugin.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOUtils.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Distortion.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Echo.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Flanger.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Gargle.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-I3DL2Reverb.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-ParamEq.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-WavesReverb.Plo -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOPlugin.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOUtils.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Distortion.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Echo.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Po -rm -f soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-WavesReverb.Po -rm -f src/openmpt/soundfile_write/$(DEPDIR)/libopenmpttest-wav_write.Po -rm -f test/$(DEPDIR)/libopenmpttest-TestToolsLib.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_base.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_binary.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_crc.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_endian.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_format.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_io.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_parse.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_random.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_string.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_string_transcode.Po -rm -f test/$(DEPDIR)/libopenmpttest-mpt_tests_uuid.Po -rm -f test/$(DEPDIR)/libopenmpttest-test.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_docDATA \ uninstall-includelibopenmptHEADERS uninstall-libLTLIBRARIES \ uninstall-man uninstall-nobase_dist_docDATA \ uninstall-pkgconfigDATA uninstall-man: uninstall-man1 .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles am--refresh check \ check-TESTS check-am clean clean-binPROGRAMS \ clean-checkPROGRAMS clean-cscope clean-generic \ clean-libLTLIBRARIES clean-libtool cscope cscopelist-am ctags \ ctags-am dist dist-all dist-bzip2 dist-gzip dist-lzip \ dist-shar dist-tarZ dist-xz dist-zip dist-zstd distcheck \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dist_docDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-includelibopenmptHEADERS install-info \ install-info-am install-libLTLIBRARIES install-man \ install-man1 install-nobase_dist_docDATA install-pdf \ install-pdf-am install-pkgconfigDATA install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am recheck tags tags-am uninstall \ uninstall-am uninstall-binPROGRAMS uninstall-dist_docDATA \ uninstall-includelibopenmptHEADERS uninstall-libLTLIBRARIES \ uninstall-man uninstall-man1 uninstall-nobase_dist_docDATA \ uninstall-pkgconfigDATA .PRECIOUS: Makefile @DX_RULES@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: libopenmpt-0.8.1+release.autotools/openmpt123/0000755000175000017500000000000015023302363016243 500000000000000libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_raw.hpp0000644000175000017500000000360314345637247021501 00000000000000/* * openmpt123_raw.hpp * ------------------ * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_RAW_HPP #define OPENMPT123_RAW_HPP #include "openmpt123_config.hpp" #include "openmpt123.hpp" #include namespace openmpt123 { class raw_stream_raii : public file_audio_stream_base { private: commandlineflags flags; mpt::IO::ofstream file; std::vector interleaved_float_buffer; std::vector interleaved_int_buffer; public: raw_stream_raii( const mpt::native_path & filename, const commandlineflags & flags_, concat_stream & /*log*/ ) : flags(flags_), file(filename, std::ios::binary) { return; } ~raw_stream_raii() { return; } void write_metadata( std::map /* metadata */ ) override { return; } void write( const std::vector buffers, std::size_t frames ) override { interleaved_float_buffer.clear(); for ( std::size_t frame = 0; frame < frames; frame++ ) { for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { interleaved_float_buffer.push_back( buffers[channel][frame] ); } } file.write( reinterpret_cast( interleaved_float_buffer.data() ), frames * buffers.size() * sizeof( float ) ); } void write( const std::vector buffers, std::size_t frames ) override { interleaved_int_buffer.clear(); for ( std::size_t frame = 0; frame < frames; frame++ ) { for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { interleaved_int_buffer.push_back( buffers[channel][frame] ); } } file.write( reinterpret_cast( interleaved_int_buffer.data() ), frames * buffers.size() * sizeof( std::int16_t ) ); } }; } // namespace openmpt123 #endif // OPENMPT123_RAW_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_flac.hpp0000644000175000017500000001660114766272237021620 00000000000000/* * openmpt123_flac.hpp * ------------------- * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_FLAC_HPP #define OPENMPT123_FLAC_HPP #include "openmpt123_config.hpp" #include "openmpt123.hpp" #if defined(MPT_WITH_FLAC) #include "mpt/base/detect.hpp" #include "mpt/base/saturate_round.hpp" #include #if MPT_PLATFORM_MULTITHREADED && !defined(MPT_COMPILER_QUIRK_NO_STDCPP_THREADS) #include #endif #if defined(_MSC_VER) && defined(__clang__) && defined(__c2__) #include #if __STDC__ typedef _off_t off_t; #endif #endif #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif #include #include #include #if defined(__clang__) #pragma clang diagnostic pop #endif namespace openmpt123 { inline constexpr auto flac_encoding = mpt::common_encoding::utf8; class flac_stream_raii : public file_audio_stream_base { private: commandlineflags flags; mpt::native_path filename; bool called_init; std::vector< std::pair< std::string, std::string > > tags; FLAC__StreamMetadata * flac_metadata[1]; FLAC__StreamEncoder * encoder; std::vector interleaved_buffer; void add_vorbiscomment_field( FLAC__StreamMetadata * vorbiscomment, const std::string & field, const std::string & value ) { if ( !value.empty() ) { FLAC__StreamMetadata_VorbisComment_Entry entry; FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair( &entry, field.c_str(), value.c_str() ); FLAC__metadata_object_vorbiscomment_append_comment( vorbiscomment, entry, false ); } } public: flac_stream_raii( const mpt::native_path & filename_, const commandlineflags & flags_, concat_stream & /*log*/ ) : flags(flags_), filename(filename_), called_init(false), encoder(0) { flac_metadata[0] = 0; encoder = FLAC__stream_encoder_new(); if ( !encoder ) { throw exception( MPT_USTRING("error creating flac encoder") ); } FLAC__stream_encoder_set_channels( encoder, flags.channels ); FLAC__stream_encoder_set_bits_per_sample( encoder, flags.use_float ? 24 : 16 ); FLAC__stream_encoder_set_sample_rate( encoder, flags.samplerate ); FLAC__stream_encoder_set_compression_level( encoder, 8 ); #if (FLAC_API_VERSION_CURRENT >= 14) && MPT_PLATFORM_MULTITHREADED && !defined(MPT_COMPILER_QUIRK_NO_STDCPP_THREADS) std::uint32_t threads = static_cast(std::max(std::thread::hardware_concurrency(), static_cast(1))); // Work-around . //FLAC__stream_encoder_set_num_threads( encoder, threads ); while ( ( FLAC__stream_encoder_set_num_threads( encoder, threads ) == FLAC__STREAM_ENCODER_SET_NUM_THREADS_TOO_MANY_THREADS ) && ( threads > 1 ) ) { threads = ( ( threads > 256 ) ? 256 : ( threads - 1 ) ); } #endif } ~flac_stream_raii() { if ( encoder ) { FLAC__stream_encoder_finish( encoder ); FLAC__stream_encoder_delete( encoder ); encoder = 0; } if ( flac_metadata[0] ) { FLAC__metadata_object_delete( flac_metadata[0] ); flac_metadata[0] = 0; } } void write_metadata( std::map metadata ) override { if ( called_init ) { return; } tags.clear(); tags.push_back( std::make_pair( "TITLE", mpt::transcode( flac_encoding, metadata[ MPT_USTRING("title") ] ) ) ); tags.push_back( std::make_pair( "ARTIST", mpt::transcode( flac_encoding, metadata[ MPT_USTRING("artist") ] ) ) ); tags.push_back( std::make_pair( "DATE", mpt::transcode( flac_encoding, metadata[ MPT_USTRING("date") ] ) ) ); tags.push_back( std::make_pair( "COMMENT", mpt::transcode( flac_encoding, metadata[ MPT_USTRING("message") ] ) ) ); if ( !metadata[ MPT_USTRING("type") ].empty() && !metadata[ MPT_USTRING("tracker") ].empty() ) { tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "'" + mpt::transcode( flac_encoding, metadata[ MPT_USTRING("type") ] ) + "' tracked music file, made with '" + mpt::transcode( flac_encoding, metadata[ MPT_USTRING("tracker") ] ) + "', rendered with '" + mpt::transcode( flac_encoding, get_encoder_tag() ) + "'" ) ); } else if ( !metadata[ MPT_USTRING("type_long") ].empty() ) { tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "'" + mpt::transcode( flac_encoding, metadata[ MPT_USTRING("type") ] ) + "' tracked music file, rendered with '" + mpt::transcode( flac_encoding, get_encoder_tag() ) + "'" ) ); } else if ( !metadata[ MPT_USTRING("tracker") ].empty() ) { tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "tracked music file, made with '" + mpt::transcode( flac_encoding, metadata[ MPT_USTRING("tracker") ] ) + "', rendered with '" + mpt::transcode( flac_encoding, get_encoder_tag() ) + "'" ) ); } else { tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "tracked music file, rendered with '" + mpt::transcode( flac_encoding, get_encoder_tag() ) + "'" ) ); } tags.push_back( std::make_pair( "ENCODER", mpt::transcode( flac_encoding, get_encoder_tag() ) ) ); flac_metadata[0] = FLAC__metadata_object_new( FLAC__METADATA_TYPE_VORBIS_COMMENT ); for ( std::vector< std::pair< std::string, std::string > >::iterator tag = tags.begin(); tag != tags.end(); ++tag ) { add_vorbiscomment_field( flac_metadata[0], tag->first, tag->second ); } FLAC__stream_encoder_set_metadata( encoder, flac_metadata, 1 ); } void write( const std::vector buffers, std::size_t frames ) override { if ( !called_init ) { #if MPT_OS_WINDOWS FLAC__stream_encoder_init_file( encoder, mpt::transcode( flac_encoding, filename ).c_str(), NULL, 0 ); #else FLAC__stream_encoder_init_file( encoder, filename.AsNative().c_str(), NULL, 0 ); #endif called_init = true; } interleaved_buffer.clear(); for ( std::size_t frame = 0; frame < frames; frame++ ) { for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { float in = buffers[channel][frame]; if ( in <= -1.0f ) { in = -1.0f; } else if ( in >= 1.0f ) { in = 1.0f; } FLAC__int32 out = mpt::saturate_round( in * (1<<23) ); out = std::max( 0 - (1<<23), out ); out = std::min( out, 0 + (1<<23) - 1 ); interleaved_buffer.push_back( out ); } } FLAC__stream_encoder_process_interleaved( encoder, interleaved_buffer.data(), static_cast( frames ) ); } void write( const std::vector buffers, std::size_t frames ) override { if ( !called_init ) { #if MPT_OS_WINDOWS FLAC__stream_encoder_init_file( encoder, mpt::transcode( flac_encoding, filename ).c_str(), NULL, 0 ); #else FLAC__stream_encoder_init_file( encoder, filename.AsNative().c_str(), NULL, 0 ); #endif called_init = true; } interleaved_buffer.clear(); for ( std::size_t frame = 0; frame < frames; frame++ ) { for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { interleaved_buffer.push_back( buffers[channel][frame] ); } } FLAC__stream_encoder_process_interleaved( encoder, interleaved_buffer.data(), static_cast( frames ) ); } }; } // namespace openmpt123 #endif // MPT_WITH_FLAC #endif // OPENMPT123_FLAC_HPP libopenmpt-0.8.1+release.autotools/openmpt123/.clang-format0000644000175000017500000001141114275750533020552 00000000000000# clang-format 14 Language: Cpp Standard: c++20 AccessModifierOffset: -2 #? AlignAfterOpenBracket: AlwaysBreak AlignArrayOfStructures: Left AlignConsecutiveAssignments: false AlignConsecutiveBitFields: false AlignConsecutiveDeclarations: false AlignConsecutiveMacros: true AlignEscapedNewlines: DontAlign AlignOperands: AlignAfterOperator AlignTrailingComments: true AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: Never AllowShortCaseLabelsOnASingleLine: false AllowShortEnumsOnASingleLine: false AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: false AllowShortLambdasOnASingleLine: Inline AllowShortLoopsOnASingleLine: false AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: Yes AttributeMacros: [] BinPackArguments: true BinPackParameters: false BitFieldColonSpacing: Both BraceWrapping: AfterCaseLabel: true AfterClass: false AfterControlStatement: MultiLine AfterEnum: false AfterFunction: false AfterNamespace: false #AfterObjCDeclaration AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false BeforeLambdaBody: true BeforeWhile: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: false SplitEmptyNamespace: true #BreakAfterJavaFieldAnnotations BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Custom BreakBeforeConceptDeclarations: true BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeComma BreakInheritanceList: BeforeComma BreakStringLiterals: false ColumnLimit: 0 CommentPragmas: '' #? CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 2 #? ContinuationIndentWidth: 2 #? Cpp11BracedListStyle: true DeriveLineEnding: true DerivePointerAlignment: false EmptyLineAfterAccessModifier: Leave EmptyLineBeforeAccessModifier: Leave FixNamespaceComments: true ForEachMacros: [] IfMacros: ['MPT_MAYBE_CONSTANT_IF'] IncludeBlocks: Preserve IncludeCategories: [] #? IncludeIsMainRegex: '' #? IncludeIsMainSourceRegex: '' #? IndentAccessModifiers: false IndentCaseBlocks: true IndentCaseLabels: true IndentExternBlock: NoIndent IndentGotoLabels: false IndentPPDirectives: None #IndentRequiresClause: true #BeforeHash IndentWidth: 2 IndentWrappedFunctionNames: true InsertTrailingCommas: None #JavaImportGroups #JavaScriptQuotes #JavaScriptWrapImports KeepEmptyLinesAtTheStartOfBlocks: true LambdaBodyIndentation: OuterScope MacroBlockBegin: '' #? MacroBlockEnd: '' #? MaxEmptyLinesToKeep: 3 NamespaceIndentation: None NamespaceMacros: [] #? #ObjCBinPackProtocolList #ObjCBlockIndentWidth #ObjCBreakBeforeNestedBlockParam #ObjCSpaceAfterProperty #ObjCSpaceBeforeProtocolList PackConstructorInitializers: Never #PenaltyBreakAssignment #PenaltyBreakBeforeFirstCallParameter #PenaltyBreakComment #PenaltyBreakFirstLessLess #PenaltyBreakOpenParenthesis #PenaltyBreakString #PenaltyBreakTemplateDeclaration #PenaltyExcessCharacter #PenaltyIndentedWhitespace #PenaltyReturnTypeOnItsOwnLine PointerAlignment: Middle PPIndentWidth: -1 #RawStringFormats QualifierAlignment: Leave #QualifierOrder: ['static', 'inline', 'constexpr', 'volatile', 'const', 'restrict', 'type'] ReferenceAlignment: Pointer ReflowComments: false RemoveBracesLLVM: false SeparateDefinitionBlocks: Leave ShortNamespaceLines: 1 SortIncludes: false #SortJavaStaticImport SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true SpaceAroundPointerQualifiers: Default SpaceBeforeAssignmentOperators: true SpaceBeforeCaseColon: false SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeParensOptions: AfterControlStatements: true AfterForeachMacros: true AfterFunctionDeclarationName: false AfterFunctionDefinitionName: false AfterIfMacros: true AfterOverloadedOperator: false #AfterRequiresInClause: false #AfterRequiresInExpression: false BeforeNonEmptyParentheses: false SpaceBeforeRangeBasedForLoopColon: true SpaceBeforeSquareBrackets: false SpaceInEmptyBlock: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInConditionalStatement: true SpacesInContainerLiterals: true SpacesInLineCommentPrefix: Minimum: 1 Maximum: -1 SpacesInParentheses: true SpacesInSquareBrackets: false StatementAttributeLikeMacros: [] StatementMacros: [ 'MPT_WARNING', 'MPT_TEST_GROUP_INLINE_IDENTIFIER', 'MPT_TEST_GROUP_INLINE', 'MPT_TEST_GROUP_STATIC' ] #? TabWidth: 2 TypenameMacros: [] #? UseCRLF: false UseTab: ForContinuationAndIndentation WhitespaceSensitiveMacros: - MPT_PP_STRINGIFY libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123.cpp0000644000175000017500000026001314734741400020610 00000000000000/* * openmpt123.cpp * -------------- * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ static const char * const license = "Copyright (c) 2004-2025, OpenMPT Project Developers and Contributors" "\n" "Copyright (c) 1997-2003, Olivier Lapicque" "\n" "All rights reserved." "\n" "" "\n" "Redistribution and use in source and binary forms, with or without" "\n" "modification, are permitted provided that the following conditions are met:" "\n" " * Redistributions of source code must retain the above copyright" "\n" " notice, this list of conditions and the following disclaimer." "\n" " * Redistributions in binary form must reproduce the above copyright" "\n" " notice, this list of conditions and the following disclaimer in the" "\n" " documentation and/or other materials provided with the distribution." "\n" " * Neither the name of the OpenMPT project nor the" "\n" " names of its contributors may be used to endorse or promote products" "\n" " derived from this software without specific prior written permission." "\n" "" "\n" "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" "\n" "AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" "\n" "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" "\n" "DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" "\n" "FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" "\n" "DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" "\n" "SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" "\n" "CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," "\n" "OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" "\n" "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." "\n" ; #include "openmpt123_config.hpp" #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_os.hpp" #include "mpt/base/detect_quirks.hpp" #if defined(MPT_LIBC_QUIRK_REQUIRES_SYS_TYPES_H) #include #endif #include "mpt/base/algorithm.hpp" #include "mpt/base/detect.hpp" #include "mpt/main/main.hpp" #include "mpt/random/crand.hpp" #include "mpt/random/default_engines.hpp" #include "mpt/random/device.hpp" #include "mpt/random/engine.hpp" #include "mpt/random/seed.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if MPT_OS_WINDOWS #include #include #endif #include #include "openmpt123.hpp" #include "openmpt123_exception.hpp" #include "openmpt123_stdio.hpp" #include "openmpt123_terminal.hpp" #include "openmpt123_flac.hpp" #include "openmpt123_mmio.hpp" #include "openmpt123_sndfile.hpp" #include "openmpt123_raw.hpp" #include "openmpt123_stdout.hpp" #include "openmpt123_allegro42.hpp" #include "openmpt123_portaudio.hpp" #include "openmpt123_pulseaudio.hpp" #include "openmpt123_sdl2.hpp" #include "openmpt123_waveout.hpp" namespace openmpt123 { struct silent_exit_exception : public std::exception { }; struct show_license_exception : public std::exception { }; struct show_credits_exception : public std::exception { }; struct show_man_version_exception : public std::exception { }; struct show_man_help_exception : public std::exception { }; struct show_short_version_number_exception : public std::exception { }; struct show_version_number_exception : public std::exception { }; struct show_long_version_number_exception : public std::exception { }; constexpr auto libopenmpt_encoding = mpt::common_encoding::utf8; class file_audio_stream : public file_audio_stream_base { private: std::unique_ptr impl; public: static void show_versions([[maybe_unused]] concat_stream & log ) { #ifdef MPT_WITH_FLAC log << MPT_USTRING(" FLAC ") << mpt::transcode( mpt::source_encoding, FLAC__VERSION_STRING ) << MPT_USTRING(", ") << mpt::transcode( mpt::source_encoding, FLAC__VENDOR_STRING ) << MPT_USTRING(", API ") << FLAC_API_VERSION_CURRENT << MPT_USTRING(".") << FLAC_API_VERSION_REVISION << MPT_USTRING(".") << FLAC_API_VERSION_AGE << MPT_USTRING(" ") << lf; #endif #ifdef MPT_WITH_SNDFILE char sndfile_info[128]; std::memset( sndfile_info, 0, sizeof( sndfile_info ) ); sf_command( 0, SFC_GET_LIB_VERSION, sndfile_info, sizeof( sndfile_info ) ); sndfile_info[127] = '\0'; log << MPT_USTRING(" libsndfile ") << mpt::transcode( sndfile_encoding, sndfile_info ) << MPT_USTRING(" ") << lf; #endif } public: file_audio_stream( const commandlineflags & flags, const mpt::native_path & filename, [[maybe_unused]] concat_stream & log ) : impl(nullptr) { if ( !flags.force_overwrite ) { mpt::IO::ifstream testfile( filename, std::ios::binary ); if ( testfile ) { throw exception( MPT_USTRING("file already exists") ); } } if ( false ) { // nothing } else if ( flags.output_extension == MPT_NATIVE_PATH("raw") ) { impl = std::make_unique( filename, flags, log ); #if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT } else if ( flags.output_extension == MPT_NATIVE_PATH("wav") ) { impl = std::make_unique( filename, flags, log ); #endif #ifdef MPT_WITH_FLAC } else if ( flags.output_extension == MPT_NATIVE_PATH("flac") ) { impl = std::make_unique( filename, flags, log ); #endif #ifdef MPT_WITH_SNDFILE } else { impl = std::make_unique( filename, flags, log ); #endif } if ( !impl ) { throw exception( MPT_USTRING("file format handler '") + mpt::transcode( flags.output_extension ) + MPT_USTRING("' not found") ); } } virtual ~file_audio_stream() { return; } void write_metadata( std::map metadata ) override { impl->write_metadata( metadata ); } void write_updated_metadata( std::map metadata ) override { impl->write_updated_metadata( metadata ); } void write( const std::vector buffers, std::size_t frames ) override { impl->write( buffers, frames ); } void write( const std::vector buffers, std::size_t frames ) override { impl->write( buffers, frames ); } }; class realtime_audio_stream : public write_buffers_interface { private: std::unique_ptr impl; public: static void show_versions( [[maybe_unused]] concat_stream & log ) { #ifdef MPT_WITH_SDL2 log << MPT_USTRING(" ") << show_sdl2_version() << lf; #endif #ifdef MPT_WITH_PULSEAUDIO log << MPT_USTRING(" ") << show_pulseaudio_version() << lf; #endif #ifdef MPT_WITH_PORTAUDIO log << MPT_USTRING(" ") << show_portaudio_version() << lf; #endif } static void show_drivers( concat_stream & drivers ) { drivers << MPT_USTRING(" Available drivers:") << lf; drivers << MPT_USTRING(" default") << lf; #if defined( MPT_WITH_PULSEAUDIO ) drivers << MPT_USTRING(" pulseaudio") << lf; #endif #if defined( MPT_WITH_SDL2 ) drivers << MPT_USTRING(" sdl2") << lf; #endif #if defined( MPT_WITH_PORTAUDIO ) drivers << MPT_USTRING(" portaudio") << lf; #endif #if MPT_OS_WINDOWS drivers << MPT_USTRING(" waveout") << lf; #endif #if defined( MPT_WITH_ALLEGRO42 ) drivers << MPT_USTRING(" allegro42") << lf; #endif } static void show_devices( concat_stream & devices, [[maybe_unused]] concat_stream & log ) { devices << MPT_USTRING(" Available devices:") << lf; devices << MPT_USTRING(" default: default") << lf; #if defined( MPT_WITH_PULSEAUDIO ) devices << MPT_USTRING(" pulseaudio:") << lf; { auto devs = show_pulseaudio_devices( log ); for ( const auto & dev : devs ) { devices << MPT_USTRING(" ") << dev << lf; } } #endif #if defined( MPT_WITH_SDL2 ) devices << MPT_USTRING(" SDL2:") << lf; { auto devs = show_sdl2_devices( log ); for ( const auto & dev : devs ) { devices << MPT_USTRING(" ") << dev << lf; } } #endif #if defined( MPT_WITH_PORTAUDIO ) devices << MPT_USTRING(" portaudio:") << lf; { auto devs = show_portaudio_devices( log ); for ( const auto & dev : devs ) { devices << MPT_USTRING(" ") << dev << lf; } } #endif #if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT devices << MPT_USTRING(" waveout:") << lf; { auto devs = show_waveout_devices( log ); for ( const auto & dev : devs ) { devices << MPT_USTRING(" ") << dev << lf; } } #endif #if defined( MPT_WITH_ALLEGRO42 ) devices << MPT_USTRING(" allegro42:") << lf; { auto devs = show_allegro42_devices( log ); for ( const auto & dev : devs ) { devices << MPT_USTRING(" ") << dev << lf; } } #endif } public: realtime_audio_stream( commandlineflags & flags, [[maybe_unused]] concat_stream & log ) : impl(nullptr) { if constexpr ( false ) { // nothing #if defined( MPT_WITH_PULSEAUDIO ) } else if ( flags.driver == MPT_USTRING("pulseaudio") || flags.driver.empty() ) { impl = std::make_unique( flags, log ); #endif #if defined( MPT_WITH_SDL2 ) } else if ( flags.driver == MPT_USTRING("sdl2") || flags.driver.empty() ) { impl = std::make_unique( flags, log ); #endif #if defined( MPT_WITH_PORTAUDIO ) } else if ( flags.driver == MPT_USTRING("portaudio") || flags.driver.empty() ) { impl = std::make_unique( flags, log ); #endif #if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT } else if ( flags.driver == MPT_USTRING("waveout") || flags.driver.empty() ) { impl = std::make_unique( flags, log ); #endif #if defined( MPT_WITH_ALLEGRO42 ) } else if ( flags.driver == MPT_USTRING("allegro42") || flags.driver.empty() ) { impl = std::make_unique( flags, log ); #endif } else if ( flags.driver.empty() ) { throw exception(MPT_USTRING("openmpt123 is compiled without any audio driver")); } else { throw exception( MPT_USTRING("audio driver '") + flags.driver + MPT_USTRING("' not found") ); } } virtual ~realtime_audio_stream() { return; } void write_metadata( std::map metadata ) override { impl->write_metadata( metadata ); } void write_updated_metadata( std::map metadata ) override { impl->write_updated_metadata( metadata ); } void write( const std::vector buffers, std::size_t frames ) override { impl->write( buffers, frames ); } void write( const std::vector buffers, std::size_t frames ) override { impl->write( buffers, frames ); } bool unpause() override { return impl->unpause(); } bool sleep( int ms ) override { return impl->sleep( ms ); } bool is_dummy() const override { return impl->is_dummy(); } }; static mpt::ustring ctls_to_string( const std::map & ctls ) { mpt::ustring result; for ( const auto & ctl : ctls ) { if ( !result.empty() ) { result += MPT_USTRING("; "); } result += mpt::transcode( libopenmpt_encoding, ctl.first ) + MPT_USTRING("=") + mpt::transcode( libopenmpt_encoding, ctl.second ); } return result; } static double tempo_flag_to_double( std::int32_t tempo ) { return std::pow( 2.0, tempo / 24.0 ); } static double pitch_flag_to_double( std::int32_t pitch ) { return std::pow( 2.0, pitch / 24.0 ); } static std::int32_t double_to_tempo_flag( double factor ) { return static_cast( mpt::round( std::log( factor ) / std::log( 2.0 ) * 24.0 ) ); } static std::int32_t double_to_pitch_flag( double factor ) { return static_cast( mpt::round( std::log( factor ) / std::log( 2.0 ) * 24.0 ) ); } static concat_stream & operator << ( concat_stream & s, const commandlineflags & flags ) { s << MPT_USTRING("Quiet: ") << flags.quiet << lf; s << MPT_USTRING("Banner: ") << flags.banner << lf; s << MPT_USTRING("Verbose: ") << flags.verbose << lf; s << MPT_USTRING("Mode : ") << mode_to_string( flags.mode ) << lf; s << MPT_USTRING("Terminal size : ") << flags.terminal_width << MPT_USTRING("*") << flags.terminal_height << lf; s << MPT_USTRING("Show progress: ") << flags.show_progress << lf; s << MPT_USTRING("Show peak meters: ") << flags.show_meters << lf; s << MPT_USTRING("Show channel peak meters: ") << flags.show_channel_meters << lf; s << MPT_USTRING("Show details: ") << flags.show_details << lf; s << MPT_USTRING("Show message: ") << flags.show_message << lf; s << MPT_USTRING("Update: ") << flags.ui_redraw_interval << MPT_USTRING("ms") << lf; s << MPT_USTRING("Device: ") << flags.device << lf; s << MPT_USTRING("Buffer: ") << flags.buffer << MPT_USTRING("ms") << lf; s << MPT_USTRING("Period: ") << flags.period << MPT_USTRING("ms") << lf; s << MPT_USTRING("Samplerate: ") << flags.samplerate << lf; s << MPT_USTRING("Channels: ") << flags.channels << lf; s << MPT_USTRING("Float: ") << flags.use_float << lf; s << MPT_USTRING("Gain: ") << flags.gain / 100.0 << lf; s << MPT_USTRING("Stereo separation: ") << flags.separation << lf; s << MPT_USTRING("Interpolation filter taps: ") << flags.filtertaps << lf; s << MPT_USTRING("Volume ramping strength: ") << flags.ramping << lf; s << MPT_USTRING("Tempo: ") << tempo_flag_to_double( flags.tempo ) << lf; s << MPT_USTRING("Pitch: ") << pitch_flag_to_double( flags.pitch ) << lf; s << MPT_USTRING("Output dithering: ") << flags.dither << lf; s << MPT_USTRING("Repeat count: ") << flags.repeatcount << lf; s << MPT_USTRING("Seek target: ") << flags.seek_target << lf; s << MPT_USTRING("End time: ") << flags.end_time << lf; s << MPT_USTRING("Standard output: ") << flags.use_stdout << lf; s << MPT_USTRING("Output filename: ") << mpt::transcode( flags.output_filename ) << lf; s << MPT_USTRING("Force overwrite output file: ") << flags.force_overwrite << lf; s << MPT_USTRING("Ctls: ") << ctls_to_string( flags.ctls ) << lf; s << lf; s << MPT_USTRING("Files: ") << lf; for ( const auto & filename : flags.filenames ) { s << MPT_USTRING(" ") << mpt::transcode( filename ) << lf; } s << lf; return s; } static std::string trim_eol( const std::string & str ) { return mpt::trim( str, std::string("\r\n") ); } static mpt::native_path get_basepath( mpt::native_path filename ) { return (filename.GetPrefix() + filename.GetDirectoryWithDrive()).WithTrailingSlash(); } static bool is_absolute( mpt::native_path filename ) { return filename.IsAbsolute(); } static mpt::native_path get_filename( const mpt::native_path & filepath ) { return filepath.GetFilename(); } static mpt::ustring prepend_lines( mpt::ustring str, const mpt::ustring & prefix ) { if ( str.empty() ) { return str; } if ( str.substr( str.length() - 1, 1 ) == MPT_USTRING("\n") ) { str = str.substr( 0, str.length() - 1 ); } return mpt::replace( str, MPT_USTRING("\n"), MPT_USTRING("\n") + prefix ); } static mpt::ustring bytes_to_string( std::uint64_t bytes ) { static const mpt::uchar * const suffixes[] = { MPT_ULITERAL("B"), MPT_ULITERAL("kB"), MPT_ULITERAL("MB"), MPT_ULITERAL("GB"), MPT_ULITERAL("TB"), MPT_ULITERAL("PB") }; int offset = 0; while ( bytes > 9999 ) { bytes /= 1000; offset += 1; if ( offset == 5 ) { break; } } return mpt::format::val( bytes ) + suffixes[offset]; } static mpt::ustring seconds_to_string( double time ) { std::int64_t time_ms = static_cast( time * 1000 ); std::int64_t milliseconds = time_ms % 1000; std::int64_t seconds = ( time_ms / 1000 ) % 60; std::int64_t minutes = ( time_ms / ( 1000 * 60 ) ) % 60; std::int64_t hours = ( time_ms / ( 1000 * 60 * 60 ) ); mpt::ustring str; if ( hours > 0 ) { str += mpt::format::val( hours ) + MPT_USTRING(":"); } str += mpt::format::dec0<2>( minutes ); str += MPT_USTRING(":"); str += mpt::format::dec0<2>( seconds ); str += MPT_USTRING("."); str += mpt::format::dec0<3>( milliseconds ); return str; } static void show_banner( concat_stream & log, verbosity banner ) { if ( banner == verbosity_hidden ) { return; } if ( banner == verbosity_shortversion ) { log << mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) << MPT_USTRING(" / ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "library_version" ) ) << MPT_USTRING(" / ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "core_version" ) ) << lf; return; } log << MPT_USTRING("openmpt123") << MPT_USTRING(" v") << mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) << MPT_USTRING(", libopenmpt ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "library_version" ) ) << MPT_USTRING(" (") << MPT_USTRING("OpenMPT ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "core_version" ) ) << MPT_USTRING(")") << lf; log << MPT_USTRING("Copyright (c) 2013-2025 OpenMPT Project Developers and Contributors ") << lf; if ( banner == verbosity_normal ) { log << lf; return; } log << MPT_USTRING(" libopenmpt source..: ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "source_url" ) ) << lf; log << MPT_USTRING(" libopenmpt date....: ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "source_date" ) ) << lf; log << MPT_USTRING(" libopenmpt srcinfo.: "); { std::vector fields; if ( openmpt::string::get( "source_is_package" ) == "1" ) { fields.push_back( MPT_USTRING("package") ); } if ( openmpt::string::get( "source_is_release" ) == "1" ) { fields.push_back( MPT_USTRING("release") ); } if ( ( !openmpt::string::get( "source_revision" ).empty() ) && ( openmpt::string::get( "source_revision" ) != "0" ) ) { mpt::ustring field = MPT_USTRING("rev") + mpt::transcode( libopenmpt_encoding, openmpt::string::get( "source_revision" ) ); if ( openmpt::string::get( "source_has_mixed_revisions" ) == "1" ) { field += MPT_USTRING("+mixed"); } if ( openmpt::string::get( "source_is_modified" ) == "1" ) { field += MPT_USTRING("+modified"); } fields.push_back( field ); } bool first = true; for ( const auto & field : fields ) { if ( first ) { first = false; } else { log << MPT_USTRING(", "); } log << field; } } log << lf; log << MPT_USTRING(" libopenmpt compiler: ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "build_compiler" ) ) << lf; log << MPT_USTRING(" libopenmpt features: ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "library_features" ) ) << lf; realtime_audio_stream::show_versions( log ); file_audio_stream::show_versions( log ); log << lf; } static void show_man_version( textout & log ) { log << MPT_USTRING("openmpt123") << MPT_USTRING(" v") << mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) << lf; log << lf; log << MPT_USTRING("Copyright (c) 2013-2025 OpenMPT Project Developers and Contributors ") << lf; } static void show_short_version( textout & log ) { show_banner( log, verbosity_shortversion ); log.writeout(); } static void show_version( textout & log ) { show_banner( log, verbosity_normal ); log.writeout(); } static void show_long_version( textout & log ) { show_banner( log, verbosity_verbose ); log.writeout(); } static void show_credits( textout & log, verbosity banner ) { show_banner( log, banner ); log << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "contact" ) ) << lf; log << lf; log << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "credits" ) ) << lf; log.writeout(); } static void show_license( textout & log, verbosity banner ) { show_banner( log, banner ); log << mpt::transcode( mpt::source_encoding, license ) << lf; log.writeout(); } static mpt::ustring get_driver_string( const mpt::ustring & driver ) { if ( driver.empty() ) { return MPT_USTRING("default"); } return driver; } static mpt::ustring get_device_string( const mpt::ustring & device ) { if ( device.empty() ) { return MPT_USTRING("default"); } return device; } static void show_help_keyboard( textout & log, bool man_version = false ) { log << MPT_USTRING("Keyboard hotkeys (use 'openmpt123 --ui'):") << lf; log << lf; log << MPT_USTRING(" [q] quit") << lf; log << MPT_USTRING(" [ ] pause / unpause") << lf; log << MPT_USTRING(" [N] skip 10 files backward") << lf; log << MPT_USTRING(" [n] prev file") << lf; log << MPT_USTRING(" [m] next file") << lf; log << MPT_USTRING(" [M] skip 10 files forward") << lf; log << MPT_USTRING(" [h] seek 10 seconds backward") << lf; log << MPT_USTRING(" [j] seek 1 seconds backward") << lf; log << MPT_USTRING(" [k] seek 1 seconds forward") << lf; log << MPT_USTRING(" [l] seek 10 seconds forward") << lf; log << MPT_USTRING(" [u]|[i] +/- tempo") << lf; log << MPT_USTRING(" [o]|[p] +/- pitch") << lf; log << MPT_USTRING(" [3]|[4] +/- gain") << lf; log << MPT_USTRING(" [5]|[6] +/- stereo separation") << lf; log << MPT_USTRING(" [7]|[8] +/- filter taps") << lf; log << MPT_USTRING(" [9]|[0] +/- volume ramping") << lf; log << lf; if ( !man_version ) { log.writeout(); } } static void show_help( textout & log, bool longhelp = false, bool man_version = false, const mpt::ustring & message = mpt::ustring() ) { { log << MPT_USTRING("Usage: openmpt123 [options] [--] file1 [file2] ...") << lf; log << lf; if ( man_version ) { log << MPT_USTRING("openmpt123 plays module music files.") << lf; log << lf; } if ( man_version ) { log << MPT_USTRING("Options:") << lf; log << lf; } log << MPT_USTRING(" -h, --help Show help") << lf; log << MPT_USTRING(" --help-keyboard Show keyboard hotkeys in ui mode") << lf; log << MPT_USTRING(" -q, --quiet Suppress non-error screen output") << lf; log << MPT_USTRING(" -v, --verbose Show more screen output") << lf; log << MPT_USTRING(" --version Show version information and exit") << lf; log << MPT_USTRING(" --short-version Show version number and nothing else") << lf; log << MPT_USTRING(" --long-version Show long version information and exit") << lf; log << MPT_USTRING(" --credits Show elaborate contributors list") << lf; log << MPT_USTRING(" --license Show license") << lf; log << lf; log << MPT_USTRING(" --probe Probe each file whether it is a supported file format") << lf; log << MPT_USTRING(" --info Display information about each file") << lf; log << MPT_USTRING(" --ui Interactively play each file") << lf; log << MPT_USTRING(" --batch Play each file") << lf; log << MPT_USTRING(" --render Render each file to individual PCM data files") << lf; if ( !longhelp ) { log << lf; log.writeout(); return; } log << lf; log << MPT_USTRING(" --banner n openmpt123 banner style [0=hide,1=show,2=verbose] [default: ") << commandlineflags().banner << MPT_USTRING("]") << lf; log << lf; log << MPT_USTRING(" --assume-terminal Skip checking whether stdin/stderr are a terminal, and always allow UI [default: ") << commandlineflags().assume_terminal << MPT_USTRING("]") << lf; log << MPT_USTRING(" --terminal-width n Assume terminal is n characters wide [default: ") << commandlineflags().terminal_width << MPT_USTRING("]") << lf; log << MPT_USTRING(" --terminal-height n Assume terminal is n characters high [default: ") << commandlineflags().terminal_height << MPT_USTRING("]") << lf; log << lf; log << MPT_USTRING(" --[no-]progress Show playback progress [default: ") << commandlineflags().show_progress << MPT_USTRING("]") << lf; log << MPT_USTRING(" --[no-]meters Show peak meters [default: ") << commandlineflags().show_meters << MPT_USTRING("]") << lf; log << MPT_USTRING(" --[no-]channel-meters Show channel peak meters (EXPERIMENTAL) [default: ") << commandlineflags().show_channel_meters << MPT_USTRING("]") << lf; log << MPT_USTRING(" --[no-]pattern Show pattern (EXPERIMENTAL) [default: ") << commandlineflags().show_pattern << MPT_USTRING("]") << lf; log << lf; log << MPT_USTRING(" --[no-]details Show song details [default: ") << commandlineflags().show_details << MPT_USTRING("]") << lf; log << MPT_USTRING(" --[no-]message Show song message [default: ") << commandlineflags().show_message << MPT_USTRING("]") << lf; log << lf; log << MPT_USTRING(" --update n Set output update interval to n ms [default: ") << commandlineflags().ui_redraw_interval << MPT_USTRING("]") << lf; log << lf; log << MPT_USTRING(" --samplerate n Set samplerate to n Hz [default: ") << commandlineflags().samplerate << MPT_USTRING("]") << lf; log << MPT_USTRING(" --channels n use n [1,2,4] output channels [default: ") << commandlineflags().channels << MPT_USTRING("]") << lf; log << MPT_USTRING(" --[no-]float Output 32bit floating point instead of 16bit integer [default: ") << commandlineflags().use_float << MPT_USTRING("]") << lf; log << lf; log << MPT_USTRING(" --gain n Set output gain to n dB [default: ") << commandlineflags().gain / 100.0 << MPT_USTRING("]") << lf; log << MPT_USTRING(" --stereo n Set stereo separation to n % [default: ") << commandlineflags().separation << MPT_USTRING("]") << lf; log << MPT_USTRING(" --filter n Set interpolation filter taps to n [1,2,4,8] [default: ") << commandlineflags().filtertaps << MPT_USTRING("]") << lf; log << MPT_USTRING(" --ramping n Set volume ramping strength n [0..5] [default: ") << commandlineflags().ramping << MPT_USTRING("]") << lf; log << MPT_USTRING(" --tempo f Set tempo factor f [default: ") << tempo_flag_to_double( commandlineflags().tempo ) << MPT_USTRING("]") << lf; log << MPT_USTRING(" --pitch f Set pitch factor f [default: ") << pitch_flag_to_double( commandlineflags().pitch ) << MPT_USTRING("]") << lf; log << MPT_USTRING(" --dither n Dither type to use (if applicable for selected output format): [0=off,1=auto,2=0.5bit,3=1bit] [default: ") << commandlineflags().dither << MPT_USTRING("]") << lf; log << lf; log << MPT_USTRING(" --playlist file Load playlist from file") << lf; log << MPT_USTRING(" --[no-]randomize Randomize playlist [default: ") << commandlineflags().randomize << MPT_USTRING("]") << lf; log << MPT_USTRING(" --[no-]shuffle Shuffle through playlist [default: ") << commandlineflags().shuffle << MPT_USTRING("]") << lf; log << MPT_USTRING(" --[no-]restart Restart playlist when finished [default: ") << commandlineflags().restart << MPT_USTRING("]") << lf; log << lf; log << MPT_USTRING(" --subsong n Select subsong n (-1 means play all subsongs consecutively) [default: ") << commandlineflags().subsong << MPT_USTRING("]") << lf; log << MPT_USTRING(" --repeat n Repeat song n times (-1 means forever) [default: ") << commandlineflags().repeatcount << MPT_USTRING("]") << lf; log << MPT_USTRING(" --seek n Seek to n seconds on start [default: ") << commandlineflags().seek_target << MPT_USTRING("]") << lf; log << MPT_USTRING(" --end-time n Play until position is n seconds (0 means until the end) [default: ") << commandlineflags().end_time << MPT_USTRING("]") << lf; log << lf; log << MPT_USTRING(" --ctl c=v Set libopenmpt ctl c to value v") << lf; log << lf; log << MPT_USTRING(" --driver n Set output driver [default: ") << get_driver_string( commandlineflags().driver ) << MPT_USTRING("],") << lf; log << MPT_USTRING(" --device n Set output device [default: ") << get_device_string( commandlineflags().device ) << MPT_USTRING("],") << lf; log << MPT_USTRING(" use --device help to show available devices") << lf; log << MPT_USTRING(" --buffer n Set output buffer size to n ms [default: ") << commandlineflags().buffer << MPT_USTRING("]") << lf; log << MPT_USTRING(" --period n Set output period size to n ms [default: ") << commandlineflags().period << MPT_USTRING("]") << lf; log << MPT_USTRING(" --stdout Write raw audio data to stdout [default: ") << commandlineflags().use_stdout << MPT_USTRING("]") << lf; log << MPT_USTRING(" --output-type t Use output format t when writing to a individual PCM files (only applies to --render mode) [default: ") << mpt::transcode( commandlineflags().output_extension ) << MPT_USTRING("]") << lf; log << MPT_USTRING(" -o, --output f Write PCM output to file f instead of streaming to audio device (only applies to --ui and --batch modes) [default: ") << mpt::transcode( commandlineflags().output_filename ) << MPT_USTRING("]") << lf; log << MPT_USTRING(" --force Force overwriting of output file [default: ") << commandlineflags().force_overwrite << MPT_USTRING("]") << lf; log << lf; log << MPT_USTRING(" -- Interpret further arguments as filenames") << lf; log << lf; if ( !man_version ) { log << MPT_USTRING(" Supported file formats: ") << lf; log << MPT_USTRING(" "); std::vector extensions = openmpt::get_supported_extensions(); bool first = true; for ( const auto & extension : extensions ) { if ( first ) { first = false; } else { log << MPT_USTRING(", "); } log << mpt::transcode( libopenmpt_encoding, extension ); } log << lf; } else { show_help_keyboard( log, true ); } } log << lf; if ( message.size() > 0 ) { log << message; log << lf; } log.writeout(); } template < typename Tmod > static void apply_mod_settings( commandlineflags & flags, Tmod & mod ) { flags.separation = std::max( flags.separation, std::int32_t( 0 ) ); flags.filtertaps = std::max( flags.filtertaps, std::int32_t( 1 ) ); flags.filtertaps = std::min( flags.filtertaps, std::int32_t( 8 ) ); flags.ramping = std::max( flags.ramping, std::int32_t( -1 ) ); flags.ramping = std::min( flags.ramping, std::int32_t( 10 ) ); flags.tempo = std::max( flags.tempo, std::int32_t( -48 ) ); flags.tempo = std::min( flags.tempo, std::int32_t( 48 ) ); flags.pitch = std::max( flags.pitch, std::int32_t( -48 ) ); flags.pitch = std::min( flags.pitch, std::int32_t( 48 ) ); mod.set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, flags.gain ); mod.set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, flags.separation ); mod.set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, flags.filtertaps ); mod.set_render_param( openmpt::module::RENDER_VOLUMERAMPING_STRENGTH, flags.ramping ); try { mod.ctl_set_floatingpoint( "play.tempo_factor", tempo_flag_to_double( flags.tempo ) ); } catch ( const openmpt::exception & ) { // ignore } try { mod.ctl_set_floatingpoint( "play.pitch_factor", pitch_flag_to_double( flags.pitch ) ); } catch ( const openmpt::exception & ) { // ignore } mod.ctl_set_integer( "dither", flags.dither ); } struct prev_file { int count; prev_file( int c ) : count(c) { } }; struct next_file { int count; next_file( int c ) : count(c) { } }; template < typename Tmod > static bool handle_keypress( int c, commandlineflags & flags, Tmod & mod, write_buffers_interface & audio_stream ) { switch ( c ) { case 'q': throw silent_exit_exception(); break; case 'N': throw prev_file(10); break; case 'n': throw prev_file(1); break; case ' ': if ( !flags.paused ) { flags.paused = audio_stream.pause(); } else { flags.paused = false; audio_stream.unpause(); } break; case 'h': mod.set_position_seconds( mod.get_position_seconds() - 10.0 ); break; case 'j': mod.set_position_seconds( mod.get_position_seconds() - 1.0 ); break; case 'k': mod.set_position_seconds( mod.get_position_seconds() + 1.0 ); break; case 'l': mod.set_position_seconds( mod.get_position_seconds() + 10.0 ); break; case 'H': mod.set_position_order_row( mod.get_current_order() - 1, 0 ); break; case 'J': mod.set_position_order_row( mod.get_current_order(), mod.get_current_row() - 1 ); break; case 'K': mod.set_position_order_row( mod.get_current_order(), mod.get_current_row() + 1 ); break; case 'L': mod.set_position_order_row( mod.get_current_order() + 1, 0 ); break; case 'm': throw next_file(1); break; case 'M': throw next_file(10); break; case 'u': flags.tempo -= 1; apply_mod_settings( flags, mod ); break; case 'i': flags.tempo += 1; apply_mod_settings( flags, mod ); break; case 'o': flags.pitch -= 1; apply_mod_settings( flags, mod ); break; case 'p': flags.pitch += 1; apply_mod_settings( flags, mod ); break; case '3': flags.gain -=100; apply_mod_settings( flags, mod ); break; case '4': flags.gain +=100; apply_mod_settings( flags, mod ); break; case '5': flags.separation -= 5; apply_mod_settings( flags, mod ); break; case '6': flags.separation += 5; apply_mod_settings( flags, mod ); break; case '7': flags.filtertaps /= 2; apply_mod_settings( flags, mod ); break; case '8': flags.filtertaps *= 2; apply_mod_settings( flags, mod ); break; case '9': flags.ramping -= 1; apply_mod_settings( flags, mod ); break; case '0': flags.ramping += 1; apply_mod_settings( flags, mod ); break; } return true; } struct meter_channel { float peak; float clip; float hold; float hold_age; meter_channel() : peak(0.0f) , clip(0.0f) , hold(0.0f) , hold_age(0.0f) { return; } }; struct meter_type { meter_channel channels[4]; }; static const float falloff_rate = 20.0f / 1.7f; static void update_meter( meter_type & meter, const commandlineflags & flags, std::size_t count, const std::int16_t * const * buffers ) { float falloff_factor = std::pow( 10.0f, -falloff_rate / static_cast( flags.samplerate ) / 20.0f ); for ( int channel = 0; channel < flags.channels; ++channel ) { meter.channels[channel].peak = 0.0f; for ( std::size_t frame = 0; frame < count; ++frame ) { if ( meter.channels[channel].clip != 0.0f ) { meter.channels[channel].clip -= ( 1.0f / 2.0f ) * 1.0f / static_cast( flags.samplerate ); if ( meter.channels[channel].clip <= 0.0f ) { meter.channels[channel].clip = 0.0f; } } float val = std::fabs( buffers[channel][frame] / 32768.0f ); if ( val >= 1.0f ) { meter.channels[channel].clip = 1.0f; } if ( val > meter.channels[channel].peak ) { meter.channels[channel].peak = val; } meter.channels[channel].hold *= falloff_factor; if ( val > meter.channels[channel].hold ) { meter.channels[channel].hold = val; meter.channels[channel].hold_age = 0.0f; } else { meter.channels[channel].hold_age += 1.0f / static_cast( flags.samplerate ); } } } } static void update_meter( meter_type & meter, const commandlineflags & flags, std::size_t count, const float * const * buffers ) { float falloff_factor = std::pow( 10.0f, -falloff_rate / static_cast( flags.samplerate ) / 20.0f ); for ( int channel = 0; channel < flags.channels; ++channel ) { if ( !count ) { meter = meter_type(); } meter.channels[channel].peak = 0.0f; for ( std::size_t frame = 0; frame < count; ++frame ) { if ( meter.channels[channel].clip != 0.0f ) { meter.channels[channel].clip -= ( 1.0f / 2.0f ) * 1.0f / static_cast( flags.samplerate ); if ( meter.channels[channel].clip <= 0.0f ) { meter.channels[channel].clip = 0.0f; } } float val = std::fabs( buffers[channel][frame] ); if ( val >= 1.0f ) { meter.channels[channel].clip = 1.0f; } if ( val > meter.channels[channel].peak ) { meter.channels[channel].peak = val; } meter.channels[channel].hold *= falloff_factor; if ( val > meter.channels[channel].hold ) { meter.channels[channel].hold = val; meter.channels[channel].hold_age = 0.0f; } else { meter.channels[channel].hold_age += 1.0f / static_cast( flags.samplerate ); } } } } static const mpt::uchar * const channel_tags[4][4] = { { MPT_ULITERAL(" C"), MPT_ULITERAL(" "), MPT_ULITERAL(" "), MPT_ULITERAL(" ") }, { MPT_ULITERAL(" L"), MPT_ULITERAL(" R"), MPT_ULITERAL(" "), MPT_ULITERAL(" ") }, { MPT_ULITERAL("FL"), MPT_ULITERAL("FR"), MPT_ULITERAL("RC"), MPT_ULITERAL(" ") }, { MPT_ULITERAL("FL"), MPT_ULITERAL("FR"), MPT_ULITERAL("RL"), MPT_ULITERAL("RR") }, }; static mpt::ustring channel_to_string( int channels, int channel, const meter_channel & meter, bool tiny = false ) { int val = std::numeric_limits::min(); int hold_pos = std::numeric_limits::min(); if ( meter.peak > 0.0f ) { float db = 20.0f * std::log10( meter.peak ); val = static_cast( db + 48.0f ); } if ( meter.hold > 0.0f ) { float db_hold = 20.0f * std::log10( meter.hold ); hold_pos = static_cast( db_hold + 48.0f ); } if ( val < 0 ) { val = 0; } int headroom = val; if ( val > 48 ) { val = 48; } headroom -= val; if ( headroom < 0 ) { headroom = 0; } if ( headroom > 12 ) { headroom = 12; } headroom -= 1; // clip indicator if ( headroom < 0 ) { headroom = 0; } if ( tiny ) { if ( meter.clip != 0.0f || meter.peak >= 1.0f ) { return MPT_USTRING("#"); } else if ( meter.peak > std::pow( 10.0f, -6.0f / 20.0f ) ) { return MPT_USTRING("O"); } else if ( meter.peak > std::pow( 10.0f, -12.0f / 20.0f ) ) { return MPT_USTRING("o"); } else if ( meter.peak > std::pow( 10.0f, -18.0f / 20.0f ) ) { return MPT_USTRING("."); } else { return MPT_USTRING(" "); } } else { mpt::ustring res1; mpt::ustring res2; res1 += MPT_USTRING(" "); res1 += channel_tags[channels-1][channel]; res1 += MPT_USTRING(" : "); res2 += mpt::ustring( val, MPT_UCHAR('>') ) + mpt::ustring( std::size_t{48} - val, MPT_UCHAR(' ') ); res2 += ( ( meter.clip != 0.0f ) ? MPT_USTRING("#") : MPT_USTRING(":") ); res2 += mpt::ustring( headroom, MPT_UCHAR('>') ) + mpt::ustring( std::size_t{12} - headroom, MPT_UCHAR(' ') ); mpt::ustring tmp = res2; if ( 0 <= hold_pos && hold_pos <= 60 ) { if ( hold_pos == 48 ) { tmp[hold_pos] = MPT_UCHAR('#'); } else { tmp[hold_pos] = MPT_UCHAR(':'); } } return res1 + tmp; } } static mpt::ustring peak_to_string( float peak ) { if ( peak >= 1.0f ) { return MPT_USTRING("#"); } else if ( peak >= 0.5f ) { return MPT_USTRING("O"); } else if ( peak >= 0.25f ) { return MPT_USTRING("o"); } else if ( peak >= 0.125f ) { return MPT_USTRING("."); } else { return MPT_USTRING(" "); } } static mpt::ustring peak_to_string_left( float peak, int width ) { mpt::ustring result; float thresh = 1.0f; while ( width-- ) { if ( peak >= thresh ) { if ( thresh == 1.0f ) { result.push_back( MPT_UCHAR('#') ); } else { result.push_back( MPT_UCHAR('<') ); } } else { result.push_back( MPT_UCHAR(' ') ); } thresh *= 0.5f; } return result; } static mpt::ustring peak_to_string_right( float peak, int width ) { mpt::ustring result; float thresh = 1.0f; while ( width-- ) { if ( peak >= thresh ) { if ( thresh == 1.0f ) { result.push_back( MPT_UCHAR('#') ); } else { result.push_back( MPT_UCHAR('>') ); } } else { result.push_back( MPT_UCHAR(' ') ); } thresh *= 0.5f; } std::reverse( result.begin(), result.end() ); return result; } static void draw_meters( concat_stream & log, const meter_type & meter, const commandlineflags & flags ) { for ( int channel = 0; channel < flags.channels; ++channel ) { log << channel_to_string( flags.channels, channel, meter.channels[channel] ) << lf; } } static void draw_meters_tiny( concat_stream & log, const meter_type & meter, const commandlineflags & flags ) { for ( int channel = 0; channel < flags.channels; ++channel ) { log << channel_to_string( flags.channels, channel, meter.channels[channel], true ); } } static void draw_channel_meters_tiny( concat_stream & log, float peak ) { log << peak_to_string( peak ); } static void draw_channel_meters_tiny( concat_stream & log, float peak_left, float peak_right ) { log << peak_to_string( peak_left ) << peak_to_string( peak_right ); } static void draw_channel_meters( concat_stream & log, float peak_left, float peak_right, int width ) { if ( width >= 8 + 1 + 8 ) { width = 8 + 1 + 8; } log << peak_to_string_left( peak_left, width / 2 ) << ( width % 2 == 1 ? MPT_USTRING(":") : MPT_USTRING("") ) << peak_to_string_right( peak_right, width / 2 ); } template < typename Tsample, typename Tmod > void render_loop( commandlineflags & flags, Tmod & mod, double & duration, textout & log, write_buffers_interface & audio_stream ) { log.writeout(); std::size_t bufsize; if ( flags.mode == Mode::UI ) { bufsize = std::min( flags.ui_redraw_interval, flags.period ) * flags.samplerate / 1000; } else if ( flags.mode == Mode::Batch ) { bufsize = flags.period * flags.samplerate / 1000; } else { bufsize = 1024; } std::int64_t last_redraw_frame = std::int64_t{0} - flags.ui_redraw_interval; std::int64_t rendered_frames = 0; std::vector left( bufsize ); std::vector right( bufsize ); std::vector rear_left( bufsize ); std::vector rear_right( bufsize ); std::vector buffers( 4 ) ; buffers[0] = left.data(); buffers[1] = right.data(); buffers[2] = rear_left.data(); buffers[3] = rear_right.data(); buffers.resize( flags.channels ); meter_type meter; const bool multiline = flags.show_ui; const bool narrow = (flags.terminal_width < 72) && (flags.terminal_height > 25); int lines = 0; int pattern_lines = 0; if ( multiline ) { lines += 1; // cppcheck-suppress identicalInnerCondition if ( flags.show_ui ) { lines += 1; if ( narrow ) { lines += 1; } } if ( flags.show_meters ) { if ( narrow ) { lines += 1; } else { for ( int channel = 0; channel < flags.channels; ++channel ) { lines += 1; } } } if ( flags.show_channel_meters ) { lines += 1; } if ( flags.show_details ) { lines += 1; if ( flags.show_progress ) { lines += 1; if ( narrow ) { lines += 2; } } } if ( flags.show_progress ) { lines += 1; } if ( flags.show_pattern ) { pattern_lines = flags.terminal_height - lines - 1; lines = flags.terminal_height - 1; } } else if ( flags.show_ui || flags.show_details || flags.show_progress ) { log << lf; } for ( int line = 0; line < lines; ++line ) { log << lf; } log.writeout(); double cpu_smooth = 0.0; while ( true ) { if ( flags.mode == Mode::UI ) { while ( terminal_input::is_input_available() ) { auto c = terminal_input::read_input_char(); if ( !c ) { break; } if ( !handle_keypress( *c, flags, mod, audio_stream ) ) { return; } } if ( flags.paused ) { audio_stream.sleep( flags.ui_redraw_interval ); continue; } } std::clock_t cpu_beg = 0; std::clock_t cpu_end = 0; if ( flags.show_details ) { cpu_beg = std::clock(); } std::size_t count = 0; switch ( flags.channels ) { case 1: count = mod.read( flags.samplerate, bufsize, left.data() ); break; case 2: count = mod.read( flags.samplerate, bufsize, left.data(), right.data() ); break; case 4: count = mod.read( flags.samplerate, bufsize, left.data(), right.data(), rear_left.data(), rear_right.data() ); break; } mpt::ustring cpu_str; if ( flags.show_details ) { cpu_end = std::clock(); if ( count > 0 ) { double cpu = 1.0; cpu *= ( static_cast( cpu_end ) - static_cast( cpu_beg ) ) / static_cast( CLOCKS_PER_SEC ); cpu /= ( static_cast( count ) ) / static_cast( flags.samplerate ); double mix = ( static_cast( count ) ) / static_cast( flags.samplerate ); cpu_smooth = ( 1.0 - mix ) * cpu_smooth + mix * cpu; cpu_str = mpt::format::fix( cpu_smooth * 100.0, 2 ) + MPT_USTRING("%"); } } if ( flags.show_meters ) { update_meter( meter, flags, count, buffers.data() ); } if ( count > 0 ) { audio_stream.write( buffers, count ); } if ( count > 0 ) { rendered_frames += count; if ( rendered_frames >= last_redraw_frame + ( flags.ui_redraw_interval * flags.samplerate / 1000 ) ) { last_redraw_frame = rendered_frames; } else { continue; } } if ( multiline ) { log.cursor_up( lines ); log << lf; if ( flags.show_meters ) { if ( narrow ) { log << MPT_USTRING("Level......: "); draw_meters_tiny( log, meter, flags ); log << lf; } else { draw_meters( log, meter, flags ); } } if ( flags.show_channel_meters ) { int width = ( flags.terminal_width - 3 ) / mod.get_num_channels(); if ( width > 11 ) { width = 11; } log << MPT_USTRING(" "); for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) { if ( width >= 3 ) { log << MPT_USTRING(":"); } if ( width == 1 ) { draw_channel_meters_tiny( log, ( mod.get_current_channel_vu_left( channel ) + mod.get_current_channel_vu_right( channel ) ) * (1.0f/std::sqrt(2.0f)) ); } else if ( width <= 4 ) { draw_channel_meters_tiny( log, mod.get_current_channel_vu_left( channel ), mod.get_current_channel_vu_right( channel ) ); } else { draw_channel_meters( log, mod.get_current_channel_vu_left( channel ), mod.get_current_channel_vu_right( channel ), width - 1 ); } } if ( width >= 3 ) { log << MPT_USTRING(":"); } log << lf; } if ( flags.show_pattern ) { int width = ( flags.terminal_width - 3 ) / mod.get_num_channels(); if ( width > 13 + 1 ) { width = 13 + 1; } for ( std::int32_t line = 0; line < pattern_lines; ++line ) { std::int32_t row = mod.get_current_row() - ( pattern_lines / 2 ) + line; if ( row == mod.get_current_row() ) { log << MPT_USTRING(">"); } else { log << MPT_USTRING(" "); } if ( row < 0 || row >= mod.get_pattern_num_rows( mod.get_current_pattern() ) ) { for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) { if ( width >= 3 ) { log << MPT_USTRING(":"); } log << mpt::ustring( width >= 3 ? width - 1 : width, MPT_UCHAR(' ') ); } } else { for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) { if ( width >= 3 ) { if ( row == mod.get_current_row() ) { log << MPT_USTRING("+"); } else { log << MPT_USTRING(":"); } } log << mpt::transcode( libopenmpt_encoding, mod.format_pattern_row_channel( mod.get_current_pattern(), row, channel, width >= 3 ? width - 1 : width ) ); } } if ( width >= 3 ) { log << MPT_USTRING(":"); } log << lf; } } if ( flags.show_ui ) { if ( narrow ) { log << MPT_USTRING("Settings...: "); log << MPT_USTRING("Gain: ") << static_cast( flags.gain ) * 0.01f << MPT_USTRING(" dB") << MPT_USTRING(" "); log << MPT_USTRING("Stereo: ") << flags.separation << MPT_USTRING(" %") << MPT_USTRING(" "); log << lf; log << MPT_USTRING("Filter.....: "); log << MPT_USTRING("Length: ") << flags.filtertaps << MPT_USTRING(" taps") << MPT_USTRING(" "); log << MPT_USTRING("Ramping: ") << flags.ramping << MPT_USTRING(" "); log << lf; } else { log << MPT_USTRING("Settings...: "); log << MPT_USTRING("Gain: ") << static_cast( flags.gain ) * 0.01f << MPT_USTRING(" dB") << MPT_USTRING(" "); log << MPT_USTRING("Stereo: ") << flags.separation << MPT_USTRING(" %") << MPT_USTRING(" "); log << MPT_USTRING("Filter: ") << flags.filtertaps << MPT_USTRING(" taps") << MPT_USTRING(" "); log << MPT_USTRING("Ramping: ") << flags.ramping << MPT_USTRING(" "); log << lf; } } if ( flags.show_details ) { log << MPT_USTRING("Mixer......: "); log << MPT_USTRING("CPU:") << align_right( MPT_UCHAR(':'), 6, cpu_str ); log << MPT_USTRING(" "); log << MPT_USTRING("Chn:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_playing_channels() ); log << MPT_USTRING(" "); log << lf; if ( flags.show_progress ) { if ( narrow ) { log << MPT_USTRING("Player.....: "); log << MPT_USTRING("Ord:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_order() ) << MPT_USTRING("/") << align_right( MPT_UCHAR(':'), 3, mod.get_num_orders() ); log << MPT_USTRING(" "); log << lf; log << MPT_USTRING("Pattern....: "); log << MPT_USTRING("Pat:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_pattern() ); log << MPT_USTRING(" "); log << MPT_USTRING("Row:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_row() ); log << MPT_USTRING(" "); log << lf; log << MPT_USTRING("Tempo......: "); log << MPT_USTRING("Spd:") << align_right( MPT_UCHAR(':'), 2, mod.get_current_speed() ); log << MPT_USTRING(" "); log << MPT_USTRING("Tmp:") << align_right( MPT_UCHAR(':'), 6, mpt::format::fix( mod.get_current_tempo2(), 2 ) ); log << MPT_USTRING(" "); log << lf; } else { log << MPT_USTRING("Player.....: "); log << MPT_USTRING("Ord:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_order() ) << MPT_USTRING("/") << align_right( MPT_UCHAR(':'), 3, mod.get_num_orders() ); log << MPT_USTRING(" "); log << MPT_USTRING("Pat:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_pattern() ); log << MPT_USTRING(" "); log << MPT_USTRING("Row:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_row() ); log << MPT_USTRING(" "); log << MPT_USTRING("Spd:") << align_right( MPT_UCHAR(':'), 2, mod.get_current_speed() ); log << MPT_USTRING(" "); log << MPT_USTRING("Tmp:") << align_right( MPT_UCHAR(':'), 6, mpt::format::fix( mod.get_current_tempo2(), 2 ) ); log << MPT_USTRING(" "); log << lf; } } } if ( flags.show_progress ) { log << MPT_USTRING("Position...: ") << seconds_to_string( mod.get_position_seconds() ) << MPT_USTRING(" / ") << seconds_to_string( duration ) << MPT_USTRING(" ") << lf; } } else if ( flags.show_channel_meters ) { if ( flags.show_ui || flags.show_details || flags.show_progress ) { int width = ( flags.terminal_width - 3 ) / mod.get_num_channels(); log << MPT_USTRING(" "); for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) { if ( width >= 3 ) { log << MPT_USTRING(":"); } if ( width == 1 ) { draw_channel_meters_tiny( log, ( mod.get_current_channel_vu_left( channel ) + mod.get_current_channel_vu_right( channel ) ) * (1.0f/std::sqrt(2.0f)) ); } else if ( width <= 4 ) { draw_channel_meters_tiny( log, mod.get_current_channel_vu_left( channel ), mod.get_current_channel_vu_right( channel ) ); } else { draw_channel_meters( log, mod.get_current_channel_vu_left( channel ), mod.get_current_channel_vu_right( channel ), width - 1 ); } } if ( width >= 3 ) { log << MPT_USTRING(":"); } } log << MPT_USTRING(" ") << MPT_USTRING("\r"); } else { if ( flags.show_ui ) { log << MPT_USTRING(" "); log << align_right( MPT_UCHAR(':'), 3, static_cast( flags.gain ) * 0.01f ) << MPT_USTRING("dB"); log << MPT_USTRING("|"); log << align_right( MPT_UCHAR(':'), 3, flags.separation ) << MPT_USTRING("%"); log << MPT_USTRING("|"); log << align_right( MPT_UCHAR(':'), 2, flags.filtertaps ) << MPT_USTRING("taps"); log << MPT_USTRING("|"); log << align_right( MPT_UCHAR(':'), 3, flags.ramping ); } if ( flags.show_meters ) { log << MPT_USTRING(" "); draw_meters_tiny( log, meter, flags ); } if ( flags.show_details && flags.show_ui ) { log << MPT_USTRING(" "); log << MPT_USTRING("CPU:") << align_right( MPT_UCHAR(':'), 6, cpu_str ); log << MPT_USTRING("|"); log << MPT_USTRING("Chn:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_playing_channels() ); } if ( flags.show_details && !flags.show_ui ) { if ( flags.show_progress ) { log << MPT_USTRING(" "); log << MPT_USTRING("Ord:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_order() ) << MPT_USTRING("/") << align_right( MPT_UCHAR(':'), 3, mod.get_num_orders() ); log << MPT_USTRING("|"); log << MPT_USTRING("Pat:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_pattern() ); log << MPT_USTRING("|"); log << MPT_USTRING("Row:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_row() ); log << MPT_USTRING(" "); log << MPT_USTRING("Spd:") << align_right( MPT_UCHAR(':'), 2, mod.get_current_speed() ); log << MPT_USTRING("|"); log << MPT_USTRING("Tmp:") << align_right( MPT_UCHAR(':'), 3, mpt::format::fix( mod.get_current_tempo2(), 2 ) ); } } if ( flags.show_progress ) { log << MPT_USTRING(" "); log << seconds_to_string( mod.get_position_seconds() ); log << MPT_USTRING("/"); log << seconds_to_string( duration ); } if ( flags.show_ui || flags.show_details || flags.show_progress ) { log << MPT_USTRING(" ") << MPT_USTRING("\r"); } } log.writeout(); if ( count == 0 ) { break; } if ( flags.end_time > 0 && mod.get_position_seconds() >= flags.end_time ) { break; } } log.writeout(); } template < typename Tmod > std::map get_metadata( const Tmod & mod ) { std::map result; const std::vector metadata_keys = mod.get_metadata_keys(); for ( const auto & key : metadata_keys ) { result[ mpt::transcode( libopenmpt_encoding, key ) ] = mpt::transcode( libopenmpt_encoding, mod.get_metadata( key ) ); } return result; } static void set_field( std::vector & fields, const mpt::ustring & name, const mpt::ustring & value ) { fields.push_back( field{ name, value } ); } static void show_fields( textout & log, const std::vector & fields ) { const std::size_t fw = 11; for ( const auto & field : fields ) { mpt::ustring key = field.key; mpt::ustring val = field.val; if ( key.length() < fw ) { key += mpt::ustring( fw - key.length(), MPT_UCHAR('.') ); } if ( key.length() > fw ) { key = key.substr( 0, fw ); } key += MPT_USTRING(": "); val = prepend_lines( val, mpt::ustring( fw, MPT_UCHAR(' ') ) + MPT_USTRING(": ") ); log << key << val << lf; } } static void probe_mod_file( commandlineflags & flags, const mpt::native_path & filename, std::uint64_t filesize, std::istream & data_stream, textout & log ) { log.writeout(); std::vector fields; if ( flags.filenames.size() > 1 ) { set_field( fields, MPT_USTRING("Playlist"), MPT_UFORMAT_MESSAGE( "{}/{}" )( flags.playlist_index + 1, flags.filenames.size() ) ); set_field( fields, MPT_USTRING("Prev/Next"), MPT_UFORMAT_MESSAGE( "'{}' / ['{}'] / '{}'" )( ( flags.playlist_index > 0 ? mpt::transcode( get_filename( flags.filenames[ flags.playlist_index - 1 ] ) ) : mpt::ustring() ), mpt::transcode( get_filename( filename ) ), ( flags.playlist_index + 1 < flags.filenames.size() ? mpt::transcode( get_filename( flags.filenames[ flags.playlist_index + 1 ] ) ) : mpt::ustring() ) ) ); } if ( flags.verbose ) { set_field( fields, MPT_USTRING("Path"), mpt::transcode( filename ) ); } if ( flags.show_details ) { set_field( fields, MPT_USTRING("Filename"), mpt::transcode( get_filename( filename ) ) ); set_field( fields, MPT_USTRING("Size"), bytes_to_string( filesize ) ); } int probe_result = openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, data_stream ); mpt::ustring probe_result_string; switch ( probe_result ) { case openmpt::probe_file_header_result_success: probe_result_string = MPT_USTRING("Success"); break; case openmpt::probe_file_header_result_failure: probe_result_string = MPT_USTRING("Failure"); break; case openmpt::probe_file_header_result_wantmoredata: probe_result_string = MPT_USTRING("Insufficient Data"); break; default: probe_result_string = MPT_USTRING("Internal Error"); break; } set_field( fields, MPT_USTRING("Probe"), probe_result_string ); show_fields( log, fields ); log.writeout(); } template < typename Tmod > void render_mod_file( commandlineflags & flags, const mpt::native_path & filename, std::uint64_t filesize, Tmod & mod, textout & log, write_buffers_interface & audio_stream ) { log.writeout(); if ( flags.mode != Mode::Probe && flags.mode != Mode::Info ) { mod.set_repeat_count( flags.repeatcount ); apply_mod_settings( flags, mod ); } double duration = mod.get_duration_seconds(); std::vector fields; if ( flags.filenames.size() > 1 ) { set_field( fields, MPT_USTRING("Playlist"), MPT_UFORMAT_MESSAGE("{}/{}")( flags.playlist_index + 1, flags.filenames.size() ) ); set_field( fields, MPT_USTRING("Prev/Next"), MPT_UFORMAT_MESSAGE("'{}' / ['{}'] / '{}'")( ( flags.playlist_index > 0 ? mpt::transcode( get_filename( flags.filenames[ flags.playlist_index - 1 ] ) ) : mpt::ustring() ), mpt::transcode( get_filename( filename ) ), ( flags.playlist_index + 1 < flags.filenames.size() ? mpt::transcode( get_filename( flags.filenames[ flags.playlist_index + 1 ] ) ) : mpt::ustring() ) ) ); } if ( flags.verbose ) { set_field( fields, MPT_USTRING("Path"), mpt::transcode( filename ) ); } if ( flags.show_details ) { set_field( fields, MPT_USTRING("Filename"), mpt::transcode( get_filename( filename ) ) ); set_field( fields, MPT_USTRING("Size"), bytes_to_string( filesize ) ); if ( !mod.get_metadata( "warnings" ).empty() ) { set_field( fields, MPT_USTRING("Warnings"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "warnings" ) ) ); } if ( !mod.get_metadata( "container" ).empty() ) { set_field( fields, MPT_USTRING("Container"), MPT_UFORMAT_MESSAGE("{} ({})")( mpt::transcode( libopenmpt_encoding, mod.get_metadata( "container" ) ), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "container_long" ) ) ) ); } set_field( fields, MPT_USTRING("Type"), MPT_UFORMAT_MESSAGE("{} ({})")( mpt::transcode( libopenmpt_encoding, mod.get_metadata( "type" ) ), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "type_long" ) ) ) ); if ( !mod.get_metadata( "originaltype" ).empty() ) { set_field( fields, MPT_USTRING("Orig. Type"), MPT_UFORMAT_MESSAGE("{} ({})")( mpt::transcode( libopenmpt_encoding, mod.get_metadata( "originaltype" ) ), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "originaltype_long" ) ) ) ); } if ( ( mod.get_num_subsongs() > 1 ) && ( flags.subsong != -1 ) ) { set_field( fields, MPT_USTRING("Subsong"), mpt::format::val( flags.subsong ) ); } set_field( fields, MPT_USTRING("Tracker"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "tracker" ) ) ); if ( !mod.get_metadata( "date" ).empty() ) { set_field( fields, MPT_USTRING("Date"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "date" ) ) ); } if ( !mod.get_metadata( "artist" ).empty() ) { set_field( fields, MPT_USTRING("Artist"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "artist" ) ) ); } } if ( true ) { set_field( fields, MPT_USTRING("Title"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "title" ) ) ); set_field( fields, MPT_USTRING("Duration"), seconds_to_string( duration ) ); } if ( flags.show_details ) { set_field( fields, MPT_USTRING("Subsongs"), mpt::format::val( mod.get_num_subsongs() ) ); set_field( fields, MPT_USTRING("Channels"), mpt::format::val( mod.get_num_channels() ) ); set_field( fields, MPT_USTRING("Orders"), mpt::format::val( mod.get_num_orders() ) ); set_field( fields, MPT_USTRING("Patterns"), mpt::format::val( mod.get_num_patterns() ) ); set_field( fields, MPT_USTRING("Instruments"), mpt::format::val( mod.get_num_instruments() ) ); set_field( fields, MPT_USTRING("Samples"), mpt::format::val( mod.get_num_samples() ) ); } if ( flags.show_message ) { set_field( fields, MPT_USTRING("Message"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "message" ) ) ); } show_fields( log, fields ); log.writeout(); if ( flags.filenames.size() == 1 || flags.mode == Mode::Render ) { audio_stream.write_metadata( get_metadata( mod ) ); } else { audio_stream.write_updated_metadata( get_metadata( mod ) ); } if ( flags.mode == Mode::Probe || flags.mode == Mode::Info ) { return; } if ( flags.seek_target > 0.0 ) { mod.set_position_seconds( flags.seek_target ); } try { if ( flags.use_float ) { render_loop( flags, mod, duration, log, audio_stream ); } else { render_loop( flags, mod, duration, log, audio_stream ); } if ( flags.show_progress ) { log << lf; } } catch ( ... ) { if ( flags.show_progress ) { log << lf; } throw; } log.writeout(); } static void probe_file( commandlineflags & flags, const mpt::native_path & filename, textout & log ) { log.writeout(); std::ostringstream silentlog; try { std::optional optional_file_stream; std::uint64_t filesize = 0; bool use_stdin = ( filename == MPT_NATIVE_PATH("-") ); if ( !use_stdin ) { optional_file_stream.emplace( filename, std::ios::binary ); std::istream & file_stream = *optional_file_stream; file_stream.seekg( 0, std::ios::end ); filesize = file_stream.tellg(); file_stream.seekg( 0, std::ios::beg ); } std::istream & data_stream = use_stdin ? std::cin : *optional_file_stream; if ( data_stream.fail() ) { throw exception( MPT_USTRING("file open error") ); } probe_mod_file( flags, filename, filesize, data_stream, log ); } catch ( silent_exit_exception & ) { throw; } catch ( std::exception & e ) { if ( !silentlog.str().empty() ) { log << MPT_USTRING("errors probing '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::transcode( libopenmpt_encoding, silentlog.str() ) << lf; } else { log << MPT_USTRING("errors probing '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } log << MPT_USTRING("error probing '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::get_exception_text( e ) << lf; } catch ( ... ) { if ( !silentlog.str().empty() ) { log << MPT_USTRING("errors probing '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::transcode( libopenmpt_encoding, silentlog.str() ) << lf; } else { log << MPT_USTRING("errors probing '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } log << MPT_USTRING("unknown error probing '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } log << lf; log.writeout(); } static void render_file( commandlineflags & flags, const mpt::native_path & filename, textout & log, write_buffers_interface & audio_stream ) { log.writeout(); std::ostringstream silentlog; try { std::optional optional_file_stream; std::uint64_t filesize = 0; bool use_stdin = ( filename == MPT_NATIVE_PATH("-") ); if ( !use_stdin ) { optional_file_stream.emplace( filename, std::ios::binary ); std::istream & file_stream = *optional_file_stream; file_stream.seekg( 0, std::ios::end ); filesize = file_stream.tellg(); file_stream.seekg( 0, std::ios::beg ); } std::istream & data_stream = use_stdin ? std::cin : *optional_file_stream; if ( data_stream.fail() ) { throw exception( MPT_USTRING("file open error") ); } { openmpt::module mod( data_stream, silentlog, flags.ctls ); mod.select_subsong( flags.subsong ); silentlog.str( std::string() ); // clear, loader messages get stored to get_metadata( "warnings" ) by libopenmpt internally render_mod_file( flags, filename, filesize, mod, log, audio_stream ); } } catch ( prev_file & ) { throw; } catch ( next_file & ) { throw; } catch ( silent_exit_exception & ) { throw; } catch ( std::exception & e ) { if ( !silentlog.str().empty() ) { log << MPT_USTRING("errors loading '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::transcode( libopenmpt_encoding, silentlog.str() ) << lf; } else { log << MPT_USTRING("errors loading '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } log << MPT_USTRING("error playing '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::get_exception_text( e ) << lf; } catch ( ... ) { if ( !silentlog.str().empty() ) { log << MPT_USTRING("errors loading '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::transcode( libopenmpt_encoding,silentlog.str() ) << lf; } else { log << MPT_USTRING("errors loading '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } log << MPT_USTRING("unknown error playing '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } log << lf; log.writeout(); } static mpt::native_path get_random_filename( std::set & filenames, mpt::good_engine & prng ) { std::size_t index = mpt::random( prng, 0, filenames.size() - 1 ); std::set::iterator it = filenames.begin(); std::advance( it, index ); return *it; } static void render_files( commandlineflags & flags, textout & log, write_buffers_interface & audio_stream, mpt::good_engine & prng ) { if ( flags.randomize ) { std::shuffle( flags.filenames.begin(), flags.filenames.end(), prng ); } try { while ( true ) { if ( flags.shuffle ) { // TODO: improve prev/next logic std::set shuffle_set; shuffle_set.insert( flags.filenames.begin(), flags.filenames.end() ); while ( true ) { if ( shuffle_set.empty() ) { break; } mpt::native_path filename = get_random_filename( shuffle_set, prng ); try { flags.playlist_index = std::find( flags.filenames.begin(), flags.filenames.end(), filename ) - flags.filenames.begin(); render_file( flags, filename, log, audio_stream ); shuffle_set.erase( filename ); continue; } catch ( prev_file & ) { shuffle_set.erase( filename ); continue; } catch ( next_file & ) { shuffle_set.erase( filename ); continue; } catch ( ... ) { throw; } } } else { std::vector::iterator filename = flags.filenames.begin(); while ( true ) { if ( filename == flags.filenames.end() ) { break; } try { flags.playlist_index = filename - flags.filenames.begin(); render_file( flags, *filename, log, audio_stream ); filename++; continue; } catch ( prev_file & e ) { while ( filename != flags.filenames.begin() && e.count ) { e.count--; --filename; } continue; } catch ( next_file & e ) { while ( filename != flags.filenames.end() && e.count ) { e.count--; ++filename; } continue; } catch ( ... ) { throw; } } } if ( !flags.restart ) { break; } } } catch ( ... ) { throw; } } static bool parse_playlist( commandlineflags & flags, mpt::native_path filename, concat_stream & log ) { bool is_playlist = false; bool m3u8 = false; if ( get_extension( filename ) == MPT_NATIVE_PATH("m3u") || get_extension( filename ) == MPT_NATIVE_PATH("m3U") || get_extension( filename ) == MPT_NATIVE_PATH("M3u") || get_extension( filename ) == MPT_NATIVE_PATH("M3U") ) { is_playlist = true; } if ( get_extension( filename ) == MPT_NATIVE_PATH("m3u8") || get_extension( filename ) == MPT_NATIVE_PATH("m3U8") || get_extension( filename ) == MPT_NATIVE_PATH("M3u8") || get_extension( filename ) == MPT_NATIVE_PATH("M3U8") ) { is_playlist = true; m3u8 = true; } if ( get_extension( filename ) == MPT_NATIVE_PATH("pls") || get_extension( filename ) == MPT_NATIVE_PATH("plS") || get_extension( filename ) == MPT_NATIVE_PATH("pLs") || get_extension( filename ) == MPT_NATIVE_PATH("pLS") || get_extension( filename ) == MPT_NATIVE_PATH("Pls") || get_extension( filename ) == MPT_NATIVE_PATH("PlS") || get_extension( filename ) == MPT_NATIVE_PATH("PLs") || get_extension( filename ) == MPT_NATIVE_PATH("PLS") ) { is_playlist = true; } mpt::native_path basepath = get_basepath( filename ); try { mpt::IO::ifstream file_stream( filename, std::ios::binary ); std::string line; bool first = true; bool extm3u = false; bool pls = false; while ( std::getline( file_stream, line ) ) { mpt::native_path newfile; line = trim_eol( line ); if ( first ) { first = false; if ( line == "#EXTM3U" ) { extm3u = true; continue; } else if ( line == "[playlist]" ) { pls = true; } } if ( line.empty() ) { continue; } constexpr auto pls_encoding = mpt::common_encoding::utf8; constexpr auto m3u8_encoding = mpt::common_encoding::utf8; #if MPT_OS_WINDOWS constexpr auto m3u_encoding = mpt::logical_encoding::locale; #else constexpr auto m3u_encoding = mpt::common_encoding::utf8; #endif if ( pls ) { if ( mpt::starts_with( line, "File" ) ) { if ( line.find( "=" ) != std::string::npos ) { flags.filenames.push_back( mpt::transcode( pls_encoding, line.substr( line.find( "=" ) + 1 ) ) ); } } else if ( mpt::starts_with( line, "Title" ) ) { continue; } else if ( mpt::starts_with( line, "Length" ) ) { continue; } else if ( mpt::starts_with( line, "NumberOfEntries" ) ) { continue; } else if ( mpt::starts_with( line, "Version" ) ) { continue; } else { continue; } } else if ( extm3u ) { if ( mpt::starts_with( line, "#EXTINF" ) ) { continue; } else if ( mpt::starts_with( line, "#" ) ) { continue; } if ( m3u8 ) { newfile = mpt::transcode( m3u8_encoding, line ); } else { newfile = mpt::transcode( m3u_encoding, line ); } } else { if ( m3u8 ) { newfile = mpt::transcode( m3u8_encoding, line ); } else { newfile = mpt::transcode( m3u_encoding, line ); } } if ( !newfile.empty() ) { if ( !is_absolute( newfile ) ) { newfile = basepath + newfile; } flags.filenames.push_back( newfile ); } } } catch ( std::exception & e ) { log << MPT_USTRING("error loading '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::get_exception_text( e ) << lf; } catch ( ... ) { log << MPT_USTRING("unknown error loading '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } return is_playlist; } static void parse_openmpt123( commandlineflags & flags, const std::vector & args, concat_stream & log ) { enum class action { help, help_keyboard, man_version, man_help, version, short_version, long_version, credits, license, }; std::optional return_action; if ( args.size() <= 1 ) { throw args_error_exception(); } bool files_only = false; // cppcheck false-positive // cppcheck-suppress StlMissingComparison for ( auto i = args.begin(); i != args.end(); ++i ) { if ( i == args.begin() ) { // skip program name continue; } mpt::ustring arg = *i; mpt::ustring nextarg = ( i+1 != args.end() ) ? *(i+1) : MPT_USTRING(""); if ( files_only ) { flags.filenames.push_back( mpt::transcode( arg ) ); } else if ( arg.substr( 0, 1 ) != MPT_USTRING("-") ) { flags.filenames.push_back( mpt::transcode( arg ) ); } else { if ( arg == MPT_USTRING("--") ) { files_only = true; } else if ( arg == MPT_USTRING("-h") || arg == MPT_USTRING("--help") ) { if ( return_action ) { throw args_error_exception(); } return_action = action::help; } else if ( arg == MPT_USTRING("--help-keyboard") ) { if ( return_action ) { throw args_error_exception(); } return_action = action::help_keyboard; } else if ( arg == MPT_USTRING("--man-version") ) { if ( return_action ) { throw args_error_exception(); } return_action = action::man_version; } else if ( arg == MPT_USTRING("--man-help") ) { if ( return_action ) { throw args_error_exception(); } return_action = action::man_help; } else if ( arg == MPT_USTRING("--version") ) { if ( return_action ) { throw args_error_exception(); } return_action = action::version; } else if ( arg == MPT_USTRING("--short-version") ) { if ( return_action ) { throw args_error_exception(); } return_action = action::short_version; } else if ( arg == MPT_USTRING("--long-version") ) { if ( return_action ) { throw args_error_exception(); } return_action = action::long_version; } else if ( arg == MPT_USTRING("--credits") ) { if ( return_action ) { throw args_error_exception(); } return_action = action::credits; } else if ( arg == MPT_USTRING("--license") ) { if ( return_action ) { throw args_error_exception(); } return_action = action::license; } else if ( arg == MPT_USTRING("-q") || arg == MPT_USTRING("--quiet") ) { flags.quiet = true; } else if ( arg == MPT_USTRING("-v") || arg == MPT_USTRING("--verbose") ) { flags.verbose = true; } else if ( arg == MPT_USTRING("--probe") ) { flags.mode = Mode::Probe; } else if ( arg == MPT_USTRING("--info") ) { flags.mode = Mode::Info; } else if ( arg == MPT_USTRING("--ui") ) { flags.mode = Mode::UI; } else if ( arg == MPT_USTRING("--batch") ) { flags.mode = Mode::Batch; } else if ( arg == MPT_USTRING("--render") ) { flags.mode = Mode::Render; } else if ( arg == MPT_USTRING("--assume-terminal") ) { flags.assume_terminal = true; } else if ( arg == MPT_USTRING("--banner") && nextarg != MPT_USTRING("") ) { std::int8_t value = static_cast( flags.banner ); mpt::parse_into( value, nextarg ); flags.banner = static_cast( value ); ++i; } else if ( arg == MPT_USTRING("--terminal-width") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.terminal_width, nextarg ); ++i; } else if ( arg == MPT_USTRING("--terminal-height") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.terminal_height, nextarg ); ++i; } else if ( arg == MPT_USTRING("--progress") ) { flags.show_progress = true; } else if ( arg == MPT_USTRING("--no-progress") ) { flags.show_progress = false; } else if ( arg == MPT_USTRING("--meters") ) { flags.show_meters = true; } else if ( arg == MPT_USTRING("--no-meters") ) { flags.show_meters = false; } else if ( arg == MPT_USTRING("--channel-meters") ) { flags.show_channel_meters = true; } else if ( arg == MPT_USTRING("--no-channel-meters") ) { flags.show_channel_meters = false; } else if ( arg == MPT_USTRING("--pattern") ) { flags.show_pattern = true; } else if ( arg == MPT_USTRING("--no-pattern") ) { flags.show_pattern = false; } else if ( arg == MPT_USTRING("--details") ) { flags.show_details = true; } else if ( arg == MPT_USTRING("--no-details") ) { flags.show_details = false; } else if ( arg == MPT_USTRING("--message") ) { flags.show_message = true; } else if ( arg == MPT_USTRING("--no-message") ) { flags.show_message = false; } else if ( arg == MPT_USTRING("--driver") && nextarg != MPT_USTRING("") ) { if ( false ) { // nothing } else if ( nextarg == MPT_USTRING("help") ) { string_concat_stream drivers; realtime_audio_stream::show_drivers( drivers ); throw show_help_exception( drivers.str() ); } else if ( nextarg == MPT_USTRING("default") ) { flags.driver = MPT_USTRING(""); } else { flags.driver = nextarg; } ++i; } else if ( arg == MPT_USTRING("--device") && nextarg != MPT_USTRING("") ) { if ( false ) { // nothing } else if ( nextarg == MPT_USTRING("help") ) { string_concat_stream devices; realtime_audio_stream::show_devices( devices, log ); throw show_help_exception( devices.str() ); } else if ( nextarg == MPT_USTRING("default") ) { flags.device = MPT_USTRING(""); } else { flags.device = nextarg; } ++i; } else if ( arg == MPT_USTRING("--buffer") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.buffer, nextarg ); ++i; } else if ( arg == MPT_USTRING("--period") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.period, nextarg ); ++i; } else if ( arg == MPT_USTRING("--update") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.ui_redraw_interval, nextarg ); ++i; } else if ( arg == MPT_USTRING("--stdout") ) { flags.use_stdout = true; } else if ( ( arg == MPT_USTRING("-o") || arg == MPT_USTRING("--output") ) && nextarg != MPT_USTRING("") ) { flags.output_filename = mpt::transcode( nextarg ); ++i; } else if ( arg == MPT_USTRING("--force") ) { flags.force_overwrite = true; } else if ( arg == MPT_USTRING("--output-type") && nextarg != MPT_USTRING("") ) { flags.output_extension = mpt::transcode( nextarg ); ++i; } else if ( arg == MPT_USTRING("--samplerate") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.samplerate, nextarg ); ++i; } else if ( arg == MPT_USTRING("--channels") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.channels, nextarg ); ++i; } else if ( arg == MPT_USTRING("--float") ) { flags.use_float = true; } else if ( arg == MPT_USTRING("--no-float") ) { flags.use_float = false; } else if ( arg == MPT_USTRING("--gain") && nextarg != MPT_USTRING("") ) { double gain = 0.0; mpt::parse_into( gain, nextarg ); flags.gain = mpt::saturate_round( gain * 100.0 ); ++i; } else if ( arg == MPT_USTRING("--stereo") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.separation, nextarg ); ++i; } else if ( arg == MPT_USTRING("--filter") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.filtertaps, nextarg ); ++i; } else if ( arg == MPT_USTRING("--ramping") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.ramping, nextarg ); ++i; } else if ( arg == MPT_USTRING("--tempo") && nextarg != MPT_USTRING("") ) { flags.tempo = double_to_tempo_flag( mpt::parse_or( nextarg, 1.0 ) ); ++i; } else if ( arg == MPT_USTRING("--pitch") && nextarg != MPT_USTRING("") ) { flags.pitch = double_to_pitch_flag( mpt::parse_or( nextarg, 1.0 ) ); ++i; } else if ( arg == MPT_USTRING("--dither") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.dither, nextarg ); ++i; } else if ( arg == MPT_USTRING("--playlist") && nextarg != MPT_USTRING("") ) { parse_playlist( flags, mpt::transcode( nextarg ), log ); ++i; } else if ( arg == MPT_USTRING("--randomize") ) { flags.randomize = true; } else if ( arg == MPT_USTRING("--no-randomize") ) { flags.randomize = false; } else if ( arg == MPT_USTRING("--shuffle") ) { flags.shuffle = true; } else if ( arg == MPT_USTRING("--no-shuffle") ) { flags.shuffle = false; } else if ( arg == MPT_USTRING("--restart") ) { flags.restart = true; } else if ( arg == MPT_USTRING("--no-restart") ) { flags.restart = false; } else if ( arg == MPT_USTRING("--subsong") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.subsong, nextarg ); ++i; } else if ( arg == MPT_USTRING("--repeat") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.repeatcount, nextarg ); ++i; } else if ( arg == MPT_USTRING("--ctl") && nextarg != MPT_USTRING("") ) { std::string ctl_c_v = mpt::transcode( libopenmpt_encoding, nextarg ); if ( ctl_c_v.find( "=" ) == std::string::npos ) { throw args_error_exception(); } std::string ctl = ctl_c_v.substr( 0, ctl_c_v.find( "=" ) ); std::string val = ctl_c_v.substr( ctl_c_v.find( "=" ) + std::string("=").length(), std::string::npos ); if ( ctl.empty() ) { throw args_error_exception(); } flags.ctls[ ctl ] = val; ++i; } else if ( arg == MPT_USTRING("--seek") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.seek_target, nextarg ); ++i; } else if ( arg == MPT_USTRING("--end-time") && nextarg != MPT_USTRING("") ) { mpt::parse_into( flags.end_time, nextarg ); ++i; } else if ( arg.size() > 0 && arg.substr( 0, 1 ) == MPT_USTRING("-") ) { throw args_error_exception(); } } } if ( return_action ) { switch ( *return_action ) { case action::help: throw show_help_exception(); break; case action::help_keyboard: throw show_help_keyboard_exception(); break; case action::man_version: throw show_man_version_exception(); break; case action::man_help: throw show_man_help_exception(); break; case action::version: throw show_version_number_exception(); break; case action::short_version: throw show_short_version_number_exception(); break; case action::long_version: throw show_long_version_number_exception(); break; case action::credits: throw show_credits_exception(); break; case action::license: throw show_license_exception(); break; } } } static mpt::uint8 main( std::vector args ) { FILE_mode_guard stdout_text_guard( stdout, FILE_mode::text ); FILE_mode_guard stderr_text_guard( stderr, FILE_mode::text ); textout_wrapper std_out; textout_wrapper std_err; commandlineflags flags; try { parse_openmpt123( flags, args, std_err ); flags.check_and_sanitize(); } catch ( args_nofiles_exception & ) { show_banner( std_out, flags.banner ); show_help( std_out ); std_out.writeout(); return 0; } catch ( args_error_exception & ) { show_banner( std_out, flags.banner ); show_help( std_out ); std_out.writeout(); if ( args.size() > 1 ) { std_err << MPT_USTRING("Error parsing command line.") << lf; std_err.writeout(); } return 1; } catch ( show_man_help_exception & ) { show_banner( std_out, flags.banner ); show_help( std_out, true, true ); return 0; } catch ( show_man_version_exception & ) { show_man_version( std_out ); return 0; } catch ( show_help_exception & e ) { show_banner( std_out, flags.banner ); show_help( std_out, e.longhelp, false, e.message ); if ( flags.verbose ) { show_credits( std_out, verbosity_hidden ); } return 0; } catch ( show_help_keyboard_exception & ) { show_banner( std_out, flags.banner ); show_help_keyboard( std_out ); return 0; } catch ( show_long_version_number_exception & ) { show_long_version( std_out ); return 0; } catch ( show_version_number_exception & ) { show_version( std_out ); return 0; } catch ( show_short_version_number_exception & ) { show_short_version( std_out ); return 0; } catch ( show_credits_exception & ) { show_credits( std_out, flags.banner ); return 0; } catch ( show_license_exception & ) { show_license( std_out, flags.banner ); return 0; } catch ( silent_exit_exception & ) { return 0; } catch ( exception & e ) { std_err << MPT_USTRING("error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); return 1; } catch ( std::exception & e ) { std_err << MPT_USTRING("error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); return 1; } catch ( ... ) { std_err << MPT_USTRING("unknown error") << lf; std_err.writeout(); return 1; } try { const FILE_mode stdin_mode = mpt::contains( flags.filenames, MPT_NATIVE_PATH("-") ) ? FILE_mode::binary : FILE_mode::text; const FILE_mode stdout_mode = flags.use_stdout ? FILE_mode::binary : FILE_mode::text; [[maybe_unused]] const bool stdin_text = ( stdin_mode == FILE_mode::text ); [[maybe_unused]] const bool stdin_data = ( stdin_mode == FILE_mode::binary ); [[maybe_unused]] const bool stdout_text = ( stdout_mode == FILE_mode::text ); [[maybe_unused]] const bool stdout_data = ( stdout_mode == FILE_mode::binary ); // set stdin/stdout to binary for data input/output [[maybe_unused]] std::optional stdin_guard{ stdin_data ? std::make_optional( stdin, FILE_mode::binary ) : std::nullopt }; [[maybe_unused]] std::optional stdout_guard{ stdout_data ? std::make_optional( stdout, FILE_mode::binary ) : std::nullopt }; // setup terminal input [[maybe_unused]] std::optional stdin_text_guard{ stdin_text ? std::make_optional( stdin, FILE_mode::text ) : std::nullopt }; [[maybe_unused]] std::optional input_guard{ stdin_text && ( flags.mode == Mode::UI ) ? std::make_optional() : std::nullopt }; // choose text output between quiet/stdout/stderr textout_dummy dummy_log; textout & log = flags.quiet ? static_cast( dummy_log ) : stdout_text ? static_cast( std_out ) : static_cast( std_err ); show_banner( log, flags.banner ); if ( !flags.warnings.empty() ) { log << flags.warnings << lf; } if ( flags.verbose ) { log << flags; } log.writeout(); mpt::sane_random_device rd; mpt::good_engine prng = mpt::make_prng( rd ); mpt::crand::reseed( prng ); switch ( flags.mode ) { case Mode::Probe: { for ( const auto & filename : flags.filenames ) { probe_file( flags, filename, log ); flags.playlist_index++; } } break; case Mode::Info: { void_audio_stream dummy; render_files( flags, log, dummy, prng ); } break; case Mode::UI: case Mode::Batch: { if ( flags.use_stdout ) { flags.apply_default_buffer_sizes(); stdout_stream_raii stdout_audio_stream; render_files( flags, log, stdout_audio_stream, prng ); } else if ( !flags.output_filename.empty() ) { flags.apply_default_buffer_sizes(); file_audio_stream file_audio_stream( flags, flags.output_filename, log ); render_files( flags, log, file_audio_stream, prng ); } else { realtime_audio_stream audio_stream( flags, log ); render_files( flags, log, audio_stream, prng ); } } break; case Mode::Render: { for ( const auto & filename : flags.filenames ) { flags.apply_default_buffer_sizes(); file_audio_stream file_audio_stream( flags, filename + MPT_NATIVE_PATH(".") + flags.output_extension, log ); render_file( flags, filename, log, file_audio_stream ); flags.playlist_index++; } } break; case Mode::None: break; } } catch ( args_error_exception & ) { show_banner( std_out, flags.banner ); show_help( std_out ); std_err << MPT_USTRING("Error parsing command line.") << lf; std_err.writeout(); return 1; } catch ( silent_exit_exception & ) { return 0; } catch ( exception & e ) { std_err << MPT_USTRING("error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); return 1; } catch ( std::exception & e ) { std_err << MPT_USTRING("error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); return 1; } catch ( ... ) { std_err << MPT_USTRING("unknown error") << lf; std_err.writeout(); return 1; } return 0; } } // namespace openmpt123 MPT_MAIN_IMPLEMENT_MAIN(openmpt123) libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_portaudio.hpp0000644000175000017500000002621014674771042022712 00000000000000/* * openmpt123_portaudio.hpp * ------------------------ * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_PORTAUDIO_HPP #define OPENMPT123_PORTAUDIO_HPP #include "openmpt123_config.hpp" #include "openmpt123.hpp" #include "mpt/base/detect.hpp" #if defined(MPT_WITH_PORTAUDIO) #include #if defined(MPT_BUILD_MSVC) && MPT_COMPILER_MSVC && MPT_ARCH_X86 extern "C" { void PaUtil_InitializeX86PlainConverters(void); } #endif namespace openmpt123 { inline constexpr auto portaudio_encoding = mpt::common_encoding::utf8; struct portaudio_exception : public exception { portaudio_exception( PaError code ) : exception( MPT_USTRING("PortAudio: ") + mpt::transcode( portaudio_encoding, Pa_GetErrorText( code ) ) ) { } }; typedef void (*PaUtilLogCallback ) (const char *log); #ifdef _MSC_VER extern "C" void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb); #endif class portaudio_raii { private: concat_stream & log; bool log_set; bool portaudio_initialized; static concat_stream * portaudio_log_stream; private: static void portaudio_log_function( const char * log ) { if ( portaudio_log_stream ) { *portaudio_log_stream << MPT_USTRING("PortAudio: ") << mpt::transcode( portaudio_encoding, log ); } } protected: void check_portaudio_error( PaError e ) { if ( e > 0 ) { return; } if ( e == paNoError ) { return; } if ( e == paOutputUnderflowed ) { log << MPT_USTRING("PortAudio warning: ") << mpt::transcode( portaudio_encoding, Pa_GetErrorText( e ) ) << lf; return; } throw portaudio_exception( e ); } public: portaudio_raii( bool verbose, concat_stream & log ) : log(log), log_set(false), portaudio_initialized(false) { if ( verbose ) { portaudio_log_stream = &log; } else { portaudio_log_stream = 0; } #ifdef _MSC_VER PaUtil_SetDebugPrintFunction( portaudio_log_function ); log_set = true; #endif #if defined(MPT_BUILD_MSVC) && MPT_COMPILER_MSVC && MPT_ARCH_X86 PaUtil_InitializeX86PlainConverters(); #endif check_portaudio_error( Pa_Initialize() ); portaudio_initialized = true; if ( verbose ) { *portaudio_log_stream << lf; } } ~portaudio_raii() { if ( portaudio_initialized ) { check_portaudio_error( Pa_Terminate() ); portaudio_initialized = false; } if ( log_set ) { #ifdef _MSC_VER PaUtil_SetDebugPrintFunction( NULL ); log_set = false; #endif } portaudio_log_stream = 0; } }; concat_stream * portaudio_raii::portaudio_log_stream = 0; class portaudio_stream_blocking_raii : public portaudio_raii, public write_buffers_interface { private: PaStream * stream; bool interleaved; std::size_t channels; std::vector sampleBufFloat; std::vector sampleBufInt; public: portaudio_stream_blocking_raii( commandlineflags & flags, concat_stream & log ) : portaudio_raii(flags.verbose, log) , stream(NULL) , interleaved(false) , channels(flags.channels) { PaStreamParameters streamparameters; std::memset( &streamparameters, 0, sizeof(PaStreamParameters) ); const int device = mpt::parse_or( flags.device, -1 ); streamparameters.device = ( device == -1 ) ? Pa_GetDefaultOutputDevice() : device; streamparameters.channelCount = flags.channels; streamparameters.sampleFormat = ( flags.use_float ? paFloat32 : paInt16 ) | paNonInterleaved; if ( flags.buffer == default_high ) { streamparameters.suggestedLatency = Pa_GetDeviceInfo( streamparameters.device )->defaultHighOutputLatency; flags.buffer = static_cast( Pa_GetDeviceInfo( streamparameters.device )->defaultHighOutputLatency * 1000.0 ); } else if ( flags.buffer == default_low ) { streamparameters.suggestedLatency = Pa_GetDeviceInfo( streamparameters.device )->defaultLowOutputLatency; flags.buffer = static_cast( Pa_GetDeviceInfo( streamparameters.device )->defaultLowOutputLatency * 1000.0 ); } else { streamparameters.suggestedLatency = flags.buffer * 0.001; } unsigned long framesperbuffer = 0; if ( flags.mode != Mode::UI ) { framesperbuffer = paFramesPerBufferUnspecified; flags.period = 50; flags.period = std::min( flags.period, flags.buffer / 3 ); } else if ( flags.period == default_high ) { framesperbuffer = paFramesPerBufferUnspecified; flags.period = 50; flags.period = std::min( flags.period, flags.buffer / 3 ); } else if ( flags.period == default_low ) { framesperbuffer = paFramesPerBufferUnspecified; flags.period = 10; flags.period = std::min( flags.period, flags.buffer / 3 ); } else { framesperbuffer = flags.period * flags.samplerate / 1000; } if ( flags.period <= 0 ) { flags.period = 1; } flags.apply_default_buffer_sizes(); if ( flags.verbose ) { log << MPT_USTRING("PortAudio:") << lf; log << MPT_USTRING(" device: ") << streamparameters.device << MPT_USTRING(" [ ") << mpt::transcode( portaudio_encoding, Pa_GetHostApiInfo( Pa_GetDeviceInfo( streamparameters.device )->hostApi )->name ) << MPT_USTRING(" / ") << mpt::transcode( portaudio_encoding, Pa_GetDeviceInfo( streamparameters.device )->name ) << MPT_USTRING(" ] ") << lf; log << MPT_USTRING(" low latency: ") << Pa_GetDeviceInfo( streamparameters.device )->defaultLowOutputLatency << lf; log << MPT_USTRING(" high latency: ") << Pa_GetDeviceInfo( streamparameters.device )->defaultHighOutputLatency << lf; log << MPT_USTRING(" suggested latency: ") << streamparameters.suggestedLatency << lf; log << MPT_USTRING(" frames per buffer: ") << framesperbuffer << lf; log << MPT_USTRING(" ui redraw: ") << flags.period << lf; } PaError e = PaError(); e = Pa_OpenStream( &stream, NULL, &streamparameters, flags.samplerate, framesperbuffer, ( flags.dither > 0 ) ? paNoFlag : paDitherOff, NULL, NULL ); if ( e != paNoError ) { // Non-interleaved failed, try interleaved next. // This might help broken portaudio on MacOS X. streamparameters.sampleFormat &= ~paNonInterleaved; e = Pa_OpenStream( &stream, NULL, &streamparameters, flags.samplerate, framesperbuffer, ( flags.dither > 0 ) ? paNoFlag : paDitherOff, NULL, NULL ); if ( e == paNoError ) { interleaved = true; } check_portaudio_error( e ); } check_portaudio_error( Pa_StartStream( stream ) ); if ( flags.verbose ) { log << MPT_USTRING(" channels: ") << streamparameters.channelCount << lf; log << MPT_USTRING(" sampleformat: ") << ( ( ( streamparameters.sampleFormat & ~paNonInterleaved ) == paFloat32 ) ? MPT_USTRING("paFloat32") : MPT_USTRING("paInt16") ) << lf; log << MPT_USTRING(" latency: ") << Pa_GetStreamInfo( stream )->outputLatency << lf; log << MPT_USTRING(" samplerate: ") << Pa_GetStreamInfo( stream )->sampleRate << lf; log << lf; } } ~portaudio_stream_blocking_raii() { if ( stream ) { PaError stopped = Pa_IsStreamStopped( stream ); check_portaudio_error( stopped ); if ( !stopped ) { check_portaudio_error( Pa_StopStream( stream ) ); } check_portaudio_error( Pa_CloseStream( stream ) ); stream = NULL; } } private: template void write_frames( const Tsample * buffer, std::size_t frames ) { while ( frames > 0 ) { unsigned long chunk_frames = static_cast( std::min( static_cast( frames ), static_cast( std::numeric_limits::max() ) ) ); check_portaudio_error( Pa_WriteStream( stream, buffer, chunk_frames ) ); buffer += chunk_frames * channels; frames -= chunk_frames; } } template void write_frames( std::vector buffers, std::size_t frames ) { while ( frames > 0 ) { unsigned long chunk_frames = static_cast( std::min( static_cast( frames ), static_cast( std::numeric_limits::max() ) ) ); check_portaudio_error( Pa_WriteStream( stream, buffers.data(), chunk_frames ) ); for ( std::size_t channel = 0; channel < channels; ++channel ) { buffers[channel] += chunk_frames; } frames -= chunk_frames; } } public: void write( const std::vector buffers, std::size_t frames ) override { if ( interleaved ) { sampleBufFloat.clear(); for ( std::size_t frame = 0; frame < frames; ++frame ) { for ( std::size_t channel = 0; channel < channels; ++channel ) { sampleBufFloat.push_back( buffers[channel][frame] ); } } write_frames( sampleBufFloat.data(), frames ); } else { write_frames( buffers, frames ); } } void write( const std::vector buffers, std::size_t frames ) override { if ( interleaved ) { sampleBufInt.clear(); for ( std::size_t frame = 0; frame < frames; ++frame ) { for ( std::size_t channel = 0; channel < channels; ++channel ) { sampleBufInt.push_back( buffers[channel][frame] ); } } write_frames( sampleBufInt.data(), frames ); } else { write_frames( buffers, frames ); } } bool unpause() override { check_portaudio_error( Pa_StartStream( stream ) ); return true; } bool pause() override { check_portaudio_error( Pa_StopStream( stream ) ); return true; } bool sleep( int ms ) override { Pa_Sleep( ms ); return true; } }; #define portaudio_stream_raii portaudio_stream_blocking_raii inline std::vector show_portaudio_devices( concat_stream & log ) { std::vector devices; portaudio_raii portaudio( false, log ); for ( PaDeviceIndex i = 0; i < Pa_GetDeviceCount(); ++i ) { if ( Pa_GetDeviceInfo( i ) && Pa_GetDeviceInfo( i )->maxOutputChannels > 0 ) { string_concat_stream device; device << i << MPT_USTRING(": "); if ( Pa_GetHostApiInfo( Pa_GetDeviceInfo( i )->hostApi ) && Pa_GetHostApiInfo( Pa_GetDeviceInfo( i )->hostApi )->name ) { device << mpt::transcode( portaudio_encoding, Pa_GetHostApiInfo( Pa_GetDeviceInfo( i )->hostApi )->name ); } else { device << MPT_USTRING("Host API ") << Pa_GetDeviceInfo( i )->hostApi; } if ( Pa_GetHostApiInfo( Pa_GetDeviceInfo( i )->hostApi ) ) { if ( i == Pa_GetHostApiInfo( Pa_GetDeviceInfo( i )->hostApi )->defaultOutputDevice ) { device << MPT_USTRING(" (default)"); } } device << MPT_USTRING(" - "); if ( Pa_GetDeviceInfo( i )->name ) { device << mpt::transcode( portaudio_encoding, Pa_GetDeviceInfo( i )->name ); } else { device << MPT_USTRING("Device ") << i; } device << MPT_USTRING(" ("); device << MPT_USTRING("high latency: ") << Pa_GetDeviceInfo( i )->defaultHighOutputLatency; device << MPT_USTRING(", "); device << MPT_USTRING("low latency: ") << Pa_GetDeviceInfo( i )->defaultLowOutputLatency; device << MPT_USTRING(")"); devices.push_back( device.str() ); } } return devices; } inline mpt::ustring show_portaudio_version() { string_concat_stream log; log << mpt::transcode( portaudio_encoding, Pa_GetVersionText() ) << MPT_USTRING(" (") << Pa_GetVersion() << MPT_USTRING(") "); return log.str(); } } // namespace openmpt123 #endif // MPT_WITH_PORTAUDIO #endif // OPENMPT123_PORTAUDIO_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_allegro42.hpp0000644000175000017500000001252214674771042022500 00000000000000/* * openmpt123_allegro42.hpp * ------------------------ * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_ALLEGRO42_HPP #define OPENMPT123_ALLEGRO42_HPP #include "openmpt123_config.hpp" #include "openmpt123.hpp" #if defined(MPT_WITH_ALLEGRO42) #if defined(__GNUC__) && !defined(__clang__) && !defined(_MSC_VER) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #pragma GCC diagnostic ignored "-Wfloat-conversion" #pragma GCC diagnostic ignored "-Wdouble-promotion" #endif #include #if defined(__GNUC__) && !defined(__clang__) && !defined(_MSC_VER) #pragma GCC diagnostic pop #endif namespace openmpt123 { inline constexpr auto allegro42_encoding = mpt::logical_encoding::locale; struct allegro42_exception : public exception { static mpt::ustring error_to_string() { try { return mpt::transcode( allegro42_encoding, std::string( allegro_error ) ); } catch ( const std::bad_alloc & ) { return mpt::ustring(); } } allegro42_exception() : exception( MPT_USTRING("Allegro-4.2: ") + error_to_string() ) { } }; class allegro42_raii { public: allegro42_raii() { if ( allegro_init() != 0 ) { throw allegro42_exception(); } } ~allegro42_raii() { allegro_exit(); } }; class allegro42_sound_raii { public: allegro42_sound_raii() { if ( install_sound( DIGI_AUTODETECT, MIDI_NONE, NULL ) != 0 ) { throw allegro42_exception(); } if ( digi_card == DIGI_NONE ) { remove_sound(); throw exception( MPT_USTRING("no audio device found") ); } } ~allegro42_sound_raii() { remove_sound(); } }; class allegro42_stream_raii : public write_buffers_polling_wrapper_int { private: allegro42_raii allegro; allegro42_sound_raii allegro_sound; AUDIOSTREAM * stream; std::size_t bits; std::size_t channels; std::uint32_t period_frames; private: std::uint32_t round_up_power2(std::uint32_t x) { std::uint32_t result = 1; while ( result < x ) { result *= 2; } return result; } public: allegro42_stream_raii( commandlineflags & flags, concat_stream & log ) : write_buffers_polling_wrapper_int(flags) , stream(NULL) , bits(16) , channels(flags.channels) , period_frames(1024) { if ( flags.use_float ) { throw exception( MPT_USTRING("floating point is unsupported") ); } if ( ( flags.channels != 1 ) && ( flags.channels != 2 ) ) { throw exception( MPT_USTRING("only mono or stereo supported") ); } if ( flags.buffer == default_high ) { flags.buffer = 1024 * 2 * 1000 / flags.samplerate; } else if ( flags.buffer == default_low ) { flags.buffer = 512 * 2 * 1000 / flags.samplerate; } if ( flags.period == default_high ) { flags.period = 1024 / 2 * 1000 / flags.samplerate; } else if ( flags.period == default_low ) { flags.period = 512 / 2 * 1000 / flags.samplerate; } flags.apply_default_buffer_sizes(); period_frames = round_up_power2( ( flags.buffer * flags.samplerate ) / ( 1000 * 2 ) ); set_queue_size_frames( period_frames ); if ( flags.verbose ) { log << MPT_USTRING("Allegro-4.2:") << lf; log << MPT_USTRING(" allegro samplerate: ") << get_mixer_frequency() << lf; log << MPT_USTRING(" latency: ") << flags.buffer << lf; log << MPT_USTRING(" period: ") << flags.period << lf; log << MPT_USTRING(" frames per buffer: ") << period_frames << lf; log << MPT_USTRING(" ui redraw: ") << flags.ui_redraw_interval << lf; } stream = play_audio_stream( period_frames, 16, ( flags.channels > 1 ) ? TRUE : FALSE, flags.samplerate, 255, 128 ); if ( !stream ) { bits = 8; stream = play_audio_stream( period_frames, 8, ( flags.channels > 1 ) ? TRUE : FALSE, flags.samplerate, 255, 128 ); if ( !stream ) { throw allegro42_exception(); } } } ~allegro42_stream_raii() { if ( stream ) { stop_audio_stream( stream ); stream = NULL; } } public: bool forward_queue() override { void * p = get_audio_stream_buffer( stream ); if ( !p ) { return false; } for ( std::size_t frame = 0; frame < period_frames; ++frame ) { for ( std::size_t channel = 0; channel < channels; ++channel ) { std::int16_t sample = pop_queue(); if ( bits == 8 ) { std::uint8_t u8sample = ( static_cast( sample ) + 0x8000u ) >> 8; std::memcpy( reinterpret_cast( p ) + ( ( ( frame * channels ) + channel ) * sizeof( std::uint8_t ) ), &u8sample, sizeof( std::uint8_t ) ); } else { std::uint16_t u16sample = static_cast( sample ) + 0x8000u; std::memcpy( reinterpret_cast( p ) + ( ( ( frame * channels ) + channel ) * sizeof( std::uint16_t ) ), &u16sample, sizeof( std::uint16_t ) ); } } } free_audio_stream_buffer( stream ); return true; } bool unpause() override { voice_start( stream->voice ); return true; } bool pause() override { voice_stop( stream->voice ); return true; } bool sleep( int ms ) override { rest( ms ); return true; } }; inline std::vector show_allegro42_devices( concat_stream & /* log */ ) { string_concat_stream device; device << MPT_USTRING("0") << MPT_USTRING(": Default Device"); return { device.str() }; } } // namespace openmpt123 #endif // MPT_WITH_ALLEGRO42 #endif // OPENMPT123_ALLEGRO42_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_stdout.hpp0000644000175000017500000000311713202011064022200 00000000000000/* * openmpt123_stdout.hpp * --------------------- * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_STDOUT_HPP #define OPENMPT123_STDOUT_HPP #include "openmpt123_config.hpp" #include "openmpt123.hpp" namespace openmpt123 { class stdout_stream_raii : public write_buffers_interface { private: std::vector interleaved_float_buffer; std::vector interleaved_int_buffer; public: stdout_stream_raii() { return; } public: void write( const std::vector buffers, std::size_t frames ) override { interleaved_float_buffer.clear(); for ( std::size_t frame = 0; frame < frames; frame++ ) { for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { interleaved_float_buffer.push_back( buffers[channel][frame] ); } } std::cout.write( reinterpret_cast( interleaved_float_buffer.data() ), interleaved_float_buffer.size() * sizeof( float ) ); } void write( const std::vector buffers, std::size_t frames ) override { interleaved_int_buffer.clear(); for ( std::size_t frame = 0; frame < frames; frame++ ) { for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { interleaved_int_buffer.push_back( buffers[channel][frame] ); } } std::cout.write( reinterpret_cast( interleaved_int_buffer.data() ), interleaved_int_buffer.size() * sizeof( std::int16_t ) ); } }; } // namespace openmpt123 #endif // OPENMPT123_STDOUT_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_sdl2.hpp0000644000175000017500000001735614674771042021563 00000000000000/* * openmpt123_sdl2.hpp * ------------------- * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_SDL2_HPP #define OPENMPT123_SDL2_HPP #include "openmpt123_config.hpp" #include "openmpt123.hpp" #if defined(MPT_WITH_SDL2) #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wimplicit-fallthrough" #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif // __clang__ #include #if defined(__clang__) #pragma clang diagnostic pop #endif // __clang__ #ifdef main #undef main #endif #ifdef SDL_main #undef SDL_main #endif #if (SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 4)) MPT_WARNING("Support for SDL2 < 2.0.4 has been deprecated and will be removed in a future openmpt123 version.") #endif namespace openmpt123 { inline constexpr auto sdl2_encoding = mpt::common_encoding::utf8; struct sdl2_exception : public exception { private: static mpt::ustring text_from_code( int code ) { string_concat_stream s; s << code; return s.str(); } public: sdl2_exception( int code, const char * error ) : exception( MPT_USTRING("SDL2: ") + text_from_code( code ) + MPT_USTRING(" (") + mpt::transcode( sdl2_encoding, error ? std::string(error) : std::string("NULL") ) + MPT_USTRING(")") ) { } }; static void check_sdl2_error( int e ) { if ( e < 0 ) { throw sdl2_exception( e, SDL_GetError() ); } } class sdl2_raii { public: sdl2_raii( Uint32 flags ) { check_sdl2_error( SDL_Init( flags ) ); } ~sdl2_raii() { SDL_Quit(); } }; class sdl2_stream_raii : public write_buffers_interface { private: concat_stream & log; sdl2_raii sdl2; int dev; std::size_t channels; bool use_float; std::size_t sampleQueueMaxFrames; std::vector sampleBufFloat; std::vector sampleBufInt; protected: std::uint32_t round_up_power2(std::uint32_t x) { std::uint32_t result = 1; while ( result < x ) { result *= 2; } return result; } public: sdl2_stream_raii( commandlineflags & flags, concat_stream & log_ ) : log(log_) , sdl2( SDL_INIT_NOPARACHUTE | SDL_INIT_TIMER | SDL_INIT_AUDIO ) , dev(-1) , channels(flags.channels) , use_float(flags.use_float) , sampleQueueMaxFrames(0) { if ( flags.buffer == default_high ) { flags.buffer = 160; } else if ( flags.buffer == default_low ) { flags.buffer = 80; } if ( flags.period == default_high ) { flags.period = 20; } else if ( flags.period == default_low ) { flags.period = 10; } flags.apply_default_buffer_sizes(); SDL_AudioSpec audiospec; std::memset( &audiospec, 0, sizeof( SDL_AudioSpec ) ); audiospec.freq = flags.samplerate; audiospec.format = ( flags.use_float ? AUDIO_F32SYS : AUDIO_S16SYS ); audiospec.channels = static_cast( flags.channels ); audiospec.silence = 0; audiospec.samples = static_cast( round_up_power2( ( flags.buffer * flags.samplerate ) / ( 1000 * 2 ) ) ); audiospec.size = static_cast( audiospec.samples * audiospec.channels * ( flags.use_float ? sizeof( float ) : sizeof( std::int16_t ) ) ); audiospec.callback = NULL; audiospec.userdata = NULL; if ( flags.verbose ) { log << MPT_USTRING("SDL2:") << lf; log << MPT_USTRING(" latency: ") << ( audiospec.samples * 2.0 / flags.samplerate ) << MPT_USTRING(" (2 * ") << audiospec.samples << MPT_USTRING(")") << lf; log << lf; } sampleQueueMaxFrames = round_up_power2( ( flags.buffer * flags.samplerate ) / ( 1000 * 2 ) ); SDL_AudioSpec audiospec_obtained; std::memset( &audiospec_obtained, 0, sizeof( SDL_AudioSpec ) ); std::memcpy( &audiospec_obtained, &audiospec, sizeof( SDL_AudioSpec ) ); dev = SDL_OpenAudioDevice( NULL, 0, &audiospec, &audiospec_obtained, 0 ); if ( dev < 0 ) { check_sdl2_error( dev ); } else if ( dev == 0 ) { check_sdl2_error( -1 ); } SDL_PauseAudioDevice( dev, 0 ); } ~sdl2_stream_raii() { SDL_PauseAudioDevice( dev, 1 ); SDL_CloseAudioDevice( dev ); } private: std::size_t get_num_writeable_frames() { std::size_t num_queued_frames = SDL_GetQueuedAudioSize( dev ) / ( use_float ? sizeof( float ) : sizeof( std::int16_t ) ) / channels; if ( num_queued_frames > sampleQueueMaxFrames ) { return 0; } return sampleQueueMaxFrames - num_queued_frames; } template void write_frames( const Tsample * buffer, std::size_t frames ) { while ( frames > 0 ) { std::size_t chunk_frames = std::min( frames, get_num_writeable_frames() ); if ( chunk_frames > 0 ) { check_sdl2_error( SDL_QueueAudio( dev, buffer, static_cast( chunk_frames * channels * ( use_float ? sizeof( float ) : sizeof( std::int16_t ) ) ) ) ); frames -= chunk_frames; buffer += chunk_frames * channels; } else { SDL_Delay( 1 ); } } } public: void write( const std::vector buffers, std::size_t frames ) override { sampleBufFloat.clear(); for ( std::size_t frame = 0; frame < frames; ++frame ) { for ( std::size_t channel = 0; channel < channels; ++channel ) { sampleBufFloat.push_back( buffers[channel][frame] ); } } write_frames( sampleBufFloat.data(), frames ); } void write( const std::vector buffers, std::size_t frames ) override { sampleBufInt.clear(); for ( std::size_t frame = 0; frame < frames; ++frame ) { for ( std::size_t channel = 0; channel < channels; ++channel ) { sampleBufInt.push_back( buffers[channel][frame] ); } } write_frames( sampleBufInt.data(), frames ); } bool pause() override { SDL_PauseAudioDevice( dev, 1 ); return true; } bool unpause() override { SDL_PauseAudioDevice( dev, 0 ); return true; } bool sleep( int ms ) override { SDL_Delay( ms ); return true; } }; inline std::vector show_sdl2_devices( concat_stream & /* log */ ) { std::vector devices; std::size_t device_index = 0; sdl2_raii sdl2( SDL_INIT_NOPARACHUTE | SDL_INIT_AUDIO ); for ( int driver = 0; driver < SDL_GetNumAudioDrivers(); ++driver ) { const char * driver_name = SDL_GetAudioDriver( driver ); if ( !driver_name ) { continue; } if ( std::string( driver_name ).empty() ) { continue; } if ( SDL_AudioInit( driver_name ) < 0 ) { continue; } for ( int device = 0; device < SDL_GetNumAudioDevices( 0 ); ++device ) { string_concat_stream dev; const char * device_name = SDL_GetAudioDeviceName( device, 0 ); if ( !device_name ) { continue; } if ( std::string( device_name ).empty() ) { continue; } dev << device_index << MPT_USTRING(": ") << mpt::transcode( sdl2_encoding, driver_name ) << MPT_USTRING(" - ") << mpt::transcode( sdl2_encoding, device_name ); device_index++; devices.push_back( dev.str() ); } SDL_AudioQuit(); } return devices; } inline mpt::ustring show_sdl2_version() { string_concat_stream log; log << MPT_USTRING("libSDL2 "); SDL_version sdlver; std::memset(&sdlver, 0, sizeof(SDL_version)); SDL_GetVersion(&sdlver); log << static_cast(sdlver.major) << MPT_USTRING(".") << static_cast(sdlver.minor) << MPT_USTRING(".") << static_cast(sdlver.patch); const char* revision = SDL_GetRevision(); if (revision) { log << MPT_USTRING(" (") << mpt::transcode(sdl2_encoding, revision) << MPT_USTRING(")"); } log << MPT_USTRING(", "); std::memset(&sdlver, 0, sizeof(SDL_version)); SDL_VERSION(&sdlver); log << MPT_USTRING("API: ") << static_cast(sdlver.major) << MPT_USTRING(".") << static_cast(sdlver.minor) << MPT_USTRING(".") << static_cast(sdlver.patch); log << MPT_USTRING(" "); return log.str(); } } // namespace openmpt123 #endif // MPT_WITH_SDL2 #endif // OPENMPT123_SDL2_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_waveout.hpp0000644000175000017500000001414714674771042022404 00000000000000/* * openmpt123_waveout.hpp * ------------------------ * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_WAVEOUT_HPP #define OPENMPT123_WAVEOUT_HPP #include "openmpt123_config.hpp" #include "openmpt123.hpp" #include "mpt/base/detect.hpp" #if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT namespace openmpt123 { struct waveout_exception : public exception { waveout_exception() : exception( MPT_USTRING("WaveOut: ") + MPT_USTRING("waveout") ) { } }; class waveout_stream_raii : public write_buffers_interface { private: HWAVEOUT waveout; std::size_t num_channels; std::size_t num_chunks; std::size_t frames_per_chunk; std::size_t bytes_per_chunk; std::vector waveheaders; std::vector > wavebuffers; std::deque byte_queue; public: waveout_stream_raii( commandlineflags & flags, concat_stream & /* log */ ) : waveout(NULL) , num_channels(0) , num_chunks(0) , frames_per_chunk(0) , bytes_per_chunk(0) { if ( flags.buffer == default_high ) { flags.buffer = 150; } else if ( flags.buffer == default_low ) { flags.buffer = 50; } if ( flags.period == default_high ) { flags.period = 30; } else if ( flags.period == default_low ) { flags.period = 10; } flags.apply_default_buffer_sizes(); WAVEFORMATEX wfx; ZeroMemory( &wfx, sizeof( wfx ) ); wfx.wFormatTag = flags.use_float ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; wfx.nChannels = static_cast( flags.channels ); wfx.nSamplesPerSec = flags.samplerate; wfx.wBitsPerSample = flags.use_float ? 32 : 16; wfx.nBlockAlign = ( wfx.wBitsPerSample / 8 ) * wfx.nChannels; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; wfx.cbSize = 0; const int device = mpt::parse_or( flags.device, -1 ); waveOutOpen( &waveout, ( device == -1 ) ? WAVE_MAPPER : device, &wfx, 0, 0, CALLBACK_NULL ); num_channels = flags.channels; std::size_t frames_per_buffer = flags.samplerate * flags.buffer / 1000; num_chunks = ( flags.buffer + flags.period - 1 ) / flags.period; if ( num_chunks < 2 ) { num_chunks = 2; } frames_per_chunk = ( frames_per_buffer + num_chunks - 1 ) / num_chunks; bytes_per_chunk = wfx.nBlockAlign * frames_per_chunk; waveheaders.resize( num_chunks ); wavebuffers.resize( num_chunks ); for ( std::size_t i = 0; i < num_chunks; ++i ) { wavebuffers[i].resize( bytes_per_chunk ); waveheaders[i] = WAVEHDR(); waveheaders[i].lpData = wavebuffers[i].data(); waveheaders[i].dwBufferLength = static_cast( wavebuffers[i].size() ); waveheaders[i].dwFlags = 0; waveOutPrepareHeader( waveout, &waveheaders[i], sizeof( WAVEHDR ) ); } } ~waveout_stream_raii() { if ( waveout ) { write_or_wait( true ); drain(); waveOutReset( waveout ); for ( std::size_t i = 0; i < num_chunks; ++i ) { waveheaders[i].dwBufferLength = static_cast( wavebuffers[i].size() ); waveOutUnprepareHeader( waveout, &waveheaders[i], sizeof( WAVEHDR ) ); } wavebuffers.clear(); waveheaders.clear(); frames_per_chunk = 0; num_chunks = 0; waveOutClose( waveout ); waveout = NULL; } } private: void drain() { std::size_t empty_chunks = 0; while ( empty_chunks != num_chunks ) { empty_chunks = 0; for ( std::size_t chunk = 0; chunk < num_chunks; ++chunk ) { DWORD flags = waveheaders[chunk].dwFlags; if ( !(flags & WHDR_INQUEUE) || (flags & WHDR_DONE) ) { empty_chunks++; } } if ( empty_chunks != num_chunks ) { Sleep( 1 ); } } } std::size_t wait_for_empty_chunk() { while ( true ) { for ( std::size_t chunk = 0; chunk < num_chunks; ++chunk ) { DWORD flags = waveheaders[chunk].dwFlags; if ( !(flags & WHDR_INQUEUE) || (flags & WHDR_DONE) ) { return chunk; } } Sleep( 1 ); } } void write_chunk() { std::size_t chunk = wait_for_empty_chunk(); std::size_t chunk_bytes = std::min( byte_queue.size(), bytes_per_chunk ); waveheaders[chunk].dwBufferLength = static_cast( chunk_bytes ); for ( std::size_t byte = 0; byte < chunk_bytes; ++byte ) { wavebuffers[chunk][byte] = byte_queue.front(); byte_queue.pop_front(); } waveOutWrite( waveout, &waveheaders[chunk], sizeof( WAVEHDR ) ); } void write_or_wait( bool flush = false ) { while ( byte_queue.size() >= bytes_per_chunk ) { write_chunk(); } if ( flush && !byte_queue.empty() ) { write_chunk(); } } template < typename Tsample > void write_buffers( const std::vector buffers, std::size_t frames ) { for ( std::size_t frame = 0; frame < frames; ++frame ) { for ( std::size_t channel = 0; channel < buffers.size(); ++channel ) { Tsample val = buffers[channel][frame]; char buf[ sizeof( Tsample ) ]; std::memcpy( buf, &val, sizeof( Tsample ) ); std::copy( buf, buf + sizeof( Tsample ), std::back_inserter( byte_queue ) ); } } write_or_wait(); } public: void write( const std::vector buffers, std::size_t frames ) override { write_buffers( buffers, frames ); } void write( const std::vector buffers, std::size_t frames ) override { write_buffers( buffers, frames ); } bool pause() override { waveOutPause( waveout ); return true; } bool unpause() override { waveOutRestart( waveout ); return true; } bool sleep( int ms ) override { Sleep( ms ); return true; } }; inline std::vector show_waveout_devices( concat_stream & /*log*/ ) { std::vector devices; for ( UINT i = 0; i < waveOutGetNumDevs(); ++i ) { string_concat_stream device; device << i << MPT_USTRING(": "); WAVEOUTCAPS caps; ZeroMemory( &caps, sizeof( caps ) ); waveOutGetDevCaps( i, &caps, sizeof( caps ) ); #if defined(UNICODE) device << mpt::transcode( caps.szPname ); #else device << mpt::transcode( mpt::logical_encoding::locale, caps.szPname ); #endif devices.push_back( device.str() ); } return devices; } } // namespace openmpt123 #endif // MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT #endif // OPENMPT123_WAVEOUT_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123.hpp0000644000175000017500000003515714675004305020626 00000000000000/* * openmpt123.hpp * -------------- * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_HPP #define OPENMPT123_HPP #include "openmpt123_config.hpp" #include "openmpt123_exception.hpp" #include "openmpt123_terminal.hpp" #include "mpt/base/compiletime_warning.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/float.hpp" #include "mpt/base/math.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/preprocessor.hpp" #include "mpt/base/saturate_round.hpp" #include "mpt/exception/exception_text.hpp" #include "mpt/format/concat.hpp" #include "mpt/format/message.hpp" #include "mpt/format/message_macros.hpp" #include "mpt/format/simple.hpp" #include "mpt/io_file/fstream.hpp" #include "mpt/parse/parse.hpp" #include "mpt/path/native_path.hpp" #include "mpt/string/types.hpp" #include "mpt/string/utility.hpp" #include "mpt/string_transcode/transcode.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { template <> struct make_string_type { using type = mpt::native_path; }; template <> struct is_string_type : public std::true_type { }; template <> struct string_transcoder { using string_type = mpt::native_path; static inline mpt::widestring decode( const string_type & src ) { return mpt::transcode( src.AsNative() ); } static inline string_type encode( const mpt::widestring & src ) { return mpt::native_path::FromNative( mpt::transcode( src ) ); } }; } // namespace MPT_INLINE_NS } // namespace mpt namespace openmpt123 { struct show_help_exception { mpt::ustring message; bool longhelp; show_help_exception( const mpt::ustring & msg = MPT_USTRING(""), bool longhelp_ = true ) : message(msg), longhelp(longhelp_) { } }; struct args_nofiles_exception { args_nofiles_exception() = default; }; struct args_error_exception { args_error_exception() = default; }; struct show_help_keyboard_exception { }; template inline Tstring align_right( const Tchar pad, std::size_t width, const T val ) { assert( Tstring( 1, pad ).length() == 1 ); Tstring str = mpt::default_formatter::template format( val ); if ( width > str.length() ) { str.insert( str.begin(), width - str.length(), pad ); } return str; } struct field { mpt::ustring key; mpt::ustring val; }; inline mpt::ustring append_software_tag( mpt::ustring software ) { mpt::ustring openmpt123 = mpt::ustring() + MPT_USTRING("openmpt123 ") + mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) + MPT_USTRING(" (libopenmpt ") + mpt::transcode( mpt::common_encoding::utf8, openmpt::string::get( "library_version" ) ) + MPT_USTRING(", OpenMPT ") + mpt::transcode( mpt::common_encoding::utf8, openmpt::string::get( "core_version" ) ) + MPT_USTRING(")") ; if ( software.empty() ) { software = openmpt123; } else { software += MPT_USTRING(" (via ") + openmpt123 + MPT_USTRING(")"); } return software; } inline mpt::ustring get_encoder_tag() { return mpt::ustring() + MPT_USTRING("openmpt123 ") + mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) + MPT_USTRING(" (libopenmpt ") + mpt::transcode( mpt::common_encoding::utf8, openmpt::string::get( "library_version" ) ) + MPT_USTRING(", OpenMPT ") + mpt::transcode( mpt::common_encoding::utf8, openmpt::string::get( "core_version" ) ) + MPT_USTRING(")"); } inline mpt::native_path get_extension( mpt::native_path filename ) { mpt::native_path tmp = filename.GetFilenameExtension(); if ( !tmp.empty() ) { tmp = mpt::native_path::FromNative( tmp.AsNative().substr( 1 ) ); } return tmp; } enum class Mode { None, Probe, Info, UI, Batch, Render }; inline mpt::ustring mode_to_string( Mode mode ) { switch ( mode ) { case Mode::None: return MPT_USTRING("none"); break; case Mode::Probe: return MPT_USTRING("probe"); break; case Mode::Info: return MPT_USTRING("info"); break; case Mode::UI: return MPT_USTRING("ui"); break; case Mode::Batch: return MPT_USTRING("batch"); break; case Mode::Render: return MPT_USTRING("render"); break; } return MPT_USTRING(""); } inline const std::int32_t default_low = -2; inline const std::int32_t default_high = -1; enum verbosity : std::int8_t { verbosity_shortversion = -1, verbosity_hidden = 0, verbosity_normal = 1, verbosity_verbose = 2, }; struct commandlineflags { Mode mode = Mode::UI; std::int32_t ui_redraw_interval = default_high; mpt::ustring driver = MPT_USTRING(""); mpt::ustring device = MPT_USTRING(""); std::int32_t buffer = default_high; std::int32_t period = default_high; std::int32_t samplerate = MPT_OS_DJGPP ? 44100 : 48000; std::int32_t channels = 2; std::int32_t gain = 0; std::int32_t separation = 100; std::int32_t filtertaps = 8; std::int32_t ramping = -1; // ramping strength : -1:default 0:off 1 2 3 4 5 // roughly milliseconds std::int32_t tempo = 0; std::int32_t pitch = 0; std::int32_t dither = 1; std::int32_t repeatcount = 0; std::int32_t subsong = -1; std::map ctls = {}; double seek_target = 0.0; double end_time = 0.0; bool quiet = false; verbosity banner = verbosity_normal; bool verbose = false; bool assume_terminal = false; int terminal_width = -1; int terminal_height = -1; bool show_details = true; bool show_message = false; bool show_ui = true; bool show_progress = true; bool show_meters = true; bool show_channel_meters = false; bool show_pattern = false; bool use_float = MPT_OS_DJGPP ? false : mpt::float_traits::is_hard && mpt::float_traits::is_ieee754_binary; bool use_stdout = false; bool randomize = false; bool shuffle = false; bool restart = false; std::size_t playlist_index = 0; std::vector filenames = {}; mpt::native_path output_filename = MPT_NATIVE_PATH(""); mpt::native_path output_extension = MPT_NATIVE_PATH("auto"); bool force_overwrite = false; bool paused = false; mpt::ustring warnings = MPT_USTRING(""); void apply_default_buffer_sizes() { if ( ui_redraw_interval == default_high ) { ui_redraw_interval = 50; } else if ( ui_redraw_interval == default_low ) { ui_redraw_interval = 10; } if ( buffer == default_high ) { buffer = 250; } else if ( buffer == default_low ) { buffer = 50; } if ( period == default_high ) { period = 50; } else if ( period == default_low ) { period = 10; } } void check_and_sanitize() { bool canUI = true; bool canProgress = true; if ( !assume_terminal ) { #if MPT_OS_WINDOWS canUI = IsTerminal( 0 ) ? true : false; canProgress = IsTerminal( 2 ) ? true : false; #else // !MPT_OS_WINDOWS canUI = isatty( STDIN_FILENO ) ? true : false; canProgress = isatty( STDERR_FILENO ) ? true : false; #endif // MPT_OS_WINDOWS } query_terminal_size( terminal_width, terminal_height ); if ( filenames.size() == 0 ) { throw args_nofiles_exception(); } if ( use_stdout && ( device != commandlineflags().device || !output_filename.empty() ) ) { throw args_error_exception(); } if ( !output_filename.empty() && ( device != commandlineflags().device || use_stdout ) ) { throw args_error_exception(); } for ( const auto & filename : filenames ) { if ( filename == MPT_NATIVE_PATH("-") ) { canUI = false; } } show_ui = canUI; if ( !canProgress ) { show_progress = false; } if ( !canUI || !canProgress ) { show_meters = false; } if ( mode == Mode::None ) { if ( canUI ) { mode = Mode::UI; } else { mode = Mode::Batch; } } if ( mode == Mode::UI && !canUI ) { throw args_error_exception(); } if ( show_progress && !canProgress ) { throw args_error_exception(); } switch ( mode ) { case Mode::None: throw args_error_exception(); break; case Mode::Probe: show_ui = false; show_progress = false; show_meters = false; show_channel_meters = false; show_pattern = false; break; case Mode::Info: show_ui = false; show_progress = false; show_meters = false; show_channel_meters = false; show_pattern = false; break; case Mode::UI: break; case Mode::Batch: show_meters = false; show_channel_meters = false; show_pattern = false; break; case Mode::Render: show_meters = false; show_channel_meters = false; show_pattern = false; show_ui = false; break; } if ( quiet ) { verbose = false; show_ui = false; show_details = false; show_progress = false; show_channel_meters = false; } if ( verbose ) { show_details = true; } if ( channels != 1 && channels != 2 && channels != 4 ) { channels = commandlineflags().channels; } if ( samplerate < 0 ) { samplerate = commandlineflags().samplerate; } if ( output_extension == MPT_NATIVE_PATH("auto") ) { output_extension = MPT_NATIVE_PATH(""); } if ( mode != Mode::Render && !output_extension.empty() ) { throw args_error_exception(); } if ( mode == Mode::Render && !output_filename.empty() ) { throw args_error_exception(); } if ( mode != Mode::Render && !output_filename.empty() ) { output_extension = get_extension( output_filename ); } if ( output_extension.empty() ) { output_extension = MPT_NATIVE_PATH("wav"); } } }; template < typename Tsample > Tsample convert_sample_to( float val ); template < > float convert_sample_to( float val ) { return val; } template < > std::int16_t convert_sample_to( float val ) { std::int32_t tmp = static_cast( val * 32768.0f ); tmp = std::min( tmp, std::int32_t( 32767 ) ); tmp = std::max( tmp, std::int32_t( -32768 ) ); return static_cast( tmp ); } class write_buffers_interface { public: virtual ~write_buffers_interface() { return; } virtual void write_metadata( std::map metadata ) { (void)metadata; return; } virtual void write_updated_metadata( std::map metadata ) { (void)metadata; return; } virtual void write( const std::vector buffers, std::size_t frames ) = 0; virtual void write( const std::vector buffers, std::size_t frames ) = 0; virtual bool pause() { return false; } virtual bool unpause() { return false; } virtual bool sleep( int /*ms*/ ) { return false; } virtual bool is_dummy() const { return false; } }; class write_buffers_polling_wrapper : public write_buffers_interface { protected: std::size_t channels; std::size_t sampleQueueMaxFrames; std::deque sampleQueue; protected: virtual ~write_buffers_polling_wrapper() { return; } protected: write_buffers_polling_wrapper( const commandlineflags & flags ) : channels(flags.channels) , sampleQueueMaxFrames(0) { return; } void set_queue_size_frames( std::size_t frames ) { sampleQueueMaxFrames = frames; } template < typename Tsample > Tsample pop_queue() { float val = 0.0f; if ( !sampleQueue.empty() ) { val = sampleQueue.front(); sampleQueue.pop_front(); } return convert_sample_to( val ); } public: void write( const std::vector buffers, std::size_t frames ) override { for ( std::size_t frame = 0; frame < frames; ++frame ) { for ( std::size_t channel = 0; channel < channels; ++channel ) { sampleQueue.push_back( buffers[channel][frame] ); } while ( sampleQueue.size() >= sampleQueueMaxFrames * channels ) { while ( !forward_queue() ) { sleep( 1 ); } } } } void write( const std::vector buffers, std::size_t frames ) override { for ( std::size_t frame = 0; frame < frames; ++frame ) { for ( std::size_t channel = 0; channel < channels; ++channel ) { sampleQueue.push_back( buffers[channel][frame] * (1.0f/32768.0f) ); } while ( sampleQueue.size() >= sampleQueueMaxFrames * channels ) { while ( !forward_queue() ) { sleep( 1 ); } } } } virtual bool forward_queue() = 0; bool sleep( int ms ) override = 0; }; class write_buffers_polling_wrapper_int : public write_buffers_interface { protected: std::size_t channels; std::size_t sampleQueueMaxFrames; std::deque sampleQueue; protected: virtual ~write_buffers_polling_wrapper_int() { return; } protected: write_buffers_polling_wrapper_int( const commandlineflags & flags ) : channels(flags.channels) , sampleQueueMaxFrames(0) { return; } void set_queue_size_frames( std::size_t frames ) { sampleQueueMaxFrames = frames; } std::int16_t pop_queue() { std::int16_t val = 0; if ( !sampleQueue.empty() ) { val = sampleQueue.front(); sampleQueue.pop_front(); } return val; } public: void write( const std::vector buffers, std::size_t frames ) override { for ( std::size_t frame = 0; frame < frames; ++frame ) { for ( std::size_t channel = 0; channel < channels; ++channel ) { sampleQueue.push_back( convert_sample_to( buffers[channel][frame] ) ); } while ( sampleQueue.size() >= sampleQueueMaxFrames * channels ) { while ( !forward_queue() ) { sleep( 1 ); } } } } void write( const std::vector buffers, std::size_t frames ) override { for ( std::size_t frame = 0; frame < frames; ++frame ) { for ( std::size_t channel = 0; channel < channels; ++channel ) { sampleQueue.push_back( buffers[channel][frame] ); } while ( sampleQueue.size() >= sampleQueueMaxFrames * channels ) { while ( !forward_queue() ) { sleep( 1 ); } } } } virtual bool forward_queue() = 0; bool sleep( int ms ) override = 0; }; class void_audio_stream : public write_buffers_interface { public: virtual ~void_audio_stream() { return; } public: void write( const std::vector buffers, std::size_t frames ) override { (void)buffers; (void)frames; } void write( const std::vector buffers, std::size_t frames ) override { (void)buffers; (void)frames; } bool is_dummy() const override { return true; } }; class file_audio_stream_base : public write_buffers_interface { protected: file_audio_stream_base() { return; } public: void write_metadata( std::map metadata ) override { (void)metadata; return; } void write_updated_metadata( std::map metadata ) override { (void)metadata; return; } void write( const std::vector buffers, std::size_t frames ) override = 0; void write( const std::vector buffers, std::size_t frames ) override = 0; virtual ~file_audio_stream_base() { return; } }; } // namespace openmpt123 #endif // OPENMPT123_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_exception.hpp0000644000175000017500000000136614675004305022677 00000000000000/* * openmpt123_exception.hpp * ------------------------ * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_EXCEPTION_HPP #define OPENMPT123_EXCEPTION_HPP #include "openmpt123_config.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include #include namespace openmpt123 { struct exception : public openmpt::exception { exception( const mpt::ustring & text ) : openmpt::exception(mpt::transcode( mpt::common_encoding::utf8, text )) { } }; } // namespace openmpt123 #endif // OPENMPT123_EXCEPTION_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_config.hpp0000644000175000017500000000067114354025507022145 00000000000000/* * openmpt123_config.hpp * --------------------- * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_CONFIG_HPP #define OPENMPT123_CONFIG_HPP #define MPT_INLINE_NS mpt_openmpt123 #define OPENMPT123_VERSION_STRING OPENMPT_API_VERSION_STRING #endif // OPENMPT123_CONFIG_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_terminal.hpp0000644000175000017500000003144314710707267022522 00000000000000/* * openmpt123_terminal.hpp * ----------------------- * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_TERMINAL_HPP #define OPENMPT123_TERMINAL_HPP #include "openmpt123_config.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/format/simple.hpp" #include "mpt/parse/parse.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include #include #include #include #include #if MPT_OS_DJGPP #include #include #include #include #include #include #include #include #elif MPT_OS_WINDOWS #include #include #include #include #if MPT_LIBC_MINGW #include #endif #include #include #include #else #include #include #include #include #include #include #endif namespace openmpt123 { template struct concat_stream { virtual concat_stream & append( Tstring str ) = 0; virtual ~concat_stream() = default; inline concat_stream & operator<<( concat_stream & (*func)( concat_stream & s ) ) { return func( *this ); } }; template inline concat_stream & lf( concat_stream & s ) { return s.append( Tstring(1, mpt::char_constants::lf) ); } template inline concat_stream & operator<<( concat_stream & s, const T & val ) { return s.append( mpt::default_formatter::template format( val ) ); } template struct string_concat_stream : public concat_stream { private: Tstring m_str; public: inline void str( Tstring s ) { m_str = std::move( s ); } inline concat_stream & append( Tstring s ) override { m_str += std::move( s ); return *this; } inline Tstring str() const { return m_str; } ~string_concat_stream() override = default; }; #if MPT_OS_WINDOWS inline std::optional StdHandleFromFd( int fd ) { std::optional stdHandle; if ( fd == _fileno( stdin ) ) { stdHandle = STD_INPUT_HANDLE; } else if ( fd == _fileno( stdout ) ) { stdHandle = STD_OUTPUT_HANDLE; } else if ( fd == _fileno( stderr ) ) { stdHandle = STD_ERROR_HANDLE; } return stdHandle; } #endif #if MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) inline bool IsConsole( DWORD stdHandle ) { HANDLE hStd = GetStdHandle( stdHandle ); if ( ( hStd == NULL ) || ( hStd == INVALID_HANDLE_VALUE ) ) { return false; } DWORD mode = 0; return GetConsoleMode( hStd, &mode ) != FALSE; } #endif // MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) inline bool IsTerminal( int fd ) { #if MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) if ( !_isatty( fd ) ) { return false; } std::optional stdHandle = StdHandleFromFd( fd ); if ( !stdHandle ) { return false; } return IsConsole( *stdHandle ); #else return isatty( fd ) ? true : false; #endif } class textout : public string_concat_stream { protected: textout() = default; public: virtual ~textout() = default; protected: mpt::ustring pop() { mpt::ustring text = str(); str( mpt::ustring() ); return text; } public: virtual void writeout() = 0; virtual void cursor_up( std::size_t lines ) = 0; }; class textout_dummy : public textout { public: textout_dummy() = default; ~textout_dummy() override { static_cast( pop() ); } public: void writeout() override { static_cast( pop() ); } void cursor_up( std::size_t lines ) override { static_cast( lines ); } }; enum class textout_destination { destination_stdout, destination_stderr, }; class textout_backend { protected: textout_backend() = default; public: virtual ~textout_backend() = default; public: virtual void write( const mpt::ustring & text ) = 0; virtual void cursor_up(std::size_t lines) = 0; }; class textout_ostream : public textout_backend { private: std::ostream & s; #if MPT_OS_DJGPP mpt::common_encoding codepage; #endif public: textout_ostream( std::ostream & s_ ) : s(s_) #if MPT_OS_DJGPP , codepage(mpt::common_encoding::cp437) #endif { #if MPT_OS_DJGPP codepage = mpt::djgpp_get_locale_encoding(); #endif return; } ~textout_ostream() override = default; public: void write( const mpt::ustring & text ) override { if ( text.length() > 0 ) { #if MPT_OS_DJGPP s << mpt::transcode( codepage, text ); #elif MPT_OS_EMSCRIPTEN s << mpt::transcode( mpt::common_encoding::utf8, text ) ; #else s << mpt::transcode( mpt::logical_encoding::locale, text ); #endif s.flush(); } } void cursor_up( std::size_t lines ) override { s.flush(); for ( std::size_t line = 0; line < lines; ++line ) { s << std::string("\x1b[1A"); } } }; #if MPT_OS_WINDOWS && defined(UNICODE) class textout_wostream : public textout_backend { private: std::wostream & s; public: textout_wostream( std::wostream & s_ ) : s(s_) { return; } ~textout_wostream() override = default; public: void write( const mpt::ustring & text ) override { if ( text.length() > 0 ) { s << mpt::transcode( text ); s.flush(); } } void cursor_up( std::size_t lines ) override { s.flush(); for ( std::size_t line = 0; line < lines; ++line ) { s << std::wstring(L"\x1b[1A"); } } }; #endif // MPT_OS_WINDOWS && UNICODE #if MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) class textout_ostream_console : public textout_backend { private: #if defined(UNICODE) std::wostream & s; #else std::ostream & s; #endif HANDLE handle; bool console; public: #if defined(UNICODE) textout_ostream_console( std::wostream & s_, DWORD stdHandle_ ) #else textout_ostream_console( std::ostream & s_, DWORD stdHandle_ ) #endif : s(s_) , handle(GetStdHandle( stdHandle_ )) , console(IsConsole( stdHandle_ )) { return; } ~textout_ostream_console() override = default; public: void write( const mpt::ustring & text ) override { if ( text.length() > 0 ) { if ( console ) { DWORD chars_written = 0; #if defined(UNICODE) std::wstring wtext = mpt::transcode( text ); WriteConsole( handle, wtext.data(), static_cast( wtext.size() ), &chars_written, NULL ); #else std::string ltext = mpt::transcode( mpt::logical_encoding::locale, text ); WriteConsole( handle, ltext.data(), static_cast( ltext.size() ), &chars_written, NULL ); #endif } else { #if defined(UNICODE) s << mpt::transcode( text ); #else s << mpt::transcode( mpt::logical_encoding::locale, text ); #endif s.flush(); } } } void cursor_up( std::size_t lines ) override { if ( console ) { s.flush(); CONSOLE_SCREEN_BUFFER_INFO csbi; ZeroMemory( &csbi, sizeof( CONSOLE_SCREEN_BUFFER_INFO ) ); COORD coord_cursor = COORD(); if ( GetConsoleScreenBufferInfo( handle, &csbi ) != FALSE ) { coord_cursor = csbi.dwCursorPosition; coord_cursor.X = 1; coord_cursor.Y -= static_cast( lines ); SetConsoleCursorPosition( handle, coord_cursor ); } } } }; #endif // MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) template class textout_wrapper : public textout { private: #if MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) #if defined(UNICODE) textout_ostream_console out{ dest == textout_destination::destination_stdout ? std::wcout : std::wclog, dest == textout_destination::destination_stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE }; #else textout_ostream_console out{ dest == textout_destination::destination_stdout ? std::cout : std::clog, dest == textout_destination::destination_stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE }; #endif #elif MPT_OS_WINDOWS #if defined(UNICODE) textout_wostream out{ dest == textout_destination::destination_stdout ? std::wcout : std::wclog }; #else textout_ostream out{ dest == textout_destination::destination_stdout ? std::cout : std::clog }; #endif #else textout_ostream out{ dest == textout_destination::destination_stdout ? std::cout : std::clog }; #endif public: textout_wrapper() = default; ~textout_wrapper() override { out.write( pop() ); } public: void writeout() override { out.write( pop() ); } void cursor_up(std::size_t lines) override { out.cursor_up( lines ); } }; inline void query_terminal_size( int & terminal_width, int & terminal_height ) { #if MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) HANDLE hStdOutput = GetStdHandle( STD_OUTPUT_HANDLE ); if ( ( hStdOutput != NULL ) && ( hStdOutput != INVALID_HANDLE_VALUE ) ) { CONSOLE_SCREEN_BUFFER_INFO csbi; ZeroMemory( &csbi, sizeof( CONSOLE_SCREEN_BUFFER_INFO ) ); if ( GetConsoleScreenBufferInfo( hStdOutput, &csbi ) != FALSE ) { if ( terminal_width <= 0 ) { terminal_width = std::min( static_cast( 1 + csbi.srWindow.Right - csbi.srWindow.Left ), static_cast( csbi.dwSize.X ) ); } if ( terminal_height <= 0 ) { terminal_height = std::min( static_cast( 1 + csbi.srWindow.Bottom - csbi.srWindow.Top ), static_cast( csbi.dwSize.Y ) ); } } } #else // !(MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10)) if ( isatty( STDERR_FILENO ) ) { if ( terminal_width <= 0 ) { const char * env_columns = std::getenv( "COLUMNS" ); if ( env_columns ) { int tmp = mpt::parse_or( env_columns, 0 ); if ( tmp > 0 ) { terminal_width = tmp; } } } if ( terminal_height <= 0 ) { const char * env_rows = std::getenv( "ROWS" ); if ( env_rows ) { int tmp = mpt::parse_or( env_rows, 0 ); if ( tmp > 0 ) { terminal_height = tmp; } } } #if defined(TIOCGWINSZ) struct winsize ts; if ( ioctl( STDERR_FILENO, TIOCGWINSZ, &ts ) >= 0 ) { if ( terminal_width <= 0 ) { terminal_width = ts.ws_col; } if ( terminal_height <= 0 ) { terminal_height = ts.ws_row; } } #elif defined(TIOCGSIZE) struct ttysize ts; if ( ioctl( STDERR_FILENO, TIOCGSIZE, &ts ) >= 0 ) { if ( terminal_width <= 0 ) { terminal_width = ts.ts_cols; } if ( terminal_height <= 0 ) { terminal_height = ts.ts_rows; } } #endif } #endif // MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) #if MPT_OS_DJGPP if ( terminal_width <= 0 ) { terminal_width = 80; } if ( terminal_height <= 0 ) { terminal_height = 25; } #else if ( terminal_width <= 0 ) { terminal_width = 72; } if ( terminal_height <= 0 ) { terminal_height = 23; } #endif } #if MPT_OS_WINDOWS class terminal_ui_guard { public: terminal_ui_guard() = default; terminal_ui_guard( const terminal_ui_guard & ) = delete; terminal_ui_guard( terminal_ui_guard && ) = default; terminal_ui_guard & operator=( const terminal_ui_guard & ) = delete; terminal_ui_guard & operator=( terminal_ui_guard && ) = default; ~terminal_ui_guard() = default; }; #else class terminal_ui_guard { private: bool changed = false; termios saved_attributes; public: terminal_ui_guard() { if ( !isatty( STDIN_FILENO ) ) { return; } tcgetattr( STDIN_FILENO, &saved_attributes ); termios tattr = saved_attributes; tattr.c_lflag &= ~( ICANON | ECHO ); tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr( STDIN_FILENO, TCSAFLUSH, &tattr ); changed = true; } terminal_ui_guard( const terminal_ui_guard & ) = delete; terminal_ui_guard( terminal_ui_guard && ) = default; terminal_ui_guard & operator=( const terminal_ui_guard & ) = delete; terminal_ui_guard & operator=( terminal_ui_guard && ) = default; ~terminal_ui_guard() { if ( changed ) { tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes); } } }; #endif class terminal_input { public: static inline bool is_input_available() { #if MPT_OS_DJGPP return kbhit() ? true : false; #elif MPT_OS_WINDOWS && defined( UNICODE ) && !MPT_OS_WINDOWS_WINRT return _kbhit() ? true : false; #elif MPT_OS_WINDOWS return _kbhit() ? true : false; #else pollfd pollfds; pollfds.fd = STDIN_FILENO; pollfds.events = POLLIN; poll(&pollfds, 1, 0); if ( !( pollfds.revents & POLLIN ) ) { return false; } return true; #endif } static inline std::optional read_input_char() { #if MPT_OS_DJGPP int c = getch(); return static_cast( c ); #elif MPT_OS_WINDOWS && defined( UNICODE ) && !MPT_OS_WINDOWS_WINRT wint_t c = _getwch(); return static_cast( c ); #elif MPT_OS_WINDOWS int c = _getch(); return static_cast( c ); #else char c = 0; if ( read( STDIN_FILENO, &c, 1 ) != 1 ) { return std::nullopt; } return static_cast( c ); #endif } }; } // namespace openmpt123 #endif // OPENMPT123_TERMINAL_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_stdio.hpp0000644000175000017500000000633714710711023022016 00000000000000/* * openmpt123_stdio.hpp * -------------------- * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_STDIO_HPP #define OPENMPT123_STDIO_HPP #include "openmpt123_config.hpp" #include "openmpt123_exception.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #include #if MPT_OS_DJGPP #include #include #elif MPT_OS_WINDOWS #include #include #endif #include namespace openmpt123 { enum class FILE_mode { text, binary, }; #if MPT_OS_DJGPP class FILE_mode_guard { private: FILE * file; int old_mode; public: FILE_mode_guard( FILE * file, FILE_mode new_mode ) : file(file) , old_mode(-1) { switch (new_mode) { case FILE_mode::text: fflush( file ); old_mode = setmode( fileno( file ), O_TEXT ); if ( old_mode == -1 ) { throw exception( MPT_USTRING("failed to set TEXT mode on file descriptor") ); } break; case FILE_mode::binary: fflush( file ); old_mode = setmode( fileno( file ), O_BINARY ); if ( old_mode == -1 ) { throw exception( MPT_USTRING("failed to set binary mode on file descriptor") ); } break; } } FILE_mode_guard( const FILE_mode_guard & ) = delete; FILE_mode_guard( FILE_mode_guard && ) = default; FILE_mode_guard & operator=( const FILE_mode_guard & ) = delete; FILE_mode_guard & operator=( FILE_mode_guard && ) = default; ~FILE_mode_guard() { if ( old_mode != -1 ) { fflush( file ); old_mode = setmode( fileno( file ), old_mode ); } } }; #elif MPT_OS_WINDOWS class FILE_mode_guard { private: FILE * file; int old_mode; public: FILE_mode_guard( FILE * file, FILE_mode new_mode ) : file(file) , old_mode(-1) { switch (new_mode) { case FILE_mode::text: fflush( file ); #if defined(UNICODE) old_mode = _setmode( _fileno( file ), _O_U8TEXT ); #else old_mode = _setmode( _fileno( file ), _O_TEXT ); #endif if ( old_mode == -1 ) { throw exception( MPT_USTRING("failed to set TEXT mode on file descriptor") ); } break; case FILE_mode::binary: fflush( file ); old_mode = _setmode( _fileno( file ), _O_BINARY ); if ( old_mode == -1 ) { throw exception( MPT_USTRING("failed to set binary mode on file descriptor") ); } break; } } FILE_mode_guard( const FILE_mode_guard & ) = delete; FILE_mode_guard( FILE_mode_guard && ) = default; FILE_mode_guard & operator=( const FILE_mode_guard & ) = delete; FILE_mode_guard & operator=( FILE_mode_guard && ) = default; ~FILE_mode_guard() { if ( old_mode != -1 ) { fflush( file ); old_mode = _setmode( _fileno( file ), old_mode ); } } }; #else class FILE_mode_guard { public: FILE_mode_guard( FILE * /* file */, FILE_mode /* new_mode */ ) { return; } FILE_mode_guard( const FILE_mode_guard & ) = delete; FILE_mode_guard( FILE_mode_guard && ) = default; FILE_mode_guard & operator=( const FILE_mode_guard & ) = delete; FILE_mode_guard & operator=( FILE_mode_guard && ) = default; ~FILE_mode_guard() = default; }; #endif } // namespace openmpt123 #endif // OPENMPT123_STDIO_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_pulseaudio.hpp0000644000175000017500000001333314674771042023060 00000000000000/* * openmpt123_pulseaudio.hpp * ------------------------- * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_PULSEAUDIO_HPP #define OPENMPT123_PULSEAUDIO_HPP #include "openmpt123_config.hpp" #include "openmpt123.hpp" #if defined(MPT_WITH_PULSEAUDIO) #include #include namespace openmpt123 { inline constexpr auto pulseaudio_encoding = mpt::common_encoding::utf8; struct pulseaudio_exception : public exception { static mpt::ustring error_to_string( int error ) { try { if ( error == 0 ) { return mpt::ustring(); } string_concat_stream e; const char * str = pa_strerror( error ); if ( !str ) { e << MPT_USTRING("error=)") << error; return e.str(); } if ( std::strlen(str) == 0 ) { e << MPT_USTRING("error=") << error; return e.str(); } e << mpt::transcode( pulseaudio_encoding, str ) << MPT_USTRING(" (error=") << error << MPT_USTRING(")"); return e.str(); } catch ( const std::bad_alloc & ) { return mpt::ustring(); } } pulseaudio_exception( int error ) : exception( MPT_USTRING("PulseAudio: ") + error_to_string( error ) ) { } }; class pulseaudio_stream_raii : public write_buffers_interface { private: pa_simple * stream; std::size_t channels; std::size_t sampleSize; std::vector sampleBufFloat; std::vector sampleBufInt; public: pulseaudio_stream_raii( commandlineflags & flags, concat_stream & /* log */ ) : stream(NULL) , channels(flags.channels) , sampleSize(flags.use_float ? sizeof( float ) : sizeof( std::int16_t )) { int error = 0; pa_sample_spec ss; std::memset( &ss, 0, sizeof( pa_sample_spec ) ); ss.format = ( flags.use_float ? PA_SAMPLE_FLOAT32 : PA_SAMPLE_S16NE ); ss.rate = flags.samplerate; ss.channels = static_cast( flags.channels ); pa_buffer_attr ba; std::memset( &ba, 0, sizeof( pa_buffer_attr ) ); bool use_ba = false; if ( flags.buffer != default_high && flags.buffer != default_low ) { use_ba = true; ba.maxlength = static_cast( channels * sampleSize * ( flags.buffer * flags.samplerate / 1000 ) ); } else { ba.maxlength = static_cast(-1); } if ( flags.period != default_high && flags.period != default_low ) { use_ba = true; ba.minreq = static_cast( channels * sampleSize * ( flags.period * flags.samplerate / 1000 ) ); if ( ba.maxlength != static_cast(-1) ) { ba.tlength = ba.maxlength - ba.minreq; ba.prebuf = ba.tlength; } else { ba.tlength = static_cast(-1); ba.prebuf = static_cast(-1); } } else { ba.minreq = static_cast(-1); ba.tlength = static_cast(-1); ba.prebuf = static_cast(-1); } ba.fragsize = 0; flags.apply_default_buffer_sizes(); sampleBufFloat.resize( channels * ( flags.ui_redraw_interval * flags.samplerate / 1000 ) ); sampleBufInt.resize( channels * ( flags.ui_redraw_interval * flags.samplerate / 1000 ) ); stream = pa_simple_new( NULL, "openmpt123", PA_STREAM_PLAYBACK, NULL, "openmpt123", &ss, NULL, ( use_ba ? &ba : NULL ), &error ); if ( !stream ) { throw pulseaudio_exception( error ); } } ~pulseaudio_stream_raii() { int error = 0; if ( stream ) { error = 0; if ( pa_simple_drain( stream, &error ) < 0 ) { // throw pulseaudio_exception( error ); } pa_simple_free( stream ); stream = NULL; } } private: template void write_frames( const Tsample * buffer, std::size_t frames ) { int error = 0; if ( pa_simple_write( stream, buffer, frames * channels * sampleSize, &error ) < 0 ) { throw pulseaudio_exception( error ); } } public: void write( const std::vector buffers, std::size_t frames ) override { sampleBufFloat.clear(); for ( std::size_t frame = 0; frame < frames; ++frame ) { for ( std::size_t channel = 0; channel < channels; ++channel ) { sampleBufFloat.push_back( buffers[channel][frame] ); } } write_frames( sampleBufFloat.data(), frames ); } void write( const std::vector buffers, std::size_t frames ) override { sampleBufInt.clear(); for ( std::size_t frame = 0; frame < frames; ++frame ) { for ( std::size_t channel = 0; channel < channels; ++channel ) { sampleBufInt.push_back( buffers[channel][frame] ); } } write_frames( sampleBufInt.data(), frames ); } bool unpause() override { return true; } bool pause() override { int error = 0; error = 0; if ( pa_simple_drain( stream, &error ) < 0 ) { throw pulseaudio_exception( error ); } return true; } bool sleep( int ms ) override { pa_msleep( ms ); return true; } }; inline std::vector show_pulseaudio_devices( concat_stream & /* log */ ) { string_concat_stream device; device << MPT_USTRING("0") << MPT_USTRING(": Default Device"); return { device.str() }; } inline mpt::ustring show_pulseaudio_version() { string_concat_stream log; log << MPT_USTRING("libpulse, libpulse-simple") << MPT_USTRING(" (headers ") << mpt::transcode( pulseaudio_encoding, pa_get_headers_version() ) << MPT_USTRING(", API ") << PA_API_VERSION << MPT_USTRING(", PROTOCOL ") << PA_PROTOCOL_VERSION << MPT_USTRING(", library ") << mpt::transcode( pulseaudio_encoding, ( pa_get_library_version() ? pa_get_library_version() : "unknown" ) ) << MPT_USTRING(") "); return log.str(); } } // namespace openmpt123 #endif // MPT_WITH_PULSEAUDIO #endif // OPENMPT123_PULSEAUDIO_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_mmio.hpp0000644000175000017500000001036714363770763021657 00000000000000/* * openmpt123_mmio.hpp * ------------------- * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_MMIO_HPP #define OPENMPT123_MMIO_HPP #include "openmpt123_config.hpp" #include "openmpt123.hpp" #include "mpt/base/detect.hpp" #if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT namespace openmpt123 { class mmio_stream_raii : public file_audio_stream_base { private: concat_stream & log; commandlineflags flags; WAVEFORMATEX waveformatex; HMMIO mmio; MMCKINFO WAVE_chunk; MMCKINFO fmt__chunk; MMCKINFO data_chunk; MMIOINFO data_info; private: void CHECKED( HRESULT err ) { if ( err != 0 ) { throw exception( MPT_USTRING("error writing wave file") ); } } void UNCHECKED( HRESULT err ) { if ( err != 0 ) { log << MPT_USTRING("error writing wave file") << lf; } } public: mmio_stream_raii( const mpt::native_path & filename, const commandlineflags & flags_, concat_stream & log_ ) : log(log_), flags(flags_), mmio(NULL) { ZeroMemory( &waveformatex, sizeof( WAVEFORMATEX ) ); waveformatex.cbSize = 0; waveformatex.wFormatTag = flags.use_float ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; waveformatex.nChannels = static_cast( flags.channels ); waveformatex.nSamplesPerSec = flags.samplerate; waveformatex.wBitsPerSample = flags.use_float ? 32 : 16; waveformatex.nBlockAlign = static_cast( flags.channels * ( waveformatex.wBitsPerSample / 8 ) ); waveformatex.nAvgBytesPerSec = waveformatex.nSamplesPerSec * waveformatex.nBlockAlign; #if defined(UNICODE) wchar_t * tmp = _wcsdup( filename.AsNative().c_str() ); mmio = mmioOpen( tmp, NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE ); free( tmp ); tmp = 0; #else char * tmp = strdup( filename.AsNative().c_str() ); mmio = mmioOpen( tmp, NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE ); free( tmp ); tmp = 0; #endif ZeroMemory( &WAVE_chunk, sizeof( MMCKINFO ) ); WAVE_chunk.fccType = mmioFOURCC('W', 'A', 'V', 'E'); CHECKED(mmioCreateChunk( mmio, &WAVE_chunk, MMIO_CREATERIFF )); ZeroMemory( &fmt__chunk, sizeof( MMCKINFO ) ); fmt__chunk.ckid = mmioFOURCC('f', 'm', 't', ' '); fmt__chunk.cksize = sizeof( WAVEFORMATEX ); CHECKED(mmioCreateChunk( mmio, &fmt__chunk, 0 )); mmioWrite( mmio, (const char*)&waveformatex, sizeof( WAVEFORMATEX ) ); CHECKED(mmioAscend( mmio, &fmt__chunk, 0 )); ZeroMemory( &data_chunk, sizeof( MMCKINFO ) ); data_chunk.ckid = mmioFOURCC('d', 'a', 't', 'a'); data_chunk.cksize = 0; CHECKED(mmioCreateChunk( mmio, &data_chunk, 0 )); ZeroMemory( &data_info, sizeof( MMIOINFO ) ); CHECKED(mmioGetInfo( mmio, &data_info, 0 )); } void write( const std::vector buffers, std::size_t frames ) override { for ( std::size_t frame = 0; frame < frames; frame++ ) { for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { if ( data_info.pchEndWrite - data_info.pchNext < static_cast( sizeof( float ) ) ) { data_info.dwFlags |= MMIO_DIRTY; CHECKED(mmioAdvance( mmio, &data_info, MMIO_WRITE )); } std::memcpy( data_info.pchNext, &( buffers[channel][frame] ), sizeof( float ) ); data_info.pchNext += sizeof( float ); } } } void write( const std::vector buffers, std::size_t frames ) override { for ( std::size_t frame = 0; frame < frames; frame++ ) { for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { if ( data_info.pchEndWrite - data_info.pchNext < static_cast( sizeof( std::int16_t ) ) ) { data_info.dwFlags |= MMIO_DIRTY; CHECKED(mmioAdvance( mmio, &data_info, MMIO_WRITE )); } std::memcpy( data_info.pchNext, &( buffers[channel][frame] ), sizeof( std::int16_t ) ); data_info.pchNext += sizeof( std::int16_t ); } } } ~mmio_stream_raii() { data_info.dwFlags |= MMIO_DIRTY; UNCHECKED(mmioSetInfo( mmio, &data_info, 0 )); UNCHECKED(mmioAscend( mmio, &data_chunk, 0 )); UNCHECKED(mmioAscend( mmio, &WAVE_chunk, 0 )); UNCHECKED(mmioClose( mmio, 0 )); mmio = NULL; } }; } // namespace openmpt123 #endif // MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT #endif // OPENMPT123_MMIO_HPP libopenmpt-0.8.1+release.autotools/openmpt123/openmpt123_sndfile.hpp0000644000175000017500000002253015021607422022314 00000000000000/* * openmpt123_sndfile.hpp * ---------------------- * Purpose: libopenmpt command line player * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef OPENMPT123_SNDFILE_HPP #define OPENMPT123_SNDFILE_HPP #include "openmpt123_config.hpp" #include "openmpt123.hpp" #if defined(MPT_WITH_SNDFILE) #include "mpt/base/detect.hpp" #include namespace openmpt123 { inline constexpr auto sndfile_encoding = mpt::common_encoding::utf8; class sndfile_stream_raii : public file_audio_stream_base { private: commandlineflags flags; concat_stream & log; SNDFILE * sndfile; std::vector interleaved_float_buffer; std::vector interleaved_int_buffer; private: enum match_mode_enum { match_print, match_recurse, match_exact, match_better, match_any }; mpt::ustring match_mode_to_string( match_mode_enum match_mode ) { switch ( match_mode ) { case match_print : return MPT_USTRING("print") ; break; case match_recurse: return MPT_USTRING("recurse"); break; case match_exact : return MPT_USTRING("exact") ; break; case match_better : return MPT_USTRING("better") ; break; case match_any : return MPT_USTRING("any") ; break; } return MPT_USTRING(""); } int matched_result( int format, const SF_FORMAT_INFO & format_info, const SF_FORMAT_INFO & subformat_info, match_mode_enum match_mode ) { if ( flags.verbose ) { log << MPT_USTRING("sndfile: using format '") << mpt::transcode( sndfile_encoding, format_info.name ) << MPT_USTRING(" (") << mpt::transcode( sndfile_encoding, format_info.extension ) << MPT_USTRING(")") << MPT_USTRING(" / ") << mpt::transcode( sndfile_encoding, subformat_info.name ) << MPT_USTRING("', ") << MPT_USTRING("match: ") << match_mode_to_string( match_mode ) << lf; } return format; } int find_format( const mpt::native_path & extension, match_mode_enum match_mode ) { if ( match_mode == match_recurse ) { int result = 0; result = find_format( extension, match_exact ); if ( result ) { return result; } result = find_format( extension, match_better ); if ( result ) { return result; } result = find_format( extension, match_any ); if ( result ) { return result; } if ( result ) { return result; } return 0; } int major_count; sf_command( 0, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof( int ) ); for ( int m = 0; m < major_count; m++ ) { SF_FORMAT_INFO format_info; format_info.format = m; sf_command( 0, SFC_GET_FORMAT_MAJOR, &format_info, sizeof( SF_FORMAT_INFO ) ); int subtype_count; sf_command( 0, SFC_GET_FORMAT_SUBTYPE_COUNT, &subtype_count, sizeof( int ) ); for ( int s = 0; s < subtype_count; s++ ) { SF_FORMAT_INFO subformat_info; subformat_info.format = s; sf_command( 0, SFC_GET_FORMAT_SUBTYPE, &subformat_info, sizeof( SF_FORMAT_INFO ) ); int format = ( format_info.format & SF_FORMAT_TYPEMASK ) | ( subformat_info.format & SF_FORMAT_SUBMASK ); SF_INFO sfinfo; std::memset( &sfinfo, 0, sizeof( SF_INFO ) ); sfinfo.channels = flags.channels; sfinfo.format = format; if ( sf_format_check( &sfinfo ) ) { switch ( match_mode ) { case match_print: log << MPT_USTRING("sndfile: ") << mpt::transcode( sndfile_encoding, ( format_info.name ? format_info.name : "" ) ) << MPT_USTRING(" (.") << mpt::transcode( sndfile_encoding, ( subformat_info.extension ? subformat_info.extension : format_info.extension ? format_info.extension : "" ) ) << MPT_USTRING(")") << MPT_USTRING(" / ") << mpt::transcode( sndfile_encoding, ( subformat_info.name ? subformat_info.name : "" ) ) << MPT_USTRING(" [") << mpt::format::hex0<8>( format ) << MPT_USTRING("]") << lf; break; case match_recurse: break; case match_exact: if ( subformat_info.extension && ( mpt::transcode( sndfile_encoding, extension ) == subformat_info.extension ) ) { if ( flags.use_float && ( subformat_info.format == SF_FORMAT_FLOAT ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } else if ( !flags.use_float && ( subformat_info.format == SF_FORMAT_PCM_16 ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } } break; if ( format_info.extension && ( mpt::transcode( sndfile_encoding, extension ) == format_info.extension ) ) { if ( flags.use_float && ( subformat_info.format == SF_FORMAT_FLOAT ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } else if ( !flags.use_float && ( subformat_info.format == SF_FORMAT_PCM_16 ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } } break; case match_better: if ( subformat_info.extension && ( mpt::transcode( sndfile_encoding, extension ) == subformat_info.extension ) ) { if ( flags.use_float && ( subformat_info.format == SF_FORMAT_FLOAT || subformat_info.format == SF_FORMAT_DOUBLE ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } else if ( !flags.use_float && ( subformat_info.format & ( subformat_info.format == SF_FORMAT_PCM_16 || subformat_info.format == SF_FORMAT_PCM_24 || subformat_info.format == SF_FORMAT_PCM_32 ) ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } } break; if ( format_info.extension && ( mpt::transcode( sndfile_encoding, extension ) == format_info.extension ) ) { if ( flags.use_float && ( subformat_info.format == SF_FORMAT_FLOAT || subformat_info.format == SF_FORMAT_DOUBLE ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } else if ( !flags.use_float && ( subformat_info.format & ( subformat_info.format == SF_FORMAT_PCM_16 || subformat_info.format == SF_FORMAT_PCM_24 || subformat_info.format == SF_FORMAT_PCM_32 ) ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } } break; case match_any: if ( subformat_info.extension && ( mpt::transcode( sndfile_encoding, extension ) == subformat_info.extension ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } if ( format_info.extension && ( mpt::transcode( sndfile_encoding, extension ) == format_info.extension ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } break; } } } } return 0; } void write_metadata_field( int str_type, const std::string & str ) { if ( !str.empty() ) { sf_set_string( sndfile, str_type, str.c_str() ); } } public: sndfile_stream_raii( const mpt::native_path & filename, const commandlineflags & flags_, concat_stream & log_ ) : flags(flags_), log(log_), sndfile(0) { if ( flags.verbose ) { find_format( MPT_NATIVE_PATH(""), match_print ); log << lf; } int format = find_format( flags.output_extension, match_recurse ); if ( !format ) { throw exception( MPT_USTRING("unknown file type") ); } SF_INFO info; std::memset( &info, 0, sizeof( SF_INFO ) ); info.samplerate = flags.samplerate; info.channels = flags.channels; info.format = format; #if MPT_OS_WINDOWS && defined(UNICODE) sndfile = sf_wchar_open( filename.AsNative().c_str(), SFM_WRITE, &info ); #else sndfile = sf_open( filename.AsNative().c_str(), SFM_WRITE, &info ); #endif } ~sndfile_stream_raii() { sf_close( sndfile ); sndfile = 0; } void write_metadata( std::map metadata ) override { write_metadata_field( SF_STR_TITLE, mpt::transcode( sndfile_encoding, metadata[ MPT_USTRING("title") ] ) ); write_metadata_field( SF_STR_ARTIST, mpt::transcode( sndfile_encoding, metadata[ MPT_USTRING("artist") ] ) ); write_metadata_field( SF_STR_DATE, mpt::transcode( sndfile_encoding, metadata[ MPT_USTRING("date") ] ) ); write_metadata_field( SF_STR_COMMENT, mpt::transcode( sndfile_encoding, metadata[ MPT_USTRING("message") ] ) ); write_metadata_field( SF_STR_SOFTWARE, mpt::transcode( sndfile_encoding, append_software_tag( metadata[ MPT_USTRING("tracker") ] ) ) ); } void write( const std::vector buffers, std::size_t frames ) override { interleaved_float_buffer.clear(); for ( std::size_t frame = 0; frame < frames; frame++ ) { for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { interleaved_float_buffer.push_back( buffers[channel][frame] ); } } sf_writef_float( sndfile, interleaved_float_buffer.data(), frames ); } void write( const std::vector buffers, std::size_t frames ) override { interleaved_int_buffer.clear(); for ( std::size_t frame = 0; frame < frames; frame++ ) { for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { interleaved_int_buffer.push_back( buffers[channel][frame] ); } } sf_writef_short( sndfile, interleaved_int_buffer.data(), frames ); } }; } // namespace openmpt123 #endif // MPT_WITH_SNDFILE #endif // OPENMPT123_SNDFILE_HPP libopenmpt-0.8.1+release.autotools/aclocal.m40000644000175000017500000012746215023302306016124 00000000000000# generated automatically by aclocal 1.16.5 -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],, [m4_warning([this file was generated for autoconf 2.71. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.16.5], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.16.5])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # Copyright (C) 2011-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_AR([ACT-IF-FAIL]) # ------------------------- # Try to determine the archiver interface, and trigger the ar-lib wrapper # if it is needed. If the detection of archiver interface fails, run # ACT-IF-FAIL (default is to abort configure with a proper error message). AC_DEFUN([AM_PROG_AR], [AC_BEFORE([$0], [LT_INIT])dnl AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([ar-lib])dnl AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) : ${AR=ar} AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], [AC_LANG_PUSH([C]) am_cv_ar_interface=ar AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a ]) AC_LANG_POP([C])]) case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) m4_default([$1], [AC_MSG_ERROR([could not determine $AR interface])]) ;; esac AC_SUBST([AR])dnl ]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE="gmake" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking is enabled. # This creates each '.Po' and '.Plo' makefile fragment that we'll need in # order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl m4_ifdef([_$0_ALREADY_INIT], [m4_fatal([$0 expanded multiple times ]m4_defn([_$0_ALREADY_INIT]))], [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi AC_SUBST([CTAGS]) if test -z "$ETAGS"; then ETAGS=etags fi AC_SUBST([ETAGS]) if test -z "$CSCOPE"; then CSCOPE=cscope fi AC_SUBST([CSCOPE]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/ax_cflags_warn_all.m4]) m4_include([m4/ax_check_compile_flag.m4]) m4_include([m4/ax_compiler_vendor.m4]) m4_include([m4/ax_cxx_compile_stdcxx.m4]) m4_include([m4/ax_cxx_exceptions.m4]) m4_include([m4/ax_cxx_rtti.m4]) m4_include([m4/ax_prepend_flag.m4]) m4_include([m4/ax_prog_doxygen.m4]) m4_include([m4/ax_pthread.m4]) m4_include([m4/ax_require_defined.m4]) m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) m4_include([m4/pkg.m4]) libopenmpt-0.8.1+release.autotools/Makefile.am0000644000175000017500000010602214765261244016326 00000000000000ACLOCAL_AMFLAGS = -I m4 --install EXTRA_DIST = EXTRA_DIST += .clang-format EXTRA_DIST += m4/emptydir EXTRA_DIST += libopenmpt/libopenmpt.pc.in EXTRA_DIST += LICENSE EXTRA_DIST += README.md EXTRA_DIST += Doxyfile.in EXTRA_DIST += doc/contributing.md EXTRA_DIST += doc/libopenmpt_styleguide.md EXTRA_DIST += doc/libopenmpt/changelog.md EXTRA_DIST += doc/libopenmpt/dependencies.md EXTRA_DIST += doc/libopenmpt/gettingstarted.md EXTRA_DIST += doc/libopenmpt/index.dox EXTRA_DIST += doc/libopenmpt/packaging.md EXTRA_DIST += doc/libopenmpt/tests.md EXTRA_DIST += doc/module_formats.md EXTRA_DIST += doc/openmpt_styleguide.md EXTRA_DIST += libopenmpt/.clang-format EXTRA_DIST += libopenmpt/libopenmpt_version.mk EXTRA_DIST += openmpt123/.clang-format EXTRA_DIST += src/mpt/.clang-format EXTRA_DIST += src/mpt/LICENSE.BSD-3-Clause.txt EXTRA_DIST += src/mpt/LICENSE.BSL-1.0.txt EXTRA_DIST += test/test.xm EXTRA_DIST += test/test.s3m EXTRA_DIST += test/test.mod EXTRA_DIST += test/test.mptm EXTRA_DIST += man/openmpt123.1 EXTRA_DIST += examples/.clang-format EXTRA_DIST += libopenmpt/bindings/freebasic/libopenmpt.bi EXTRA_DIST += libopenmpt/bindings/freebasic/libopenmpt_ext.bi MOSTLYCLEANFILES = dist_doc_DATA = dist_doc_DATA += LICENSE dist_doc_DATA += README.md nobase_dist_doc_DATA = nobase_dist_doc_DATA += examples/libopenmpt_example_cxx.cpp nobase_dist_doc_DATA += examples/libopenmpt_example_c_mem.c nobase_dist_doc_DATA += examples/libopenmpt_example_c_unsafe.c nobase_dist_doc_DATA += examples/libopenmpt_example_c.c nobase_dist_doc_DATA += examples/libopenmpt_example_c_pipe.c nobase_dist_doc_DATA += examples/libopenmpt_example_c_probe.c nobase_dist_doc_DATA += examples/libopenmpt_example_c_stdout.c bin_PROGRAMS = check_PROGRAMS = lib_LTLIBRARIES = if ENABLE_TESTS TESTS = libopenmpttest endif if ENABLE_EXAMPLES check_PROGRAMS += libopenmpt_example_c_pipe check_PROGRAMS += libopenmpt_example_c_probe check_PROGRAMS += libopenmpt_example_c_stdout if HAVE_PORTAUDIO check_PROGRAMS += libopenmpt_example_c check_PROGRAMS += libopenmpt_example_c_mem check_PROGRAMS += libopenmpt_example_c_unsafe endif if HAVE_PORTAUDIOCPP check_PROGRAMS += libopenmpt_example_cxx endif libopenmpt_example_c_pipe_SOURCES = examples/libopenmpt_example_c_pipe.c libopenmpt_example_c_probe_SOURCES = examples/libopenmpt_example_c_probe.c libopenmpt_example_c_stdout_SOURCES = examples/libopenmpt_example_c_stdout.c if HAVE_PORTAUDIO libopenmpt_example_c_SOURCES = examples/libopenmpt_example_c.c libopenmpt_example_c_mem_SOURCES = examples/libopenmpt_example_c_mem.c libopenmpt_example_c_unsafe_SOURCES = examples/libopenmpt_example_c_unsafe.c endif if HAVE_PORTAUDIOCPP libopenmpt_example_cxx_SOURCES = examples/libopenmpt_example_cxx.cpp endif libopenmpt_example_c_pipe_CPPFLAGS = $(WIN32_CPPFLAGS) libopenmpt_example_c_probe_CPPFLAGS = $(WIN32_CPPFLAGS) libopenmpt_example_c_stdout_CPPFLAGS = $(WIN32_CPPFLAGS) if HAVE_PORTAUDIO libopenmpt_example_c_CPPFLAGS = $(WIN32_CPPFLAGS) $(PORTAUDIO_CFLAGS) libopenmpt_example_c_mem_CPPFLAGS = $(WIN32_CPPFLAGS) $(PORTAUDIO_CFLAGS) libopenmpt_example_c_unsafe_CPPFLAGS = $(WIN32_CPPFLAGS) $(PORTAUDIO_CFLAGS) endif if HAVE_PORTAUDIOCPP libopenmpt_example_cxx_CPPFLAGS = $(WIN32_CPPFLAGS) $(PORTAUDIOCPP_CFLAGS) endif libopenmpt_example_c_pipe_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) libopenmpt_example_c_probe_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) libopenmpt_example_c_stdout_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) if HAVE_PORTAUDIO libopenmpt_example_c_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) libopenmpt_example_c_mem_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) libopenmpt_example_c_unsafe_CFLAGS = $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(WIN32_CONSOLE_CFLAGS) endif if HAVE_PORTAUDIOCPP libopenmpt_example_cxx_CXXFLAGS = $(GLOBAL_CXXFLAGS) $(WIN32_CXXFLAGS) $(WIN32_CONSOLE_CXXFLAGS) endif libopenmpt_example_c_pipe_LDADD = $(lib_LTLIBRARIES) libopenmpt_example_c_probe_LDADD = $(lib_LTLIBRARIES) libopenmpt_example_c_stdout_LDADD = $(lib_LTLIBRARIES) if HAVE_PORTAUDIO libopenmpt_example_c_LDADD = $(lib_LTLIBRARIES) $(PORTAUDIO_LIBS) libopenmpt_example_c_mem_LDADD = $(lib_LTLIBRARIES) $(PORTAUDIO_LIBS) libopenmpt_example_c_unsafe_LDADD = $(lib_LTLIBRARIES) $(PORTAUDIO_LIBS) endif if HAVE_PORTAUDIOCPP libopenmpt_example_cxx_LDADD = $(lib_LTLIBRARIES) $(PORTAUDIOCPP_LIBS) endif endif pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = includelibopenmptdir = $(includedir)/libopenmpt includelibopenmpt_HEADERS = MPT_FILES_SRC_MPT = MPT_FILES_SRC_MPT += src/mpt/arch/arch.hpp MPT_FILES_SRC_MPT += src/mpt/arch/feature_flags.hpp MPT_FILES_SRC_MPT += src/mpt/arch/x86_amd64.hpp MPT_FILES_SRC_MPT += src/mpt/audio/sample.hpp MPT_FILES_SRC_MPT += src/mpt/audio/span.hpp MPT_FILES_SRC_MPT += src/mpt/base/algorithm.hpp MPT_FILES_SRC_MPT += src/mpt/base/aligned_array.hpp MPT_FILES_SRC_MPT += src/mpt/base/alloc.hpp MPT_FILES_SRC_MPT += src/mpt/base/arithmetic_shift.hpp MPT_FILES_SRC_MPT += src/mpt/base/array.hpp MPT_FILES_SRC_MPT += src/mpt/base/bit.hpp MPT_FILES_SRC_MPT += src/mpt/base/check_platform.hpp MPT_FILES_SRC_MPT += src/mpt/base/compiletime_warning.hpp MPT_FILES_SRC_MPT += src/mpt/base/constexpr_throw.hpp MPT_FILES_SRC_MPT += src/mpt/base/debugging.hpp MPT_FILES_SRC_MPT += src/mpt/base/detect.hpp MPT_FILES_SRC_MPT += src/mpt/base/detect_arch.hpp MPT_FILES_SRC_MPT += src/mpt/base/detect_compiler.hpp MPT_FILES_SRC_MPT += src/mpt/base/detect_libc.hpp MPT_FILES_SRC_MPT += src/mpt/base/detect_libcxx.hpp MPT_FILES_SRC_MPT += src/mpt/base/detect_os.hpp MPT_FILES_SRC_MPT += src/mpt/base/detect_quirks.hpp MPT_FILES_SRC_MPT += src/mpt/base/float.hpp MPT_FILES_SRC_MPT += src/mpt/base/integer.hpp MPT_FILES_SRC_MPT += src/mpt/base/macros.hpp MPT_FILES_SRC_MPT += src/mpt/base/math.hpp MPT_FILES_SRC_MPT += src/mpt/base/memory.hpp MPT_FILES_SRC_MPT += src/mpt/base/namespace.hpp MPT_FILES_SRC_MPT += src/mpt/base/numbers.hpp MPT_FILES_SRC_MPT += src/mpt/base/numeric.hpp MPT_FILES_SRC_MPT += src/mpt/base/pointer.hpp MPT_FILES_SRC_MPT += src/mpt/base/preprocessor.hpp MPT_FILES_SRC_MPT += src/mpt/base/saturate_cast.hpp MPT_FILES_SRC_MPT += src/mpt/base/saturate_round.hpp MPT_FILES_SRC_MPT += src/mpt/base/secure.hpp MPT_FILES_SRC_MPT += src/mpt/base/semantic_version.hpp MPT_FILES_SRC_MPT += src/mpt/base/size.hpp MPT_FILES_SRC_MPT += src/mpt/base/source_location.hpp MPT_FILES_SRC_MPT += src/mpt/base/span.hpp MPT_FILES_SRC_MPT += src/mpt/base/type_traits.hpp MPT_FILES_SRC_MPT += src/mpt/base/utility.hpp MPT_FILES_SRC_MPT += src/mpt/base/version.hpp MPT_FILES_SRC_MPT += src/mpt/base/wrapping_divide.hpp MPT_FILES_SRC_MPT += src/mpt/binary/base64.hpp MPT_FILES_SRC_MPT += src/mpt/binary/base64url.hpp MPT_FILES_SRC_MPT += src/mpt/binary/hex.hpp MPT_FILES_SRC_MPT += src/mpt/check/compiler.hpp MPT_FILES_SRC_MPT += src/mpt/check/libc.hpp MPT_FILES_SRC_MPT += src/mpt/check/libcxx.hpp MPT_FILES_SRC_MPT += src/mpt/check/mfc.hpp MPT_FILES_SRC_MPT += src/mpt/check/windows.hpp MPT_FILES_SRC_MPT += src/mpt/crc/crc.hpp #MPT_FILES_SRC_MPT += src/mpt/crypto/exception.hpp #MPT_FILES_SRC_MPT += src/mpt/crypto/hash.hpp #MPT_FILES_SRC_MPT += src/mpt/crypto/jwk.hpp MPT_FILES_SRC_MPT += src/mpt/detect/dl.hpp MPT_FILES_SRC_MPT += src/mpt/detect/ltdl.hpp MPT_FILES_SRC_MPT += src/mpt/detect/mfc.hpp MPT_FILES_SRC_MPT += src/mpt/detect/nlohmann_json.hpp MPT_FILES_SRC_MPT += src/mpt/endian/floatingpoint.hpp MPT_FILES_SRC_MPT += src/mpt/endian/int24.hpp MPT_FILES_SRC_MPT += src/mpt/endian/integer.hpp MPT_FILES_SRC_MPT += src/mpt/endian/type_traits.hpp MPT_FILES_SRC_MPT += src/mpt/environment/environment.hpp MPT_FILES_SRC_MPT += src/mpt/exception/exception.hpp MPT_FILES_SRC_MPT += src/mpt/exception/exception_text.hpp MPT_FILES_SRC_MPT += src/mpt/exception/logic_error.hpp MPT_FILES_SRC_MPT += src/mpt/exception/runtime_error.hpp MPT_FILES_SRC_MPT += src/mpt/format/concat.hpp MPT_FILES_SRC_MPT += src/mpt/format/default_floatingpoint.hpp MPT_FILES_SRC_MPT += src/mpt/format/default_formatter.hpp MPT_FILES_SRC_MPT += src/mpt/format/default_integer.hpp MPT_FILES_SRC_MPT += src/mpt/format/default_string.hpp MPT_FILES_SRC_MPT += src/mpt/format/helpers.hpp MPT_FILES_SRC_MPT += src/mpt/format/join.hpp MPT_FILES_SRC_MPT += src/mpt/format/message.hpp MPT_FILES_SRC_MPT += src/mpt/format/message_macros.hpp MPT_FILES_SRC_MPT += src/mpt/format/simple.hpp MPT_FILES_SRC_MPT += src/mpt/format/simple_floatingpoint.hpp MPT_FILES_SRC_MPT += src/mpt/format/simple_integer.hpp MPT_FILES_SRC_MPT += src/mpt/format/simple_spec.hpp #MPT_FILES_SRC_MPT += src/mpt/fs/common_directories.hpp #MPT_FILES_SRC_MPT += src/mpt/fs/fs.hpp MPT_FILES_SRC_MPT += src/mpt/io/base.hpp MPT_FILES_SRC_MPT += src/mpt/io/io.hpp MPT_FILES_SRC_MPT += src/mpt/io/io_span.hpp MPT_FILES_SRC_MPT += src/mpt/io/io_stdstream.hpp MPT_FILES_SRC_MPT += src/mpt/io/io_virtual_wrapper.hpp MPT_FILES_SRC_MPT += src/mpt/io_file/fileref.hpp MPT_FILES_SRC_MPT += src/mpt/io_file/fstream.hpp MPT_FILES_SRC_MPT += src/mpt/io_file/inputfile.hpp MPT_FILES_SRC_MPT += src/mpt/io_file/outputfile.hpp MPT_FILES_SRC_MPT += src/mpt/io_file_adapter/fileadapter.hpp MPT_FILES_SRC_MPT += src/mpt/io_file_read/inputfile_filecursor.hpp MPT_FILES_SRC_MPT += src/mpt/io_file_unique/unique_basename.hpp MPT_FILES_SRC_MPT += src/mpt/io_file_unique/unique_tempfilename.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/callbackstream.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filecursor.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filecursor_callbackstream.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filecursor_filename_traits.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filecursor_memory.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filecursor_stdstream.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filecursor_traits_filedata.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filecursor_traits_memory.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filedata.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filedata_base.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filedata_base_buffered.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filedata_base_seekable.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filedata_base_unseekable.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filedata_base_unseekable_buffer.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filedata_callbackstream.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filedata_memory.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filedata_stdstream.hpp MPT_FILES_SRC_MPT += src/mpt/io_read/filereader.hpp MPT_FILES_SRC_MPT += src/mpt/io_write/buffer.hpp #MPT_FILES_SRC_MPT += src/mpt/json/json.hpp #MPT_FILES_SRC_MPT += src/mpt/library/library.hpp MPT_FILES_SRC_MPT += src/mpt/main/main.hpp MPT_FILES_SRC_MPT += src/mpt/mutex/mutex.hpp MPT_FILES_SRC_MPT += src/mpt/osinfo/class.hpp MPT_FILES_SRC_MPT += src/mpt/osinfo/dos_memory.hpp MPT_FILES_SRC_MPT += src/mpt/osinfo/dos_version.hpp MPT_FILES_SRC_MPT += src/mpt/osinfo/windows_version.hpp MPT_FILES_SRC_MPT += src/mpt/osinfo/windows_wine_version.hpp MPT_FILES_SRC_MPT += src/mpt/out_of_memory/out_of_memory.hpp MPT_FILES_SRC_MPT += src/mpt/parse/parse.hpp MPT_FILES_SRC_MPT += src/mpt/parse/split.hpp MPT_FILES_SRC_MPT += src/mpt/path/basic_path.hpp MPT_FILES_SRC_MPT += src/mpt/path/native_path.hpp MPT_FILES_SRC_MPT += src/mpt/path/path.hpp MPT_FILES_SRC_MPT += src/mpt/path/os_path.hpp MPT_FILES_SRC_MPT += src/mpt/path/os_path_long.hpp MPT_FILES_SRC_MPT += src/mpt/random/any_engine.hpp MPT_FILES_SRC_MPT += src/mpt/random/crand.hpp MPT_FILES_SRC_MPT += src/mpt/random/default_engines.hpp MPT_FILES_SRC_MPT += src/mpt/random/device.hpp MPT_FILES_SRC_MPT += src/mpt/random/engine.hpp MPT_FILES_SRC_MPT += src/mpt/random/engine_lcg.hpp MPT_FILES_SRC_MPT += src/mpt/random/random.hpp MPT_FILES_SRC_MPT += src/mpt/random/seed.hpp MPT_FILES_SRC_MPT += src/mpt/string/buffer.hpp MPT_FILES_SRC_MPT += src/mpt/string/types.hpp MPT_FILES_SRC_MPT += src/mpt/string/utility.hpp MPT_FILES_SRC_MPT += src/mpt/string_transcode/transcode.hpp MPT_FILES_SRC_MPT += src/mpt/string_transcode/macros.hpp MPT_FILES_SRC_MPT += src/mpt/system_error/system_error.hpp MPT_FILES_SRC_MPT += src/mpt/test/test.hpp MPT_FILES_SRC_MPT += src/mpt/test/test_macros.hpp MPT_FILES_SRC_MPT += src/mpt/uuid/guid.hpp MPT_FILES_SRC_MPT += src/mpt/uuid/uuid.hpp #MPT_FILES_SRC_MPT += src/mpt/uuid_namespace/uuid_namespace.hpp MPT_FILES_SRC_MPT += src/mpt/base/tests/tests_base_arithmetic_shift.hpp MPT_FILES_SRC_MPT += src/mpt/base/tests/tests_base_bit.hpp MPT_FILES_SRC_MPT += src/mpt/base/tests/tests_base_math.hpp MPT_FILES_SRC_MPT += src/mpt/base/tests/tests_base_numeric.hpp MPT_FILES_SRC_MPT += src/mpt/base/tests/tests_base_saturate_cast.hpp MPT_FILES_SRC_MPT += src/mpt/base/tests/tests_base_saturate_round.hpp MPT_FILES_SRC_MPT += src/mpt/base/tests/tests_base_wrapping_divide.hpp MPT_FILES_SRC_MPT += src/mpt/binary/tests/tests_binary.hpp MPT_FILES_SRC_MPT += src/mpt/crc/tests/tests_crc.hpp #MPT_FILES_SRC_MPT += src/mpt/crypto/tests/tests_crypto.hpp MPT_FILES_SRC_MPT += src/mpt/endian/tests/tests_endian_floatingpoint.hpp MPT_FILES_SRC_MPT += src/mpt/endian/tests/tests_endian_int24.hpp MPT_FILES_SRC_MPT += src/mpt/endian/tests/tests_endian_integer.hpp MPT_FILES_SRC_MPT += src/mpt/format/tests/tests_format_message.hpp MPT_FILES_SRC_MPT += src/mpt/format/tests/tests_format_simple.hpp MPT_FILES_SRC_MPT += src/mpt/io/tests/tests_io.hpp MPT_FILES_SRC_MPT += src/mpt/parse/tests/tests_parse.hpp MPT_FILES_SRC_MPT += src/mpt/random/tests/tests_random.hpp MPT_FILES_SRC_MPT += src/mpt/string/tests/tests_string_buffer.hpp MPT_FILES_SRC_MPT += src/mpt/string/tests/tests_string_utility.hpp MPT_FILES_SRC_MPT += src/mpt/string_transcode/tests/tests_string_transcode.hpp MPT_FILES_SRC_MPT += src/mpt/uuid/tests/tests_uuid.hpp #MPT_FILES_SRC_MPT += src/mpt/uuid_namespace/tests/tests_uuid_namespace.hpp MPT_FILES_SRC_OPENMPT = MPT_FILES_SRC_OPENMPT += src/openmpt/all/BuildSettings.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/all/PlatformFixes.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/base/Endian.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/base/FlagSet.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/base/Int24.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/base/Types.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/fileformat_base/magic.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/logging/Logger.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/random/ModPlug.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/Copy.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/CopyMix.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/Dither.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/DitherModPlug.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/DitherNone.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/DitherSimple.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/MixSample.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/MixSampleConvert.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/SampleClip.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/SampleClipFixedPoint.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/SampleConvert.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/SampleConvertFixedPoint.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/SampleDecode.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/SampleEncode.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/SampleFormat.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundfile_data/tags.hpp MPT_FILES_SRC_OPENMPT += src/openmpt/soundfile_data/wav.hpp MPT_FILES_SRC_OPENMPT_SOUNDFILE_WRITE = MPT_FILES_SRC_OPENMPT_SOUNDFILE_WRITE += src/openmpt/soundfile_write/wav_write.cpp MPT_FILES_SRC_OPENMPT_SOUNDFILE_WRITE += src/openmpt/soundfile_write/wav_write.hpp MPT_FILES_COMMON = MPT_FILES_COMMON += common/BuildSettings.h MPT_FILES_COMMON += common/BuildSettingsCompiler.h MPT_FILES_COMMON += common/ComponentManager.cpp MPT_FILES_COMMON += common/ComponentManager.h MPT_FILES_COMMON += common/FileReader.h MPT_FILES_COMMON += common/FileReaderFwd.h MPT_FILES_COMMON += common/GzipWriter.h MPT_FILES_COMMON += common/Logging.cpp MPT_FILES_COMMON += common/Logging.h MPT_FILES_COMMON += common/misc_util.h MPT_FILES_COMMON += common/mptAssert.h MPT_FILES_COMMON += common/mptBaseMacros.h MPT_FILES_COMMON += common/mptBaseTypes.h MPT_FILES_COMMON += common/mptBaseUtils.h MPT_FILES_COMMON += common/mptCPU.h MPT_FILES_COMMON += common/mptFileIO.h MPT_FILES_COMMON += common/mptFileTemporary.h MPT_FILES_COMMON += common/mptFileType.cpp MPT_FILES_COMMON += common/mptFileType.h MPT_FILES_COMMON += common/mptPathString.cpp MPT_FILES_COMMON += common/mptPathString.h MPT_FILES_COMMON += common/mptRandom.cpp MPT_FILES_COMMON += common/mptRandom.h MPT_FILES_COMMON += common/mptString.h MPT_FILES_COMMON += common/mptStringBuffer.cpp MPT_FILES_COMMON += common/mptStringBuffer.h MPT_FILES_COMMON += common/mptStringFormat.h MPT_FILES_COMMON += common/mptTime.cpp MPT_FILES_COMMON += common/mptTime.h MPT_FILES_COMMON += common/Profiler.cpp MPT_FILES_COMMON += common/Profiler.h MPT_FILES_COMMON += common/serialization_utils.cpp MPT_FILES_COMMON += common/serialization_utils.h MPT_FILES_COMMON += common/stdafx.h MPT_FILES_COMMON += common/version.cpp MPT_FILES_COMMON += common/version.h MPT_FILES_COMMON += common/versionNumber.h MPT_FILES_SOUNDLIB = MPT_FILES_SOUNDLIB += soundlib/AudioCriticalSection.cpp MPT_FILES_SOUNDLIB += soundlib/AudioCriticalSection.h MPT_FILES_SOUNDLIB += soundlib/AudioReadTarget.h MPT_FILES_SOUNDLIB += soundlib/BitReader.h MPT_FILES_SOUNDLIB += soundlib/ContainerMMCMP.cpp MPT_FILES_SOUNDLIB += soundlib/ContainerPP20.cpp MPT_FILES_SOUNDLIB += soundlib/ContainerUMX.cpp MPT_FILES_SOUNDLIB += soundlib/ContainerXPK.cpp MPT_FILES_SOUNDLIB += soundlib/Container.h MPT_FILES_SOUNDLIB += soundlib/Dlsbank.cpp MPT_FILES_SOUNDLIB += soundlib/Dlsbank.h MPT_FILES_SOUNDLIB += soundlib/Fastmix.cpp MPT_FILES_SOUNDLIB += soundlib/FloatMixer.h MPT_FILES_SOUNDLIB += soundlib/InstrumentExtensions.cpp MPT_FILES_SOUNDLIB += soundlib/InstrumentSynth.cpp MPT_FILES_SOUNDLIB += soundlib/InstrumentSynth.h MPT_FILES_SOUNDLIB += soundlib/IntMixer.h MPT_FILES_SOUNDLIB += soundlib/ITCompression.cpp MPT_FILES_SOUNDLIB += soundlib/ITCompression.h MPT_FILES_SOUNDLIB += soundlib/ITTools.cpp MPT_FILES_SOUNDLIB += soundlib/ITTools.h MPT_FILES_SOUNDLIB += soundlib/Load_667.cpp MPT_FILES_SOUNDLIB += soundlib/Load_669.cpp MPT_FILES_SOUNDLIB += soundlib/Load_amf.cpp MPT_FILES_SOUNDLIB += soundlib/Load_ams.cpp MPT_FILES_SOUNDLIB += soundlib/Load_c67.cpp MPT_FILES_SOUNDLIB += soundlib/Load_cba.cpp MPT_FILES_SOUNDLIB += soundlib/Load_dbm.cpp MPT_FILES_SOUNDLIB += soundlib/Load_digi.cpp MPT_FILES_SOUNDLIB += soundlib/Load_dmf.cpp MPT_FILES_SOUNDLIB += soundlib/Load_dsm.cpp MPT_FILES_SOUNDLIB += soundlib/Load_dsym.cpp MPT_FILES_SOUNDLIB += soundlib/Load_dtm.cpp MPT_FILES_SOUNDLIB += soundlib/Loaders.h MPT_FILES_SOUNDLIB += soundlib/Load_etx.cpp MPT_FILES_SOUNDLIB += soundlib/Load_far.cpp MPT_FILES_SOUNDLIB += soundlib/Load_fc.cpp MPT_FILES_SOUNDLIB += soundlib/Load_fmt.cpp MPT_FILES_SOUNDLIB += soundlib/Load_ftm.cpp MPT_FILES_SOUNDLIB += soundlib/Load_gdm.cpp MPT_FILES_SOUNDLIB += soundlib/Load_gmc.cpp MPT_FILES_SOUNDLIB += soundlib/Load_gt2.cpp MPT_FILES_SOUNDLIB += soundlib/Load_ice.cpp MPT_FILES_SOUNDLIB += soundlib/Load_imf.cpp MPT_FILES_SOUNDLIB += soundlib/Load_ims.cpp MPT_FILES_SOUNDLIB += soundlib/Load_it.cpp MPT_FILES_SOUNDLIB += soundlib/Load_itp.cpp MPT_FILES_SOUNDLIB += soundlib/load_j2b.cpp MPT_FILES_SOUNDLIB += soundlib/Load_kris.cpp MPT_FILES_SOUNDLIB += soundlib/Load_mdl.cpp MPT_FILES_SOUNDLIB += soundlib/Load_med.cpp MPT_FILES_SOUNDLIB += soundlib/Load_mid.cpp MPT_FILES_SOUNDLIB += soundlib/Load_mo3.cpp MPT_FILES_SOUNDLIB += soundlib/Load_mod.cpp MPT_FILES_SOUNDLIB += soundlib/Load_mt2.cpp MPT_FILES_SOUNDLIB += soundlib/Load_mtm.cpp MPT_FILES_SOUNDLIB += soundlib/Load_mus_km.cpp MPT_FILES_SOUNDLIB += soundlib/Load_okt.cpp MPT_FILES_SOUNDLIB += soundlib/Load_plm.cpp MPT_FILES_SOUNDLIB += soundlib/Load_psm.cpp MPT_FILES_SOUNDLIB += soundlib/Load_pt36.cpp MPT_FILES_SOUNDLIB += soundlib/Load_ptm.cpp MPT_FILES_SOUNDLIB += soundlib/Load_puma.cpp MPT_FILES_SOUNDLIB += soundlib/Load_rtm.cpp MPT_FILES_SOUNDLIB += soundlib/Load_s3m.cpp MPT_FILES_SOUNDLIB += soundlib/Load_sfx.cpp MPT_FILES_SOUNDLIB += soundlib/Load_stk.cpp MPT_FILES_SOUNDLIB += soundlib/Load_stm.cpp MPT_FILES_SOUNDLIB += soundlib/Load_stp.cpp MPT_FILES_SOUNDLIB += soundlib/Load_symmod.cpp MPT_FILES_SOUNDLIB += soundlib/Load_tcb.cpp MPT_FILES_SOUNDLIB += soundlib/Load_uax.cpp MPT_FILES_SOUNDLIB += soundlib/Load_ult.cpp MPT_FILES_SOUNDLIB += soundlib/Load_unic.cpp MPT_FILES_SOUNDLIB += soundlib/Load_wav.cpp MPT_FILES_SOUNDLIB += soundlib/Load_xm.cpp MPT_FILES_SOUNDLIB += soundlib/Load_xmf.cpp MPT_FILES_SOUNDLIB += soundlib/Message.cpp MPT_FILES_SOUNDLIB += soundlib/Message.h MPT_FILES_SOUNDLIB += soundlib/MIDIEvents.cpp MPT_FILES_SOUNDLIB += soundlib/MIDIEvents.h MPT_FILES_SOUNDLIB += soundlib/MIDIMacroParser.cpp MPT_FILES_SOUNDLIB += soundlib/MIDIMacroParser.h MPT_FILES_SOUNDLIB += soundlib/MIDIMacros.cpp MPT_FILES_SOUNDLIB += soundlib/MIDIMacros.h MPT_FILES_SOUNDLIB += soundlib/Mixer.h MPT_FILES_SOUNDLIB += soundlib/MixerInterface.h MPT_FILES_SOUNDLIB += soundlib/MixerLoops.cpp MPT_FILES_SOUNDLIB += soundlib/MixerLoops.h MPT_FILES_SOUNDLIB += soundlib/MixerSettings.cpp MPT_FILES_SOUNDLIB += soundlib/MixerSettings.h MPT_FILES_SOUNDLIB += soundlib/MixFuncTable.cpp MPT_FILES_SOUNDLIB += soundlib/MixFuncTable.h MPT_FILES_SOUNDLIB += soundlib/ModChannel.cpp MPT_FILES_SOUNDLIB += soundlib/ModChannel.h MPT_FILES_SOUNDLIB += soundlib/modcommand.cpp MPT_FILES_SOUNDLIB += soundlib/modcommand.h MPT_FILES_SOUNDLIB += soundlib/ModInstrument.cpp MPT_FILES_SOUNDLIB += soundlib/ModInstrument.h MPT_FILES_SOUNDLIB += soundlib/ModSample.cpp MPT_FILES_SOUNDLIB += soundlib/ModSample.h MPT_FILES_SOUNDLIB += soundlib/ModSampleCopy.h MPT_FILES_SOUNDLIB += soundlib/ModSequence.cpp MPT_FILES_SOUNDLIB += soundlib/ModSequence.h MPT_FILES_SOUNDLIB += soundlib/modsmp_ctrl.cpp MPT_FILES_SOUNDLIB += soundlib/modsmp_ctrl.h MPT_FILES_SOUNDLIB += soundlib/mod_specifications.cpp MPT_FILES_SOUNDLIB += soundlib/mod_specifications.h MPT_FILES_SOUNDLIB += soundlib/MODTools.cpp MPT_FILES_SOUNDLIB += soundlib/MODTools.h MPT_FILES_SOUNDLIB += soundlib/MPEGFrame.cpp MPT_FILES_SOUNDLIB += soundlib/MPEGFrame.h MPT_FILES_SOUNDLIB += soundlib/OggStream.cpp MPT_FILES_SOUNDLIB += soundlib/OggStream.h MPT_FILES_SOUNDLIB += soundlib/opal.h MPT_FILES_SOUNDLIB += soundlib/OPL.cpp MPT_FILES_SOUNDLIB += soundlib/OPL.h MPT_FILES_SOUNDLIB += soundlib/Paula.cpp MPT_FILES_SOUNDLIB += soundlib/Paula.h MPT_FILES_SOUNDLIB += soundlib/patternContainer.cpp MPT_FILES_SOUNDLIB += soundlib/patternContainer.h MPT_FILES_SOUNDLIB += soundlib/pattern.cpp MPT_FILES_SOUNDLIB += soundlib/pattern.h MPT_FILES_SOUNDLIB += soundlib/PlaybackTest.cpp MPT_FILES_SOUNDLIB += soundlib/PlaybackTest.h MPT_FILES_SOUNDLIB += soundlib/PlayState.cpp MPT_FILES_SOUNDLIB += soundlib/PlayState.h MPT_FILES_SOUNDLIB += soundlib/Resampler.h MPT_FILES_SOUNDLIB += soundlib/RowVisitor.cpp MPT_FILES_SOUNDLIB += soundlib/RowVisitor.h MPT_FILES_SOUNDLIB += soundlib/S3MTools.cpp MPT_FILES_SOUNDLIB += soundlib/S3MTools.h MPT_FILES_SOUNDLIB += soundlib/SampleCopy.h MPT_FILES_SOUNDLIB += soundlib/SampleFormats.cpp MPT_FILES_SOUNDLIB += soundlib/SampleFormatBRR.cpp MPT_FILES_SOUNDLIB += soundlib/SampleFormatFLAC.cpp MPT_FILES_SOUNDLIB += soundlib/SampleFormatMediaFoundation.cpp MPT_FILES_SOUNDLIB += soundlib/SampleFormatMP3.cpp MPT_FILES_SOUNDLIB += soundlib/SampleFormatOpus.cpp MPT_FILES_SOUNDLIB += soundlib/SampleFormatSFZ.cpp MPT_FILES_SOUNDLIB += soundlib/SampleFormatVorbis.cpp MPT_FILES_SOUNDLIB += soundlib/SampleIO.cpp MPT_FILES_SOUNDLIB += soundlib/SampleIO.h MPT_FILES_SOUNDLIB += soundlib/SampleNormalize.h MPT_FILES_SOUNDLIB += soundlib/Snd_defs.h MPT_FILES_SOUNDLIB += soundlib/Sndfile.cpp MPT_FILES_SOUNDLIB += soundlib/Sndfile.h MPT_FILES_SOUNDLIB += soundlib/Snd_flt.cpp MPT_FILES_SOUNDLIB += soundlib/Snd_fx.cpp MPT_FILES_SOUNDLIB += soundlib/Sndmix.cpp MPT_FILES_SOUNDLIB += soundlib/SoundFilePlayConfig.cpp MPT_FILES_SOUNDLIB += soundlib/SoundFilePlayConfig.h MPT_FILES_SOUNDLIB += soundlib/Tables.cpp MPT_FILES_SOUNDLIB += soundlib/Tables.h MPT_FILES_SOUNDLIB += soundlib/Tagging.cpp MPT_FILES_SOUNDLIB += soundlib/Tagging.h MPT_FILES_SOUNDLIB += soundlib/TinyFFT.cpp MPT_FILES_SOUNDLIB += soundlib/TinyFFT.h MPT_FILES_SOUNDLIB += soundlib/tuningbase.h MPT_FILES_SOUNDLIB += soundlib/tuningCollection.cpp MPT_FILES_SOUNDLIB += soundlib/tuningcollection.h MPT_FILES_SOUNDLIB += soundlib/tuning.cpp MPT_FILES_SOUNDLIB += soundlib/tuning.h MPT_FILES_SOUNDLIB += soundlib/UMXTools.cpp MPT_FILES_SOUNDLIB += soundlib/UMXTools.h MPT_FILES_SOUNDLIB += soundlib/UpgradeModule.cpp MPT_FILES_SOUNDLIB += soundlib/WAVTools.cpp MPT_FILES_SOUNDLIB += soundlib/WAVTools.h MPT_FILES_SOUNDLIB += soundlib/WindowedFIR.cpp MPT_FILES_SOUNDLIB += soundlib/WindowedFIR.h MPT_FILES_SOUNDLIB += soundlib/XMTools.cpp MPT_FILES_SOUNDLIB += soundlib/XMTools.h MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/DMOPlugin.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/DMOPlugin.h MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/DMOUtils.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/DMOUtils.h MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Chorus.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Chorus.h MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Compressor.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Compressor.h MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Distortion.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Distortion.h MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Echo.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Echo.h MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Flanger.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Flanger.h MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Gargle.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Gargle.h MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/I3DL2Reverb.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/I3DL2Reverb.h MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/ParamEq.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/ParamEq.h MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/WavesReverb.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/WavesReverb.h MPT_FILES_SOUNDLIB += soundlib/plugins/DigiBoosterEcho.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/DigiBoosterEcho.h MPT_FILES_SOUNDLIB += soundlib/plugins/LFOPlugin.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/LFOPlugin.h MPT_FILES_SOUNDLIB += soundlib/plugins/PluginManager.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/PluginManager.h MPT_FILES_SOUNDLIB += soundlib/plugins/PluginMixBuffer.h MPT_FILES_SOUNDLIB += soundlib/plugins/PluginStructs.h MPT_FILES_SOUNDLIB += soundlib/plugins/PlugInterface.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/PlugInterface.h MPT_FILES_SOUNDLIB += soundlib/plugins/SymMODEcho.cpp MPT_FILES_SOUNDLIB += soundlib/plugins/SymMODEcho.h MPT_FILES_SOUNDDSP = MPT_FILES_SOUNDDSP += sounddsp/AGC.cpp MPT_FILES_SOUNDDSP += sounddsp/AGC.h MPT_FILES_SOUNDDSP += sounddsp/DSP.cpp MPT_FILES_SOUNDDSP += sounddsp/DSP.h MPT_FILES_SOUNDDSP += sounddsp/EQ.cpp MPT_FILES_SOUNDDSP += sounddsp/EQ.h MPT_FILES_SOUNDDSP += sounddsp/Reverb.cpp MPT_FILES_SOUNDDSP += sounddsp/Reverb.h pkgconfig_DATA += libopenmpt/libopenmpt.pc lib_LTLIBRARIES += libopenmpt.la libopenmpt_la_LDFLAGS = -version-info $(LIBOPENMPT_LTVER_CURRENT):$(LIBOPENMPT_LTVER_REVISION):$(LIBOPENMPT_LTVER_AGE) -no-undefined includelibopenmpt_HEADERS += libopenmpt/libopenmpt.h includelibopenmpt_HEADERS += libopenmpt/libopenmpt.hpp includelibopenmpt_HEADERS += libopenmpt/libopenmpt_version.h includelibopenmpt_HEADERS += libopenmpt/libopenmpt_config.h includelibopenmpt_HEADERS += libopenmpt/libopenmpt_stream_callbacks_buffer.h includelibopenmpt_HEADERS += libopenmpt/libopenmpt_stream_callbacks_fd.h includelibopenmpt_HEADERS += libopenmpt/libopenmpt_stream_callbacks_file.h includelibopenmpt_HEADERS += libopenmpt/libopenmpt_stream_callbacks_file_mingw.h includelibopenmpt_HEADERS += libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h includelibopenmpt_HEADERS += libopenmpt/libopenmpt_stream_callbacks_file_posix.h includelibopenmpt_HEADERS += libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h includelibopenmpt_HEADERS += libopenmpt/libopenmpt_ext.h includelibopenmpt_HEADERS += libopenmpt/libopenmpt_ext.hpp libopenmpt_la_CPPFLAGS = libopenmpt_la_CPPFLAGS += $(GLOBAL_CPPFLAGS) $(WIN32_CPPFLAGS) -DLIBOPENMPT_BUILD -I$(srcdir)/ -I$(srcdir)/src -I$(srcdir)/common $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) libopenmpt_la_CXXFLAGS = libopenmpt_la_CXXFLAGS += $(GLOBAL_CXXFLAGS) $(WIN32_CXXFLAGS) $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) libopenmpt_la_CFLAGS = libopenmpt_la_CFLAGS += $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) libopenmpt_la_LIBADD = libopenmpt_la_LIBADD += $(ZLIB_LIBS) $(MPG123_LIBS) $(OGG_LIBS) $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(LIBOPENMPT_WIN32_LIBS) libopenmpt_la_SOURCES = libopenmpt_la_SOURCES += build/svn_version/svn_version.h libopenmpt_la_SOURCES += $(MPT_FILES_SRC_MPT) libopenmpt_la_SOURCES += $(MPT_FILES_SRC_OPENMPT) libopenmpt_la_SOURCES += $(MPT_FILES_COMMON) libopenmpt_la_SOURCES += $(MPT_FILES_SOUNDBASE) libopenmpt_la_SOURCES += $(MPT_FILES_SOUNDLIB) libopenmpt_la_SOURCES += $(MPT_FILES_SOUNDDSP) libopenmpt_la_SOURCES += libopenmpt/libopenmpt_c.cpp libopenmpt_la_SOURCES += libopenmpt/libopenmpt_cxx.cpp libopenmpt_la_SOURCES += libopenmpt/libopenmpt_ext_impl.cpp libopenmpt_la_SOURCES += libopenmpt/libopenmpt_impl.cpp libopenmpt_la_SOURCES += libopenmpt/libopenmpt_config.h libopenmpt_la_SOURCES += libopenmpt/libopenmpt_ext.h libopenmpt_la_SOURCES += libopenmpt/libopenmpt_ext.hpp libopenmpt_la_SOURCES += libopenmpt/libopenmpt_ext_impl.hpp libopenmpt_la_SOURCES += libopenmpt/libopenmpt.h libopenmpt_la_SOURCES += libopenmpt/libopenmpt.hpp libopenmpt_la_SOURCES += libopenmpt/libopenmpt_impl.hpp libopenmpt_la_SOURCES += libopenmpt/libopenmpt_internal.h libopenmpt_la_SOURCES += libopenmpt/libopenmpt_stream_callbacks_buffer.h libopenmpt_la_SOURCES += libopenmpt/libopenmpt_stream_callbacks_fd.h libopenmpt_la_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file.h libopenmpt_la_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file_mingw.h libopenmpt_la_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h libopenmpt_la_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file_posix.h libopenmpt_la_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h libopenmpt_la_SOURCES += libopenmpt/libopenmpt_version.h if ENABLE_TESTS check_PROGRAMS += libopenmpttest libopenmpttest_CPPFLAGS = libopenmpttest_CPPFLAGS += $(GLOBAL_CPPFLAGS) $(WIN32_CPPFLAGS) -DLIBOPENMPT_BUILD -DLIBOPENMPT_BUILD_TEST -I$(srcdir)/ -I$(srcdir)/src -I$(srcdir)/common $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) libopenmpttest_CXXFLAGS = libopenmpttest_CXXFLAGS += $(GLOBAL_CXXFLAGS) $(WIN32_CXXFLAGS) $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) $(WIN32_CONSOLE_CXXFLAGS) libopenmpttest_CFLAGS = libopenmpttest_CFLAGS += $(GLOBAL_CFLAGS) $(WIN32_CFLAGS) $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) $(WIN32_CONSOLE_CFLAGS) libopenmpttest_LDADD = libopenmpttest_LDADD += $(ZLIB_LIBS) $(MPG123_LIBS) $(OGG_LIBS) $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(LIBOPENMPT_WIN32_LIBS) $(LIBOPENMPTTEST_WIN32_LIBS) libopenmpttest_SOURCES = libopenmpttest_SOURCES += test/mpt_tests_base.cpp libopenmpttest_SOURCES += test/mpt_tests_binary.cpp libopenmpttest_SOURCES += test/mpt_tests_crc.cpp #libopenmpttest_SOURCES += test/mpt_tests_crypto.cpp libopenmpttest_SOURCES += test/mpt_tests_endian.cpp libopenmpttest_SOURCES += test/mpt_tests_format.cpp libopenmpttest_SOURCES += test/mpt_tests_io.cpp libopenmpttest_SOURCES += test/mpt_tests_parse.cpp libopenmpttest_SOURCES += test/mpt_tests_random.cpp libopenmpttest_SOURCES += test/mpt_tests_string.cpp libopenmpttest_SOURCES += test/mpt_tests_string_transcode.cpp libopenmpttest_SOURCES += test/mpt_tests_uuid.cpp #libopenmpttest_SOURCES += test/mpt_tests_uuid_namespace.cpp libopenmpttest_SOURCES += test/test.cpp libopenmpttest_SOURCES += test/test.h libopenmpttest_SOURCES += test/TestTools.h libopenmpttest_SOURCES += test/TestToolsLib.cpp libopenmpttest_SOURCES += test/TestToolsLib.h libopenmpttest_SOURCES += test/TestToolsTracker.h libopenmpttest_SOURCES += build/svn_version/svn_version.h libopenmpttest_SOURCES += $(MPT_FILES_SRC_MPT) libopenmpttest_SOURCES += $(MPT_FILES_SRC_OPENMPT) libopenmpttest_SOURCES += $(MPT_FILES_SRC_OPENMPT_SOUNDFILE_WRITE) libopenmpttest_SOURCES += $(MPT_FILES_COMMON) libopenmpttest_SOURCES += $(MPT_FILES_SOUNDBASE) libopenmpttest_SOURCES += $(MPT_FILES_SOUNDLIB) libopenmpttest_SOURCES += $(MPT_FILES_SOUNDDSP) libopenmpttest_SOURCES += libopenmpt/libopenmpt_c.cpp libopenmpttest_SOURCES += libopenmpt/libopenmpt_cxx.cpp libopenmpttest_SOURCES += libopenmpt/libopenmpt_ext_impl.cpp libopenmpttest_SOURCES += libopenmpt/libopenmpt_impl.cpp libopenmpttest_SOURCES += libopenmpt/libopenmpt_config.h libopenmpttest_SOURCES += libopenmpt/libopenmpt_ext.h libopenmpttest_SOURCES += libopenmpt/libopenmpt_ext.hpp libopenmpttest_SOURCES += libopenmpt/libopenmpt_ext_impl.hpp libopenmpttest_SOURCES += libopenmpt/libopenmpt.h libopenmpttest_SOURCES += libopenmpt/libopenmpt.hpp libopenmpttest_SOURCES += libopenmpt/libopenmpt_impl.hpp libopenmpttest_SOURCES += libopenmpt/libopenmpt_internal.h libopenmpttest_SOURCES += libopenmpt/libopenmpt_stream_callbacks_buffer.h libopenmpttest_SOURCES += libopenmpt/libopenmpt_stream_callbacks_fd.h libopenmpttest_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file.h libopenmpttest_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file_mingw.h libopenmpttest_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h libopenmpttest_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file_posix.h libopenmpttest_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h libopenmpttest_SOURCES += libopenmpt/libopenmpt_version.h libopenmpttest_SOURCES += libopenmpt/libopenmpt_test/libopenmpt_test.cpp endif if ENABLE_OPENMPT123 bin_PROGRAMS += bin/openmpt123 bin_openmpt123_CPPFLAGS = bin_openmpt123_CPPFLAGS += $(GLOBAL_CPPFLAGS) $(WIN32_CPPFLAGS) -I$(srcdir)/src $(PORTAUDIO_CFLAGS) $(PULSEAUDIO_CFLAGS) $(SDL2_CFLAGS) $(SNDFILE_CFLAGS) $(FLAC_CFLAGS) bin_openmpt123_CXXFLAGS = bin_openmpt123_CXXFLAGS += $(GLOBAL_CXXFLAGS) $(WIN32_CXXFLAGS) $(WIN32_CONSOLE_CXXFLAGS) bin_openmpt123_LDADD = libopenmpt.la $(PORTAUDIO_LIBS) $(PULSEAUDIO_LIBS) $(SDL2_LIBS) $(SNDFILE_LIBS) $(FLAC_LIBS) $(OPENMPT123_WIN32_LIBS) bin_openmpt123_SOURCES = bin_openmpt123_SOURCES += $(MPT_FILES_SRC_MPT) bin_openmpt123_SOURCES += openmpt123/openmpt123_allegro42.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_config.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123.cpp bin_openmpt123_SOURCES += openmpt123/openmpt123_exception.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_flac.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_mmio.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_portaudio.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_pulseaudio.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_raw.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_sdl2.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_sndfile.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_stdio.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_stdout.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_terminal.hpp bin_openmpt123_SOURCES += openmpt123/openmpt123_waveout.hpp man1_MANS = man/openmpt123.1 endif @DX_RULES@ MOSTLYCLEANFILES += $(DX_CLEANFILES) libopenmpt-0.8.1+release.autotools/build/0000755000175000017500000000000015023302361015430 500000000000000libopenmpt-0.8.1+release.autotools/build/svn_version/0000755000175000017500000000000015023302361020003 500000000000000libopenmpt-0.8.1+release.autotools/build/svn_version/svn_version.h0000644000175000017500000000054712666471503022474 00000000000000 #pragma once #if defined(MPT_PACKAGE) #define OPENMPT_VERSION_IS_PACKAGE 1 #else #define OPENMPT_VERSION_IS_PACKAGE 0 #endif #if defined(MPT_SVNURL) #define OPENMPT_VERSION_URL MPT_SVNURL #endif #if defined(MPT_SVNVERSION) #define OPENMPT_VERSION_SVNVERSION MPT_SVNVERSION #endif #if defined(MPT_SVNDATE) #define OPENMPT_VERSION_DATE MPT_SVNDATE #endif libopenmpt-0.8.1+release.autotools/common/0000755000175000017500000000000015023302362015622 500000000000000libopenmpt-0.8.1+release.autotools/common/mptStringFormat.h0000644000175000017500000001557214361772061021100 00000000000000/* * mptStringFormat.h * ----------------- * Purpose: Convert other types to strings. * Notes : Currently none. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/detect.hpp" #include "mpt/endian/integer.hpp" #include "mpt/format/default_formatter.hpp" #include "mpt/format/message.hpp" #include "mpt/format/message_macros.hpp" #include "mpt/format/simple.hpp" #include "mpt/format/simple_spec.hpp" #include "mpt/string/types.hpp" #include "mpt/string_transcode/transcode.hpp" #include "openmpt/base/FlagSet.hpp" #include "mptString.h" #include // The following section demands a rationale. // 1. mpt::afmt::val(), mpt::wfmt::val() and mpt::ufmt::val() mimic the semantics of c++11 std::to_string() and std::to_wstring(). // There is an important difference though. The c++11 versions are specified in terms of sprintf formatting which in turn // depends on the current C locale. This renders these functions unusable in a library context because the current // C locale is set by the library-using application and could be anything. There is no way a library can get reliable semantics // out of these functions. It is thus better to just avoid them. // ToAString() and ToWString() are based on iostream internally, but the the locale of the stream is forced to std::locale::classic(), // which results in "C" ASCII locale behavior. // 2. The full suite of printf-like or iostream like number formatting is generally not required. Instead, a sane subset functionality // is provided here. // When formatting integers, it is recommended to use mpt::afmt::dec or mpt::afmt::hex. Appending a template argument '' sets the width, // the same way as '%nd' would do. Appending a '0' to the function name causes zero-filling as print-like '%0nd' would do. Spelling 'HEX' // in upper-case generates upper-case hex digits. If these are not known at compile-time, a more verbose FormatValA(int, format) can be // used. // 3. mpt::format(format)(...) provides simplified and type-safe message and localization string formatting. // The only specifier allowed is '{}' enclosing a number n. It references to n-th parameter after the format string (1-based). // This mimics the behaviour of QString::arg() in QT4/5 or MFC AfxFormatString2(). C printf-like functions offer similar functionality // with a '%n$TYPE' syntax. In .NET, the syntax is '{n}'. This is useful to support localization strings that can change the parameter // ordering. // 4. Every function is available for std::string, std::wstring and mpt::ustring. std::string makes no assumption about the encoding, which // basically means, it should work for any 7-bit or 8-bit encoding, including for example ASCII, UTF8 or the current locale encoding. // std::string std::wstring mpt::ustring mpt::tsrtring CString // mpt::afmt mpt::wfmt mpt::ufmt mpt::tfmt mpt::cfmt // MPT_AFORMAT("{}") MPT_WFORMAT("{}") MPT_UFORMAT("{}") MPT_TFORMAT("{}") MPT_CFORMAT("{}") // 5. All functionality here delegates real work outside of the header file so that and do not need to be included when // using this functionality. // Advantages: // - Avoids binary code bloat when too much of iostream operator << gets inlined at every usage site. // - Faster compile times because and (2 very complex headers) are not included everywhere. // Disadvantages: // - Slightly more c++ code is required for delegating work. // - As the header does not use iostreams, custom types need to overload mpt::UString instead of iostream operator << to allow for custom type // formatting. // - std::string, std::wstring and mpt::ustring are returned from somewhat deep cascades of helper functions. Where possible, code is // written in such a way that return-value-optimization (RVO) or named-return-value-optimization (NRVO) should be able to eliminate // almost all these copies. This should not be a problem for any decent modern compiler (and even less so for a c++11 compiler where // move-semantics will kick in if RVO/NRVO fails). namespace mpt { inline namespace MPT_INLINE_NS { template inline auto format_value_default(const mpt::packed & x) -> decltype(mpt::default_formatter::format(x)) { return mpt::default_formatter::format(x); } } // namespace MPT_INLINE_NS } // namespace mpt OPENMPT_NAMESPACE_BEGIN template inline auto format_value_default(const T & x) -> decltype(mpt::transcode(x.ToUString())) { return mpt::transcode(x.ToUString()); } template inline auto format_value_default(const T & x) -> decltype(mpt::transcode(ToUString(x))) { return mpt::transcode(ToUString(x)); } namespace mpt { template inline auto format_value_default(const T & x) -> decltype(mpt::transcode(x.ToUString())) { return mpt::transcode(x.ToUString()); } template inline auto format_value_default(const T & x) -> decltype(mpt::transcode(ToUString(x))) { return mpt::transcode(ToUString(x)); } template using fmtT = mpt::format; using afmt = fmtT; #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) using wfmt = fmtT; #endif using ufmt = fmtT; #if defined(MPT_ENABLE_CHARSET_LOCALE) using lfmt = fmtT; #endif // MPT_ENABLE_CHARSET_LOCALE #if MPT_OS_WINDOWS using tfmt = fmtT; #endif #if defined(MPT_WITH_MFC) using cfmt = fmtT; #endif // MPT_WITH_MFC #define MPT_AFORMAT(f) MPT_AFORMAT_MESSAGE(f) #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) #define MPT_WFORMAT(f) MPT_WFORMAT_MESSAGE(f) #endif #define MPT_UFORMAT(f) MPT_UFORMAT_MESSAGE(f) #if defined(MPT_ENABLE_CHARSET_LOCALE) #define MPT_LFORMAT(f) MPT_LFORMAT_MESSAGE(f) #endif // MPT_ENABLE_CHARSET_LOCALE #if MPT_OS_WINDOWS #define MPT_TFORMAT(f) MPT_TFORMAT_MESSAGE(f) #endif // MPT_OS_WINDOWS #if defined(MPT_WITH_MFC) #define MPT_CFORMAT(f) MPT_CFORMAT_MESSAGE(f) #endif // MPT_WITH_MFC } // namespace mpt template mpt::ustring ToUString(FlagSet flagset) { mpt::ustring str(flagset.size_bits(), UC_('0')); for(std::size_t x = 0; x < flagset.size_bits(); ++x) { str[flagset.size_bits() - x - 1] = (flagset.value().as_bits() & (static_cast::store_type>(1) << x) ? UC_('1') : UC_('0')); } return str; } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptTime.cpp0000644000175000017500000002317014765274341017711 00000000000000/* * mptTime.cpp * ----------- * Purpose: Various time utility functions. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "mptTime.h" #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS #include "mpt/osinfo/windows_wine_version.hpp" #endif // MODPLUG_TRACKER && MPT_OS_WINDOWS #include "mptStringBuffer.h" #if MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO_DATE) #include #endif #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS #include #endif // MODPLUG_TRACKER && MPT_OS_WINDOWS #if defined(MPT_FALLBACK_TIMEZONE_C) #include #endif // MPT_FALLBACK_TIMEZONE_C #if MPT_OS_WINDOWS #include #endif OPENMPT_NAMESPACE_BEGIN namespace mpt { namespace Date { #if defined(MODPLUG_TRACKER) #if MPT_OS_WINDOWS namespace ANSI { uint64 Now() { FILETIME filetime; #if MPT_WIN_AT_LEAST(MPT_WIN_8) GetSystemTimePreciseAsFileTime(&filetime); #else GetSystemTimeAsFileTime(&filetime); #endif return ((uint64)filetime.dwHighDateTime << 32 | filetime.dwLowDateTime); } mpt::ustring ToUString(uint64 time100ns) { constexpr std::size_t bufsize = 256; mpt::ustring result; FILETIME filetime; SYSTEMTIME systime; filetime.dwHighDateTime = (DWORD)(((uint64)time100ns) >> 32); filetime.dwLowDateTime = (DWORD)((uint64)time100ns); FileTimeToSystemTime(&filetime, &systime); TCHAR buf[bufsize]; GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &systime, TEXT("yyyy-MM-dd"), buf, bufsize); result.append(mpt::ToUnicode(mpt::String::ReadWinBuf(buf))); result.append(U_(" ")); GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, &systime, TEXT("HH:mm:ss"), buf, bufsize); result.append(mpt::ToUnicode(mpt::String::ReadWinBuf(buf))); result.append(U_(".")); result.append(mpt::ufmt::dec0<3>((unsigned)systime.wMilliseconds)); return result; } } // namespace ANSI #endif // MPT_OS_WINDOWS #endif // MODPLUG_TRACKER namespace nochrono { static int32 ToDaynum(int32 year, int32 month, int32 day) { month = (month + 9) % 12; year = year - (month / 10); int32 daynum = year*365 + year/4 - year/100 + year/400 + (month*306 + 5)/10 + (day - 1); return daynum; } static void FromDaynum(int32 d, int32 & year, int32 & month, int32 & day) { int64 g = d; int64 y,ddd,mi,mm,dd; y = (10000*g + 14780)/3652425; ddd = g - (365*y + y/4 - y/100 + y/400); if(ddd < 0) { y = y - 1; ddd = g - (365*y + y/4 - y/100 + y/400); } mi = (100*ddd + 52)/3060; mm = (mi + 2)%12 + 1; y = y + (mi + 2)/12; dd = ddd - (mi*306 + 5)/10 + 1; year = static_cast(y); month = static_cast(mm); day = static_cast(dd); } Unix UnixFromUTC(UTC timeUtc) { int32 daynum = ToDaynum(timeUtc.year, timeUtc.month, timeUtc.day); int64 seconds = static_cast(daynum - ToDaynum(1970, 1, 1)) * 24 * 60 * 60 + timeUtc.hours * 60 * 60 + timeUtc.minutes * 60 + timeUtc.seconds; return Unix{seconds}; } UTC UnixAsUTC(Unix tp) { int64 tmp = tp.value; int64 seconds = tmp % 60; tmp /= 60; int64 minutes = tmp % 60; tmp /= 60; int64 hours = tmp % 24; tmp /= 24; int32 year = 0, month = 0, day = 0; FromDaynum(static_cast(tmp) + ToDaynum(1970,1,1), year, month, day); UTC result = {}; result.year = year; result.month = month; result.day = day; result.hours = static_cast(hours); result.minutes = static_cast(minutes); result.seconds = seconds; return result; } #if defined(MODPLUG_TRACKER) struct tz_error { }; Unix UnixFromLocal(Local timeLocal) { #if defined(MPT_FALLBACK_TIMEZONE_WINDOWS_HISTORIC) try { if(mpt::osinfo::windows::current_is_wine()) { throw tz_error{}; } SYSTEMTIME sys_local{}; sys_local.wYear = static_cast(timeLocal.year); sys_local.wMonth = static_cast(timeLocal.month); sys_local.wDay = static_cast(timeLocal.day); sys_local.wHour = static_cast(timeLocal.hours); sys_local.wMinute = static_cast(timeLocal.minutes); sys_local.wSecond = static_cast(timeLocal.seconds); sys_local.wMilliseconds = 0; DYNAMIC_TIME_ZONE_INFORMATION dtzi{}; if(GetDynamicTimeZoneInformation(&dtzi) == TIME_ZONE_ID_INVALID) // WinVista { throw tz_error{}; } SYSTEMTIME sys_utc{}; if(TzSpecificLocalTimeToSystemTimeEx(&dtzi, &sys_local, &sys_utc) == FALSE) // Win7/Win8 { throw tz_error{}; } FILETIME ft{}; if(SystemTimeToFileTime(&sys_utc, &ft) == FALSE) // Win 2000 { throw tz_error{}; } ULARGE_INTEGER time_value{}; time_value.LowPart = ft.dwLowDateTime; time_value.HighPart = ft.dwHighDateTime; return UnixFromSeconds(static_cast((time_value.QuadPart - 116444736000000000LL) / 10000000LL)); } catch(const tz_error &) { // nothing } #endif #if defined(MPT_FALLBACK_TIMEZONE_WINDOWS_CURRENT) try { SYSTEMTIME sys_local{}; sys_local.wYear = static_cast(timeLocal.year); sys_local.wMonth = static_cast(timeLocal.month); sys_local.wDay = static_cast(timeLocal.day); sys_local.wHour = static_cast(timeLocal.hours); sys_local.wMinute = static_cast(timeLocal.minutes); sys_local.wSecond = static_cast(timeLocal.seconds); sys_local.wMilliseconds = 0; SYSTEMTIME sys_utc{}; if(TzSpecificLocalTimeToSystemTime(NULL, &sys_local, &sys_utc) == FALSE) // WinXP { throw tz_error{}; } FILETIME ft{}; if(SystemTimeToFileTime(&sys_utc, &ft) == FALSE) // Win 2000 { throw tz_error{}; } ULARGE_INTEGER time_value{}; time_value.LowPart = ft.dwLowDateTime; time_value.HighPart = ft.dwHighDateTime; return UnixFromSeconds(static_cast((time_value.QuadPart - 116444736000000000LL) / 10000000LL)); } catch(const tz_error &) { // nothing } #endif #if defined(MPT_FALLBACK_TIMEZONE_C) std::tm tmp{}; tmp.tm_year = timeLocal.year - 1900; tmp.tm_mon = timeLocal.month - 1; tmp.tm_mday = timeLocal.day; tmp.tm_hour = timeLocal.hours; tmp.tm_min = timeLocal.minutes; tmp.tm_sec = static_cast(timeLocal.seconds); return UnixFromSeconds(static_cast(std::mktime(&tmp))); #endif } Local UnixAsLocal(Unix tp) { #if defined(MPT_FALLBACK_TIMEZONE_WINDOWS_HISTORIC) try { if(mpt::osinfo::windows::current_is_wine()) { throw tz_error{}; } ULARGE_INTEGER time_value{}; time_value.QuadPart = static_cast(UnixAsSeconds(tp)) * 10000000LL + 116444736000000000LL; FILETIME ft{}; ft.dwLowDateTime = time_value.LowPart; ft.dwHighDateTime = time_value.HighPart; SYSTEMTIME sys_utc{}; if(FileTimeToSystemTime(&ft, &sys_utc) == FALSE) // WinXP { throw tz_error{}; } DYNAMIC_TIME_ZONE_INFORMATION dtzi{}; if(GetDynamicTimeZoneInformation(&dtzi) == TIME_ZONE_ID_INVALID) // WinVista { throw tz_error{}; } SYSTEMTIME sys_local{}; if(SystemTimeToTzSpecificLocalTimeEx(&dtzi, &sys_utc, &sys_local) == FALSE) // Win7/Win8 { throw tz_error{}; } Local result{}; result.year = sys_local.wYear; result.month = sys_local.wMonth; result.day = sys_local.wDay; result.hours = sys_local.wHour; result.minutes = sys_local.wMinute; result.seconds = sys_local.wSecond; return result; } catch(const tz_error&) { // nothing } #endif #if defined(MPT_FALLBACK_TIMEZONE_WINDOWS_CURRENT) try { ULARGE_INTEGER time_value{}; time_value.QuadPart = static_cast(UnixAsSeconds(tp)) * 10000000LL + 116444736000000000LL; FILETIME ft{}; ft.dwLowDateTime = time_value.LowPart; ft.dwHighDateTime = time_value.HighPart; SYSTEMTIME sys_utc{}; if(FileTimeToSystemTime(&ft, &sys_utc) == FALSE) // WinXP { throw tz_error{}; } SYSTEMTIME sys_local{}; if(SystemTimeToTzSpecificLocalTime(NULL, &sys_utc, &sys_local) == FALSE) // Win2000 { throw tz_error{}; } Local result{}; result.year = sys_local.wYear; result.month = sys_local.wMonth; result.day = sys_local.wDay; result.hours = sys_local.wHour; result.minutes = sys_local.wMinute; result.seconds = sys_local.wSecond; return result; } catch(const tz_error&) { // nothing } #endif #if defined(MPT_FALLBACK_TIMEZONE_C) std::time_t time_tp = static_cast(UnixAsSeconds(tp)); std::tm *tmp = std::localtime(&time_tp); if(!tmp) { return Local{}; } std::tm local = *tmp; Local result{}; result.year = local.tm_year + 1900; result.month = local.tm_mon + 1; result.day = local.tm_mday; result.hours = local.tm_hour; result.minutes = local.tm_min; result.seconds = local.tm_sec; return result; #endif } #endif // MODPLUG_TRACKER } // namespace nochrono template static mpt::ustring ToShortenedISO8601Impl(mpt::Date::Gregorian date) { mpt::ustring result; mpt::ustring tz; if constexpr(TZ == LogicalTimezone::Unspecified) { tz = U_(""); } else if constexpr(TZ == LogicalTimezone::UTC) { tz = U_("Z"); } else { tz = U_(""); } if(date.year == 0) { return result; } result += mpt::ufmt::dec0<4>(date.year); result += U_("-") + mpt::ufmt::dec0<2>(date.month); result += U_("-") + mpt::ufmt::dec0<2>(date.day); if(date.hours == 0 && date.minutes == 0 && date.seconds) { return result; } result += U_("T"); result += mpt::ufmt::dec0<2>(date.hours) + U_(":") + mpt::ufmt::dec0<2>(date.minutes); if(date.seconds == 0) { return result + tz; } result += U_(":") + mpt::ufmt::dec0<2>(date.seconds); result += tz; return result; } mpt::ustring ToShortenedISO8601(mpt::Date::AnyGregorian date) { return ToShortenedISO8601Impl(date); } mpt::ustring ToShortenedISO8601(mpt::Date::UTC date) { return ToShortenedISO8601Impl(date); } #ifdef MODPLUG_TRACKER mpt::ustring ToShortenedISO8601(Local date) { return ToShortenedISO8601Impl(date); } #endif // MODPLUG_TRACKER } // namespace Date } // namespace mpt OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptFileType.cpp0000644000175000017500000000504214250574063020523 00000000000000/* * mptFileType.cpp * --------------- * Purpose: * Notes : Currently none. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "mptFileType.h" OPENMPT_NAMESPACE_BEGIN #ifdef MODPLUG_TRACKER mpt::PathString FileType::AsFilterString(FlagSet format) const { mpt::PathString filter; if(GetShortName().empty() || GetExtensions().empty()) { return filter; } if(!GetDescription().empty()) { filter += mpt::PathString::FromUnicode(GetDescription()); } else { filter += mpt::PathString::FromUnicode(GetShortName()); } const auto extensions = GetExtensions(); if(format[FileTypeFormatShowExtensions]) { filter += P_(" ("); bool first = true; for(const auto &ext : extensions) { if(first) { first = false; } else { filter += P_(","); } filter += P_("*."); filter += ext; } filter += P_(")"); } filter += P_("|"); { bool first = true; for(const auto &ext : extensions) { if(first) { first = false; } else { filter += P_(";"); } filter += P_("*."); filter += ext; } } filter += P_("|"); return filter; } mpt::PathString FileType::AsFilterOnlyString() const { mpt::PathString filter; const auto extensions = GetExtensions(); { bool first = true; for(const auto &ext : extensions) { if(first) { first = false; } else { filter += P_(";"); } filter += P_("*."); filter += ext; } } return filter; } mpt::PathString ToFilterString(const FileType &fileType, FlagSet format) { return fileType.AsFilterString(format); } mpt::PathString ToFilterString(const std::vector &fileTypes, FlagSet format) { mpt::PathString filter; for(const auto &type : fileTypes) { filter += type.AsFilterString(format); } return filter; } mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicolonWhenNotEmpty) { mpt::PathString filter = fileType.AsFilterOnlyString(); return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter; } mpt::PathString ToFilterOnlyString(const std::vector &fileTypes, bool prependSemicolonWhenNotEmpty) { mpt::PathString filter; for(const auto &type : fileTypes) { filter += type.AsFilterOnlyString(); } return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter; } #else MPT_MSVC_WORKAROUND_LNK4221(mptFileType) #endif // MODPLUG_TRACKER OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptPathString.cpp0000644000175000017500000000561414765324671021103 00000000000000/* * mptPathString.cpp * ----------------- * Purpose: Wrapper class around the platform-native representation of path names. Should be the only type that is used to store path names. * Notes : Currently none. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "mptPathString.h" #include #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS #include #endif OPENMPT_NAMESPACE_BEGIN namespace mpt { #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS // Convert an absolute path to a path that's relative to "&relativeTo". mpt::PathString AbsolutePathToRelative(const mpt::PathString &path, const mpt::PathString &relativeTo) { using namespace path_literals; using char_type = RawPathString::value_type; mpt::PathString result = path; if(path.empty() || relativeTo.empty()) { return result; } if(!_tcsncicmp(relativeTo.AsNative().c_str(), path.AsNative().c_str(), relativeTo.AsNative().length())) { // Path is OpenMPT's directory or a sub directory ("C:\OpenMPT\Somepath" => ".\Somepath") result = mpt::PathString::FromNative(L(".\\")); // ".\" result += mpt::PathString::FromNative(path.AsNative().substr(relativeTo.AsNative().length())); } else if(!_tcsncicmp(relativeTo.AsNative().c_str(), path.AsNative().c_str(), 2)) { // Path is on the same drive as OpenMPT ("C:\Somepath" => "\Somepath") result = mpt::PathString::FromNative(path.AsNative().substr(2)); } return result; } // Convert a path that is relative to "&relativeTo" to an absolute path. mpt::PathString RelativePathToAbsolute(const mpt::PathString &path, const mpt::PathString &relativeTo) { using namespace path_literals; using char_type = RawPathString::value_type; mpt::PathString result = path; if(path.empty() || relativeTo.empty()) { return result; } if(path.length() >= 2 && path.AsNative()[0] == L('\\') && path.AsNative()[1] == L('\\')) { // Network / UNC paths return result; } if(path.length() >= 1 && path.AsNative()[0] == L('\\')) { // Path is on the same drive as relativeTo ("\Somepath\" => "C:\Somepath\") result = mpt::PathString::FromNative(relativeTo.AsNative().substr(0, 2)); result += mpt::PathString(path); } else if(path.length() >= 2 && path.AsNative().substr(0, 2) == L(".\\")) { // Path is in relativeTo or a sub directory (".\Somepath\" => "C:\OpenMPT\Somepath\") result = relativeTo; // "C:\OpenMPT\" result += mpt::PathString::FromNative(path.AsNative().substr(2)); } else if(path.length() < 3 || path.AsNative()[1] != L(':') || path.AsNative()[2] != L('\\')) { // Any other path not starting with drive letter result = relativeTo; // "C:\OpenMPT\" result += mpt::PathString(path); } return result; } #endif // MODPLUG_TRACKER && MPT_OS_WINDOWS } // namespace mpt OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptFileTemporary.h0000644000175000017500000000512414762355233021236 00000000000000/* * mptFileTemporary.h * ------------------ * Purpose: * Notes : Currently none. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/namespace.hpp" #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS #include "mpt/fs/common_directories.hpp" #include "mpt/fs/fs.hpp" #include "mpt/io_file_unique/unique_basename.hpp" #include "mpt/io_file_unique/unique_tempfilename.hpp" #include "mpt/uuid/uuid.hpp" #include "mptPathString.h" #include "mptRandom.h" #if MPT_OS_WINDOWS #include #endif #endif // MODPLUG_TRACKER && MPT_OS_WINDOWS OPENMPT_NAMESPACE_BEGIN namespace mpt { #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS // Returns a new unique absolute path. class TemporaryPathname { private: mpt::PathString m_Path; public: TemporaryPathname(const mpt::PathString &fileNameExtension = P_("tmp")) { mpt::PathString prefix; #if defined(LIBOPENMPT_BUILD) prefix = P_("libopenmpt"); #else prefix = P_("OpenMPT"); #endif m_Path = mpt::PathString::FromNative(mpt::IO::unique_tempfilename{mpt::IO::unique_basename{prefix, mpt::UUID::GenerateLocalUseOnly(mpt::global_prng())}, fileNameExtension}); } public: mpt::PathString GetPathname() const { return m_Path; } }; // Scoped temporary file guard. Deletes the file when going out of scope. // The file itself is not created automatically. class TempFileGuard { private: const mpt::PathString filename; public: TempFileGuard(const mpt::TemporaryPathname &pathname = mpt::TemporaryPathname{}) : filename(pathname.GetPathname()) { return; } mpt::PathString GetFilename() const { return filename; } ~TempFileGuard() { if(!filename.empty()) { DeleteFile(mpt::support_long_path(filename.AsNative()).c_str()); } } }; // Scoped temporary directory guard. Deletes the directory when going out of scope. // The directory itself is created automatically. class TempDirGuard { private: mpt::PathString dirname; public: TempDirGuard(const mpt::TemporaryPathname &pathname = mpt::TemporaryPathname{}) : dirname(pathname.GetPathname().WithTrailingSlash()) { if(dirname.empty()) { return; } if(::CreateDirectory(mpt::support_long_path(dirname.AsNative()).c_str(), NULL) == 0) { // fail dirname = mpt::PathString(); } } mpt::PathString GetDirname() const { return dirname; } ~TempDirGuard() { if(!dirname.empty()) { mpt::native_fs{}.delete_tree(dirname); } } }; #endif // MODPLUG_TRACKER && MPT_OS_WINDOWS } // namespace mpt OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/FileReaderFwd.h0000644000175000017500000000356114766002420020370 00000000000000/* * FileReaderFwd.h * --------------- * Purpose: Forward declaration for class FileReader. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/namespace.hpp" namespace mpt { inline namespace MPT_INLINE_NS { template class BasicPathString; struct NativePathTraits; struct Utf8PathTraits; using native_path = BasicPathString; namespace IO { class FileCursorTraitsMemory; class FileCursorTraitsFileData; class FileCursorFilenameTraitsNone; template class FileCursorFilenameTraits; template class FileCursor; } // namespace IO } // inline namespace MPT_INLINE_NS } // namespace mpt OPENMPT_NAMESPACE_BEGIN namespace mpt { } // namespace mpt namespace detail { template using FileCursor = mpt::IO::FileCursor; template class FileReader; } // namespace detail namespace mpt { #if defined(MPT_ENABLE_CHARSET_LOCALE) using PathString = mpt::native_path; #else using PathString = mpt::BasicPathString; #endif } // namespace mpt using FileCursor = detail::FileCursor>; using FileReader = detail::FileReader>; using MemoryFileCursor = detail::FileCursor; using MemoryFileReader = detail::FileReader; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/ComponentManager.cpp0000644000175000017500000002267214631306026021521 00000000000000/* * ComponentManager.cpp * -------------------- * Purpose: Manages loading of optional components. * Notes : (currently none) * Authors: Joern Heusipp * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "ComponentManager.h" #include "mpt/mutex/mutex.hpp" #include "Logging.h" OPENMPT_NAMESPACE_BEGIN ComponentBase::ComponentBase(ComponentType type) : m_Type(type) , m_Initialized(false) , m_Available(false) { return; } ComponentBase::~ComponentBase() { return; } void ComponentBase::SetInitialized() { m_Initialized = true; } void ComponentBase::SetAvailable() { m_Available = true; } ComponentType ComponentBase::GetType() const { return m_Type; } bool ComponentBase::IsInitialized() const { return m_Initialized; } bool ComponentBase::IsAvailable() const { return m_Initialized && m_Available; } mpt::ustring ComponentBase::GetVersion() const { return mpt::ustring(); } void ComponentBase::Initialize() { if(IsInitialized()) { return; } if(DoInitialize()) { SetAvailable(); } SetInitialized(); } #if defined(MODPLUG_TRACKER) ComponentLibrary::ComponentLibrary(ComponentType type) : ComponentBase(type) , m_BindFailed(false) { return; } ComponentLibrary::~ComponentLibrary() { return; } bool ComponentLibrary::AddLibrary(const std::string &libName, const mpt::LibraryPath &libPath) { if(m_Libraries[libName].IsValid()) { // prefer previous return true; } mpt::Library lib(libPath); if(!lib.IsValid()) { return false; } m_Libraries[libName] = lib; return true; } void ComponentLibrary::ClearLibraries() { m_Libraries.clear(); } void ComponentLibrary::SetBindFailed() { m_BindFailed = true; } void ComponentLibrary::ClearBindFailed() { m_BindFailed = false; } bool ComponentLibrary::HasBindFailed() const { return m_BindFailed; } mpt::Library ComponentLibrary::GetLibrary(const std::string &libName) const { const auto it = m_Libraries.find(libName); if(it == m_Libraries.end()) { return mpt::Library(); } return it->second; } #endif // MODPLUG_TRACKER #if MPT_COMPONENT_MANAGER ComponentFactoryBase::ComponentFactoryBase(const std::string &id, const std::string &settingsKey) : m_ID(id) , m_SettingsKey(settingsKey) { return; } ComponentFactoryBase::~ComponentFactoryBase() { return; } std::string ComponentFactoryBase::GetID() const { return m_ID; } std::string ComponentFactoryBase::GetSettingsKey() const { return m_SettingsKey; } void ComponentFactoryBase::PreConstruct() const { MPT_LOG_GLOBAL(LogInformation, "Components", MPT_UFORMAT("Constructing Component {}") ( mpt::ToUnicode(mpt::Charset::ASCII, m_ID) ) ); } void ComponentFactoryBase::Initialize(ComponentManager &componentManager, std::shared_ptr component) const { if(componentManager.IsComponentBlocked(GetSettingsKey())) { return; } componentManager.InitializeComponent(component); } // Global list of component register functions. // We do not use a global scope static list head because the corresponding // mutex would be no POD type and would thus not be safe to be usable in // zero-initialized state. // Function scope static initialization is guaranteed to be thread safe // in C++11. // We use this implementation to be future-proof. // MSVC currently does not exploit the possibility of using multiple threads // for global lifetime object's initialization. // An implementation with a simple global list head and no mutex at all would // thus work fine for MSVC (currently). static mpt::mutex & ComponentListMutex() { static mpt::mutex g_ComponentListMutex; return g_ComponentListMutex; } static ComponentListEntry * & ComponentListHead() { static ComponentListEntry g_ComponentListHeadEmpty = {nullptr, nullptr}; static ComponentListEntry *g_ComponentListHead = &g_ComponentListHeadEmpty; return g_ComponentListHead; } bool ComponentListPush(ComponentListEntry *entry) { mpt::lock_guard guard(ComponentListMutex()); #if MPT_MSVC_BEFORE(2019,0) // Guard against VS2017 compiler bug causing repeated initialization of inline variables. // See . if(entry->next) { return false; } #endif entry->next = ComponentListHead(); ComponentListHead() = entry; return true; } static std::shared_ptr g_ComponentManager; void ComponentManager::Init(const IComponentManagerSettings &settings) { MPT_LOG_GLOBAL(LogInformation, "Components", U_("Init")); // cannot use make_shared because the constructor is private g_ComponentManager = std::shared_ptr(new ComponentManager(settings)); } void ComponentManager::Release() { MPT_LOG_GLOBAL(LogInformation, "Components", U_("Release")); g_ComponentManager = nullptr; } std::shared_ptr ComponentManager::Instance() { return g_ComponentManager; } ComponentManager::ComponentManager(const IComponentManagerSettings &settings) : m_Settings(settings) { mpt::lock_guard guard(ComponentListMutex()); for(ComponentListEntry *entry = ComponentListHead(); entry; entry = entry->next) { if(entry->reg) { entry->reg(*this); } } } void ComponentManager::Register(const IComponentFactory &componentFactory) { if(m_Components.find(componentFactory.GetID()) != m_Components.end()) { return; } RegisteredComponent registeredComponent; registeredComponent.settingsKey = componentFactory.GetSettingsKey(); registeredComponent.factoryMethod = componentFactory.GetStaticConstructor(); registeredComponent.instance = nullptr; registeredComponent.weakInstance = std::weak_ptr(); m_Components.insert(std::make_pair(componentFactory.GetID(), registeredComponent)); } void ComponentManager::Startup() { MPT_LOG_GLOBAL(LogDebug, "Components", U_("Startup")); if(m_Settings.LoadOnStartup()) { for(auto &it : m_Components) { it.second.instance = it.second.factoryMethod(*this); it.second.weakInstance = it.second.instance; } } if(!m_Settings.KeepLoaded()) { for(auto &it : m_Components) { it.second.instance = nullptr; } } } bool ComponentManager::IsComponentBlocked(const std::string &settingsKey) const { if(settingsKey.empty()) { return false; } return m_Settings.IsBlocked(settingsKey); } void ComponentManager::InitializeComponent(std::shared_ptr component) const { if(!component) { return; } if(component->IsInitialized()) { return; } component->Initialize(); } std::shared_ptr ComponentManager::GetComponent(const IComponentFactory &componentFactory) { std::shared_ptr component = nullptr; auto it = m_Components.find(componentFactory.GetID()); if(it != m_Components.end()) { // registered component if((*it).second.instance) { // loaded component = (*it).second.instance; } else { // not loaded component = (*it).second.weakInstance.lock(); if(!component) { component = (*it).second.factoryMethod(*this); } if(m_Settings.KeepLoaded()) { // keep the component loaded (*it).second.instance = component; } (*it).second.weakInstance = component; } } else { // unregistered component component = componentFactory.Construct(*this); } MPT_ASSERT(component); return component; } std::shared_ptr ComponentManager::ReloadComponent(const IComponentFactory &componentFactory) { std::shared_ptr component = nullptr; auto it = m_Components.find(componentFactory.GetID()); if(it != m_Components.end()) { // registered component if((*it).second.instance) { // loaded (*it).second.instance = nullptr; if(!(*it).second.weakInstance.expired()) { throw std::runtime_error("Component not completely unloaded. Cannot reload."); } (*it).second.weakInstance = std::weak_ptr(); } // not loaded component = (*it).second.factoryMethod(*this); if(m_Settings.KeepLoaded()) { // keep the component loaded (*it).second.instance = component; } (*it).second.weakInstance = component; } else { // unregistered component component = componentFactory.Construct(*this); } MPT_ASSERT(component); return component; } std::vector ComponentManager::GetRegisteredComponents() const { std::vector result; result.reserve(m_Components.size()); for(const auto &it : m_Components) { result.push_back(it.first); } return result; } ComponentInfo ComponentManager::GetComponentInfo(std::string name) const { ComponentInfo result; result.name = name; result.state = ComponentStateUnregistered; result.settingsKey = ""; result.type = ComponentTypeUnknown; const auto it = m_Components.find(name); if(it == m_Components.end()) { result.state = ComponentStateUnregistered; return result; } result.settingsKey = it->second.settingsKey; if(IsComponentBlocked(it->second.settingsKey)) { result.state = ComponentStateBlocked; return result; } std::shared_ptr component = it->second.instance; if(!component) { component = it->second.weakInstance.lock(); } if(!component) { result.state = ComponentStateUnintialized; return result; } result.type = component->GetType(); if(!component->IsInitialized()) { result.state = ComponentStateUnintialized; return result; } if(!component->IsAvailable()) { result.state = ComponentStateUnavailable; return result; } result.state = ComponentStateAvailable; return result; } #endif // MPT_COMPONENT_MANAGER OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptFileIO.h0000644000175000017500000000175714763562020017566 00000000000000/* * mptFileIO.h * ----------- * Purpose: * Notes : You should only ever use these wrappers instead of plain std::fstream classes. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #if defined(MPT_ENABLE_FILEIO) #include "mpt/io_file_read/inputfile_filecursor.hpp" #include "../common/mptPathString.h" #include "../common/FileReaderFwd.h" #include #endif // MPT_ENABLE_FILEIO OPENMPT_NAMESPACE_BEGIN #if defined(MPT_ENABLE_FILEIO) template inline FileCursor GetFileReader(Targ1 &&arg1) { return mpt::IO::make_FileCursor(std::forward(arg1)); } template inline FileCursor GetFileReader(Targ1 &&arg1, Targ2 &&arg2) { return mpt::IO::make_FileCursor(std::forward(arg1), std::forward(arg2)); } #endif // MPT_ENABLE_FILEIO OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptPathString.h0000644000175000017500000000473514765324671020553 00000000000000/* * mptPathString.h * --------------- * Purpose: Wrapper class around the platform-native representation of path names. Should be the only type that is used to store path names. * Notes : Currently none. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/path/basic_path.hpp" #include "mpt/path/native_path.hpp" #include "mpt/path/os_path.hpp" #include "mpt/string/types.hpp" #if defined(MODPLUG_TRACKER) #include "mpt/string_transcode/transcode.hpp" #endif #include "mptString.h" #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS #include #endif OPENMPT_NAMESPACE_BEGIN namespace mpt { #if defined(MPT_ENABLE_CHARSET_LOCALE) using PathString = mpt::native_path; #define MPT_PATHSTRING_LITERAL(x) MPT_OS_PATH_LITERAL( x ) #define MPT_PATHSTRING(x) mpt::PathString::FromNative(MPT_OS_PATH_LITERAL( x )) #else // !MPT_ENABLE_CHARSET_LOCALE using PathString = mpt::BasicPathString; #define MPT_PATHSTRING_LITERAL(x) ( x ) #define MPT_PATHSTRING(x) mpt::PathString::FromNative( x ) #endif // MPT_ENABLE_CHARSET_LOCALE using RawPathString = PathString::raw_path_type; #define PC_(x) MPT_PATHSTRING_LITERAL(x) #define PL_(x) MPT_PATHSTRING_LITERAL(x) #define P_(x) MPT_PATHSTRING(x) template ::value, bool>::type = true> inline mpt::ustring ToUString(const T &x) { return x.ToUnicode(); } #if defined(MODPLUG_TRACKER) #if MPT_OS_WINDOWS // Relative / absolute paths conversion mpt::PathString AbsolutePathToRelative(const mpt::PathString &p, const mpt::PathString &relativeTo); // similar to std::fs::path::lexically_approximate mpt::PathString RelativePathToAbsolute(const mpt::PathString &p, const mpt::PathString &relativeTo); #if !MPT_OS_WINDOWS_WINRT inline int PathCompareNoCase(const PathString &a, const PathString &b) { return lstrcmpi(a.AsNative().c_str(), b.AsNative().c_str()); } #endif // !MPT_OS_WINDOWS_WINRT #endif // MPT_OS_WINDOWS template inline Tstring SanitizePathComponent(const Tstring &str) { return mpt::transcode(mpt::native_path::FromNative(mpt::transcode(str)).AsSanitizedComponent().AsNative()); } #endif // MODPLUG_TRACKER } // namespace mpt OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/Logging.cpp0000644000175000017500000002472014763563375017670 00000000000000/* * Logging.cpp * ----------- * Purpose: General logging * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Logging.h" #include "mpt/base/macros.hpp" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #if defined(MODPLUG_TRACKER) #include "mpt/io_file/fstream.hpp" #endif #if defined(MODPLUG_TRACKER) #include "mptFileIO.h" #endif #if defined(MODPLUG_TRACKER) #include #endif #include "version.h" #include #include #include #include OPENMPT_NAMESPACE_BEGIN namespace mpt { namespace log { #if !defined(MPT_LOG_GLOBAL_LEVEL_STATIC) #if defined(MPT_LOG_GLOBAL_LEVEL) MPT_CONSTINIT int GlobalLogLevel = static_cast(MPT_LOG_GLOBAL_LEVEL); #else MPT_CONSTINIT int GlobalLogLevel = static_cast(LogDebug); #endif #endif #if defined(MODPLUG_TRACKER) && !defined(MPT_LOG_IS_DISABLED) MPT_CONSTINIT bool FileEnabled = false; MPT_CONSTINIT bool DebuggerEnabled = true; MPT_CONSTINIT bool ConsoleEnabled = false; static MPT_CONSTINIT char g_FacilitySolo[1024] = {0}; static MPT_CONSTINIT char g_FacilityBlocked[1024] = {0}; void SetFacilities(const std::string &solo, const std::string &blocked) { std::strcpy(g_FacilitySolo, solo.c_str()); std::strcpy(g_FacilityBlocked, blocked.c_str()); } bool IsFacilityActive(const char *facility) noexcept { if(facility) { if(std::strlen(g_FacilitySolo) > 0) { if(std::strcmp(facility, g_FacilitySolo) != 0) { return false; } } if(std::strlen(g_FacilityBlocked) > 0) { if(std::strcmp(facility, g_FacilitySolo) == 0) { return false; } } } return true; } #endif void GlobalLogger::SendLogMessage(const mpt::source_location &loc, LogLevel level, const char *facility, const mpt::ustring &text) const { #ifdef MPT_LOG_IS_DISABLED MPT_UNREFERENCED_PARAMETER(loc); MPT_UNREFERENCED_PARAMETER(level); MPT_UNREFERENCED_PARAMETER(facility); MPT_UNREFERENCED_PARAMETER(text); #else // !MPT_LOG_IS_DISABLED MPT_MAYBE_CONSTANT_IF(mpt::log::GlobalLogLevel < level) { return; } #if defined(MODPLUG_TRACKER) if(!IsFacilityActive(facility)) { return; } #else // !MODPLUG_TRACKER MPT_UNREFERENCED_PARAMETER(facility); #endif // MODPLUG_TRACKER // remove eol if already present and add log level prefix const mpt::ustring message = LogLevelToString(level) + U_(": ") + mpt::trim_right(text, U_("\r\n")); const mpt::ustring file = mpt::transcode(mpt::source_encoding, loc.file_name() ? loc.file_name() : ""); const mpt::ustring function = mpt::transcode(mpt::source_encoding, loc.function_name() ? loc.function_name() : ""); const mpt::ustring line = mpt::ufmt::dec(loc.line()); #if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT) #if MPT_OS_WINDOWS static uint64 s_lastlogtime = 0; uint64 cur = mpt::Date::ANSI::Now(); uint64 diff = cur/10000 - s_lastlogtime; s_lastlogtime = cur/10000; #else uint64 cur = 0; uint64 diff = 0; #endif if(mpt::log::FileEnabled) { static std::optional s_logfile; if(!s_logfile) { s_logfile.emplace(P_("mptrack.log"), std::ios::app); } if(s_logfile) { mpt::IO::WriteText(*s_logfile, mpt::transcode(mpt::logfile_encoding, MPT_UFORMAT("{}+{} {}({}): {} [{}]\n") ( mpt::Date::ANSI::ToUString(cur) , mpt::ufmt::right(6, mpt::ufmt::dec(diff)) , file , line , message , function ))); mpt::IO::Flush(*s_logfile); } } if(mpt::log::DebuggerEnabled) { OutputDebugStringW(mpt::ToWide(MPT_UFORMAT("{}({}): +{} {} [{}]\n") ( file , line , mpt::ufmt::right(6, mpt::ufmt::dec(diff)) , message , function )).c_str()); } if(mpt::log::ConsoleEnabled) { static bool consoleInited = false; if(!consoleInited) { AllocConsole(); consoleInited = true; } std::wstring consoletext = mpt::ToWide(message) + L"\r\n"; DWORD dummy = 0; WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), consoletext.c_str(), mpt::saturate_cast(consoletext.length()), &dummy, NULL); } #elif defined(MODPLUG_TRACKER) && defined(MPT_BUILD_WINESUPPORT) std::clog << "NativeSupport: " << mpt::transcode(mpt::stdio_encoding, file) << "(" << mpt::transcode(mpt::stdio_encoding, line) << ")" << ": " << mpt::transcode(mpt::stdio_encoding, message) << " [" << mpt::transcode(mpt::stdio_encoding, function) << "]" << std::endl; #else // !MODPLUG_TRACKER std::clog << "libopenmpt: " << mpt::transcode(mpt::stdio_encoding, file) << "(" << mpt::transcode(mpt::stdio_encoding, line) << ")" << ": " << mpt::transcode(mpt::stdio_encoding, message) << " [" << mpt::transcode(mpt::stdio_encoding, function) << "]" << std::endl; #endif // MODPLUG_TRACKER #endif // MPT_LOG_IS_DISABLED } #if defined(MODPLUG_TRACKER) namespace Trace { #if MPT_OS_WINDOWS // Debugging functionality will use simple globals. MPT_CONSTINIT std::atomic g_Enabled{false}; static MPT_CONSTINIT bool g_Sealed = false; struct Entry { uint32 Index; uint32 ThreadId; uint64 Timestamp; const char * Function; const char * File; int Line; Direction Direction; }; static MPT_FORCEINLINE bool operator < (const Entry &a, const Entry &b) noexcept { /* return false || (a.Timestamp < b.Timestamp) || (a.ThreadID < b.ThreadID) || (a.File < b.File) || (a.Line < b.Line) || (a.Function < b.Function) ; */ return false || (a.Index < b.Index) ; } #if MPT_COMPILER_MSVC // VS2022 still does nto have constexpr vector default ctor static /*MPT_CONSTINIT*/ std::vector Entries; #else static MPT_CONSTINIT std::vector Entries; #endif static MPT_CONSTINIT std::atomic NextIndex(0); static MPT_CONSTINIT uint32 ThreadIdGUI = 0; static MPT_CONSTINIT uint32 ThreadIdAudio = 0; static MPT_CONSTINIT uint32 ThreadIdNotify = 0; static MPT_CONSTINIT uint32 ThreadIdWatchdir = 0; void Enable(std::size_t numEntries) { if(g_Sealed) { return; } Entries.clear(); Entries.resize(numEntries); NextIndex.store(0); g_Enabled = (numEntries > 0); } void Disable() { if(g_Sealed) { return; } g_Enabled = false; } MPT_NOINLINE void Trace(const mpt::source_location & loc, Direction direction) noexcept { // This will get called in realtime contexts and hot paths. // No blocking allowed here. const uint32 index = NextIndex.fetch_add(1); const std::size_t numEntries = Entries.size(); #if 1 LARGE_INTEGER time; time.QuadPart = 0; QueryPerformanceCounter(&time); const uint64 timestamp = time.QuadPart; #else FILETIME time = FILETIME(); GetSystemTimeAsFileTime(&time); const uint64 timestamp = (static_cast(time.dwHighDateTime) << 32) | (static_cast(time.dwLowDateTime) << 0); #endif const uint32 threadid = static_cast(GetCurrentThreadId()); mpt::log::Trace::Entry & entry = Entries[index % numEntries]; entry.Index = index; entry.ThreadId = threadid; entry.Timestamp = timestamp; entry.Function = loc.function_name(); entry.File = loc.file_name(); entry.Line = loc.line(); entry.Direction = direction; } void Seal() { if(!g_Enabled) { return; } g_Enabled = false; g_Sealed = true; uint32 count = NextIndex.fetch_add(0); if(count < Entries.size()) { Entries.resize(count); } } bool Dump(const mpt::PathString &filename) { if(!g_Sealed) { return false; } LARGE_INTEGER qpcNow; qpcNow.QuadPart = 0; QueryPerformanceCounter(&qpcNow); uint64 ftNow = mpt::Date::ANSI::Now(); // sort according to index in case of overflows std::stable_sort(Entries.begin(), Entries.end()); mpt::IO::ofstream f(filename); f << "Build: OpenMPT " << mpt::transcode(mpt::logfile_encoding, Build::GetVersionStringExtended()) << std::endl; bool qpcValid = false; LARGE_INTEGER qpcFreq; qpcFreq.QuadPart = 0; QueryPerformanceFrequency(&qpcFreq); if(qpcFreq.QuadPart > 0) { qpcValid = true; } f << "Dump: " << mpt::transcode(mpt::logfile_encoding, mpt::Date::ANSI::ToUString(ftNow)) << std::endl; f << "Captured events: " << Entries.size() << std::endl; if(qpcValid && (Entries.size() > 0)) { double period = static_cast(Entries[Entries.size() - 1].Timestamp - Entries[0].Timestamp) / static_cast(qpcFreq.QuadPart); double eventsPerSecond = Entries.size() / period; f << "Period [s]: " << mpt::afmt::fix(period) << std::endl; f << "Events/second: " << mpt::afmt::fix(eventsPerSecond) << std::endl; } for(auto &entry : Entries) { if(!entry.Function) entry.Function = ""; if(!entry.File) entry.File = ""; std::string time; if(qpcValid) { time = mpt::transcode(mpt::logfile_encoding, mpt::Date::ANSI::ToUString( ftNow - static_cast( static_cast(qpcNow.QuadPart - entry.Timestamp) * (10000000.0 / static_cast(qpcFreq.QuadPart) ) ) ) ); } else { time = MPT_AFORMAT("0x{}")(mpt::afmt::hex0<16>(entry.Timestamp)); } f << time; if(entry.ThreadId == ThreadIdGUI) { f << " -----GUI "; } else if(entry.ThreadId == ThreadIdAudio) { f << " ---Audio "; } else if(entry.ThreadId == ThreadIdNotify) { f << " --Notify "; } else if(entry.ThreadId == ThreadIdWatchdir) { f << " WatchDir "; } else { f << " " << mpt::afmt::hex0<8>(entry.ThreadId) << " "; } f << (entry.Direction == mpt::log::Trace::Direction::Enter ? ">" : entry.Direction == mpt::log::Trace::Direction::Leave ? "<" : " ") << " "; f << entry.File << "(" << entry.Line << "): " << entry.Function; f << std::endl; } return true; } void SetThreadId(mpt::log::Trace::ThreadKind kind, uint32 id) { if(id == 0) { return; } switch(kind) { case ThreadKindGUI: ThreadIdGUI = id; break; case ThreadKindAudio: ThreadIdAudio = id; break; case ThreadKindNotify: ThreadIdNotify = id; break; case ThreadKindWatchdir: ThreadIdWatchdir = id; break; } } uint32 GetThreadId(mpt::log::Trace::ThreadKind kind) { uint32 result = 0; switch(kind) { case ThreadKindGUI: result = ThreadIdGUI; break; case ThreadKindAudio: result = ThreadIdAudio; break; case ThreadKindNotify: result = ThreadIdNotify; break; case ThreadKindWatchdir: result = ThreadIdWatchdir; break; } return result; } #endif // MPT_OS_WINDOWS } // namespace Trace #endif // MODPLUG_TRACKER } // namespace log } // namespace mpt OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/version.cpp0000644000175000017500000005205014734741400017745 00000000000000/* * version.cpp * ----------- * Purpose: OpenMPT version handling. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "version.h" #include "mpt/format/join.hpp" #include "mpt/parse/parse.hpp" #include "mpt/string/utility.hpp" #include "mptString.h" #include "mptStringFormat.h" #include "versionNumber.h" #if __has_include("svn_version.h") #include "svn_version.h" #else #include "../build/svn_version/svn_version.h" #endif OPENMPT_NAMESPACE_BEGIN #define MPT_MAKE_VERSION_NUMERIC_HELPER(prefix,v0,v1,v2,v3) Version( prefix ## v0 , prefix ## v1 , prefix ## v2 , prefix ## v3 ) #define MPT_MAKE_VERSION_NUMERIC(v0,v1,v2,v3) MPT_MAKE_VERSION_NUMERIC_HELPER(0x, v0, v1, v2, v3) #define MPT_VERSION_CURRENT MPT_MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR) static_assert((MPT_VERSION_CURRENT.GetRawVersion() & 0xffffu) != 0x0000u, "Version numbers ending in .00.00 shall never exist again, as they make interpreting the version number ambiguous for file formats which can only store the two major parts of the version number (e.g. IT and S3M)."); Version Version::Current() noexcept { return MPT_VERSION_CURRENT; } mpt::ustring Version::GetOpenMPTVersionString() const { return U_("OpenMPT ") + ToUString(); } Version Version::Parse(const mpt::ustring &s) { uint32 result = 0; std::vector numbers = mpt::split(s, U_(".")); for (std::size_t i = 0; i < numbers.size() && i < 4; ++i) { result |= (mpt::parse_hex(numbers[i]) & 0xff) << ((3 - i) * 8); } return Version(result); } mpt::ustring Version::ToUString() const { uint32 v = m_Version; if(v == 0) { // Unknown version return U_("Unknown"); } else if((v & 0xFFFF) == 0) { // Only parts of the version number are known (e.g. when reading the version from the IT or S3M file header) return MPT_UFORMAT("{}.{}")(mpt::ufmt::HEX((v >> 24) & 0xFF), mpt::ufmt::HEX0<2>((v >> 16) & 0xFF)); } else { // Full version info available return MPT_UFORMAT("{}.{}.{}.{}")(mpt::ufmt::HEX((v >> 24) & 0xFF), mpt::ufmt::HEX0<2>((v >> 16) & 0xFF), mpt::ufmt::HEX0<2>((v >> 8) & 0xFF), mpt::ufmt::HEX0<2>((v) & 0xFF)); } } Version Version::WithoutTestNumber() const noexcept { return Version(m_Version & 0xFFFFFF00u); } Version Version::WithoutPatchOrTestNumbers() const noexcept { return Version(m_Version & 0xFFFF0000u); } bool Version::IsTestVersion() const noexcept { return ( // Legacy (*this > MPT_V("1.17.02.54") && *this < MPT_V("1.18.02.00") && *this != MPT_V("1.18.00.00")) || // Test builds have non-zero VER_MINORMINOR (*this > MPT_V("1.18.02.00") && ((m_Version & 0xFFFFFF00u) != m_Version)) ); } namespace Source { static mpt::ustring GetUrl() { #ifdef OPENMPT_VERSION_URL return mpt::ToUnicode(mpt::Charset::ASCII, OPENMPT_VERSION_URL); #else return mpt::ustring(); #endif } static int GetRevision() { #if defined(OPENMPT_VERSION_REVISION) return OPENMPT_VERSION_REVISION; #elif defined(OPENMPT_VERSION_SVNVERSION) std::string svnversion = OPENMPT_VERSION_SVNVERSION; if(svnversion.length() == 0) { return 0; } if(svnversion.find(":") != std::string::npos) { svnversion = svnversion.substr(svnversion.find(":") + 1); } if(svnversion.find("-") != std::string::npos) { svnversion = svnversion.substr(svnversion.find("-") + 1); } if(svnversion.find("M") != std::string::npos) { svnversion = svnversion.substr(0, svnversion.find("M")); } if(svnversion.find("S") != std::string::npos) { svnversion = svnversion.substr(0, svnversion.find("S")); } if(svnversion.find("P") != std::string::npos) { svnversion = svnversion.substr(0, svnversion.find("P")); } return mpt::parse(svnversion); #else MPT_WARNING_STATEMENT("SVN revision unknown. Please check your build system."); return 0; #endif } static bool IsDirty() { #if defined(OPENMPT_VERSION_DIRTY) return OPENMPT_VERSION_DIRTY != 0; #elif defined(OPENMPT_VERSION_SVNVERSION) std::string svnversion = OPENMPT_VERSION_SVNVERSION; if(svnversion.length() == 0) { return false; } if(svnversion.find("M") != std::string::npos) { return true; } return false; #else return false; #endif } static bool HasMixedRevisions() { #if defined(OPENMPT_VERSION_MIXEDREVISIONS) return OPENMPT_VERSION_MIXEDREVISIONS != 0; #elif defined(OPENMPT_VERSION_SVNVERSION) std::string svnversion = OPENMPT_VERSION_SVNVERSION; if(svnversion.length() == 0) { return false; } if(svnversion.find(":") != std::string::npos) { return true; } if(svnversion.find("-") != std::string::npos) { return true; } if(svnversion.find("S") != std::string::npos) { return true; } if(svnversion.find("P") != std::string::npos) { return true; } return false; #else return false; #endif } static bool IsPackage() { #if defined(OPENMPT_VERSION_IS_PACKAGE) return OPENMPT_VERSION_IS_PACKAGE != 0; #else return false; #endif } static mpt::ustring GetSourceDate() { #if defined(OPENMPT_VERSION_DATE) return mpt::ToUnicode(mpt::Charset::ASCII, OPENMPT_VERSION_DATE); #else return mpt::ustring(); #endif } } // namespace Source SourceInfo::SourceInfo() : m_Url(Source::GetUrl()) , m_Revision(Source::GetRevision()) , m_IsDirty(Source::IsDirty()) , m_HasMixedRevisions(Source::HasMixedRevisions()) , m_IsPackage(Source::IsPackage()) , m_Date(Source::GetSourceDate()) { } mpt::ustring SourceInfo::GetUrlWithRevision() const { if(m_Url.empty() || (m_Revision == 0)) { return mpt::ustring(); } return m_Url + UL_("@") + mpt::ufmt::val(m_Revision); } mpt::ustring SourceInfo::GetStateString() const { mpt::ustring retval; if(m_IsDirty) { retval += UL_("+dirty"); } if(m_HasMixedRevisions) { retval += UL_("+mixed"); } if(retval.empty()) { retval += UL_("clean"); } if(m_IsPackage) { retval += UL_("-pkg"); } return retval; } SourceInfo SourceInfo::Current() { return SourceInfo(); } VersionWithRevision VersionWithRevision::Current() { return {Version::Current(), static_cast(SourceInfo::Current().Revision())}; } VersionWithRevision VersionWithRevision::Parse(const mpt::ustring &s) { Version version = Version::Parse(mpt::ustring()); uint64 revision = 0; const auto tokens = mpt::split(s, U_("-")); if(tokens.size() >= 1) { version = Version::Parse(tokens[0]); } if(tokens.size() >= 2) { revision = mpt::parse(tokens[1].substr(1)); } return {version, revision}; } mpt::ustring VersionWithRevision::ToUString() const { if(!HasRevision()) { return mpt::ufmt::val(version); } if(!version.IsTestVersion()) { return mpt::ufmt::val(version); } return MPT_UFORMAT("{}-r{}")(version, revision); } namespace Build { bool IsReleasedBuild() { return !(Version::Current().IsTestVersion() || IsDebugBuild() || Source::IsDirty() || Source::HasMixedRevisions()); } bool IsDebugBuild() { #if defined(MPT_BUILD_DEBUG) || defined(DEBUG) || defined(_DEBUG) return true; #else return false; #endif } mpt::ustring GetBuildDateString() { mpt::ustring result; #ifdef MODPLUG_TRACKER #if defined(OPENMPT_BUILD_DATE) result = mpt::ToUnicode(mpt::Charset::ASCII, OPENMPT_BUILD_DATE ); #else result = mpt::ToUnicode(mpt::Charset::ASCII, __DATE__ " " __TIME__ ); #endif #else // !MODPLUG_TRACKER result = SourceInfo::Current().Date(); #endif // MODPLUG_TRACKER return result; } static mpt::ustring GetBuildFlagsString() { mpt::ustring retval; #ifdef MODPLUG_TRACKER #if defined(MPT_BUILD_RETRO) retval += UL_(" RETRO"); #endif // MPT_BUILD_RETRO if(Version::Current().IsTestVersion()) { retval += UL_(" TEST"); } #endif // MODPLUG_TRACKER if(IsDebugBuild()) { retval += UL_(" DEBUG"); } return retval; } mpt::ustring GetBuildFeaturesString() { mpt::ustring retval; #ifdef LIBOPENMPT_BUILD retval = UL_("") #if defined(MPT_WITH_ZLIB) UL_(" +ZLIB") #endif #if defined(MPT_WITH_MINIZ) UL_(" +MINIZ") #endif #if !defined(MPT_WITH_ZLIB) && !defined(MPT_WITH_MINIZ) UL_(" -INFLATE") #endif #if defined(MPT_WITH_MPG123) UL_(" +MPG123") #endif #if defined(MPT_WITH_MINIMP3) UL_(" +MINIMP3") #endif #if defined(MPT_WITH_MEDIAFOUNDATION) UL_(" +MF") #endif #if !defined(MPT_WITH_MPG123) && !defined(MPT_WITH_MINIMP3) && !defined(MPT_WITH_MEDIAFOUNDATION) UL_(" -MP3") #endif #if defined(MPT_WITH_OGG) && defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE) UL_(" +VORBIS") #endif #if defined(MPT_WITH_STBVORBIS) UL_(" +STBVORBIS") #endif #if !(defined(MPT_WITH_OGG) && defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)) && !defined(MPT_WITH_STBVORBIS) UL_(" -VORBIS") #endif #if !defined(NO_PLUGINS) UL_(" +PLUGINS") #else UL_(" -PLUGINS") #endif #if defined(MPT_WITH_DMO) UL_(" +DMO") #endif ; #endif #ifdef MODPLUG_TRACKER retval += UL_("") #if defined(UNICODE) UL_(" UNICODE") #else UL_(" ANSI") #endif #ifndef MPT_WITH_VST UL_(" NO_VST") #endif #ifndef MPT_WITH_DMO UL_(" NO_DMO") #endif #ifdef NO_PLUGINS UL_(" NO_PLUGINS") #endif ; #endif return retval; } mpt::ustring GetBuildCompilerString() { mpt::ustring retval; #if MPT_COMPILER_GENERIC retval += U_("Generic C++11 Compiler"); #elif MPT_COMPILER_MSVC #if defined(_MSC_FULL_VER) && defined(_MSC_BUILD) && (_MSC_BUILD > 0) retval += MPT_UFORMAT("Microsoft Compiler {}.{}.{}.{}") ( _MSC_FULL_VER / 10000000 , mpt::ufmt::dec0<2>((_MSC_FULL_VER / 100000) % 100) , mpt::ufmt::dec0<5>(_MSC_FULL_VER % 100000) , mpt::ufmt::dec0<2>(_MSC_BUILD) ); #elif defined(_MSC_FULL_VER) retval += MPT_UFORMAT("Microsoft Compiler {}.{}.{}") ( _MSC_FULL_VER / 10000000 , mpt::ufmt::dec0<2>((_MSC_FULL_VER / 100000) % 100) , mpt::ufmt::dec0<5>(_MSC_FULL_VER % 100000) ); #else retval += MPT_UFORMAT("Microsoft Compiler {}.{}")(MPT_COMPILER_MSVC_VERSION / 100, MPT_COMPILER_MSVC_VERSION % 100); #endif #elif MPT_COMPILER_GCC retval += MPT_UFORMAT("GNU Compiler Collection {}.{}.{}")(MPT_COMPILER_GCC_VERSION / 10000, (MPT_COMPILER_GCC_VERSION / 100) % 100, MPT_COMPILER_GCC_VERSION % 100); #elif MPT_COMPILER_CLANG retval += MPT_UFORMAT("Clang {}.{}.{}")(MPT_COMPILER_CLANG_VERSION / 10000, (MPT_COMPILER_CLANG_VERSION / 100) % 100, MPT_COMPILER_CLANG_VERSION % 100); #else retval += U_("unknown"); #endif return retval; } static mpt::ustring GetRevisionString() { mpt::ustring result; if(Source::GetRevision() == 0) { return result; } result = U_("-r") + mpt::ufmt::val(Source::GetRevision()); if(Source::HasMixedRevisions()) { result += UL_("!"); } if(Source::IsDirty()) { result += UL_("+"); } if(Source::IsPackage()) { result += UL_("p"); } return result; } mpt::ustring GetVersionString(FlagSet strings) { std::vector result; if(strings[StringVersion]) { result.push_back(mpt::ufmt::val(Version::Current())); } if(strings[StringRevision]) { if(!IsReleasedBuild()) { result.push_back(GetRevisionString()); } } if(strings[StringSourceInfo]) { const SourceInfo sourceInfo = SourceInfo::Current(); if(!sourceInfo.GetUrlWithRevision().empty()) { result.push_back(MPT_UFORMAT(" {}")(sourceInfo.GetUrlWithRevision())); } if(!sourceInfo.Date().empty()) { result.push_back(MPT_UFORMAT(" ({})")(sourceInfo.Date())); } if(!sourceInfo.GetStateString().empty()) { result.push_back(MPT_UFORMAT(" {}")(sourceInfo.GetStateString())); } } if(strings[StringBuildFlags]) { if(!IsReleasedBuild()) { result.push_back(GetBuildFlagsString()); } } if(strings[StringBuildFeatures]) { result.push_back(GetBuildFeaturesString()); } return mpt::trim(mpt::join_format(result, U_(""))); } mpt::ustring GetVersionStringPure() { FlagSet strings; strings |= Build::StringVersion; strings |= Build::StringRevision; return GetVersionString(strings); } mpt::ustring GetVersionStringSimple() { FlagSet strings; strings |= Build::StringVersion; strings |= Build::StringRevision; strings |= Build::StringBuildFlags; return GetVersionString(strings); } mpt::ustring GetVersionStringExtended() { FlagSet strings; strings |= Build::StringVersion; strings |= Build::StringRevision; #ifndef MODPLUG_TRACKER strings |= Build::StringSourceInfo; #endif strings |= Build::StringBuildFlags; #ifdef MODPLUG_TRACKER strings |= Build::StringBuildFeatures; #endif return GetVersionString(strings); } mpt::ustring GetURL(Build::Url key) { mpt::ustring result; switch(key) { case Url::Website: #ifdef LIBOPENMPT_BUILD result = U_("https://lib.openmpt.org/"); #else result = U_("https://openmpt.org/"); #endif break; case Url::Download: #ifdef MODPLUG_TRACKER result = IsReleasedBuild() ? U_("https://openmpt.org/download") : U_("https://builds.openmpt.org/builds/"); #else result = U_("https://lib.openmpt.org/libopenmpt/download/"); #endif break; case Url::Forum: result = U_("https://forum.openmpt.org/"); break; case Url::Bugtracker: result = U_("https://bugs.openmpt.org/"); break; case Url::Updates: result = U_("https://openmpt.org/download"); break; case Url::TopPicks: result = U_("https://openmpt.org/top_picks"); break; } return result; } mpt::ustring GetFullCreditsString() { return mpt::ToUnicode(mpt::Charset::UTF8, #ifdef MODPLUG_TRACKER "OpenMPT / Open ModPlug Tracker\n" #else "libopenmpt (based on OpenMPT / Open ModPlug Tracker)\n" #endif "\n" "Copyright \xC2\xA9 2004-2025 OpenMPT Project Developers and Contributors\n" "Copyright \xC2\xA9 1997-2003 Olivier Lapicque\n" "\n" "Developers:\n" "Johannes Schultz (2008-2025)\n" "J\xC3\xB6rn Heusipp (2012-2025)\n" "Ahti Lepp\xC3\xA4nen (2005-2011)\n" "Robin Fernandes (2004-2007)\n" "Sergiy Pylypenko (2007)\n" "Eric Chavanon (2004-2005)\n" "Trevor Nunes (2004)\n" "Olivier Lapicque (1997-2003)\n" "\n" "Additional contributors:\n" "coda (https://coda.s3m.us/)\n" "cs127 (https://cs127.github.io/)\n" "Jo\xC3\xA3o Baptista de Paula e Silva (https://joaobapt.com/)\n" "kode54 (https://kode54.net/)\n" "Revenant (https://revenant1.net/)\n" "SYRiNX\n" "xaimus (http://xaimus.com/)\n" "zersal\n" "\n" "Thanks to:\n" "\n" "Konstanty for the XMMS-ModPlug resampling implementation\n" "http://modplug-xmms.sourceforge.net/\n" "\n" #ifdef MODPLUG_TRACKER "Geraint Luff for Signalsmith Stretch\n" "https://signalsmith-audio.co.uk/code/stretch/\n" "\n" "Aleksey Vaneev of Voxengo for r8brain sample rate converter\n" "https://github.com/avaneev/r8brain-free-src\n" "\n" #endif #ifdef MPT_WITH_VST "Hermann Seib for his example VST Host implementation\n" "http://www.hermannseib.com/english/vsthost.htm\n" "\n" "Benjamin \"BeRo\" Rosseaux for his independent VST header\n" "https://blog.rosseaux.net/\n" "\n" #endif "Storlek for all the IT compatibility hints and testcases\n" "as well as the IMF, MDL, OKT and ULT loaders\n" "http://schismtracker.org/\n" "\n" "Sergei \"x0r\" Kolzun for various hints on Scream Tracker 2 compatibility\n" "https://github.com/viiri/st2play\n" "\n" "Laurent Cl\xc3\xA9vy for unofficial MO3 documentation and decompression code\n" "https://github.com/lclevy/unmo3\n" "\n" "Ben \"GreaseMonkey\" Russell for IT sample compression code\n" "https://github.com/iamgreaser/it2everything/\n" "\n" "Antti S. Lankila for Amiga resampler implementation\n" "https://web.archive.org/web/20221228071135/https://bel.fi/alankila/modguide/\n" "\n" "Shayde / Reality Productions for Opal OPL3 emulator\n" "https://www.3eality.com/\n" "\n" "Ryuhei Mori for TinyFFT\n" "https://github.com/ryuhei-mori/tinyfft\n" "\n" #ifdef MPT_WITH_ZLIB "Jean-loup Gailly and Mark Adler for zlib\n" "https://zlib.net/\n" "\n" #endif #ifdef MPT_WITH_MINIZ "Rich Geldreich et al. for miniz\n" "https://github.com/richgel999/miniz\n" "\n" #endif #ifdef MPT_WITH_LHASA "Simon Howard for lhasa\n" "https://fragglet.github.io/lhasa/\n" "\n" #endif #ifdef MPT_WITH_UNRAR "Alexander L. Roshal for UnRAR\n" "https://rarlab.com/\n" "\n" #endif #ifdef MPT_WITH_ANCIENT "Teemu Suutari for ancient\n" "https://github.com/temisu/ancient\n" "\n" #endif #ifdef MPT_WITH_PORTAUDIO "PortAudio contributors\n" "http://www.portaudio.com/\n" "\n" #endif #ifdef MPT_WITH_RTAUDIO "Gary P. Scavone, McGill University for RtAudio\n" "https://www.music.mcgill.ca/~gary/rtaudio/\n" "\n" #endif #ifdef MPT_WITH_FLAC "Josh Coalson / Xiph.Org Foundation for libFLAC\n" "https://xiph.org/flac/\n" "\n" #endif #if defined(MPT_WITH_MPG123) "The mpg123 project for libmpg123\n" "https://mpg123.de/\n" "\n" #endif #ifdef MPT_WITH_MINIMP3 "Lion (github.com/lieff) for minimp3\n" "https://github.com/lieff/minimp3/\n" "\n" #endif #ifdef MPT_WITH_STBVORBIS "Sean Barrett for stb_vorbis\n" "https://github.com/nothings/stb/\n" "\n" #endif #ifdef MPT_WITH_OGG "Xiph.Org Foundation for libogg\n" "https://xiph.org/ogg/\n" "\n" #endif #if defined(MPT_WITH_VORBIS) || defined(MPT_WITH_LIBVORBISFILE) "Xiph.Org Foundation for libvorbis\n" "https://xiph.org/vorbis/\n" "\n" #endif #if defined(MPT_WITH_OPUS) "Xiph.Org, Skype Limited, Octasic, Jean-Marc Valin, Timothy B. Terriberry,\n" "CSIRO, Gregory Maxwell, Mark Borgerding, Erik de Castro Lopo,\n" "Xiph.Org Foundation, Microsoft Corporation, Broadcom Corporation for libopus\n" "https://opus-codec.org/\n" "\n" #endif #if defined(MPT_WITH_OPUSFILE) "Xiph.Org Foundation and contributors for libopusfile\n" "https://opus-codec.org/\n" "\n" #endif #if defined(MPT_WITH_OPUSENC) "Xiph.Org Foundation, Jean-Marc Valin and contributors for libopusenc\n" "https://git.xiph.org/?p=libopusenc.git;a=summary\n" "\n" #endif #if defined(MPT_WITH_LAME) "The LAME project for LAME\n" "https://lame.sourceforge.io/\n" "\n" #endif #if defined(MPT_WITH_NLOHMANNJSON) "Niels Lohmann et al. for nlohmann-json\n" "https://github.com/nlohmann/json\n" "\n" #endif #ifdef MODPLUG_TRACKER "Lennart Poettering and David Henningsson for RealtimeKit\n" "http://git.0pointer.net/rtkit.git/\n" "\n" "Gary P. Scavone for RtMidi\n" "https://www.music.mcgill.ca/~gary/rtmidi/\n" "\n" "Alexander Uckun for decimal input field\n" "https://www.codeproject.com/Articles/21257/_\n" "\n" "\xc3\x9alfur Kolka for application icon, splash and about screen\n" "https://www.behance.net/ulfurkolka\n" "\n" "Nobuyuki for file icon\n" "https://github.com/nobuyukinyuu/\n" "\n" #endif "Daniel Collin (emoon/TBL) for providing test infrastructure\n" "https://mastodon.gamedev.place/@daniel_collin\n" "\n" "The people in the ModPlug community for crucial contribution\n" "in the form of ideas, testing and support;\n" "thanks particularly to:\n" "33, 8bitbubsy, AliceLR, Anboi, BooT-SectoR-ViruZ, Bvanoudtshoorn\n" "a11cf0, christofori, cubaxd, Diamond, Ganja, Georg, Goor00,\n" "Harbinger, jmkz, KrazyKatz, LPChip, MiDoRi, Nofold, Rakib, Sam Zen\n" "Skaven, Skilletaudio, Snu, Squirrel Havoc, Teimoso, Waxhead\n" "\n" #ifdef MPT_WITH_VST "VST PlugIn Technology by Steinberg Media Technologies GmbH\n" "\n" #endif #ifdef MPT_WITH_ASIO "ASIO Technology by Steinberg Media Technologies GmbH\n" "\n" #endif ); } mpt::ustring GetLicenseString() { return MPT_UTF8( "Copyright (c) 2004-2025, OpenMPT Project Developers and Contributors" "\n" "Copyright (c) 1997-2003, Olivier Lapicque" "\n" "All rights reserved." "\n" "" "\n" "Redistribution and use in source and binary forms, with or without" "\n" "modification, are permitted provided that the following conditions are met:" "\n" " * Redistributions of source code must retain the above copyright" "\n" " notice, this list of conditions and the following disclaimer." "\n" " * Redistributions in binary form must reproduce the above copyright" "\n" " notice, this list of conditions and the following disclaimer in the" "\n" " documentation and/or other materials provided with the distribution." "\n" " * Neither the name of the OpenMPT project nor the" "\n" " names of its contributors may be used to endorse or promote products" "\n" " derived from this software without specific prior written permission." "\n" "" "\n" "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" "\n" "AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" "\n" "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" "\n" "DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" "\n" "FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" "\n" "DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" "\n" "SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" "\n" "CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," "\n" "OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" "\n" "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." "\n" ); } } // namespace Build OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/versionNumber.h0000644000175000017500000000067415023271333020563 00000000000000/* * versionNumber.h * --------------- * Purpose: OpenMPT version number. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once // Version definitions. The only thing that needs to be changed when changing version number. #define VER_MAJORMAJOR 1 #define VER_MAJOR 32 #define VER_MINOR 01 #define VER_MINORMINOR 04 libopenmpt-0.8.1+release.autotools/common/mptBaseMacros.h0000644000175000017500000000354614052666041020473 00000000000000/* * mptBaseMacros.h * --------------- * Purpose: Basic assorted compiler-related helpers. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/preprocessor.hpp" #include "mpt/base/compiletime_warning.hpp" #include "mpt/base/macros.hpp" #if MPT_CXX_AT_LEAST(20) #include #else // !C++20 #include #endif // C++20 #include #include #include #include #include #include #include OPENMPT_NAMESPACE_BEGIN #define MPT_UNREFERENCED_PARAMETER(x) MPT_UNUSED(x) #define MPT_UNUSED_VARIABLE(x) MPT_UNUSED(x) #if MPT_COMPILER_MSVC // warning LNK4221: no public symbols found; archive member will be inaccessible // There is no way to selectively disable linker warnings. // #pragma warning does not apply and a command line option does not exist. // Some options: // 1. Macro which generates a variable with a unique name for each file (which means we have to pass the filename to the macro) // 2. unnamed namespace containing any symbol (does not work for c++11 compilers because they actually have internal linkage now) // 3. An unused trivial inline function. // Option 3 does not actually solve the problem though, which leaves us with option 1. // In any case, for optimized builds, the linker will just remove the useless symbol. #define MPT_MSVC_WORKAROUND_LNK4221_CONCAT_DETAIL(x,y) x##y #define MPT_MSVC_WORKAROUND_LNK4221_CONCAT(x,y) MPT_MSVC_WORKAROUND_LNK4221_CONCAT_DETAIL(x,y) #define MPT_MSVC_WORKAROUND_LNK4221(x) int MPT_MSVC_WORKAROUND_LNK4221_CONCAT(mpt_msvc_workaround_lnk4221_,x) = 0; #endif #ifndef MPT_MSVC_WORKAROUND_LNK4221 #define MPT_MSVC_WORKAROUND_LNK4221(x) #endif OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/serialization_utils.cpp0000644000175000017500000004706314375432552022373 00000000000000/* * serialization_utils.cpp * ----------------------- * Purpose: Serializing data to and from MPTM files. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "serialization_utils.h" #include "mpt/base/utility.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include #include #include #include #include "misc_util.h" OPENMPT_NAMESPACE_BEGIN namespace srlztn { static const uint8 HeaderId_FlagByte = 0; // Indexing starts from 0. static inline bool Testbit(uint8 val, uint8 bitindex) {return ((val & (1 << bitindex)) != 0);} static inline void Setbit(uint8& val, uint8 bitindex, bool newval) { if(newval) { val |= static_cast(1u << bitindex); } else { val &= static_cast(~(1u << bitindex)); } } #ifdef SSB_LOGGING bool ID::IsPrintable() const { for(std::size_t i = 0; i < m_ID.length(); ++i) { if(m_ID[i] <= 0 || isprint(static_cast(m_ID[i])) == 0) { return false; } } return true; } #endif //Format: First bit tells whether the size indicator is 1 or 2 bytes. static void WriteAdaptive12String(std::ostream& oStrm, const std::string& str) { uint16 s = static_cast(str.size()); LimitMax(s, uint16(std::numeric_limits::max() / 2)); mpt::IO::WriteAdaptiveInt16LE(oStrm, s); oStrm.write(str.c_str(), s); } void WriteItemString(std::ostream& oStrm, const std::string &str) { uint32 id = static_cast(std::min(str.size(), static_cast((std::numeric_limits::max() >> 4)))) << 4; id |= 12; // 12 == 1100b Binarywrite(oStrm, id); id >>= 4; if(id > 0) oStrm.write(str.data(), id); } void ReadItemString(std::istream& iStrm, std::string& str, const std::size_t) { // bits 0,1: Bytes per char type: 1,2,3,4. // bits 2,3: Bytes in size indicator, 1,2,3,4 uint32 id = 0; Binaryread(iStrm, id, 1); const uint8 nSizeBytes = (id & 12) >> 2; // 12 == 1100b if (nSizeBytes > 0) { uint8 bytes = std::min(uint8(3), nSizeBytes); uint8 v2 = 0; uint8 v3 = 0; uint8 v4 = 0; if(bytes >= 1) Binaryread(iStrm, v2); if(bytes >= 2) Binaryread(iStrm, v3); if(bytes >= 3) Binaryread(iStrm, v4); id &= 0xff; id |= (v2 << 8) | (v3 << 16) | (v4 << 24); } // Limit to 1 MB. str.resize(std::min(id >> 4, uint32(1000000))); for(size_t i = 0; i < str.size(); i++) iStrm.read(&str[i], 1); id = (id >> 4) - static_cast(str.size()); if(id > 0) iStrm.ignore(id); } #ifdef SSB_LOGGING mpt::ustring ID::AsString() const { if(IsPrintable()) { return mpt::ToUnicode(mpt::Charset::ISO8859_1, m_ID); } if(m_ID.length() > 8) { return mpt::ustring(); } uint64le val; val.set(0); std::memcpy(&val, m_ID.data(), m_ID.length()); return mpt::ufmt::val(val); } #endif const char Ssb::s_EntryID[3] = {'2','2','8'}; Ssb::Ssb() : m_Status(Status{}) , m_nFixedEntrySize(0) , m_posStart(0) , m_nIdbytes(IdSizeVariable) , m_nCounter(0) , m_Flags((1 << RwfWMapStartPosEntry) + (1 << RwfWMapSizeEntry) + (1 << RwfWVersionNum)) { return; } SsbWrite::SsbWrite(std::ostream& os) : oStrm(os) , m_posEntrycount(0) , m_posMapPosField(0) { return; } SsbRead::SsbRead(std::istream& is) : iStrm(is) , m_nReadVersion(0) , m_rposMapBegin(0) , m_posMapEnd(0) , m_posDataBegin(0) , m_rposEndofHdrData(0) , m_nReadEntrycount(0) , m_nNextReadHint(0) { return; } void SsbWrite::AddWriteNote(const Status s) { m_Status.level = static_cast(mpt::to_underlying(m_Status.level) | mpt::to_underlying(s.level)); m_Status.messages = static_cast(mpt::to_underlying(m_Status.messages) | mpt::to_underlying(s.messages)); SSB_LOG(MPT_UFORMAT("{}: 0x{} 0x{}")(U_("Write note: "), mpt::ufmt::hex(mpt::to_underlying(s.level)), mpt::ufmt::hex(mpt::to_underlying(s.messages)))); } void SsbRead::AddReadNote(const Status s) { m_Status.level = static_cast(mpt::to_underlying(m_Status.level) | mpt::to_underlying(s.level)); m_Status.messages = static_cast(mpt::to_underlying(m_Status.messages) | mpt::to_underlying(s.messages)); SSB_LOG(MPT_UFORMAT("{}: 0x{} 0x{}")(U_("Read note: "), mpt::ufmt::hex(mpt::to_underlying(s.level)), mpt::ufmt::hex(mpt::to_underlying(s.messages)))); } #ifdef SSB_LOGGING void SsbRead::LogReadEntry(const ReadEntry &pRe, const std::size_t nNum) { SSB_LOG(MPT_UFORMAT("Read entry: {{num, id, rpos, size, desc}} = {{{}, {}, {}, {}, {}}}")( nNum, (pRe.nIdLength < 30 && m_Idarray.size() > 0) ? ID(&m_Idarray[pRe.nIdpos], pRe.nIdLength).AsString() : U_(""), pRe.rposStart, (pRe.nSize != invalidDatasize) ? mpt::ufmt::val(pRe.nSize) : U_(""), U_(""))); } #endif #ifdef SSB_LOGGING // Called after writing an entry. void SsbWrite::LogWriteEntry(const ID &id, const std::size_t nEntryNum, const std::size_t nBytecount, const std::streamoff rposStart) { SSB_LOG(MPT_UFORMAT("Wrote entry: {{num, id, rpos, size}} = {{{}, {}, {}, {}}}")(nEntryNum, id.AsString(), rposStart, nBytecount)); } #endif void SsbRead::ResetReadstatus() { m_Status = Status{}; m_Idarray.reserve(32); m_Idarray.push_back(0); } void SsbWrite::WriteMapItem(const ID &id, const std::streamoff& rposDataStart, const std::size_t& nDatasize, const std::string &pszDesc) { SSB_LOG(MPT_UFORMAT("Writing map entry: id={}, rpos={}, size={}")( (id.GetSize() > 0) ? id.AsString() : U_(""), rposDataStart, nDatasize)); std::ostringstream mapStream; if(m_nIdbytes > 0) { if (m_nIdbytes != IdSizeVariable && id.GetSize() != m_nIdbytes) { AddWriteNote(SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING); return; } if (m_nIdbytes == IdSizeVariable) //Variablesize ID? mpt::IO::WriteAdaptiveInt16LE(mapStream, static_cast(id.GetSize())); if(id.GetSize() > 0) mapStream.write(id.AsSpan().data(), id.AsSpan().size()); } if(m_Flags[RwfWMapStartPosEntry]) // Startpos mpt::IO::WriteAdaptiveInt64LE(mapStream, rposDataStart); if(m_Flags[RwfWMapSizeEntry]) // Entrysize mpt::IO::WriteAdaptiveInt64LE(mapStream, nDatasize); if(m_Flags[RwfWMapDescEntry]) // Entry descriptions WriteAdaptive12String(mapStream, pszDesc); m_MapStreamString.append(mapStream.str()); } void SsbWrite::BeginWrite(const ID &id, const uint64& nVersion) { SSB_LOG(MPT_UFORMAT("Write header with ID = {}")(id.AsString())); ResetWritestatus(); if(!oStrm.good()) { AddWriteNote(SNRW_BADGIVEN_STREAM); return; } // Start bytes. oStrm.write(s_EntryID, sizeof(s_EntryID)); m_posStart = static_cast(oStrm.tellp()) - static_cast(sizeof(s_EntryID)); // Object ID. { uint8 idsize = static_cast(id.GetSize()); Binarywrite(oStrm, idsize); if(idsize > 0) oStrm.write(id.AsSpan().data(), id.AsSpan().size()); } // Form header. uint8 header = 0; m_Flags[RwfWMapStartPosEntry] = m_Flags[RwfWMapStartPosEntry] && m_nFixedEntrySize == 0; m_Flags[RwfWMapSizeEntry] = m_Flags[RwfWMapSizeEntry] && m_nFixedEntrySize == 0; header = (m_nIdbytes != 4) ? (m_nIdbytes & 3) : 3; //0,1 : Bytes per IDtype, 0,1,2,4 Setbit(header, 2, m_Flags[RwfWMapStartPosEntry]); //2 : Startpos in map? Setbit(header, 3, m_Flags[RwfWMapSizeEntry]); //3 : Datasize in map? Setbit(header, 4, m_Flags[RwfWVersionNum]); //4 : Version numeric field? Setbit(header, 7, m_Flags[RwfWMapDescEntry]); //7 : Entrydescriptions in map? // Write header Binarywrite(oStrm, header); // Additional options. uint8 tempU8 = 0; Setbit(tempU8, 0, (m_nIdbytes == IdSizeVariable) || (m_nIdbytes == 3) || (m_nIdbytes > 4)); Setbit(tempU8, 1, m_nFixedEntrySize != 0); const uint8 flags = tempU8; if(flags != s_DefaultFlagbyte) { mpt::IO::WriteAdaptiveInt32LE(oStrm, 2); //Headersize - now it is 2. Binarywrite(oStrm, HeaderId_FlagByte); Binarywrite(oStrm, flags); } else mpt::IO::WriteAdaptiveInt32LE(oStrm, 0); if(Testbit(header, 4)) // Version(numeric)? mpt::IO::WriteAdaptiveInt64LE(oStrm, nVersion); if(Testbit(flags, 0)) // Custom IDbytecount? { uint8 n = (m_nIdbytes == IdSizeVariable) ? 1 : static_cast((m_nIdbytes << 1)); Binarywrite(oStrm, n); } if(Testbit(flags, 1)) // Fixedsize entries? mpt::IO::WriteAdaptiveInt32LE(oStrm, m_nFixedEntrySize); //Entrycount. Reserve two bytes(max uint16_max / 4 entries), actual value is written after writing data. m_posEntrycount = static_cast(oStrm.tellp()); Binarywrite(oStrm, 0); m_Flags[RwfRwHasMap] = (m_nIdbytes != 0 || m_Flags[RwfWMapStartPosEntry] || m_Flags[RwfWMapSizeEntry] || m_Flags[RwfWMapDescEntry]); m_posMapPosField = static_cast(oStrm.tellp()); if(m_Flags[RwfRwHasMap]) // Mapping begin pos(reserve space - actual value is written after writing data) Binarywrite(oStrm, 0); } void SsbRead::OnReadEntry(const ReadEntry* pE, const ID &id, const std::streamoff& posReadBegin) { #ifdef SSB_LOGGING if(pE) { LogReadEntry(*pE, m_nCounter); } else if(!m_Flags[RwfRMapHasId]) // Not ID's in map. { ReadEntry e; e.rposStart = posReadBegin - m_posStart; e.nSize = mpt::saturate_cast(static_cast(static_cast(iStrm.tellg()) - posReadBegin)); LogReadEntry(e, m_nCounter); } else // Entry not found. { SSB_LOG(MPT_UFORMAT("No entry with id {} found.")(id.AsString())); } #else MPT_UNREFERENCED_PARAMETER(id); MPT_UNREFERENCED_PARAMETER(posReadBegin); #endif const bool entryFound = (pE || !m_Flags[RwfRMapHasId]); if(entryFound) { m_nCounter++; } } void SsbWrite::OnWroteItem(const ID &id, const std::streamoff& posBeforeWrite) { const std::streamoff nRawEntrySize = static_cast(oStrm.tellp()) - posBeforeWrite; MPT_MAYBE_CONSTANT_IF(!mpt::in_range(nRawEntrySize)) { AddWriteNote(SNW_INSUFFICIENT_DATASIZETYPE); return; } if(m_Flags[RwfRMapHasSize] && (static_cast(nRawEntrySize) > (std::numeric_limits::max() >> 2))) { AddWriteNote(SNW_DATASIZETYPE_OVERFLOW); return; } std::size_t nEntrySize = static_cast(nRawEntrySize); // Handle fixed size entries: if (m_nFixedEntrySize > 0) { if(nEntrySize <= m_nFixedEntrySize) { for(uint32 i = 0; i= static_cast(std::numeric_limits::max() >> 2)) { FinishWrite(); AddWriteNote(SNW_MAX_WRITE_COUNT_REACHED); } } void SsbRead::BeginRead(const ID &id, const uint64& nVersion) { SSB_LOG(MPT_UFORMAT("Read header with expected ID = {}")(id.AsString())); ResetReadstatus(); if (!iStrm.good()) { AddReadNote(SNRW_BADGIVEN_STREAM); return; } m_posStart = static_cast(iStrm.tellg()); // Start bytes. { char temp[sizeof(s_EntryID)]; ArrayReader(sizeof(s_EntryID))(iStrm, temp, sizeof(s_EntryID)); if(std::memcmp(temp, s_EntryID, sizeof(s_EntryID))) { AddReadNote(SNR_STARTBYTE_MISMATCH); return; } } // Compare IDs. uint8 storedIdLen = 0; Binaryread(iStrm, storedIdLen); std::array storedIdBuf; storedIdBuf = {}; if(storedIdLen > 0) { iStrm.read(storedIdBuf.data(), storedIdLen); } if(!(id == ID(storedIdBuf.data(), storedIdLen))) { AddReadNote(SNR_OBJECTCLASS_IDMISMATCH); } if(HasFailed()) { SSB_LOG(U_("ID mismatch, terminating read.")); return; } SSB_LOG(U_("ID match, continuing reading.")); // Header uint8 tempU8; Binaryread(iStrm, tempU8); const uint8 header = tempU8; m_nIdbytes = ((header & 3) == 3) ? 4 : (header & 3); if (Testbit(header, 6)) m_Flags[RwfRTwoBytesDescChar] = true; // Read headerdata size uint32 tempU32 = 0; mpt::IO::ReadAdaptiveInt32LE(iStrm, tempU32); const uint32 headerdatasize = tempU32; // If headerdatasize != 0, read known headerdata and ignore rest. uint8 flagbyte = s_DefaultFlagbyte; if(headerdatasize >= 2) { Binaryread(iStrm, tempU8); if(tempU8 == HeaderId_FlagByte) Binaryread(iStrm, flagbyte); iStrm.ignore( (tempU8 == HeaderId_FlagByte) ? headerdatasize - 2 : headerdatasize - 1); } uint64 tempU64 = 0; // Read version numeric if available. if (Testbit(header, 4)) { mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64); m_nReadVersion = tempU64; if(tempU64 > nVersion) AddReadNote(SNR_LOADING_OBJECT_WITH_LARGER_VERSION); } if (Testbit(header, 5)) { Binaryread(iStrm, tempU8); iStrm.ignore(tempU8); } if(Testbit(flagbyte, 0)) // Custom ID? { Binaryread(iStrm, tempU8); if ((tempU8 & 1) != 0) m_nIdbytes = IdSizeVariable; else m_nIdbytes = (tempU8 >> 1); if(m_nIdbytes == 0) AddReadNote(SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED); } m_nFixedEntrySize = 0; if(Testbit(flagbyte, 1)) // Fixedsize entries? mpt::IO::ReadAdaptiveInt32LE(iStrm, m_nFixedEntrySize); m_Flags[RwfRMapHasStartpos] = Testbit(header, 2); m_Flags[RwfRMapHasSize] = Testbit(header, 3); m_Flags[RwfRMapHasId] = (m_nIdbytes > 0); m_Flags[RwfRMapHasDesc] = Testbit(header, 7); m_Flags[RwfRwHasMap] = m_Flags[RwfRMapHasId] || m_Flags[RwfRMapHasStartpos] || m_Flags[RwfRMapHasSize] || m_Flags[RwfRMapHasDesc]; if(!m_Flags[RwfRwHasMap]) { SSB_LOG(U_("No map in the file.")); } if (Testbit(flagbyte, 2)) // Object description? { uint16 size = 0; mpt::IO::ReadAdaptiveInt16LE(iStrm, size); iStrm.ignore(size * (m_Flags[RwfRTwoBytesDescChar] ? 2 : 1)); } if(Testbit(flagbyte, 3)) iStrm.ignore(5); // Read entrycount mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64); if(tempU64 > 16000) // The current code can only write 16383 entries because it uses a Adaptive64LE with a fixed size=2 // Additionally, 16000 is an arbitrary limit to avoid an out-of-memory DoS when caching the map. { AddReadNote(SNR_TOO_MANY_ENTRIES_TO_READ); return; } m_nReadEntrycount = static_cast(tempU64); if(m_nReadEntrycount == 0) AddReadNote(SNR_ZEROENTRYCOUNT); // Read map rpos if map exists. if(m_Flags[RwfRwHasMap]) { mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64); if(!mpt::in_range(tempU64)) { AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; } } const std::streamoff rawEndOfHdrData = static_cast(iStrm.tellg()) - m_posStart; if(rawEndOfHdrData < 0) { AddReadNote(SNR_INSUFFICIENT_RPOSTYPE); return; } m_rposEndofHdrData = rawEndOfHdrData; m_rposMapBegin = (m_Flags[RwfRwHasMap]) ? static_cast(tempU64) : m_rposEndofHdrData; if(!m_Flags[RwfRwHasMap]) m_posMapEnd = m_posStart + m_rposEndofHdrData; m_Flags[RwfRHeaderIsRead] = true; } void SsbRead::CacheMap() { if(m_Flags[RwfRwHasMap] || m_nFixedEntrySize > 0) { iStrm.seekg(m_posStart + m_rposMapBegin, std::ios::beg); if(iStrm.fail()) { AddReadNote(SNR_BADSTREAM_AFTER_MAPHEADERSEEK); return; } SSB_LOG(MPT_UFORMAT("Reading map from rpos: {}")(m_rposMapBegin)); mapData.resize(m_nReadEntrycount); m_Idarray.reserve(m_nReadEntrycount * 4); //Read map for(std::size_t i = 0; i 0 && (Util::MaxValueOfType(nOldEnd) - nOldEnd >= nIdsize)) { m_Idarray.resize(nOldEnd + nIdsize); iStrm.read(&m_Idarray[nOldEnd], nIdsize); } mapData[i].nIdLength = nIdsize; mapData[i].nIdpos = nOldEnd; // Read position. if(m_Flags[RwfRMapHasStartpos]) { uint64 tempU64; mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64); if(!mpt::in_range(tempU64)) { AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; } mapData[i].rposStart = static_cast(tempU64); } // Read entry size. if (m_nFixedEntrySize > 0) mapData[i].nSize = m_nFixedEntrySize; else if(m_Flags[RwfRMapHasSize]) // Map has datasize field. { uint64 tempU64; mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64); if(!mpt::in_range(tempU64)) { AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; } mapData[i].nSize = static_cast(tempU64); } // If there's no entry startpos in map, count start pos from datasizes. // Here readentry.rposStart is set to relative position from databegin. if(mapData[i].nSize != invalidDatasize && !m_Flags[RwfRMapHasStartpos]) mapData[i].rposStart = (i > 0) ? mapData[i-1].rposStart + mapData[i-1].nSize : 0; if(m_Flags[RwfRMapHasDesc]) // Map has entrydescriptions? { uint16 size = 0; mpt::IO::ReadAdaptiveInt16LE(iStrm, size); if(m_Flags[RwfRTwoBytesDescChar]) iStrm.ignore(size * 2); else iStrm.ignore(size); } } m_posMapEnd = static_cast(iStrm.tellg()); SSB_LOG(MPT_UFORMAT("End of map(rpos): {}")(m_posMapEnd - m_posStart)); } m_Flags[RwfRMapCached] = true; m_posDataBegin = (m_rposMapBegin == m_rposEndofHdrData) ? m_posMapEnd : m_posStart + m_rposEndofHdrData; iStrm.seekg(m_posDataBegin, std::ios::beg); // If there are no positions in the map but there are entry sizes, rposStart will // be relative to data start. Now that posDataBegin is known, make them relative to // startpos. if(!m_Flags[RwfRMapHasStartpos] && (m_Flags[RwfRMapHasSize] || m_nFixedEntrySize > 0)) { const std::streamoff offset = m_posDataBegin - m_posStart; for(size_t i = 0; i < m_nReadEntrycount; i++) mapData[i].rposStart += offset; } } const ReadEntry* SsbRead::Find(const ID &id) { iStrm.clear(); if(!m_Flags[RwfRMapCached]) CacheMap(); if(m_nFixedEntrySize > 0 && !m_Flags[RwfRMapHasStartpos] && !m_Flags[RwfRMapHasSize]) iStrm.seekg(m_posDataBegin + static_cast(m_nFixedEntrySize * m_nCounter), std::ios::beg); if(m_Flags[RwfRMapHasId]) { const size_t nEntries = mapData.size(); for(size_t i0 = 0; i0 < nEntries; i0++) { const size_t i = (i0 + m_nNextReadHint) % nEntries; if(mapData[i].nIdpos < m_Idarray.size() && id == ID(&m_Idarray[mapData[i].nIdpos], mapData[i].nIdLength)) { m_nNextReadHint = (i + 1) % nEntries; if (mapData[i].rposStart != 0) iStrm.seekg(m_posStart + mapData[i].rposStart, std::ios::beg); return &mapData[i]; } } } return nullptr; } void SsbWrite::FinishWrite() { const std::streamoff posDataEnd = static_cast(oStrm.tellp()); std::streamoff posMapStart = static_cast(oStrm.tellp()); SSB_LOG(MPT_UFORMAT("Writing map to rpos: {}")(posMapStart - m_posStart)); if(m_Flags[RwfRwHasMap]) // Write map { oStrm.write(m_MapStreamString.c_str(), m_MapStreamString.length()); } const std::streamoff posMapEnd = static_cast(oStrm.tellp()); // Write entry count. oStrm.seekp(m_posEntrycount, std::ios::beg); // Write a fixed size=2 Adaptive64LE because space for this value has already been reserved berforehand. mpt::IO::WriteAdaptiveInt64LE(oStrm, m_nCounter, 2); if(m_Flags[RwfRwHasMap]) { // Write map start position. oStrm.seekp(m_posMapPosField, std::ios::beg); const uint64 rposMap = posMapStart - m_posStart; // Write a fixed size=8 Adaptive64LE because space for this value has already been reserved berforehand. mpt::IO::WriteAdaptiveInt64LE(oStrm, rposMap, 8); } // Seek to end. oStrm.seekp(std::max(posMapEnd, posDataEnd), std::ios::beg); SSB_LOG(MPT_UFORMAT("End of stream(rpos): {}")(static_cast(oStrm.tellp()) - m_posStart)); } } // namespace srlztn OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/ComponentManager.h0000644000175000017500000002631614631306026021165 00000000000000/* * ComponentManager.h * ------------------ * Purpose: Manages loading of optional components. * Notes : (currently none) * Authors: Joern Heusipp * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/mutex/mutex.hpp" #include #include #include "../common/misc_util.h" #if defined(MODPLUG_TRACKER) #include "../misc/mptLibrary.h" #endif OPENMPT_NAMESPACE_BEGIN enum ComponentType { ComponentTypeUnknown = 0, ComponentTypeBuiltin, // PortAudio ComponentTypeSystem, // mf.dll ComponentTypeSystemInstallable, // acm mp3 codec ComponentTypeBundled, // libsoundtouch ComponentTypeForeign, // libmp3lame }; class ComponentFactoryBase; class IComponent { friend class ComponentFactoryBase; protected: IComponent() = default; public: virtual ~IComponent() = default; public: virtual ComponentType GetType() const = 0; virtual bool IsInitialized() const = 0; // Initialize() has been called virtual bool IsAvailable() const = 0; // Initialize() has been successfull virtual mpt::ustring GetVersion() const = 0; virtual void Initialize() = 0; // try to load the component }; class ComponentBase : public IComponent { private: ComponentType m_Type; bool m_Initialized; bool m_Available; protected: ComponentBase(ComponentType type); public: ~ComponentBase() override; protected: void SetInitialized(); void SetAvailable(); public: ComponentType GetType() const override; bool IsInitialized() const override; bool IsAvailable() const override; mpt::ustring GetVersion() const override; public: void Initialize() override; protected: virtual bool DoInitialize() = 0; }; class ComponentBuiltin : public ComponentBase { public: ComponentBuiltin() : ComponentBase(ComponentTypeBuiltin) { return; } bool DoInitialize() override { return true; } }; #define MPT_GLOBAL_BIND(lib, name) name = &::name; #if defined(MODPLUG_TRACKER) class ComponentLibrary : public ComponentBase { private: using TLibraryMap = std::map; TLibraryMap m_Libraries; bool m_BindFailed; protected: ComponentLibrary(ComponentType type); public: virtual ~ComponentLibrary(); protected: bool AddLibrary(const std::string &libName, const mpt::LibraryPath &libPath); void ClearLibraries(); void SetBindFailed(); void ClearBindFailed(); bool HasBindFailed() const; public: virtual mpt::Library GetLibrary(const std::string &libName) const; template bool Bind(Tfunc * & f, const std::string &libName, const std::string &symbol) const { return GetLibrary(libName).Bind(f, symbol); } protected: bool DoInitialize() override = 0; }; #define MPT_COMPONENT_BIND(libName, func) do { if(!Bind( func , libName , #func )) { SetBindFailed(); } } while(0) #define MPT_COMPONENT_BIND_OPTIONAL(libName, func) Bind( func , libName , #func ) #define MPT_COMPONENT_BIND_SYMBOL(libName, symbol, func) do { if(!Bind( func , libName , symbol )) { SetBindFailed(); } } while(0) #define MPT_COMPONENT_BIND_SYMBOL_OPTIONAL(libName, symbol, func) Bind( func , libName , symbol ) #if MPT_OS_WINDOWS #ifdef UNICODE #define MPT_COMPONENT_BINDWIN_SUFFIX "W" #else #define MPT_COMPONENT_BINDWIN_SUFFIX "A" #endif #define MPT_COMPONENT_BINDWIN(libName, func) do { if(!Bind( func , libName , #func MPT_COMPONENT_BINDWIN_SUFFIX )) { SetBindFailed(); } } while(0) #define MPT_COMPONENT_BINDWIN_OPTIONAL(libName, func) Bind( func , libName , #func MPT_COMPONENT_BINDWIN_SUFFIX ) #define MPT_COMPONENT_BINDWIN_SYMBOL(libName, symbol, func) do { if(!Bind( func , libName , symbol MPT_COMPONENT_BINDWIN_SUFFIX )) { SetBindFailed(); } } while(0) #define MPT_COMPONENT_BINDWIN_SYMBOL_OPTIONAL(libName, symbol, func) Bind( func , libName , symbol MPT_COMPONENT_BINDWIN_SUFFIX ) #endif class ComponentSystemDLL : public ComponentLibrary { private: mpt::PathString m_BaseName; public: ComponentSystemDLL(const mpt::PathString &baseName) : ComponentLibrary(ComponentTypeSystem) , m_BaseName(baseName) { return; } bool DoInitialize() override { AddLibrary(m_BaseName.ToUTF8(), mpt::LibraryPath::System(m_BaseName)); return GetLibrary(m_BaseName.ToUTF8()).IsValid(); } }; class ComponentBundledDLL : public ComponentLibrary { private: mpt::PathString m_FullName; public: ComponentBundledDLL(const mpt::PathString &fullName) : ComponentLibrary(ComponentTypeBundled) , m_FullName(fullName) { return; } bool DoInitialize() override { AddLibrary(m_FullName.ToUTF8(), mpt::LibraryPath::AppFullName(m_FullName)); return GetLibrary(m_FullName.ToUTF8()).IsValid(); } }; #endif // MODPLUG_TRACKER #if MPT_COMPONENT_MANAGER class ComponentManager; using ComponentFactoryMethod = std::shared_ptr (*)(ComponentManager &componentManager); class IComponentFactory { protected: IComponentFactory() = default; public: virtual ~IComponentFactory() = default; public: virtual std::string GetID() const = 0; virtual std::string GetSettingsKey() const = 0; virtual std::shared_ptr Construct(ComponentManager &componentManager) const = 0; virtual ComponentFactoryMethod GetStaticConstructor() const = 0; }; class ComponentFactoryBase : public IComponentFactory { private: std::string m_ID; std::string m_SettingsKey; protected: ComponentFactoryBase(const std::string &id, const std::string &settingsKey); void PreConstruct() const; void Initialize(ComponentManager &componentManager, std::shared_ptr component) const; public: virtual ~ComponentFactoryBase(); std::string GetID() const override; std::string GetSettingsKey() const override; std::shared_ptr Construct(ComponentManager &componentManager) const override = 0; ComponentFactoryMethod GetStaticConstructor() const override = 0; }; template class ComponentFactory : public ComponentFactoryBase { public: ComponentFactory() : ComponentFactoryBase(T::g_ID, T::g_SettingsKey) { return; } public: std::shared_ptr Construct(ComponentManager &componentManager) const override { PreConstruct(); std::shared_ptr component = std::make_shared(); Initialize(componentManager, component); return component; } static std::shared_ptr StaticConstruct(ComponentManager &componentManager) { return ComponentFactory().Construct(componentManager); } virtual ComponentFactoryMethod GetStaticConstructor() const override { return &StaticConstruct; } }; class IComponentManagerSettings { public: virtual bool LoadOnStartup() const = 0; virtual bool KeepLoaded() const = 0; virtual bool IsBlocked(const std::string &key) const = 0; protected: virtual ~IComponentManagerSettings() = default; }; class ComponentManagerSettingsDefault : public IComponentManagerSettings { public: bool LoadOnStartup() const override { return false; } bool KeepLoaded() const override { return true; } bool IsBlocked(const std::string & /*key*/ ) const override { return false; } }; enum ComponentState { ComponentStateUnregistered, ComponentStateBlocked, ComponentStateUnintialized, ComponentStateUnavailable, ComponentStateAvailable, }; struct ComponentInfo { std::string name; ComponentState state; std::string settingsKey; ComponentType type; }; class ComponentManager { friend class ComponentFactoryBase; public: static void Init(const IComponentManagerSettings &settings); static void Release(); static std::shared_ptr Instance(); private: ComponentManager(const IComponentManagerSettings &settings); private: struct RegisteredComponent { std::string settingsKey; ComponentFactoryMethod factoryMethod; std::shared_ptr instance; std::weak_ptr weakInstance; }; using TComponentMap = std::map; const IComponentManagerSettings &m_Settings; TComponentMap m_Components; private: bool IsComponentBlocked(const std::string &settingsKey) const; void InitializeComponent(std::shared_ptr component) const; public: void Register(const IComponentFactory &componentFactory); void Startup(); std::shared_ptr GetComponent(const IComponentFactory &componentFactory); std::shared_ptr ReloadComponent(const IComponentFactory &componentFactory); std::vector GetRegisteredComponents() const; ComponentInfo GetComponentInfo(std::string name) const; }; struct ComponentListEntry { ComponentListEntry *next; void (*reg)(ComponentManager &componentManager); }; bool ComponentListPush(ComponentListEntry *entry); template struct ComponentRegisterer { static inline void RegisterComponent(ComponentManager &componentManager) { componentManager.Register(ComponentFactory()); } static inline ComponentListEntry &GetComponentListEntry() { static ComponentListEntry s_ComponentListEntry = {nullptr, &RegisterComponent}; return s_ComponentListEntry; } static inline bool g_ComponentRegistered = ComponentListPush(&GetComponentListEntry()); }; #define MPT_DECLARE_COMPONENT_MEMBERS(name, settingsKey) \ public: \ static constexpr const char *g_ID = #name ; \ static constexpr const char *g_SettingsKey = settingsKey ; \ static inline ComponentRegisterer< name > s_ComponentRegisterer; \ /**/ template std::shared_ptr GetComponent() { return std::dynamic_pointer_cast(ComponentManager::Instance()->GetComponent(ComponentFactory())); } template std::shared_ptr ReloadComponent() { return std::dynamic_pointer_cast(ComponentManager::Instance()->ReloadComponent(ComponentFactory())); } #else // !MPT_COMPONENT_MANAGER #define MPT_DECLARE_COMPONENT_MEMBERS(name, settingsKey) template std::shared_ptr GetComponent() { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wexit-time-destructors" #endif // MPT_COMPILER_CLANG static std::weak_ptr cache; static mpt::mutex m; #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG mpt::lock_guard l(m); mpt::lock_guard l(m); std::shared_ptr component = cache.lock(); if(!component) { component = std::make_shared(); component->Initialize(); cache = component; } return component; } #endif // MPT_COMPONENT_MANAGER // Simple wrapper around std::shared_ptr which automatically // gets a reference to the component (or constructs it) on initialization. template class ComponentHandle { private: std::shared_ptr component; public: ComponentHandle() : component(GetComponent()) { return; } ~ComponentHandle() { return; } bool IsAvailable() const { return component && component->IsAvailable(); } const T *get() const { return component.get(); } const T &operator*() const { return *component; } const T *operator->() const { return &*component; } #if MPT_COMPONENT_MANAGER void Reload() { component = nullptr; component = ReloadComponent(); } #endif }; template bool IsComponentAvailable(const ComponentHandle &handle) { return handle.IsAvailable(); } OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/Profiler.cpp0000644000175000017500000000707414053176735020057 00000000000000/* * Profiler.cpp * ------------ * Purpose: Performance measuring * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "Profiler.h" OPENMPT_NAMESPACE_BEGIN #ifdef USE_PROFILER class Statistics { public: Profile &profile; Profile::Data data; double usage; Statistics(Profile &p) : profile(p) { usage = 0.0; Update(); } void Update() { data = profile.GetAndResetData(); uint64 now = profile.GetTime(); uint64 timewindow = now - data.Start; if(data.Calls > 0 && timewindow > 0) { usage = (double)data.Sum / (double)timewindow; } else { usage = 0.0; } } }; struct ProfileBlock { class Profile * profile; const char * name; class Statistics * stats; }; static constexpr std::size_t MAX_PROFILES = 1024; static ProfileBlock Profiles[ MAX_PROFILES ]; static std::size_t NextProfile = 0; static void RegisterProfile(Profile *newprofile) { if(NextProfile < MAX_PROFILES) { Profiles[NextProfile].profile = newprofile; Profiles[NextProfile].stats = 0; NextProfile++; } } static void UnregisterProfile(Profile *oldprofile) { for(std::size_t i=0; iUpdate(); } } } std::string Profiler::DumpProfiles() { std::string ret; for(std::size_t i=0; i Profiler::DumpCategories() { std::vector ret; ret.resize(Profiler::CategoriesCount); for(std::size_t i=0; iCategory] += Profiles[i].stats->usage; } } return ret; } uint64 Profile::GetTime() const { LARGE_INTEGER ret; ret.QuadPart = 0; QueryPerformanceCounter(&ret); return ret.QuadPart; } uint64 Profile::GetFrequency() const { LARGE_INTEGER ret; ret.QuadPart = 0; QueryPerformanceFrequency(&ret); return ret.QuadPart; } Profile::Profile(Profiler::Category category, const char *name) : Category(category), Name(name) { data.Calls = 0; data.Sum = 0; data.Overhead = 0; data.Start = GetTime(); EnterTime = 0; RegisterProfile(this); } Profile::~Profile() { UnregisterProfile(this); } Profile::Data Profile::GetAndResetData() { Profile::Data ret; datamutex.lock(); ret = data; data.Calls = 0; data.Sum = 0; data.Overhead = 0; data.Start = GetTime(); datamutex.unlock(); return ret; } void Profile::Reset() { datamutex.lock(); data.Calls = 0; data.Sum = 0; data.Overhead = 0; data.Start = GetTime(); datamutex.unlock(); } void Profile::Enter() { EnterTime = GetTime(); } void Profile::Leave() { uint64 LeaveTime = GetTime(); datamutex.lock(); data.Calls += 1; data.Sum += LeaveTime - EnterTime; datamutex.unlock(); } #else // !USE_PROFILER MPT_MSVC_WORKAROUND_LNK4221(Profiler) #endif // USE_PROFILER OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/version.h0000644000175000017500000002361114460001065017403 00000000000000/* * version.h * --------- * Purpose: OpenMPT version handling. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mptString.h" #include "openmpt/base/FlagSet.hpp" #include OPENMPT_NAMESPACE_BEGIN class Version { private: uint32 m_Version; // e.g. 0x01170208 public: enum class Field { Major, Minor, Patch, Test, }; public: static Version Current() noexcept; public: MPT_CONSTEXPRINLINE Version() noexcept : m_Version(0) {} explicit MPT_CONSTEXPRINLINE Version(uint32 version) noexcept : m_Version(version) {} explicit MPT_CONSTEXPRINLINE Version(uint8 v1, uint8 v2, uint8 v3, uint8 v4) noexcept : m_Version((static_cast(v1) << 24) | (static_cast(v2) << 16) | (static_cast(v3) << 8) | (static_cast(v4) << 0)) {} public: mpt::ustring ToUString() const; // e.g "1.17.02.08" // Returns numerical version value from given version string. static Version Parse(const mpt::ustring &s); public: explicit MPT_CONSTEXPRINLINE operator bool () const noexcept { return m_Version != 0; } MPT_CONSTEXPRINLINE bool operator ! () const noexcept { return m_Version == 0; } MPT_CONSTEXPRINLINE uint32 GetRawVersion() const noexcept { return m_Version; } MPT_CONSTEXPRINLINE Version Masked(uint32 mask) const noexcept { return Version(m_Version & mask); } MPT_CONSTEXPRINLINE uint8 GetField(Field field) const noexcept { return (field == Field::Major) ? static_cast((m_Version >> 24) & 0xffu) : (field == Field::Minor) ? static_cast((m_Version >> 16) & 0xffu) : (field == Field::Patch) ? static_cast((m_Version >> 8) & 0xffu) : (field == Field::Test ) ? static_cast((m_Version >> 0) & 0xffu) : 0u; } // Return a version without build number (the last number in the version). // The current versioning scheme uses this number only for test builds, and it should be 00 for official builds, // So sometimes it might be wanted to do comparisons without the build number. Version WithoutTestNumber() const noexcept; Version WithoutPatchOrTestNumbers() const noexcept; public: // Return a OpenMPT version string suitable for file format tags mpt::ustring GetOpenMPTVersionString() const; // e.g. "OpenMPT 1.17.02.08" // Returns true if a given version number is from a test build, false if it's a release build. bool IsTestVersion() const noexcept; public: struct LiteralParser { public: // Work-around for GCC 5 which complains about instanciating non-literal type inside a constexpr function when using mpt::constexpr_throw(std::runtime_error("")). struct ParseException {}; private: static MPT_CONSTEXPRINLINE uint8 NibbleFromChar(char x) { return ('0' <= x && x <= '9') ? static_cast(x - '0' + 0) : ('a' <= x && x <= 'z') ? static_cast(x - 'a' + 10) : ('A' <= x && x <= 'Z') ? static_cast(x - 'A' + 10) : mpt::constexpr_throw(std::domain_error("")); } public: static MPT_CONSTEXPRINLINE Version Parse(const char * str, std::size_t len) { // 0123456789 // 1.23.45.67 uint8 v[4] = {0, 0, 0, 0}; std::size_t field = 0; std::size_t fieldlen = 0; for(std::size_t i = 0; i < len; ++i) { char c = str[i]; if(c == '.') { if(field >= 3) { mpt::constexpr_throw(ParseException()); } if(fieldlen == 0) { mpt::constexpr_throw(ParseException()); } field++; fieldlen = 0; } else if(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) { fieldlen++; if(fieldlen > 2) { mpt::constexpr_throw(ParseException()); } v[field] <<= 4; v[field] |= NibbleFromChar(c); } else { mpt::constexpr_throw(ParseException()); } } if(fieldlen == 0) { mpt::constexpr_throw(ParseException()); } return Version(v[0], v[1], v[2], v[3]); } }; }; MPT_CONSTEXPRINLINE bool operator == (const Version &a, const Version &b) noexcept { return a.GetRawVersion() == b.GetRawVersion(); } MPT_CONSTEXPRINLINE bool operator != (const Version &a, const Version &b) noexcept { return a.GetRawVersion() != b.GetRawVersion(); } MPT_CONSTEXPRINLINE bool operator <= (const Version &a, const Version &b) noexcept { return a.GetRawVersion() <= b.GetRawVersion(); } MPT_CONSTEXPRINLINE bool operator >= (const Version &a, const Version &b) noexcept { return a.GetRawVersion() >= b.GetRawVersion(); } MPT_CONSTEXPRINLINE bool operator < (const Version &a, const Version &b) noexcept { return a.GetRawVersion() < b.GetRawVersion(); } MPT_CONSTEXPRINLINE bool operator > (const Version &a, const Version &b) noexcept { return a.GetRawVersion() > b.GetRawVersion(); } MPT_CONSTEVAL Version operator ""_LiteralVersionImpl (const char * str, std::size_t len) { return Version::LiteralParser::Parse(str, len); } // Create Version object from version string and check syntax, all at compile time. // cppcheck false-positive // cppcheck-suppress preprocessorErrorDirective #define MPT_V(strver) MPT_FORCE_CONSTEVAL_VALUE(Version{( strver ## _LiteralVersionImpl ).GetRawVersion()}) class SourceInfo { private: mpt::ustring m_Url; // svn repository url (or empty string) int m_Revision; // svn revision (or 0) bool m_IsDirty; // svn working copy is dirty (or false) bool m_HasMixedRevisions; // svn working copy has mixed revisions (or false) bool m_IsPackage; // source code originates from a packaged version of the source code mpt::ustring m_Date; // svn date (or empty string) private: SourceInfo(); public: static SourceInfo Current(); public: const mpt::ustring & Url() const { return m_Url; } int Revision() const { return m_Revision; } bool IsDirty() const { return m_IsDirty; } bool HasMixedRevisions() const { return m_HasMixedRevisions; } bool IsPackage() const { return m_IsPackage; } const mpt::ustring & Date() const { return m_Date; } public: mpt::ustring GetUrlWithRevision() const; // i.e. "https://source.openmpt.org/svn/openmpt/trunk/OpenMPT@1234" or empty string mpt::ustring GetStateString() const; // i.e. "+dirty" or "clean" }; struct VersionWithRevision { Version version; uint64 revision; static VersionWithRevision Current(); static VersionWithRevision Parse(const mpt::ustring &s); mpt::ustring ToUString() const; constexpr bool HasRevision() const noexcept { return revision != 0; } constexpr bool IsEqualTo(VersionWithRevision other) const noexcept { return version == other.version && revision == other.revision; } constexpr bool IsEquivalentTo(VersionWithRevision other) const noexcept { if(version == other.version && revision == other.revision) { return true; } if(HasRevision() && other.HasRevision()) { return false; } return version == other.version; } constexpr bool IsNewerThan(VersionWithRevision other) const noexcept { if(version < other.version) { return false; } if(version > other.version) { return true; } if(!HasRevision() && !other.HasRevision()) { return false; } if(HasRevision() && other.HasRevision()) { if(revision < other.revision) { return false; } if(revision > other.revision) { return true; } return false; } return false; } constexpr bool IsOlderThan(VersionWithRevision other) const noexcept { if(version < other.version) { return true; } if(version > other.version) { return false; } if(!HasRevision() && !other.HasRevision()) { return false; } if(HasRevision() && other.HasRevision()) { if(revision < other.revision) { return true; } if(revision > other.revision) { return false; } return false; } return false; } }; namespace Build { // Returns true if all conditions for an official release build are met bool IsReleasedBuild(); // Return true if this is a debug build with no optimizations bool IsDebugBuild(); // Return a string decribing the time of the build process (if built from a svn working copy and tsvn was available during build, otherwise it returns the time version.cpp was last rebuild which could be unreliable as it does not get rebuild every time without tsvn) mpt::ustring GetBuildDateString(); // Return a string decribing some of the build features mpt::ustring GetBuildFeaturesString(); // e.g. " NO_VST NO_DSOUND" // Return a string describing the compiler version used for building. mpt::ustring GetBuildCompilerString(); // e.g. "Microsoft Compiler 15.00.20706.01" enum Strings { StringsNone = 0, StringVersion = 1<<0, // "1.23.35.45" StringRevision = 1<<2, // "-r1234+" StringSourceInfo = 1<<5, // "https://source.openmpt.org/svn/openmpt/trunk/OpenMPT@1234 (2016-01-02) +dirty" StringBuildFlags = 1<<6, // "TEST DEBUG" StringBuildFeatures = 1<<7, // "NO_VST NO_DSOUND" }; MPT_DECLARE_ENUM(Strings) // Returns a versions string with the fields selected via @strings. mpt::ustring GetVersionString(FlagSet strings); // Returns a pure version string mpt::ustring GetVersionStringPure(); // e.g. "1.17.02.08-r1234+" // Returns a simple version string mpt::ustring GetVersionStringSimple(); // e.g. "1.17.02.08-r1234+ TEST" // Returns Version::CurrentAsString() if the build is a clean release build straight from the repository or an extended string otherwise (if built from a svn working copy and tsvn was available during build) mpt::ustring GetVersionStringExtended(); // e.g. "1.17.02.08-r1234+ DEBUG" enum class Url { Website, Download, Forum, Bugtracker, Updates, TopPicks, }; // Returns a URL for the respective key. mpt::ustring GetURL(Build::Url key); // Returns a multi-line string containing the full credits for the code base mpt::ustring GetFullCreditsString(); // Returns the OpenMPT license text mpt::ustring GetLicenseString(); } //namespace Build OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/GzipWriter.h0000644000175000017500000000301614616613542020035 00000000000000/* * GzipWriter.h * ------------ * Purpose: Simple wrapper around zlib's Gzip writer * Notes : miniz doesn't implement Gzip writing, so this is only compatible with zlib. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mptString.h" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #ifdef MPT_WITH_ZLIB #include OPENMPT_NAMESPACE_BEGIN inline void WriteGzip(std::ostream &output, std::string &outData, const mpt::ustring &fileName) { z_stream strm{}; strm.avail_in = static_cast(outData.size()); strm.next_in = reinterpret_cast(outData.data()); if(deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, 15 | 16, 9, Z_DEFAULT_STRATEGY) != Z_OK) throw std::runtime_error{"zlib init failed"}; gz_header gzHeader{}; gzHeader.time = static_cast(time(nullptr)); std::string filenameISO = mpt::ToCharset(mpt::Charset::ISO8859_1, fileName); gzHeader.name = reinterpret_cast(filenameISO.data()); deflateSetHeader(&strm, &gzHeader); try { do { std::array buffer; strm.avail_out = static_cast(buffer.size()); strm.next_out = buffer.data(); deflate(&strm, Z_FINISH); mpt::IO::WritePartial(output, buffer, buffer.size() - strm.avail_out); } while(strm.avail_out == 0); deflateEnd(&strm); } catch(const std::exception &) { deflateEnd(&strm); throw; } } OPENMPT_NAMESPACE_END #endif libopenmpt-0.8.1+release.autotools/common/mptCPU.h0000644000175000017500000000466014765351704017111 00000000000000/* * mptCPU.h * -------- * Purpose: CPU feature detection. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/macros.hpp" #ifdef MPT_ENABLE_ARCH_INTRINSICS #include "mpt/arch/arch.hpp" #endif OPENMPT_NAMESPACE_BEGIN namespace CPU { #ifdef MPT_ENABLE_ARCH_INTRINSICS #if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT) namespace detail { inline MPT_CONSTINIT mpt::arch::current::feature_flags EnabledFeatures; inline MPT_CONSTINIT mpt::arch::current::mode_flags EnabledModes; } // namespace detail inline void EnableAvailableFeatures() noexcept { CPU::detail::EnabledFeatures = mpt::arch::get_cpu_info().get_features(); CPU::detail::EnabledModes = mpt::arch::get_cpu_info().get_modes(); } // enabled processor features for inline asm and intrinsics [[nodiscard]] MPT_FORCEINLINE mpt::arch::current::feature_flags GetEnabledFeatures() noexcept { return CPU::detail::EnabledFeatures; } [[nodiscard]] MPT_FORCEINLINE mpt::arch::current::mode_flags GetEnabledModes() noexcept { return CPU::detail::EnabledModes; } struct Info { [[nodiscard]] MPT_FORCEINLINE bool HasFeatureSet(mpt::arch::current::feature_flags features) const noexcept { return features == (GetEnabledFeatures() & features); } [[nodiscard]] MPT_FORCEINLINE bool HasModesEnabled(mpt::arch::current::mode_flags modes) const noexcept { return modes == (GetEnabledModes() & modes); } }; #else // !MODPLUG_TRACKER struct Info { private: const mpt::arch::flags_cache m_flags{mpt::arch::get_cpu_info()}; public: [[nodiscard]] MPT_FORCEINLINE bool HasFeatureSet(mpt::arch::current::feature_flags features) const noexcept { return m_flags[features]; } [[nodiscard]] MPT_FORCEINLINE bool HasModesEnabled(mpt::arch::current::mode_flags modes) const noexcept { return m_flags[modes]; } }; #endif // MODPLUG_TRACKER namespace feature = mpt::arch::current::feature; namespace mode = mpt::arch::current::mode; [[nodiscard]] MPT_FORCEINLINE bool HasFeatureSet(mpt::arch::current::feature_flags features) noexcept { return CPU::Info{}.HasFeatureSet(features); } [[nodiscard]] MPT_FORCEINLINE bool HasModesEnabled(mpt::arch::current::mode_flags modes) noexcept { return CPU::Info{}.HasModesEnabled(modes); } #endif // MPT_ENABLE_ARCH_INTRINSICS } // namespace CPU OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptTime.h0000644000175000017500000002201014765351635017350 00000000000000/* * mptTime.h * --------- * Purpose: Various time utility functions. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #if MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO_DATE) #include #include #elif MPT_CXX_AT_LEAST(17) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO) && defined(MODPLUG_TRACKER) #include #endif #if MPT_CXX_BEFORE(20) || defined(MPT_LIBCXX_QUIRK_NO_CHRONO) || defined(MPT_LIBCXX_QUIRK_NO_CHRONO_DATE) #include #endif #if MPT_WINNT_AT_LEAST(MPT_WIN_8) #define MPT_FALLBACK_TIMEZONE_WINDOWS_HISTORIC #define MPT_FALLBACK_TIMEZONE_WINDOWS_CURRENT #define MPT_FALLBACK_TIMEZONE_C #elif MPT_WINNT_AT_LEAST(MPT_WIN_XP) #define MPT_FALLBACK_TIMEZONE_WINDOWS_CURRENT #define MPT_FALLBACK_TIMEZONE_C #else #define MPT_FALLBACK_TIMEZONE_C #endif OPENMPT_NAMESPACE_BEGIN #if defined(MODPLUG_TRACKER) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO) namespace mpt { namespace chrono { #if MPT_CXX_AT_LEAST(20) using days = std::chrono::days; using weeks = std::chrono::weeks; using years = std::chrono::years; using months = std::chrono::months; #else using days = std::chrono::duration, std::chrono::hours::period>>; using weeks = std::chrono::duration, mpt::chrono::days::period>>; using years = std::chrono::duration, mpt::chrono::days::period>>; using months = std::chrono::duration>>; #endif } } #endif // !MPT_LIBCXX_QUIRK_NO_CHRONO namespace mpt { namespace Date { #if defined(MODPLUG_TRACKER) #if MPT_OS_WINDOWS namespace ANSI { // uint64 counts 100ns since 1601-01-01T00:00Z uint64 Now(); mpt::ustring ToUString(uint64 time100ns); // i.e. 2015-01-15 18:32:01.718 } // namespacee ANSI #endif // MPT_OS_WINDOWS #endif // MODPLUG_TRACKER enum class LogicalTimezone { Unspecified, UTC, #if defined(MODPLUG_TRACKER) Local, #endif // MODPLUG_TRACKER }; template struct Gregorian { int year = 0; unsigned int month = 0; unsigned int day = 0; int32 hours = 0; int32 minutes = 0; int64 seconds = 0; friend bool operator==(const Gregorian& lhs, const Gregorian& rhs) { return std::tie(lhs.year, lhs.month, lhs.day, lhs.hours, lhs.minutes, lhs.seconds) == std::tie(rhs.year, rhs.month, rhs.day, rhs.hours, rhs.minutes, rhs.seconds); } friend bool operator!=(const Gregorian& lhs, const Gregorian& rhs) { return std::tie(lhs.year, lhs.month, lhs.day, lhs.hours, lhs.minutes, lhs.seconds) != std::tie(rhs.year, rhs.month, rhs.day, rhs.hours, rhs.minutes, rhs.seconds); } friend bool operator<(const Gregorian &lhs, const Gregorian &rhs) { return std::tie(lhs.year, lhs.month, lhs.day, lhs.hours, lhs.minutes, lhs.seconds) < std::tie(rhs.year, rhs.month, rhs.day, rhs.hours, rhs.minutes, rhs.seconds); } }; using AnyGregorian = Gregorian; using UTC = Gregorian; #if defined(MODPLUG_TRACKER) using Local = Gregorian; #endif // MODPLUG_TRACKER template inline Gregorian interpret_as_timezone(AnyGregorian gregorian) { Gregorian result; result.year = gregorian.year; result.month = gregorian.month; result.day = gregorian.day; result.hours = gregorian.hours; result.minutes = gregorian.minutes; result.seconds = gregorian.seconds; return result; } template inline Gregorian forget_timezone(Gregorian gregorian) { Gregorian result; result.year = gregorian.year; result.month = gregorian.month; result.day = gregorian.day; result.hours = gregorian.hours; result.minutes = gregorian.minutes; result.seconds = gregorian.seconds; return result; } namespace nochrono { // int64 counts 1s since 1970-01-01T00:00Z struct Unix { int64 value{}; friend bool operator==(const Unix &a, const Unix &b) { return a.value == b.value; } friend bool operator!=(const Unix &a, const Unix &b) { return a.value != b.value; } }; #if MPT_CXX_BEFORE(20) || defined(MPT_LIBCXX_QUIRK_NO_CHRONO) || defined(MPT_LIBCXX_QUIRK_NO_CHRONO_DATE) inline Unix UnixNow() { return Unix{static_cast(std::time(nullptr))}; } #endif inline int64 UnixAsSeconds(Unix tp) { return tp.value; } inline Unix UnixFromSeconds(int64 seconds) { return Unix{seconds}; } Unix UnixFromUTC(UTC timeUtc); UTC UnixAsUTC(Unix tp); #if defined(MODPLUG_TRACKER) Unix UnixFromLocal(Local timeLocal); Local UnixAsLocal(Unix tp); #endif // MODPLUG_TRACKER } // namespace nochrono #if MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO_DATE) using Unix = std::chrono::system_clock::time_point; inline Unix UnixNow() { return std::chrono::system_clock::now(); } inline int64 UnixAsSeconds(Unix tp) { return std::chrono::duration_cast(tp.time_since_epoch()).count(); } inline Unix UnixFromSeconds(int64 seconds) { return std::chrono::system_clock::time_point{std::chrono::seconds{seconds}}; } inline mpt::Date::Unix UnixFromUTC(UTC utc) { try { return std::chrono::system_clock::time_point{ std::chrono::sys_days { std::chrono::year{ utc.year } / std::chrono::month{ utc.month } / std::chrono::day{ utc.day } } + std::chrono::hours{ utc.hours } + std::chrono::minutes{ utc.minutes } + std::chrono::seconds{ utc.seconds }}; } catch(const std::exception &) { return mpt::Date::UnixFromSeconds(mpt::Date::nochrono::UnixAsSeconds(mpt::Date::nochrono::UnixFromUTC(utc))); } } inline mpt::Date::UTC UnixAsUTC(Unix tp) { try { std::chrono::sys_days dp = std::chrono::floor(tp); std::chrono::year_month_day ymd{dp}; std::chrono::hh_mm_ss hms{tp - dp}; mpt::Date::UTC result; result.year = static_cast(ymd.year()); result.month = static_cast(ymd.month()); result.day = static_cast(ymd.day()); result.hours = static_cast(hms.hours().count()); result.minutes = static_cast(hms.minutes().count()); result.seconds = static_cast(hms.seconds().count()); return result; } catch(const std::exception &) { return mpt::Date::nochrono::UnixAsUTC(mpt::Date::nochrono::UnixFromSeconds(mpt::Date::UnixAsSeconds(tp))); } } #if defined(MODPLUG_TRACKER) inline mpt::Date::Unix UnixFromLocal(Local local) { #if !defined(MPT_LIBCXX_QUIRK_CHRONO_DATE_NO_ZONED_TIME) try { std::chrono::time_point local_tp = std::chrono::local_days { std::chrono::year{ local.year } / std::chrono::month{ local.month } / std::chrono::day{ local.day } } + std::chrono::hours{ local.hours } + std::chrono::minutes{ local.minutes } + std::chrono::seconds{ local.seconds }; #if defined(MPT_LIBCXX_QUIRK_CHRONO_DATE_BROKEN_ZONED_TIME) return std::chrono::zoned_time{std::chrono::current_zone(), std::chrono::current_zone()->to_sys(local_tp)}.get_sys_time(); #else return std::chrono::zoned_time{std::chrono::current_zone(), local_tp}.get_sys_time(); #endif } catch(const std::exception &) #endif { return mpt::Date::UnixFromSeconds(mpt::Date::nochrono::UnixAsSeconds(mpt::Date::nochrono::UnixFromLocal(local))); } } inline mpt::Date::Local UnixAsLocal(Unix tp) { #if !defined(MPT_LIBCXX_QUIRK_CHRONO_DATE_NO_ZONED_TIME) try { std::chrono::zoned_time local_tp{ std::chrono::current_zone(), tp }; std::chrono::local_days dp = std::chrono::floor(local_tp.get_local_time()); std::chrono::year_month_day ymd{dp}; std::chrono::hh_mm_ss hms{local_tp.get_local_time() - dp}; mpt::Date::Local result; result.year = static_cast(ymd.year()); result.month = static_cast(ymd.month()); result.day = static_cast(ymd.day()); result.hours = static_cast(hms.hours().count()); result.minutes = static_cast(hms.minutes().count()); result.seconds = static_cast(hms.seconds().count()); return result; } catch(const std::exception &) #endif { return mpt::Date::nochrono::UnixAsLocal(mpt::Date::nochrono::UnixFromSeconds(mpt::Date::UnixAsSeconds(tp))); } } #endif // MODPLUG_TRACKER #else using Unix = nochrono::Unix; using nochrono::UnixNow; using nochrono::UnixAsSeconds; using nochrono::UnixFromSeconds; using nochrono::UnixFromUTC; using nochrono::UnixAsUTC; #if defined(MODPLUG_TRACKER) using nochrono::UnixFromLocal; using nochrono::UnixAsLocal; #endif // MODPLUG_TRACKER #endif mpt::ustring ToShortenedISO8601(AnyGregorian date); // i.e. 2015-01-15T18:32:01 mpt::ustring ToShortenedISO8601(UTC date); // i.e. 2015-01-15T18:32:01Z #ifdef MODPLUG_TRACKER mpt::ustring ToShortenedISO8601(Local date); // i.e. 2015-01-15T18:32:01 #endif // MODPLUG_TRACKER } // namespace Date } // namespace mpt OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptStringBuffer.cpp0000644000175000017500000000456014053531056021402 00000000000000/* * mptStringBuffer.cpp * ------------------- * Purpose: Various functions for "fixing" char array strings for writing to or * reading from module files, or for securing char arrays in general. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "mptStringBuffer.h" OPENMPT_NAMESPACE_BEGIN namespace mpt { namespace String { namespace detail { std::string ReadStringBuffer(String::ReadWriteMode mode, const char *srcBuffer, std::size_t srcSize) { std::string dest; const char *src = srcBuffer; if(mode == nullTerminated || mode == spacePaddedNull) { // We assume that the last character of the source buffer is null. if(srcSize > 0) { srcSize -= 1; } } if(mode == nullTerminated || mode == maybeNullTerminated) { // Copy null-terminated string, stopping at null. dest.assign(src, std::find(src, src + srcSize, '\0')); } else if(mode == spacePadded || mode == spacePaddedNull) { // Copy string over. dest.assign(src, src + srcSize); // Convert null characters to spaces. std::transform(dest.begin(), dest.end(), dest.begin(), [] (char c) -> char { return (c != '\0') ? c : ' '; }); // Trim trailing spaces. dest = mpt::trim_right(dest, std::string(" ")); } return dest; } void WriteStringBuffer(String::ReadWriteMode mode, char *destBuffer, const std::size_t destSize, const char *srcBuffer, const std::size_t srcSize) { MPT_ASSERT(destSize > 0); const size_t maxSize = std::min(destSize, srcSize); char *dst = destBuffer; const char *src = srcBuffer; // First, copy over null-terminated string. size_t pos = maxSize; while(pos > 0) { if((*dst = *src) == '\0') { break; } pos--; dst++; src++; } if(mode == nullTerminated || mode == maybeNullTerminated) { // Fill rest of string with nulls. std::fill(dst, dst + destSize - maxSize + pos, '\0'); } else if(mode == spacePadded || mode == spacePaddedNull) { // Fill the rest of the destination string with spaces. std::fill(dst, dst + destSize - maxSize + pos, ' '); } if(mode == nullTerminated || mode == spacePaddedNull) { // Make sure that destination is really null-terminated. SetNullTerminator(destBuffer, destSize); } } } // namespace detail } // namespace String } // namespace mpt OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/misc_util.h0000644000175000017500000001100714406300415017703 00000000000000/* * misc_util.h * ----------- * Purpose: Various useful utility functions. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/span.hpp" #include "mpt/exception/exception_text.hpp" #include "mptAssert.h" #include "mptBaseMacros.h" #include "mptBaseTypes.h" #include "mptBaseUtils.h" #include "mptString.h" // old #include "mptBaseUtils.h" #include "mptStringFormat.h" #include "mptTime.h" #include #include #include #include #include OPENMPT_NAMESPACE_BEGIN namespace Util { // Insert a range of items [insStart, insEnd], and possibly shift item fix to the left. template void InsertItem(const T insStart, const T insEnd, T &fix) { MPT_ASSERT(insEnd >= insStart); if(fix >= insStart) { fix += (insEnd - insStart + 1); } } // Insert a range of items [insStart, insEnd], and possibly shift items in range [fixStart, fixEnd] to the right. template void InsertRange(const T insStart, const T insEnd, T &fixStart, T &fixEnd) { MPT_ASSERT(insEnd >= insStart); const T insLength = insEnd - insStart + 1; if(fixStart >= insEnd) { fixStart += insLength; } if(fixEnd >= insEnd) { fixEnd += insLength; } } // Delete a range of items [delStart, delEnd], and possibly shift item fix to the left. template void DeleteItem(const T delStart, const T delEnd, T &fix) { MPT_ASSERT(delEnd >= delStart); if(fix > delEnd) { fix -= (delEnd - delStart + 1); } } // Delete a range of items [delStart, delEnd], and possibly shift items in range [fixStart, fixEnd] to the left. template void DeleteRange(const T delStart, const T delEnd, T &fixStart, T &fixEnd) { MPT_ASSERT(delEnd >= delStart); const T delLength = delEnd - delStart + 1; if(delStart < fixStart && delEnd < fixStart) { // cut part is before loop start fixStart -= delLength; fixEnd -= delLength; } else if(delStart < fixStart && delEnd < fixEnd) { // cut part is partly before loop start fixStart = delStart; fixEnd -= delLength; } else if(delStart >= fixStart && delEnd < fixEnd) { // cut part is in the loop fixEnd -= delLength; } else if(delStart >= fixStart && delStart < fixEnd && delEnd > fixEnd) { // cut part is partly before loop end fixEnd = delStart; } } template class fixed_size_queue { private: T buffer[n+1]; std::size_t read_position; std::size_t write_position; public: fixed_size_queue() : read_position(0), write_position(0) { return; } void clear() { read_position = 0; write_position = 0; } std::size_t read_size() const { if ( write_position > read_position ) { return write_position - read_position; } else if ( write_position < read_position ) { return write_position - read_position + n + 1; } else { return 0; } } std::size_t write_size() const { if ( write_position > read_position ) { return read_position - write_position + n; } else if ( write_position < read_position ) { return read_position - write_position - 1; } else { return n; } } bool push( const T & v ) { if ( !write_size() ) { return false; } buffer[write_position] = v; write_position = ( write_position + 1 ) % ( n + 1 ); return true; } bool pop() { if ( !read_size() ) { return false; } read_position = ( read_position + 1 ) % ( n + 1 ); return true; } T peek() { if ( !read_size() ) { return T(); } return buffer[read_position]; } const T * peek_p() { if ( !read_size() ) { return nullptr; } return &(buffer[read_position]); } const T * peek_next_p() { if ( read_size() < 2 ) { return nullptr; } return &(buffer[(read_position+1)%(n+1)]); } }; } // namespace Util #if MPT_OS_WINDOWS template Tstring ParseMaybeNullTerminatedStringFromBufferWithSizeInBytes(const Tbuf *buf, Tsize sizeBytes) { // REG_SZ may contain a single NUL terminator, multiple NUL terminators, or no NUL terminator at all return Tstring(reinterpret_cast(buf), reinterpret_cast(buf) + (sizeBytes / sizeof(typename Tstring::value_type))).c_str(); } #endif // MPT_OS_WINDOWS OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/Logging.h0000644000175000017500000001350614053470755017324 00000000000000/* * Logging.h * --------- * Purpose: General logging * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/logging/Logger.hpp" #include "mptPathString.h" #include "mptString.h" #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS #include #endif OPENMPT_NAMESPACE_BEGIN /* Build time logging configuration: * #define MPT_LOG_GLOBAL_LEVEL_STATIC #define MPT_LOG_GLOBAL_LEVEL # Define the former (to anything) and the latter (to one of the log levels below) in order to statically select the verbosity of logging at build time. MPT_LOG calls that exceed the specified logging level will get dead-code eliminated at compile time. This especially means that, when setting MPT_LOG_GLOBAL_LEVEL to 0, no MPT_LOG call (with a constant level parameter) remains in the resulting binary, however, they still do get parsed and properly type checked by the compiler. Logging: If the context is related to a particular CSoundfile instance, use CSoundfile::AddToLog. Logging a simple message: MPT_LOG_GLOBAL(LogWarning, "sounddev", "some message"); MPT_LOG_GLOBAL(LogWarning, "sounddev", U_("some message")); Facility is some course grained code section identifier (more coarse grained than the current file name probably), useful to do some selective logging. Logging a more complex message: MPT_LOG_GLOBAL(LogWarning, "sounddev", MPT_UFORMAT("Some message: foo={}, bar=0x{}")(foo, mpt::ufmt::hex0<8>(bar))); Note that even with full enabled logging and a runtime configurable logging level, the runtime overhead of a MPT_LOG_GLOBAL(level, facility, text) call is just a single conditional in case the verbosity does not require logging the respective message. Even the expression "text" is not evaluated. */ inline mpt::ustring LogLevelToString(LogLevel level) { switch(level) { case LogError: return U_("error"); break; case LogWarning: return U_("warning"); break; case LogNotification: return U_("notify"); break; case LogInformation: return U_("info"); break; case LogDebug: return U_("debug"); break; } return U_("unknown"); } class ILog { protected: virtual ~ILog() { } public: virtual void AddToLog(LogLevel level, const mpt::ustring &text) const = 0; }; namespace mpt { namespace log { #if defined(MPT_LOG_GLOBAL_LEVEL_STATIC) #if (MPT_LOG_GLOBAL_LEVEL <= 0) // All logging has beeen statically disabled. // All logging code gets compiled and immediately dead-code eliminated. #define MPT_LOG_IS_DISABLED #endif inline constexpr int GlobalLogLevel = MPT_LOG_GLOBAL_LEVEL ; #else extern int GlobalLogLevel; #endif #if defined(MODPLUG_TRACKER) && !defined(MPT_LOG_IS_DISABLED) extern bool FileEnabled; extern bool DebuggerEnabled; extern bool ConsoleEnabled; void SetFacilities(const std::string &solo, const std::string &blocked); bool IsFacilityActive(const char *facility) noexcept; #else MPT_FORCEINLINE bool IsFacilityActive(const char * /*facility*/ ) noexcept { return true; } #endif class GlobalLogger final : public ILogger { public: GlobalLogger() = default; ~GlobalLogger() final = default; public: bool IsLevelActive(LogLevel level) const noexcept override { return (mpt::log::GlobalLogLevel >= level); } bool IsFacilityActive(const char *facility) const noexcept override { return mpt::log::IsFacilityActive(facility); } void SendLogMessage(const mpt::source_location &loc, LogLevel level, const char *facility, const mpt::ustring &message) const override; }; #define MPT_LOG_GLOBAL(level, facility, text) MPT_LOG(mpt::log::GlobalLogger{}, (level), (facility), (text)) #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS namespace Trace { // This is not strictly thread safe in all corner cases because of missing barriers. // We do not care in order to not harm the fast path with additional barriers. // Enabled tracing incurs a runtime overhead with multiple threads as a global atomic variable // gets modified. // This cacheline bouncing does not matter at all // if there are not multiple thread adding trace points at high frequency (way greater than 1000Hz), // which, in OpenMPT, is only ever the case for just a single thread (the audio thread), if at all. extern std::atomic g_Enabled; inline bool IsEnabled() { return g_Enabled; } enum class Direction : int8 { Unknown = 0, Enter = 1, Leave = -1, }; MPT_NOINLINE void Trace(const mpt::source_location & loc, Direction direction = Direction::Unknown) noexcept; enum ThreadKind { ThreadKindGUI, ThreadKindAudio, ThreadKindNotify, ThreadKindWatchdir, }; void Enable(std::size_t numEntries); void Disable(); void SetThreadId(mpt::log::Trace::ThreadKind kind, uint32 id); uint32 GetThreadId(mpt::log::Trace::ThreadKind kind); void Seal(); bool Dump(const mpt::PathString &filename); class Scope { private: const mpt::source_location loc; public: MPT_FORCEINLINE Scope(mpt::source_location loc) noexcept : loc(loc) { if(mpt::log::Trace::g_Enabled) { mpt::log::Trace::Trace(loc, mpt::log::Trace::Direction::Enter); } } MPT_FORCEINLINE ~Scope() noexcept { if(mpt::log::Trace::g_Enabled) { mpt::log::Trace::Trace(loc, mpt::log::Trace::Direction::Leave); } } }; #define MPT_TRACE_CONCAT_HELPER(x, y) x ## y #define MPT_TRACE_CONCAT(x, y) MPT_TRACE_CONCAT_HELPER(x, y) #define MPT_TRACE_SCOPE() mpt::log::Trace::Scope MPT_TRACE_CONCAT(MPT_TRACE_VAR, __LINE__)(MPT_SOURCE_LOCATION_CURRENT()) #define MPT_TRACE() do { if(mpt::log::Trace::g_Enabled) { mpt::log::Trace::Trace(MPT_SOURCE_LOCATION_CURRENT()); } } while(0) } // namespace Trace #else // !MODPLUG_TRACKER #define MPT_TRACE_SCOPE() do { } while(0) #define MPT_TRACE() do { } while(0) #endif // MODPLUG_TRACKER } // namespace log } // namespace mpt OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptFileType.h0000644000175000017500000000664014250574063020175 00000000000000/* * mptFileType.h * ------------- * Purpose: * Notes : Currently none. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/alloc.hpp" #include "mpt/base/namespace.hpp" #include "mpt/string/types.hpp" #include "openmpt/base/FlagSet.hpp" #include OPENMPT_NAMESPACE_BEGIN #if defined(MODPLUG_TRACKER) enum FileTypeFormat { FileTypeFormatNone = 0 , // do not show extensions after description, i.e. "Foo Files" FileTypeFormatShowExtensions = 1<<0, // show extensions after descripten, i.e. "Foo Files (*.foo,*.bar)" }; MPT_DECLARE_ENUM(FileTypeFormat) class FileType { private: mpt::ustring m_ShortName; // "flac", "mod" (lowercase) mpt::ustring m_Description; // "FastTracker 2 Module" std::vector m_MimeTypes; // "audio/ogg" (in ASCII) std::vector m_Extensions; // "mod", "xm" (lowercase) std::vector m_Prefixes; // "mod" for "mod.*" public: FileType() { } FileType(const std::vector &group) { for(const auto &type : group) { mpt::append(m_MimeTypes, type.m_MimeTypes); mpt::append(m_Extensions, type.m_Extensions); mpt::append(m_Prefixes, type.m_Prefixes); } } static FileType Any() { return FileType().ShortName(U_("*")).Description(U_("All Files")).AddExtension(P_("*")); } public: FileType& ShortName(const mpt::ustring &shortName) { m_ShortName = shortName; return *this; } FileType& Description(const mpt::ustring &description) { m_Description = description; return *this; } FileType& MimeTypes(const std::vector &mimeTypes) { m_MimeTypes = mimeTypes; return *this; } FileType& Extensions(const std::vector &extensions) { m_Extensions = extensions; return *this; } FileType& Prefixes(const std::vector &prefixes) { m_Prefixes = prefixes; return *this; } FileType& AddMimeType(const std::string &mimeType) { m_MimeTypes.push_back(mimeType); return *this; } FileType& AddExtension(const mpt::PathString &extension) { m_Extensions.push_back(extension); return *this; } FileType& AddPrefix(const mpt::PathString &prefix) { m_Prefixes.push_back(prefix); return *this; } public: mpt::ustring GetShortName() const { return m_ShortName; } mpt::ustring GetDescription() const { return m_Description; } std::vector GetMimeTypes() const { return m_MimeTypes; } std::vector GetExtensions() const { return m_Extensions; } std::vector GetPrefixes() const { return m_Prefixes; } public: mpt::PathString AsFilterString(FlagSet format = FileTypeFormatNone) const; mpt::PathString AsFilterOnlyString() const; }; // class FileType // "Ogg Vorbis|*.ogg;*.oga|" // FileTypeFormatNone // "Ogg Vorbis (*.ogg,*.oga)|*.ogg;*.oga|" // FileTypeFormatShowExtensions mpt::PathString ToFilterString(const FileType &fileType, FlagSet format = FileTypeFormatNone); mpt::PathString ToFilterString(const std::vector &fileTypes, FlagSet format = FileTypeFormatNone); // "*.ogg;*.oga" / ";*.ogg;*.oga" mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicolonWhenNotEmpty = false); mpt::PathString ToFilterOnlyString(const std::vector &fileTypes, bool prependSemicolonWhenNotEmpty = false); #endif // MODPLUG_TRACKER OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptBaseUtils.h0000644000175000017500000001031214705177003020334 00000000000000/* * mptBaseUtils.h * -------------- * Purpose: Various useful utility functions. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/algorithm.hpp" #include "mpt/base/arithmetic_shift.hpp" #include "mpt/base/array.hpp" #include "mpt/base/bit.hpp" #include "mpt/base/constexpr_throw.hpp" #include "mpt/base/detect_arch.hpp" #include "mpt/base/detect_compiler.hpp" #include "mpt/base/math.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/numeric.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/base/saturate_round.hpp" #include "mpt/base/utility.hpp" #include "mpt/base/wrapping_divide.hpp" #include "mptBaseMacros.h" #include "mptBaseTypes.h" #include #include #include #include #include #include #include #include #if MPT_COMPILER_MSVC #include #endif OPENMPT_NAMESPACE_BEGIN template inline void Clear(T& x) { static_assert(!std::is_pointer::value); mpt::reset(x); } // Memset given object to zero. template inline void MemsetZero(T& a) { static_assert(std::is_pointer::value == false, "Won't memset pointers."); mpt::memclear(a); } // Limits 'val' to given range. If 'val' is less than 'lowerLimit', 'val' is set to value 'lowerLimit'. // Similarly if 'val' is greater than 'upperLimit', 'val' is set to value 'upperLimit'. // If 'lowerLimit' > 'upperLimit', 'val' won't be modified. template inline void Limit(T& val, const C lowerLimit, const C upperLimit) { if(lowerLimit > upperLimit) return; if(val < lowerLimit) val = lowerLimit; else if(val > upperLimit) val = upperLimit; } // Like Limit, but returns value template inline T Clamp(T val, const C lowerLimit, const C upperLimit) { if(val < lowerLimit) return lowerLimit; else if(val > upperLimit) return upperLimit; else return val; } // Like Limit, but with upperlimit only. template inline void LimitMax(T& val, const C upperLimit) { if(val > upperLimit) val = upperLimit; } namespace Util { // Returns maximum value of given integer type. template constexpr T MaxValueOfType(const T&) {static_assert(std::numeric_limits::is_integer == true, "Only integer types are allowed."); return (std::numeric_limits::max)();} } // namespace Util namespace Util { // Multiply two 32-bit integers, receive 64-bit result. // MSVC generates unnecessarily complicated code for the unoptimized variant using _allmul. MPT_CONSTEXPR20_FUN int64 mul32to64(int32 a, int32 b) { #if MPT_COMPILER_MSVC && (MPT_ARCH_X86 || MPT_ARCH_AMD64) MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return static_cast(a) * b; } else { return __emul(a, b); } #else return static_cast(a) * b; #endif } MPT_CONSTEXPR20_FUN uint64 mul32to64_unsigned(uint32 a, uint32 b) { #if MPT_COMPILER_MSVC && (MPT_ARCH_X86 || MPT_ARCH_AMD64) MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return static_cast(a) * b; } else { return __emulu(a, b); } #else return static_cast(a) * b; #endif } MPT_CONSTEXPR20_FUN int32 muldiv(int32 a, int32 b, int32 c) { return mpt::saturate_cast( mul32to64( a, b ) / c ); } MPT_CONSTEXPR20_FUN int32 muldivr(int32 a, int32 b, int32 c) { return mpt::saturate_cast( ( mul32to64( a, b ) + ( c / 2 ) ) / c ); } // Do not use overloading because catching unsigned version by accident results in slower X86 code. MPT_CONSTEXPR20_FUN uint32 muldiv_unsigned(uint32 a, uint32 b, uint32 c) { return mpt::saturate_cast( mul32to64_unsigned( a, b ) / c ); } MPT_CONSTEXPR20_FUN uint32 muldivr_unsigned(uint32 a, uint32 b, uint32 c) { return mpt::saturate_cast( ( mul32to64_unsigned( a, b ) + ( c / 2u ) ) / c ); } constexpr MPT_FORCEINLINE int32 muldivrfloor(int64 a, uint32 b, uint32 c) { a *= b; a += c / 2u; return (a >= 0) ? mpt::saturate_cast(a / c) : mpt::saturate_cast((a - (c - 1)) / c); } } // namespace Util OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptBaseTypes.h0000644000175000017500000000307014657607003020347 00000000000000/* * mptBaseTypes.h * -------------- * Purpose: Basic data type definitions. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/check_platform.hpp" #include "mpt/base/float.hpp" #include "mpt/base/integer.hpp" #include "mpt/base/pointer.hpp" #include "mpt/base/size.hpp" #include "mpt/base/source_location.hpp" #include "openmpt/base/Types.hpp" #include "mptBaseMacros.h" #include #include #include #include #include #include OPENMPT_NAMESPACE_BEGIN constexpr inline int8 int8_min = std::numeric_limits::min(); constexpr inline int16 int16_min = std::numeric_limits::min(); constexpr inline int32 int32_min = std::numeric_limits::min(); constexpr inline int64 int64_min = std::numeric_limits::min(); constexpr inline int8 int8_max = std::numeric_limits::max(); constexpr inline int16 int16_max = std::numeric_limits::max(); constexpr inline int32 int32_max = std::numeric_limits::max(); constexpr inline int64 int64_max = std::numeric_limits::max(); constexpr inline uint8 uint8_max = std::numeric_limits::max(); constexpr inline uint16 uint16_max = std::numeric_limits::max(); constexpr inline uint32 uint32_max = std::numeric_limits::max(); constexpr inline uint64 uint64_max = std::numeric_limits::max(); OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptAssert.h0000644000175000017500000001114714052666041017711 00000000000000/* * mptAssert.h * ----------- * Purpose: assert and static_assert * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/source_location.hpp" #include "mptBaseMacros.h" OPENMPT_NAMESPACE_BEGIN // Static code checkers might need to get the knowledge of our assertions transferred to them. #define MPT_CHECKER_ASSUME_ASSERTIONS 1 //#define MPT_CHECKER_ASSUME_ASSERTIONS 0 #ifdef MPT_BUILD_ANALYZED #if MPT_COMPILER_MSVC #if MPT_CHECKER_ASSUME_ASSERTIONS #define MPT_CHECKER_ASSUME(x) __analysis_assume(!!(x)) #endif #elif MPT_COMPILER_CLANG #if MPT_CHECKER_ASSUME_ASSERTIONS #ifdef NDEBUG #error "Builds for static analyzers depend on assert() being enabled, but the current build has #define NDEBUG. This makes no sense." #endif OPENMPT_NAMESPACE_END #include OPENMPT_NAMESPACE_BEGIN #define MPT_CHECKER_ASSUME(x) assert(!!(x)) #endif #endif // MPT_COMPILER #endif // MPT_BUILD_ANALYZED #ifndef MPT_CHECKER_ASSUME #define MPT_CHECKER_ASSUME(x) do { } while(0) #endif #if defined(MPT_WITH_MFC) && !defined(MPT_CPPCHECK_CUSTOM) #if !defined(ASSERT) #error "MFC is expected to #define ASSERT" #endif // !defined(ASERRT) #define MPT_FRAMEWORK_ASSERT_IS_DEFINED #if defined(_DEBUG) #define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 1 #else // !_DEBUG #define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 0 #endif // _DEBUG // let MFC handle our asserts #define MPT_ASSERT_USE_FRAMEWORK 1 #else // !MPT_WITH_MFC #if defined(ASSERT) #define MPT_FRAMEWORK_ASSERT_IS_DEFINED #if defined(_DEBUG) #define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 1 #else // !_DEBUG #define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 0 #endif // _DEBUG #endif // !defined(ASERRT) // handle assert in our own way without relying on some platform-/framework-specific assert implementation #define MPT_ASSERT_USE_FRAMEWORK 0 #endif // MPT_WITH_MFC #if defined(MPT_FRAMEWORK_ASSERT_IS_DEFINED) && (MPT_ASSERT_USE_FRAMEWORK == 1) #define MPT_ASSERT_NOTREACHED() ASSERT(0) #define MPT_ASSERT(expr) ASSERT((expr)) #define MPT_ASSERT_MSG(expr, msg) ASSERT((expr) && (msg)) #if (MPT_FRAMEWORK_ASSERT_IS_ACTIVE == 1) #define MPT_ASSERT_ALWAYS(expr) ASSERT((expr)) #define MPT_ASSERT_ALWAYS_MSG(expr, msg) ASSERT((expr) && (msg)) #else #define MPT_ASSERT_ALWAYS(expr) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } while(0) #define MPT_ASSERT_ALWAYS_MSG(expr, msg) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } while(0) #ifndef MPT_ASSERT_HANDLER_NEEDED #define MPT_ASSERT_HANDLER_NEEDED #endif #endif #elif defined(NO_ASSERTS) #define MPT_ASSERT_NOTREACHED() MPT_CHECKER_ASSUME(0) #define MPT_ASSERT(expr) MPT_CHECKER_ASSUME(expr) #define MPT_ASSERT_MSG(expr, msg) MPT_CHECKER_ASSUME(expr) #define MPT_ASSERT_ALWAYS(expr) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } while(0) #define MPT_ASSERT_ALWAYS_MSG(expr, msg) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } while(0) #ifndef MPT_ASSERT_HANDLER_NEEDED #define MPT_ASSERT_HANDLER_NEEDED #endif #else // !NO_ASSERTS #define MPT_ASSERT_NOTREACHED() do { if constexpr(!(0)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), "0"); } MPT_CHECKER_ASSUME(0); } while(0) #define MPT_ASSERT(expr) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } while(0) #define MPT_ASSERT_MSG(expr, msg) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } while(0) #define MPT_ASSERT_ALWAYS(expr) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } while(0) #define MPT_ASSERT_ALWAYS_MSG(expr, msg) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } while(0) #ifndef MPT_ASSERT_HANDLER_NEEDED #define MPT_ASSERT_HANDLER_NEEDED #endif #endif // NO_ASSERTS #if defined(MPT_ASSERT_HANDLER_NEEDED) // custom assert handler needed MPT_NOINLINE void AssertHandler(const mpt::source_location &loc, const char *expr, const char *msg=nullptr); #endif // MPT_ASSERT_HANDLER_NEEDED OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptRandom.h0000644000175000017500000000675514617421600017676 00000000000000/* * mptRandom.h * ----------- * Purpose: PRNG * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/bit.hpp" #include "mpt/mutex/mutex.hpp" #ifdef MODPLUG_TRACKER #include "mpt/random/crand.hpp" #endif // MODPLUG_TRACKER #include "mpt/random/default_engines.hpp" #include "mpt/random/device.hpp" #include "mpt/random/engine.hpp" #include "mpt/random/engine_lcg.hpp" #include "mpt/random/seed.hpp" #include #include OPENMPT_NAMESPACE_BEGIN // NOTE: // We implement our own PRNG and distribution functions as the implementations // of std::uniform_int_distribution is either wrong (not uniform in MSVC2010) or // not guaranteed to be livelock-free for bad PRNGs (in GCC, Clang, boost). // We resort to a simpler implementation with only power-of-2 result ranges for // both the underlying PRNG and our interface function. This saves us from // complicated code having to deal with partial bits of entropy. // Our interface still somewhat follows the mindset of C++11 (with the // addition of a simple wrapper function mpt::random which saves the caller from // instantiating distribution objects for the common uniform distribution case. // We are still using std::random_device for initial seeding when avalable and // after working around its set of problems. namespace mpt { template class thread_safe_prng : private Trng { private: mpt::mutex m; public: using result_type = typename Trng::result_type; public: template explicit thread_safe_prng(Trd & rd) : Trng(mpt::make_prng(rd)) { return; } thread_safe_prng(Trng rng) : Trng(rng) { return; } public: static MPT_CONSTEXPRINLINE typename engine_traits::result_type min() { return Trng::min(); } static MPT_CONSTEXPRINLINE typename engine_traits::result_type max() { return Trng::max(); } static MPT_CONSTEXPRINLINE int result_bits() { return engine_traits::result_bits(); } public: typename engine_traits::result_type operator()() { mpt::lock_guard l(m); return Trng::operator()(); } }; #ifdef MPT_BUILD_FUZZER // Use deterministic seeding using random_device = deterministic_random_device; #else // !MPT_BUILD_FUZZER // mpt::random_device always generates 32 bits of entropy using random_device = mpt::sane_random_device; #endif // MPT_BUILD_FUZZER #ifdef MPT_BUILD_FUZZER // Use fast PRNGs in order to not waste time fuzzing more complex PRNG // implementations. using fast_prng = deterministic_fast_engine; using good_prng = deterministic_good_engine; #else // !MPT_BUILD_FUZZER // We cannot use std::minstd_rand here because it has not a power-of-2 sized // output domain which we rely upon. using fast_prng = fast_engine; // about 3 ALU operations, ~32bit of state, suited for inner loops using good_prng = good_engine; #endif // MPT_BUILD_FUZZER using default_prng = mpt::good_prng; mpt::random_device & global_random_device(); mpt::thread_safe_prng & global_prng(); #ifdef MPT_BUILD_FUZZER void reinit_global_random(); #endif // MPT_BUILD_FUZZER #if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT) void set_global_random_device(mpt::random_device *rd); void set_global_prng(mpt::thread_safe_prng *rng); #endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT } // namespace mpt OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/mptStringBuffer.h0000644000175000017500000002047714405572636021066 00000000000000/* * mptStringBuffer.h * ----------------- * Purpose: Various functions for "fixing" char array strings for writing to or * reading from module files, or for securing char arrays in general. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/string/buffer.hpp" #include "mptString.h" #include #include #include OPENMPT_NAMESPACE_BEGIN namespace mpt { namespace String { enum ReadWriteMode : uint8 { // Reading / Writing: Standard null-terminated string handling. nullTerminated = 1, // Reading: Source string is not guaranteed to be null-terminated (if it fills the whole char array). // Writing: Destination string is not guaranteed to be null-terminated (if it fills the whole char array). maybeNullTerminated = 2, // Reading: String may contain null characters anywhere. They should be treated as spaces. // Writing: A space-padded string is written. spacePadded = 3, // Reading: String may contain null characters anywhere. The last character is ignored (it is supposed to be 0). // Writing: A space-padded string with a trailing null is written. spacePaddedNull = 4, }; namespace detail { std::string ReadStringBuffer(String::ReadWriteMode mode, const char *srcBuffer, std::size_t srcSize); void WriteStringBuffer(String::ReadWriteMode mode, char *destBuffer, const std::size_t destSize, const char *srcBuffer, const std::size_t srcSize); } // namespace detail } // namespace String namespace String { using mpt::ReadTypedBuf; using mpt::WriteTypedBuf; } // namespace String namespace String { using mpt::ReadAutoBuf; using mpt::WriteAutoBuf; } // namespace String template class StringModeBufRefImpl { private: Tchar * buf; std::size_t size; String::ReadWriteMode mode; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar StringModeBufRefImpl(Tchar * buf_, std::size_t size_, String::ReadWriteMode mode_) : buf(buf_) , size(size_) , mode(mode_) { static_assert(sizeof(Tchar) == 1); } StringModeBufRefImpl(const StringModeBufRefImpl &) = delete; StringModeBufRefImpl(StringModeBufRefImpl &&) = default; StringModeBufRefImpl & operator = (const StringModeBufRefImpl &) = delete; StringModeBufRefImpl & operator = (StringModeBufRefImpl &&) = delete; operator std::string () const { return String::detail::ReadStringBuffer(mode, buf, size); } bool empty() const { return String::detail::ReadStringBuffer(mode, buf, size).empty(); } StringModeBufRefImpl & operator = (const std::string & str) { String::detail::WriteStringBuffer(mode, buf, size, str.data(), str.size()); return *this; } }; template class StringModeBufRefImpl { private: const Tchar * buf; std::size_t size; String::ReadWriteMode mode; public: // cppcheck false-positive // cppcheck-suppress uninitMemberVar StringModeBufRefImpl(const Tchar * buf_, std::size_t size_, String::ReadWriteMode mode_) : buf(buf_) , size(size_) , mode(mode_) { static_assert(sizeof(Tchar) == 1); } StringModeBufRefImpl(const StringModeBufRefImpl &) = delete; StringModeBufRefImpl(StringModeBufRefImpl &&) = default; StringModeBufRefImpl & operator = (const StringModeBufRefImpl &) = delete; StringModeBufRefImpl & operator = (StringModeBufRefImpl &&) = delete; operator std::string () const { return String::detail::ReadStringBuffer(mode, buf, size); } bool empty() const { return String::detail::ReadStringBuffer(mode, buf, size).empty(); } }; namespace String { template inline StringModeBufRefImpl::type> ReadBuf(String::ReadWriteMode mode, const std::array &buf) { return StringModeBufRefImpl::type>(buf.data(), size, mode); } template inline StringModeBufRefImpl::type> ReadBuf(String::ReadWriteMode mode, const Tchar (&buf)[size]) { return StringModeBufRefImpl::type>(buf, size, mode); } template inline StringModeBufRefImpl::type> ReadBuf(String::ReadWriteMode mode, const Tchar * buf, std::size_t size) { return StringModeBufRefImpl::type>(buf, size, mode); } template inline StringModeBufRefImpl WriteBuf(String::ReadWriteMode mode, std::array &buf) { return StringModeBufRefImpl(buf.data(), size, mode); } template inline StringModeBufRefImpl WriteBuf(String::ReadWriteMode mode, Tchar (&buf)[size]) { return StringModeBufRefImpl(buf, size, mode); } template inline StringModeBufRefImpl WriteBuf(String::ReadWriteMode mode, Tchar * buf, std::size_t size) { return StringModeBufRefImpl(buf, size, mode); } } // namespace String template struct modecharbuf { public: using Tchar = char; using char_type = Tchar; using string_type = std::basic_string; public: Tchar buf[len]; public: modecharbuf() = default; modecharbuf(const modecharbuf &) = default; modecharbuf(modecharbuf &&) = default; modecharbuf & operator = (const modecharbuf &) = default; modecharbuf & operator = (modecharbuf &&) = default; operator string_type () const { return mpt::String::ReadBuf(mode, buf); } bool empty() const { return mpt::String::ReadBuf(mode, buf).empty(); } modecharbuf & operator = (const string_type & str) { mpt::String::WriteBuf(mode, buf) = str; return *this; } }; // see MPT_BINARY_STRUCT template constexpr bool declare_binary_safe(const typename mpt::modecharbuf &) { return true; } //struct is_binary_safe> : public std::true_type { }; static_assert(sizeof(mpt::modecharbuf<7, mpt::String::ReadWriteMode::nullTerminated>) == 7); static_assert(alignof(mpt::modecharbuf<7, mpt::String::ReadWriteMode::nullTerminated>) == 1); static_assert(std::is_standard_layout>::value); #ifdef MODPLUG_TRACKER #if MPT_OS_WINDOWS namespace String { using mpt::ReadWinBuf; using mpt::WriteWinBuf; } // namespace String #if defined(MPT_WITH_MFC) namespace String { using mpt::ReadCStringBuf; using mpt::WriteCStringBuf; } // namespace String #endif // MPT_WITH_MFC #endif // MPT_OS_WINDOWS #endif // MODPLUG_TRACKER namespace String { #if MPT_COMPILER_MSVC #pragma warning(push) #pragma warning(disable:4127) // conditional expression is constant #endif // MPT_COMPILER_MSVC // Sets last character to null in given char array. // Size of the array must be known at compile time. template void SetNullTerminator(char (&buffer)[size]) { static_assert(size > 0); buffer[size - 1] = 0; } inline void SetNullTerminator(char *buffer, size_t size) { MPT_ASSERT(size > 0); buffer[size - 1] = 0; } #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template void SetNullTerminator(wchar_t (&buffer)[size]) { static_assert(size > 0); buffer[size - 1] = 0; } inline void SetNullTerminator(wchar_t *buffer, size_t size) { MPT_ASSERT(size > 0); buffer[size - 1] = 0; } #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_COMPILER_MSVC #pragma warning(pop) #endif // MPT_COMPILER_MSVC } // namespace String } // namespace mpt OPENMPT_NAMESPACE_END template struct mpt::make_string_type> { using type = std::basic_string::type>; }; template struct mpt::make_string_view_type> { using type = std::basic_string_view::type>; }; template struct mpt::make_string_type> { using type = std::string; }; template struct mpt::make_string_view_type> { using type = std::string_view; }; libopenmpt-0.8.1+release.autotools/common/BuildSettingsCompiler.h0000644000175000017500000000447014646257074022216 00000000000000/* * BuildSettingsCompiler.h * ----------------------- * Purpose: Global compiler setting overrides * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "mpt/base/detect_compiler.hpp" // compiler configuration #if MPT_COMPILER_MSVC #pragma warning(default:4800) // Implicit conversion from 'int' to bool. Possible information loss #pragma warning(disable:4355) // 'this' : used in base member initializer list // happens for immutable classes (i.e. classes containing const members) #pragma warning(disable:4512) // assignment operator could not be generated #pragma warning(error:4309) // Treat "truncation of constant value"-warning as error. #pragma warning(error:4463) // Treat overflow; assigning value to bit-field that can only hold values from low_value to high_value"-warning as error. #ifdef MPT_BUILD_ANALYZED // Disable Visual Studio static analyzer warnings that generate too many false positives in VS2010. //#pragma warning(disable:6246) //#pragma warning(disable:6262) #pragma warning(disable:6297) // 32-bit value is shifted, then cast to 64-bit value. Results might not be an expected value. #pragma warning(disable:6326) // Potential comparison of a constant with another constant //#pragma warning(disable:6385) //#pragma warning(disable:6386) #endif // MPT_BUILD_ANALYZED #endif // MPT_COMPILER_MSVC #if MPT_COMPILER_GCC #ifdef MPT_COMPILER_SETTING_QUIRK_GCC_BROKEN_IPA // See . #if MPT_GCC_BEFORE(9, 0, 0) // Earlier GCC get confused about setting a global function attribute. // We need to check for 9.0 instead of 9.1 because of // . // It also gets confused when setting global optimization -O1, // so we have no way of fixing GCC 8 or earlier. //#pragma GCC optimize("O1") #else #pragma GCC optimize("no-ipa-ra") #endif #endif // MPT_COMPILER_SETTING_QUIRK_GCC_BROKEN_IPA #endif // MPT_COMPILER_GCC #if MPT_COMPILER_CLANG #if defined(MPT_BUILD_MSVC) #pragma clang diagnostic warning "-Wimplicit-fallthrough" #endif // MPT_BUILD_MSVC #if defined(MODPLUG_TRACKER) #pragma clang diagnostic ignored "-Wunused-local-typedef" #endif // MODPLUG_TRACKER #endif // MPT_COMPILER_CLANG libopenmpt-0.8.1+release.autotools/common/Profiler.h0000644000175000017500000000424214052666041017507 00000000000000/* * Profiler.h * ---------- * Purpose: Performance measuring * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/mutex/mutex.hpp" #include #include OPENMPT_NAMESPACE_BEGIN #if defined(MODPLUG_TRACKER) //#define USE_PROFILER #endif #ifdef USE_PROFILER class Profiler { public: enum Category { GUI, Audio, Notify, CategoriesCount }; static std::vector GetCategoryNames() { std::vector ret; ret.push_back("GUI"); ret.push_back("Audio"); ret.push_back("Notify"); return ret; } public: static void Update(); static std::string DumpProfiles(); static std::vector DumpCategories(); }; class Profile { private: mutable mpt::mutex datamutex; public: struct Data { uint64 Calls; uint64 Sum; int64 Overhead; uint64 Start; }; public: Data data; uint64 EnterTime; Profiler::Category Category; const char * const Name; uint64 GetTime() const; uint64 GetFrequency() const; public: Profile(Profiler::Category category, const char *name); ~Profile(); void Reset(); void Enter(); void Leave(); class Scope { private: Profile &profile; public: Scope(Profile &p) : profile(p) { profile.Enter(); } ~Scope() { profile.Leave(); } }; public: Data GetAndResetData(); }; #define OPENMPT_PROFILE_SCOPE(cat, name) \ static Profile OPENMPT_PROFILE_VAR(cat, name);\ Profile::Scope OPENMPT_PROFILE_SCOPE_VAR(OPENMPT_PROFILE_VAR); \ /**/ #define OPENMPT_PROFILE_FUNCTION(cat) OPENMPT_PROFILE_SCOPE(cat, __func__) #else // !USE_PROFILER class Profiler { public: enum Category { CategoriesCount }; static std::vector GetCategoryNames() { return std::vector(); } public: static void Update() { } static std::string DumpProfiles() { return std::string(); } static std::vector DumpCategories() { return std::vector(); } }; #define OPENMPT_PROFILE_SCOPE(cat, name) do { } while(0) #define OPENMPT_PROFILE_FUNCTION(cat) do { } while(0) #endif // USE_PROFILER OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/serialization_utils.h0000644000175000017500000004043514765307336022040 00000000000000/* * serialization_utils.h * --------------------- * Purpose: Serializing data to and from MPTM files. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/alloc.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "openmpt/base/Endian.hpp" #include "../common/mptBaseTypes.h" #include #include #include #include #include #include #include #include #include #include #include OPENMPT_NAMESPACE_BEGIN #ifdef MPT_ALL_LOGGING #define SSB_LOGGING #endif #ifdef SSB_LOGGING #define SSB_LOG(x) MPT_LOG_GLOBAL(LogDebug, "serialization", x) #else #define SSB_LOG(x) do { } while(0) #endif namespace srlztn //SeRiaLiZaTioN { constexpr inline std::size_t invalidDatasize = static_cast(0) - 1; enum class StatusLevel : uint8 { Failure = 0x2, Note = 0x1, None = 0x0, }; enum class StatusMessages : uint32 { None = 0, // Read notes and warnings. SNR_ZEROENTRYCOUNT = 0x00'00'00'01, SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED = 0x00'00'00'02, SNR_LOADING_OBJECT_WITH_LARGER_VERSION = 0x00'00'00'04, // Read failures. SNR_BADSTREAM_AFTER_MAPHEADERSEEK = 0x00'00'01'00, SNR_STARTBYTE_MISMATCH = 0x00'00'02'00, SNR_BADSTREAM_AT_MAP_READ = 0x00'00'04'00, SNR_INSUFFICIENT_STREAM_OFFTYPE = 0x00'00'08'00, SNR_OBJECTCLASS_IDMISMATCH = 0x00'00'10'00, SNR_TOO_MANY_ENTRIES_TO_READ = 0x00'00'20'00, SNR_INSUFFICIENT_RPOSTYPE = 0x00'00'40'00, // Write failures. SNW_INSUFFICIENT_FIXEDSIZE = 0x00'01'00'00, SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING = 0x00'02'00'00, SNW_DATASIZETYPE_OVERFLOW = 0x00'04'00'00, SNW_MAX_WRITE_COUNT_REACHED = 0x00'08'00'00, SNW_INSUFFICIENT_DATASIZETYPE = 0x00'10'00'00, SNRW_BADGIVEN_STREAM = 0x01'00'00'00, }; struct Status { StatusLevel level = StatusLevel::None; StatusMessages messages = StatusMessages::None; }; constexpr inline Status SNR_ZEROENTRYCOUNT = {StatusLevel::Note, StatusMessages::SNR_ZEROENTRYCOUNT}; constexpr inline Status SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED = {StatusLevel::Note, StatusMessages::SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED}; constexpr inline Status SNR_LOADING_OBJECT_WITH_LARGER_VERSION = {StatusLevel::Note, StatusMessages::SNR_LOADING_OBJECT_WITH_LARGER_VERSION}; constexpr inline Status SNR_BADSTREAM_AFTER_MAPHEADERSEEK = {StatusLevel::Failure, StatusMessages::SNR_BADSTREAM_AFTER_MAPHEADERSEEK}; constexpr inline Status SNR_STARTBYTE_MISMATCH = {StatusLevel::Failure, StatusMessages::SNR_STARTBYTE_MISMATCH}; constexpr inline Status SNR_BADSTREAM_AT_MAP_READ = {StatusLevel::Failure, StatusMessages::SNR_BADSTREAM_AT_MAP_READ}; constexpr inline Status SNR_INSUFFICIENT_STREAM_OFFTYPE = {StatusLevel::Failure, StatusMessages::SNR_INSUFFICIENT_STREAM_OFFTYPE}; constexpr inline Status SNR_OBJECTCLASS_IDMISMATCH = {StatusLevel::Failure, StatusMessages::SNR_OBJECTCLASS_IDMISMATCH}; constexpr inline Status SNR_TOO_MANY_ENTRIES_TO_READ = {StatusLevel::Failure, StatusMessages::SNR_TOO_MANY_ENTRIES_TO_READ}; constexpr inline Status SNR_INSUFFICIENT_RPOSTYPE = {StatusLevel::Failure, StatusMessages::SNR_INSUFFICIENT_RPOSTYPE}; constexpr inline Status SNW_INSUFFICIENT_FIXEDSIZE = {StatusLevel::Failure, StatusMessages::SNW_INSUFFICIENT_FIXEDSIZE}; constexpr inline Status SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING = {StatusLevel::Failure, StatusMessages::SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING}; constexpr inline Status SNW_DATASIZETYPE_OVERFLOW = {StatusLevel::Failure, StatusMessages::SNW_DATASIZETYPE_OVERFLOW}; constexpr inline Status SNW_MAX_WRITE_COUNT_REACHED = {StatusLevel::Failure, StatusMessages::SNW_MAX_WRITE_COUNT_REACHED}; constexpr inline Status SNW_INSUFFICIENT_DATASIZETYPE = {StatusLevel::Failure, StatusMessages::SNW_INSUFFICIENT_DATASIZETYPE}; constexpr inline Status SNRW_BADGIVEN_STREAM = {StatusLevel::Failure, StatusMessages::SNRW_BADGIVEN_STREAM}; enum : uint16 { IdSizeVariable = std::numeric_limits::max(), IdSizeMaxFixedSize = (std::numeric_limits::max() >> 1) }; struct ReadEntry { std::size_t nIdpos = 0; // Index of id start in ID array. std::streamoff rposStart = 0; // Entry start position. std::size_t nSize = invalidDatasize; // Entry size. uint16 nIdLength = 0; // Length of id. }; enum Rwf { RwfWMapStartPosEntry, // Write. True to include data start pos entry to map. RwfWMapSizeEntry, // Write. True to include data size entry to map. RwfWMapDescEntry, // Write. True to include description entry to map. RwfWVersionNum, // Write. True to include version numeric. RwfRMapCached, // Read. True if map has been cached. RwfRMapHasId, // Read. True if map has IDs RwfRMapHasStartpos, // Read. True if map data start pos. RwfRMapHasSize, // Read. True if map has entry size. RwfRMapHasDesc, // Read. True if map has entry description. RwfRTwoBytesDescChar, // Read. True if map description characters are two bytes. RwfRHeaderIsRead, // Read. True when header is read. RwfRwHasMap, // Read/write. True if map exists. RwfNumFlags }; template inline void Binarywrite(std::ostream& oStrm, const T& data) { mpt::IO::WriteIntLE(oStrm, data); } template<> inline void Binarywrite(std::ostream& oStrm, const float& data) { IEEE754binary32LE tmp = IEEE754binary32LE(data); mpt::IO::Write(oStrm, tmp); } template<> inline void Binarywrite(std::ostream& oStrm, const double& data) { IEEE754binary64LE tmp = IEEE754binary64LE(data); mpt::IO::Write(oStrm, tmp); } template inline void WriteItem(std::ostream& oStrm, const T& data) { static_assert(std::is_trivial::value == true, ""); Binarywrite(oStrm, data); } void WriteItemString(std::ostream& oStrm, const std::string &str); template <> inline void WriteItem(std::ostream& oStrm, const std::string& str) {WriteItemString(oStrm, str);} template inline void Binaryread(std::istream& iStrm, T& data) { mpt::IO::ReadIntLE(iStrm, data); } template<> inline void Binaryread(std::istream& iStrm, float& data) { IEEE754binary32LE tmp = IEEE754binary32LE(0.0f); mpt::IO::Read(iStrm, tmp); data = tmp; } template<> inline void Binaryread(std::istream& iStrm, double& data) { IEEE754binary64LE tmp = IEEE754binary64LE(0.0); mpt::IO::Read(iStrm, tmp); data = tmp; } //Read only given number of bytes to the beginning of data; data bytes are memset to 0 before reading. template inline void Binaryread(std::istream& iStrm, T& data, const std::size_t bytecount) { mpt::IO::ReadBinaryTruncatedLE(iStrm, data, bytecount); } template <> inline void Binaryread(std::istream& iStrm, float& data, const std::size_t bytecount) { using T = IEEE754binary32LE; mpt::IO::SeekRelative(iStrm, std::min(bytecount, sizeof(T))); // There is not much we can sanely do for truncated floats, // thus we ignore what we could read and return 0. data = 0.0f; } template <> inline void Binaryread(std::istream& iStrm, double& data, const std::size_t bytecount) { using T = IEEE754binary64LE; mpt::IO::SeekRelative(iStrm, std::min(bytecount, sizeof(T))); // There is not much we can sanely do for truncated floats, // thus we ignore what we could read and return 0. data = 0.0; } template inline void ReadItem(std::istream& iStrm, T& data, const std::size_t nSize) { static_assert(std::is_trivial::value == true, ""); if (nSize == sizeof(T) || nSize == invalidDatasize) Binaryread(iStrm, data); else Binaryread(iStrm, data, nSize); } void ReadItemString(std::istream& iStrm, std::string& str, const std::size_t); template <> inline void ReadItem(std::istream& iStrm, std::string& str, const std::size_t nSize) { ReadItemString(iStrm, str, nSize); } class ID { private: std::string m_ID; // NOTE: can contain null characters ('\0') public: ID() = default; ID(const std::string &id) : m_ID(id) { } ID(const char *id) : m_ID(id ? id : "") { } ID(const char * str, std::size_t len) : m_ID(str, len) { } template static ID FromInt(const T &val) { static_assert(std::numeric_limits::is_integer); typename mpt::make_le::type valle; valle = val; return ID(mpt::byte_cast(mpt::as_raw_memory(valle).data()), mpt::as_raw_memory(valle).size()); } #ifdef SSB_LOGGING bool IsPrintable() const; mpt::ustring AsString() const; #endif std::size_t GetSize() const { return m_ID.size(); } mpt::span AsSpan() const { return mpt::as_span(m_ID); } bool operator == (const ID &other) const { return m_ID == other.m_ID; } bool operator != (const ID &other) const { return m_ID != other.m_ID; } }; class Ssb { protected: Ssb(); public: bool HasFailed() const { return (m_Status.level >= StatusLevel::Failure); } protected: Status m_Status; uint32 m_nFixedEntrySize; // Read/write: If > 0, data entries have given fixed size. std::streamoff m_posStart; // Read/write: Stream position at the beginning of object. uint16 m_nIdbytes; // Read/Write: Tells map ID entry size in bytes. If size is variable, value is IdSizeVariable. std::size_t m_nCounter; // Read/write: Keeps count of entries written/read. std::bitset m_Flags; // Read/write: Various flags. protected: enum : uint8 { s_DefaultFlagbyte = 0 }; static const char s_EntryID[3]; }; class SsbRead : public Ssb { public: using ReadIterator = std::vector::const_iterator; SsbRead(std::istream& iStrm); // Call this to begin reading: must be called before other read functions. void BeginRead(const ID &id, const uint64& nVersion); // After calling BeginRead(), this returns number of entries in the file. std::size_t GetNumEntries() const {return m_nReadEntrycount;} // Returns read iterator to the beginning of entries. // The behaviour of read iterators is undefined if map doesn't // contain entry ids or data begin positions. ReadIterator GetReadBegin(); // Returns read iterator to the end(one past last) of entries. ReadIterator GetReadEnd(); // Compares given id with read entry id bool MatchesId(const ReadIterator& iter, const ID &id); uint64 GetReadVersion() {return m_nReadVersion;} // Read item using default read implementation. template bool ReadItem(T& obj, const ID &id) {return ReadItem(obj, id, srlztn::ReadItem);} // Read item using given function. template bool ReadItem(T& obj, const ID &id, FuncObj); // Read item using read iterator. template bool ReadIterItem(const ReadIterator& iter, T& obj) {return ReadIterItem(iter, obj, srlztn::ReadItem);} template bool ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func); private: // Reads map to cache. void CacheMap(); // Searches for entry with given ID. If found, returns pointer to corresponding entry, else // returns nullptr. const ReadEntry* Find(const ID &id); // Called after reading an object. void OnReadEntry(const ReadEntry* pE, const ID &id, const std::streamoff& posReadBegin); void AddReadNote(const Status s); #ifdef SSB_LOGGING // Called after reading entry. pRe is a pointer to associated map entry if exists. void LogReadEntry(const ReadEntry &pRe, const std::size_t nNum); #endif void ResetReadstatus(); private: // mapData is a cache that facilitates faster access to the stored data // without having to reparse on every access. // Iterator invalidation in CacheMap() is not a problem because every code // path that ever returns an iterator into mapData does CacheMap exactly once // beforehand. Following calls use this already cached map. As the data is // immutable when reading, there is no need to ever invalidate the cache and // redo CacheMap(). std::istream& iStrm; std::vector m_Idarray; // Read: Holds entry ids. std::vector mapData; // Read: Contains map information. uint64 m_nReadVersion; // Read: Version is placed here when reading. std::streamoff m_rposMapBegin; // Read: If map exists, rpos of map begin, else m_rposEndofHdrData. std::streamoff m_posMapEnd; // Read: If map exists, map end position, else pos of end of hdrData. std::streamoff m_posDataBegin; // Read: Data begin position. std::streamoff m_rposEndofHdrData; // Read: rpos of end of header data. std::size_t m_nReadEntrycount; // Read: Number of entries. std::size_t m_nNextReadHint; // Read: Hint where to start looking for the next read entry. }; class SsbWrite : public Ssb { public: SsbWrite(std::ostream& oStrm); // Write header void BeginWrite(const ID &id, const uint64& nVersion); // Write item using default write implementation. template void WriteItem(const T& obj, const ID &id) {WriteItem(obj, id, &srlztn::WriteItem);} // Write item using given function. template void WriteItem(const T& obj, const ID &id, FuncObj); // Writes mapping. void FinishWrite(); private: // Called after writing an item. void OnWroteItem(const ID &id, const std::streamoff& posBeforeWrite); void AddWriteNote(const Status s); #ifdef SSB_LOGGING void LogWriteEntry(const ID &id, const std::size_t nEntryNum, const std::size_t nBytecount, const std::streamoff rposStart); #endif // Writes mapping item to mapstream. void WriteMapItem(const ID &id, const std::streamoff& rposDataStart, const std::size_t& nDatasize, const std::string &pszDesc); void ResetWritestatus() { m_Status = Status{}; } private: std::ostream& oStrm; std::streamoff m_posEntrycount; // Write: Pos of entrycount field. std::streamoff m_posMapPosField; // Write: Pos of map position field. std::string m_MapStreamString; // Write: Map stream string. }; template void SsbWrite::WriteItem(const T& obj, const ID &id, FuncObj Func) { const std::streamoff pos = static_cast(oStrm.tellp()); Func(oStrm, obj); OnWroteItem(id, pos); } template bool SsbRead::ReadItem(T& obj, const ID &id, FuncObj Func) { const ReadEntry* pE = Find(id); const std::streamoff pos = static_cast(iStrm.tellg()); const bool entryFound = (pE || !m_Flags[RwfRMapHasId]); if(entryFound) { Func(iStrm, obj, (pE) ? (pE->nSize) : invalidDatasize); } OnReadEntry(pE, id, pos); return entryFound; } template bool SsbRead::ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func) { iStrm.clear(); if (iter->rposStart != 0) iStrm.seekg(m_posStart + iter->rposStart); const std::streamoff pos = static_cast(iStrm.tellg()); func(iStrm, obj, iter->nSize); OnReadEntry(&(*iter), ID(&m_Idarray[iter->nIdpos], iter->nIdLength), pos); return true; } inline bool SsbRead::MatchesId(const ReadIterator& iter, const ID &id) { if(iter->nIdpos >= m_Idarray.size()) { return false; } return (id == ID(&m_Idarray[iter->nIdpos], iter->nIdLength)); } inline SsbRead::ReadIterator SsbRead::GetReadBegin() { MPT_ASSERT(m_Flags[RwfRMapHasId] && (m_Flags[RwfRMapHasStartpos] || m_Flags[RwfRMapHasSize] || m_nFixedEntrySize > 0)); if(!m_Flags[RwfRMapCached]) CacheMap(); return mapData.begin(); } inline SsbRead::ReadIterator SsbRead::GetReadEnd() { if(!m_Flags[RwfRMapCached]) CacheMap(); return mapData.end(); } template struct VectorWriter { VectorWriter(size_t nCount) : m_nCount(nCount) {} void operator()(std::ostream &oStrm, const std::vector &vec) { for(size_t i = 0; i < m_nCount; i++) { Binarywrite(oStrm, vec[i]); } } size_t m_nCount; }; template struct VectorReader { VectorReader(size_t nCount) : m_nCount(nCount) {} void operator()(std::istream& iStrm, std::vector &vec, const size_t) { vec.resize(m_nCount); for(std::size_t i = 0; i < m_nCount; ++i) { Binaryread(iStrm, vec[i]); } } size_t m_nCount; }; template struct ArrayReader { ArrayReader(size_t nCount) : m_nCount(nCount) {} void operator()(std::istream& iStrm, T* pData, const size_t) { for(std::size_t i=0; i #include #include #include #include #if defined(MODPLUG_TRACKER) #include #endif // MODPLUG_TRACKER OPENMPT_NAMESPACE_BEGIN namespace mpt { enum class CharsetEnum { UTF8, ASCII, // strictly 7-bit ASCII ISO8859_1, ISO8859_15, CP437, CP737, CP775, CP850, CP852, CP855, CP857, CP860, CP861, CP862, CP863, CP864, CP865, CP866, CP869, CP874, CP437AMS, CP437AMS2, Windows1252, Amiga, RISC_OS, AtariST, ISO8859_1_no_C1, ISO8859_15_no_C1, Amiga_no_C1, #if defined(MPT_ENABLE_CHARSET_LOCALE) Locale, // CP_ACP on windows, current C locale otherwise #endif // MPT_ENABLE_CHARSET_LOCALE }; namespace CharsetTable { #define C(x) (mpt::char_value((x))) // AMS1 actually only supports ASCII plus the modified control characters and no high chars at all. // Just default to CP437 for those to keep things simple. inline constexpr char32_t CP437AMS[256] = { C(' '),0x0001,0x0002,0x0003,0x00e4,0x0005,0x00e5,0x0007,0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x00c4,0x00c5, // differs from CP437 0x0010,0x0011,0x0012,0x0013,0x00f6,0x0015,0x0016,0x0017,0x0018,0x00d6,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, // differs from CP437 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2302, 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; // AMS2: Looking at Velvet Studio's bitmap font (TPIC32.PCX), these appear to be the only supported non-ASCII chars. inline constexpr char32_t CP437AMS2[256] = { C(' '),0x00a9,0x221a,0x00b7,C('0'),C('1'),C('2'),C('3'),C('4'),C('5'),C('6'),C('7'),C('8'),C('9'),C('A'),C('B'), // differs from CP437 C('C'),C('D'),C('E'),C('F'),C(' '),0x00a7,C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '), // differs from CP437 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2302, 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 }; #undef C } // namespace CharsetTable struct CharsetTranscoder { private: CharsetEnum m_Charset; public: constexpr CharsetEnum GetCharset() const noexcept { return m_Charset; } constexpr CharsetTranscoder(CharsetEnum charset) noexcept : m_Charset(charset) { return; } constexpr operator CharsetEnum() const noexcept { return m_Charset; } // templated on 8bit strings because of type-safe variants template inline Tdststring encode(const mpt::widestring &src) const { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); switch(m_Charset) { #if defined(MPT_ENABLE_CHARSET_LOCALE) case CharsetEnum::Locale: return mpt::encode(mpt::logical_encoding::locale, src); break; #endif case CharsetEnum::UTF8: return mpt::encode(mpt::common_encoding::utf8, src); break; case CharsetEnum::ASCII: return mpt::encode(mpt::common_encoding::ascii, src); break; case CharsetEnum::ISO8859_1: return mpt::encode(mpt::common_encoding::iso8859_1, src); break; case CharsetEnum::ISO8859_15: return mpt::encode(mpt::common_encoding::iso8859_15, src); break; case CharsetEnum::CP437: return mpt::encode(mpt::common_encoding::cp437, src); break; case CharsetEnum::CP737: return mpt::encode(mpt::common_encoding::cp737, src); break; case CharsetEnum::CP775: return mpt::encode(mpt::common_encoding::cp775, src); break; case CharsetEnum::CP850: return mpt::encode(mpt::common_encoding::cp850, src); break; case CharsetEnum::CP852: return mpt::encode(mpt::common_encoding::cp852, src); break; case CharsetEnum::CP855: return mpt::encode(mpt::common_encoding::cp855, src); break; case CharsetEnum::CP857: return mpt::encode(mpt::common_encoding::cp857, src); break; case CharsetEnum::CP860: return mpt::encode(mpt::common_encoding::cp860, src); break; case CharsetEnum::CP861: return mpt::encode(mpt::common_encoding::cp861, src); break; case CharsetEnum::CP862: return mpt::encode(mpt::common_encoding::cp862, src); break; case CharsetEnum::CP863: return mpt::encode(mpt::common_encoding::cp863, src); break; case CharsetEnum::CP864: return mpt::encode(mpt::common_encoding::cp864, src); break; case CharsetEnum::CP865: return mpt::encode(mpt::common_encoding::cp865, src); break; case CharsetEnum::CP866: return mpt::encode(mpt::common_encoding::cp866, src); break; case CharsetEnum::CP869: return mpt::encode(mpt::common_encoding::cp869, src); break; case CharsetEnum::CP874: return mpt::encode(mpt::common_encoding::cp874, src); break; case CharsetEnum::CP437AMS: return mpt::encode(CharsetTable::CP437AMS, src); break; case CharsetEnum::CP437AMS2: return mpt::encode(CharsetTable::CP437AMS2, src); break; case CharsetEnum::Windows1252: return mpt::encode(mpt::common_encoding::windows1252, src); break; case CharsetEnum::Amiga: return mpt::encode(mpt::common_encoding::amiga, src); break; case CharsetEnum::RISC_OS: return mpt::encode(mpt::common_encoding::riscos, src); break; case CharsetEnum::AtariST: return mpt::encode(mpt::common_encoding::atarist, src); break; case CharsetEnum::ISO8859_1_no_C1: return mpt::encode(mpt::common_encoding::iso8859_1_no_c1, src); break; case CharsetEnum::ISO8859_15_no_C1: return mpt::encode(mpt::common_encoding::iso8859_15_no_c1, src); break; case CharsetEnum::Amiga_no_C1: return mpt::encode(mpt::common_encoding::amiga_no_c1, src); break; } return Tdststring(); } // templated on 8bit strings because of type-safe variants template inline mpt::widestring decode(const Tsrcstring &src) const { static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); switch(m_Charset) { #if defined(MPT_ENABLE_CHARSET_LOCALE) case CharsetEnum::Locale: return mpt::decode(mpt::logical_encoding::locale, src); break; #endif case CharsetEnum::UTF8: return mpt::decode(mpt::common_encoding::utf8, src); break; case CharsetEnum::ASCII: return mpt::decode(mpt::common_encoding::ascii, src); break; case CharsetEnum::ISO8859_1: return mpt::decode(mpt::common_encoding::iso8859_1, src); break; case CharsetEnum::ISO8859_15: return mpt::decode(mpt::common_encoding::iso8859_15, src); break; case CharsetEnum::CP437: return mpt::decode(mpt::common_encoding::cp437, src); break; case CharsetEnum::CP737: return mpt::decode(mpt::common_encoding::cp737, src); break; case CharsetEnum::CP775: return mpt::decode(mpt::common_encoding::cp775, src); break; case CharsetEnum::CP850: return mpt::decode(mpt::common_encoding::cp850, src); break; case CharsetEnum::CP852: return mpt::decode(mpt::common_encoding::cp852, src); break; case CharsetEnum::CP855: return mpt::decode(mpt::common_encoding::cp855, src); break; case CharsetEnum::CP857: return mpt::decode(mpt::common_encoding::cp857, src); break; case CharsetEnum::CP860: return mpt::decode(mpt::common_encoding::cp860, src); break; case CharsetEnum::CP861: return mpt::decode(mpt::common_encoding::cp861, src); break; case CharsetEnum::CP862: return mpt::decode(mpt::common_encoding::cp862, src); break; case CharsetEnum::CP863: return mpt::decode(mpt::common_encoding::cp863, src); break; case CharsetEnum::CP864: return mpt::decode(mpt::common_encoding::cp864, src); break; case CharsetEnum::CP865: return mpt::decode(mpt::common_encoding::cp865, src); break; case CharsetEnum::CP866: return mpt::decode(mpt::common_encoding::cp866, src); break; case CharsetEnum::CP869: return mpt::decode(mpt::common_encoding::cp869, src); break; case CharsetEnum::CP874: return mpt::decode(mpt::common_encoding::cp874, src); break; case CharsetEnum::CP437AMS: return mpt::decode(CharsetTable::CP437AMS, src); break; case CharsetEnum::CP437AMS2: return mpt::decode(CharsetTable::CP437AMS2, src); break; case CharsetEnum::Windows1252: return mpt::decode(mpt::common_encoding::windows1252, src); break; case CharsetEnum::Amiga: return mpt::decode(mpt::common_encoding::amiga, src); break; case CharsetEnum::RISC_OS: return mpt::decode(mpt::common_encoding::riscos, src); break; case CharsetEnum::AtariST: return mpt::decode(mpt::common_encoding::atarist, src); break; case CharsetEnum::ISO8859_1_no_C1: return mpt::decode(mpt::common_encoding::iso8859_1_no_c1, src); break; case CharsetEnum::ISO8859_15_no_C1: return mpt::decode(mpt::common_encoding::iso8859_15_no_c1, src); break; case CharsetEnum::Amiga_no_C1: return mpt::decode(mpt::common_encoding::amiga_no_c1, src); break; } return mpt::widestring(); } }; struct Charset : public CharsetTranscoder { constexpr Charset(mpt::CharsetEnum charset) noexcept : CharsetTranscoder(charset) { return; } constexpr Charset(mpt::CharsetTranscoder charset) noexcept : CharsetTranscoder(charset.GetCharset()) { return; } static inline constexpr auto UTF8 = mpt::CharsetTranscoder{ mpt::CharsetEnum::UTF8 }; static inline constexpr auto ASCII = mpt::CharsetTranscoder{ mpt::CharsetEnum::ASCII }; static inline constexpr auto ISO8859_1 = mpt::CharsetTranscoder{ mpt::CharsetEnum::ISO8859_1 }; static inline constexpr auto ISO8859_15 = mpt::CharsetTranscoder{ mpt::CharsetEnum::ISO8859_15 }; static inline constexpr auto CP437 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP437 }; static inline constexpr auto CP737 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP737 }; static inline constexpr auto CP775 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP775 }; static inline constexpr auto CP850 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP850 }; static inline constexpr auto CP852 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP852 }; static inline constexpr auto CP855 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP855 }; static inline constexpr auto CP857 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP857 }; static inline constexpr auto CP860 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP860 }; static inline constexpr auto CP861 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP861 }; static inline constexpr auto CP862 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP862 }; static inline constexpr auto CP863 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP863 }; static inline constexpr auto CP864 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP864 }; static inline constexpr auto CP865 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP865 }; static inline constexpr auto CP866 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP866 }; static inline constexpr auto CP869 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP869 }; static inline constexpr auto CP874 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP874 }; static inline constexpr auto CP437AMS = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP437AMS }; static inline constexpr auto CP437AMS2 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP437AMS2 }; static inline constexpr auto Windows1252 = mpt::CharsetTranscoder{ mpt::CharsetEnum::Windows1252 }; static inline constexpr auto Amiga = mpt::CharsetTranscoder{ mpt::CharsetEnum::Amiga }; static inline constexpr auto RISC_OS = mpt::CharsetTranscoder{ mpt::CharsetEnum::RISC_OS }; static inline constexpr auto AtariST = mpt::CharsetTranscoder{ mpt::CharsetEnum::AtariST }; static inline constexpr auto ISO8859_1_no_C1 = mpt::CharsetTranscoder{ mpt::CharsetEnum::ISO8859_1_no_C1 }; static inline constexpr auto ISO8859_15_no_C1 = mpt::CharsetTranscoder{ mpt::CharsetEnum::ISO8859_15_no_C1 }; static inline constexpr auto Amiga_no_C1 = mpt::CharsetTranscoder{ mpt::CharsetEnum::Amiga_no_C1 }; #if defined(MPT_ENABLE_CHARSET_LOCALE) static inline constexpr auto Locale = mpt::CharsetTranscoder{ mpt::CharsetEnum::Locale }; #endif // MPT_ENABLE_CHARSET_LOCALE }; // Checks if the std::string represents an UTF8 string. // This is currently implemented as converting to std::wstring and back assuming UTF8 both ways, // and comparing the result to the original string. // Caveats: // - can give false negatives because of possible unicode normalization during conversion // - can give false positives if the 8bit encoding contains high-ascii only in valid utf8 groups // - slow because of double conversion inline bool IsUTF8(const std::string &str) { return mpt::is_utf8(str); } template inline mpt::ustring ToUnicode(Tsrc &&str) { return mpt::transcode(std::forward(str)); } template inline mpt::ustring ToUnicode(Tencoding &&from, Tsrc &&str) { return mpt::transcode(std::forward(from), std::forward(str)); } #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) // Convert to a wide character string. // The wide encoding is UTF-16 or UTF-32, based on sizeof(wchar_t). // If str does not contain any invalid characters, this conversion is lossless. // Invalid source bytes will be replaced by some replacement character or string. template inline std::wstring ToWide(Tsrc &&str) { return mpt::transcode(std::forward(str)); } template inline std::wstring ToWide(Tencoding &&from, Tsrc &&str) { return mpt::transcode(std::forward(from), std::forward(str)); } #endif // Convert to a string encoded in the 'to'-specified character set. // If str does not contain any invalid characters, // this conversion will be lossless iff, and only iff, // 'to' is UTF8. // Invalid source bytes or characters that are not representable in the // destination charset will be replaced by some replacement character or string. template inline std::string ToCharset(Tencoding &&to, Tsrc &&str) { return mpt::transcode(std::forward(to), std::forward(str)); } template inline std::string ToCharset(Tto &&to, Tfrom &&from, Tsrc &&str) { return mpt::transcode(std::forward(to), std::forward(from), std::forward(str)); } #if defined(MPT_ENABLE_CHARSET_LOCALE) template inline mpt::lstring ToLocale(Tsrc &&str) { return mpt::transcode(std::forward(str)); } template inline mpt::lstring ToLocale(Tencoding &&from, Tsrc &&str) { return mpt::transcode(std::forward(from), std::forward(str)); } #endif // MPT_ENABLE_CHARSET_LOCALE #if MPT_OS_WINDOWS template inline mpt::winstring ToWin(Tsrc &&str) { return mpt::transcode(std::forward(str)); } template inline mpt::winstring ToWin(Tencoding &&from, Tsrc &&str) { return mpt::transcode(std::forward(from), std::forward(str)); } #endif // MPT_OS_WINDOWS #if defined(MPT_WITH_MFC) template inline CString ToCString(Tsrc &&str) { return mpt::transcode(std::forward(str)); } template inline CString ToCString(Tencoding &&from, Tsrc &&str) { return mpt::transcode(std::forward(from), std::forward(str)); } #endif // MPT_WITH_MFC #define UC_(x) MPT_UCHAR(x) #define UL_(x) MPT_ULITERAL(x) #define UV_(x) MPT_USTRINGVIEW(x) #define U_(x) MPT_USTRING(x) // The MPT_UTF8 allows specifying UTF8 char arrays. // The resulting type is mpt::ustring and the construction might require runtime translation, // i.e. it is NOT generally available at compile time. // Use explicit UTF8 encoding, // i.e. U+00FC (LATIN SMALL LETTER U WITH DIAERESIS) would be written as "\xC3\xBC". #define MPT_UTF8(x) mpt::transcode(mpt::common_encoding::utf8, x) template inline mpt::ustring ToUnicode(uint16 codepage, Tencoding &&fallback, Tsrc &&str) { #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) mpt::ustring result; std::optional charset = mpt::optional_encoding_from_codepage(codepage); if(charset.has_value()) { #if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE) result = mpt::transcode(*charset, std::forward(str)); #else result = mpt::transcode(charset.value(), std::forward(str)); #endif } else if(mpt::has_codepage(static_cast(codepage))) { result = mpt::transcode(static_cast(codepage), std::forward(str)); } else { result = mpt::transcode(std::forward(fallback), std::forward(str)); } return result; #else // !MPT_OS_WINDOWS std::optional charset = mpt::optional_encoding_from_codepage(codepage); #if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE) return charset.has_value() ? mpt::transcode(charset.value(), std::forward(str)) : mpt::transcode(std::forward(fallback), std::forward(str)); #else return charset.has_value() ? mpt::transcode(*charset, std::forward(str)) : mpt::transcode(std::forward(fallback), std::forward(str)); #endif #endif // MPT_OS_WINDOWS } inline char ToLowerCaseAscii(char c) { return mpt::to_lower_ascii(c); } inline char ToUpperCaseAscii(char c) { return mpt::to_upper_ascii(c); } inline std::string ToLowerCaseAscii(std::string s) { std::transform(s.begin(), s.end(), s.begin(), static_cast(&mpt::ToLowerCaseAscii)); return s; } inline std::string ToUpperCaseAscii(std::string s) { std::transform(s.begin(), s.end(), s.begin(), static_cast(&mpt::ToUpperCaseAscii)); return s; } inline int CompareNoCaseAscii(const char *a, const char *b, std::size_t n) { while(n--) { unsigned char ac = mpt::char_value(mpt::ToLowerCaseAscii(*a)); unsigned char bc = mpt::char_value(mpt::ToLowerCaseAscii(*b)); if(ac != bc) { return ac < bc ? -1 : 1; } else if(!ac && !bc) { return 0; } ++a; ++b; } return 0; } inline int CompareNoCaseAscii(std::string_view a, std::string_view b) { for(std::size_t i = 0; i < std::min(a.length(), b.length()); ++i) { unsigned char ac = mpt::char_value(mpt::ToLowerCaseAscii(a[i])); unsigned char bc = mpt::char_value(mpt::ToLowerCaseAscii(b[i])); if(ac != bc) { return ac < bc ? -1 : 1; } else if(!ac && !bc) { return 0; } } if(a.length() == b.length()) { return 0; } return a.length() < b.length() ? -1 : 1; } inline int CompareNoCaseAscii(const std::string &a, const std::string &b) { return CompareNoCaseAscii(std::string_view(a), std::string_view(b)); } #if defined(MODPLUG_TRACKER) inline mpt::ustring ToLowerCase(const mpt::ustring &s) { #if defined(MPT_WITH_MFC) #if defined(UNICODE) return mpt::transcode(mpt::transcode(s).MakeLower()); #else // !UNICODE return mpt::transcode(mpt::transcode(s).MakeLower()); #endif // UNICODE #else // !MPT_WITH_MFC std::wstring ws = mpt::transcode(s); std::transform(ws.begin(), ws.end(), ws.begin(), &std::towlower); return mpt::transcode(ws); #endif // MPT_WITH_MFC } inline mpt::ustring ToUpperCase(const mpt::ustring &s) { #if defined(MPT_WITH_MFC) #if defined(UNICODE) return mpt::transcode(mpt::transcode(s).MakeUpper()); #else // !UNICODE return mpt::transcode(mpt::transcode(s).MakeUpper()); #endif // UNICODE #else // !MPT_WITH_MFC std::wstring ws = mpt::transcode(s); std::transform(ws.begin(), ws.end(), ws.begin(), &std::towupper); return mpt::transcode(ws); #endif // MPT_WITH_MFC } #endif // MODPLUG_TRACKER } // namespace mpt // The AnyString types are meant to be used as function argument types only, // and only during the transition phase to all-unicode strings in the whole codebase. // Using an AnyString type as function argument avoids the need to overload a function for all the // different string types that we currently have. // Warning: These types will silently do charset conversions. Only use them when this can be tolerated. // BasicAnyString is convertable to mpt::ustring and constructable from any string at all. template class BasicAnyString : public mpt::ustring { private: static mpt::ustring From8bit(std::string str) { if constexpr(charset == mpt::CharsetEnum::UTF8) { return mpt::transcode(mpt::common_encoding::utf8, std::move(str)); } else { // auto utf8 detection if constexpr(tryUTF8) { if(mpt::is_utf8(str)) { return mpt::transcode(mpt::common_encoding::utf8, std::move(str)); } else { return mpt::transcode(mpt::CharsetTranscoder(charset), std::move(str)); } } else { return mpt::transcode(mpt::CharsetTranscoder(charset), std::move(str)); } } } public: // 8 bit BasicAnyString(const char *str) : mpt::ustring(From8bit(str ? str : std::string())) { return; } BasicAnyString(std::string str) : mpt::ustring(From8bit(std::move(str))) { return; } template BasicAnyString(Tstring &&str) : mpt::ustring(mpt::transcode(std::forward(str))) { return; } }; // AnyUnicodeString is convertable to mpt::ustring and constructable from any known encoding class AnyUnicodeString : public mpt::ustring { public: template AnyUnicodeString(Tstring &&str) : mpt::ustring(mpt::transcode(std::forward(str))) { return; } }; // AnyString // Try to do the smartest auto-magic we can do. #if defined(MPT_ENABLE_CHARSET_LOCALE) using AnyString = BasicAnyString; #elif MPT_OS_WINDOWS using AnyString = BasicAnyString; #else using AnyString = BasicAnyString; #endif // AnyStringLocale // char-based strings are assumed to be in locale encoding. #if defined(MPT_ENABLE_CHARSET_LOCALE) using AnyStringLocale = BasicAnyString; #else using AnyStringLocale = BasicAnyString; #endif // AnyStringUTF8orLocale // char-based strings are tried in UTF8 first, if this fails, locale is used. #if defined(MPT_ENABLE_CHARSET_LOCALE) using AnyStringUTF8orLocale = BasicAnyString; #else using AnyStringUTF8orLocale = BasicAnyString; #endif // AnyStringUTF8 // char-based strings are assumed to be in UTF8. using AnyStringUTF8 = BasicAnyString; OPENMPT_NAMESPACE_END template struct mpt::make_string_type> { using type = mpt::ustring; }; template <> struct mpt::make_string_type { using type = mpt::ustring; }; libopenmpt-0.8.1+release.autotools/common/mptRandom.cpp0000644000175000017500000000365014617421600020220 00000000000000/* * mptRandom.cpp * ------------- * Purpose: PRNG * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "mptRandom.h" OPENMPT_NAMESPACE_BEGIN namespace mpt { #if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT) static mpt::random_device *g_rd = nullptr; static mpt::thread_safe_prng *g_global_prng = nullptr; void set_global_random_device(mpt::random_device *rd) { g_rd = rd; } void set_global_prng(mpt::thread_safe_prng *prng) { g_global_prng = prng; } mpt::random_device & global_random_device() { return *g_rd; } mpt::thread_safe_prng & global_prng() { return *g_global_prng; } #else mpt::random_device & global_random_device() { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wexit-time-destructors" #endif // MPT_COMPILER_CLANG static mpt::random_device g_rd; #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG return g_rd; } mpt::thread_safe_prng & global_prng() { #if MPT_COMPILER_CLANG #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wexit-time-destructors" #endif // MPT_COMPILER_CLANG static mpt::thread_safe_prng g_global_prng(mpt::make_prng(global_random_device())); #if MPT_COMPILER_CLANG #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG return g_global_prng; } #ifdef MPT_BUILD_FUZZER void reinit_global_random() { global_prng().~thread_safe_prng(); global_random_device().~random_device(); new(&global_random_device()) mpt::random_device{}; new(&global_prng()) thread_safe_prng{global_random_device()}; } #endif // MPT_BUILD_FUZZER #endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT } // namespace mpt OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/common/BuildSettings.h0000644000175000017500000002156014767226626020525 00000000000000/* * BuildSettings.h * --------------- * Purpose: Global, user settable compile time flags (and some global system header configuration) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "BuildSettingsCompiler.h" #include "mpt/base/detect_arch.hpp" #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_os.hpp" #include "mpt/base/detect_quirks.hpp" #if defined(MODPLUG_TRACKER) && defined(LIBOPENMPT_BUILD) #error "either MODPLUG_TRACKER or LIBOPENMPT_BUILD has to be defined" #elif defined(MODPLUG_TRACKER) // nothing #define MPT_INLINE_NS mptx #elif defined(LIBOPENMPT_BUILD) // nothing #define MPT_INLINE_NS mpt_libopenmpt #else #error "either MODPLUG_TRACKER or LIBOPENMPT_BUILD has to be defined" #endif // MODPLUG_TRACKER || LIBOPENMPT_BUILD #if defined(MODPLUG_TRACKER) #if defined(MPT_BUILD_RETRO) #define OPENMPT_BUILD_VARIANT "Retro" #define OPENMPT_BUILD_VARIANT_MONIKER " RETRO" #else #if MPT_OS_WINDOWS #if MPT_WINNT_AT_LEAST(MPT_WIN_10) #define OPENMPT_BUILD_VARIANT "Standard" #define OPENMPT_BUILD_VARIANT_MONIKER "" #else #define OPENMPT_BUILD_VARIANT "Legacy" #define OPENMPT_BUILD_VARIANT_MONIKER "" #endif #else #define OPENMPT_BUILD_VARIANT "Unknown" #define OPENMPT_BUILD_VARIANT_MONIKER "" #endif #endif #define MPT_WITH_DMO #define MPT_WITH_VST #if MPT_OS_WINDOWS #if MPT_WINNT_AT_LEAST(MPT_WIN_7) #define MPT_WITH_MEDIAFOUNDATION #endif #endif #if MPT_OS_WINDOWS #if MPT_WINNT_AT_LEAST(MPT_WIN_10) #define MPT_WITH_WINDOWS10 #endif #endif #endif // MODPLUG_TRACKER #if defined(MODPLUG_TRACKER) // Enable built-in test suite. #if defined(MPT_BUILD_DEBUG) || defined(MPT_BUILD_CHECKED) #define ENABLE_TESTS #endif // Enable generation and verification of playback traces #define MPT_ENABLE_PLAYBACK_TRACE // Disable any file saving functionality (not really useful except for the player library) //#define MODPLUG_NO_FILESAVE // Disable any debug logging #if !defined(MPT_BUILD_DEBUG) && !defined(MPT_BUILD_CHECKED) && !defined(MPT_BUILD_WINESUPPORT) #define MPT_LOG_GLOBAL_LEVEL_STATIC #define MPT_LOG_GLOBAL_LEVEL 0 #endif // Enable all individual logging macros and MPT_LOG calls //#define MPT_ALL_LOGGING // Disable all runtime asserts #if !defined(MPT_BUILD_DEBUG) && !defined(MPT_BUILD_CHECKED) && !defined(MPT_BUILD_WINESUPPORT) #define NO_ASSERTS #endif // Enable global ComponentManager #define MPT_COMPONENT_MANAGER 1 // Support for externally linked samples e.g. in MPTM files #define MPT_EXTERNAL_SAMPLES // Support mpt::CharsetLocale #define MPT_ENABLE_CHARSET_LOCALE // Use architecture-specific intrinsics #define MPT_ENABLE_ARCH_INTRINSICS #define MPT_ENABLE_UPDATE #if defined(MPT_BUILD_DEBUG) #define MPT_ENABLE_PLAYBACK_TEST_MENU #endif // Disable unarchiving support //#define NO_ARCHIVE_SUPPORT // Disable the built-in reverb effect //#define NO_REVERB // Disable built-in miscellaneous DSP effects (surround, mega bass, noise reduction) //#define NO_DSP // Disable the built-in equalizer. //#define NO_EQ // Disable the built-in automatic gain control //#define NO_AGC // (HACK) Define to build without any plugin support //#define NO_PLUGINS #endif // MODPLUG_TRACKER #if defined(LIBOPENMPT_BUILD) #ifdef MPT_WITH_FLAC #error "Building libopenmpt with FLAC is useless and not a supported configuration. Please fix your build system to not list libflac as a dependency for libopenmpt itself. It is only a dependency of openmpt123." #endif #ifndef LIBOPENMPT_NO_DEPRECATE #define LIBOPENMPT_NO_DEPRECATE #endif #if (defined(_DEBUG) || defined(DEBUG)) && !defined(MPT_BUILD_DEBUG) #define MPT_BUILD_DEBUG #endif #if defined(LIBOPENMPT_BUILD_TEST) #define ENABLE_TESTS #define MPT_ENABLE_PLAYBACK_TRACE #else #define MODPLUG_NO_FILESAVE #endif #if defined(MPT_BUILD_ANALZYED) || defined(MPT_BUILD_DEBUG) || defined(MPT_BUILD_CHECKED) || defined(ENABLE_TESTS) // enable asserts #else #define NO_ASSERTS #endif //#define MPT_ALL_LOGGING #define MPT_COMPONENT_MANAGER 0 //#define MPT_EXTERNAL_SAMPLES #if defined(ENABLE_TESTS) || defined(MPT_BUILD_HACK_ARCHIVE_SUPPORT) #define MPT_ENABLE_CHARSET_LOCALE #else //#define MPT_ENABLE_CHARSET_LOCALE #endif // Do not use architecture-specifid intrinsics in library builds. There is just about no codepath which would use it anyway. //#define MPT_ENABLE_ARCH_INTRINSICS #if defined(MPT_BUILD_HACK_ARCHIVE_SUPPORT) //#define NO_ARCHIVE_SUPPORT #else #define NO_ARCHIVE_SUPPORT #endif //#define NO_REVERB #define NO_DSP #define NO_EQ #define NO_AGC //#define NO_PLUGINS #endif // LIBOPENMPT_BUILD #if MPT_OS_WINDOWS #ifndef MPT_ENABLE_CHARSET_LOCALE #define MPT_ENABLE_CHARSET_LOCALE #endif #elif MPT_OS_LINUX #elif MPT_OS_ANDROID #elif MPT_OS_EMSCRIPTEN #elif MPT_OS_MACOSX_OR_IOS #elif MPT_OS_DJGPP #endif #define MPT_TIME_UTC_ON_DISK 0 #define MPT_TIME_UTC_ON_DISK_VERSION MPT_V("1.31.00.13") // fixing stuff up #if defined(MPT_BUILD_ANALYZED) || defined(MPT_BUILD_CHECKED) #ifdef NO_ASSERTS #undef NO_ASSERTS // static or dynamic analyzers want assertions on #endif #endif #if defined(MPT_BUILD_FUZZER) #ifndef MPT_FUZZ_TRACKER #define MPT_FUZZ_TRACKER #endif #endif #if defined(MPT_ENABLE_ARCH_INTRINSICS) #if MPT_ARCH_X86 #define MPT_ENABLE_ARCH_X86 #define MPT_WANT_ARCH_INTRINSICS_X86_SSE #define MPT_WANT_ARCH_INTRINSICS_X86_SSE2 #elif MPT_ARCH_AMD64 #define MPT_ENABLE_ARCH_AMD64 #define MPT_WANT_ARCH_INTRINSICS_X86_SSE #define MPT_WANT_ARCH_INTRINSICS_X86_SSE2 #endif // arch #endif // MPT_ENABLE_ARCH_INTRINSICS #if defined(ENABLE_TESTS) && defined(MODPLUG_NO_FILESAVE) #undef MODPLUG_NO_FILESAVE // tests recommend file saving #endif #if defined(MPT_WITH_ZLIB) && defined(MPT_WITH_MINIZ) // Only one deflate implementation should be used. Prefer zlib. #undef MPT_WITH_MINIZ #endif #if !MPT_OS_WINDOWS && defined(MPT_WITH_MEDIAFOUNDATION) #undef MPT_WITH_MEDIAFOUNDATION // MediaFoundation requires Windows #endif #if !MPT_COMPILER_MSVC && !MPT_COMPILER_CLANG && defined(MPT_WITH_MEDIAFOUNDATION) #undef MPT_WITH_MEDIAFOUNDATION // MediaFoundation requires MSVC or Clang due to ATL (no MinGW support) #endif #if (defined(MPT_WITH_MPG123) || defined(MPT_WITH_MINIMP3)) && !defined(MPT_ENABLE_MP3_SAMPLES) #define MPT_ENABLE_MP3_SAMPLES #endif #if defined(ENABLE_TESTS) #define MPT_ENABLE_FILEIO // Test suite requires PathString for file loading. #endif #if defined(MODPLUG_TRACKER) && !defined(MPT_ENABLE_FILEIO) #define MPT_ENABLE_FILEIO // Tracker requires disk file io #endif #if defined(MPT_EXTERNAL_SAMPLES) && !defined(MPT_ENABLE_FILEIO) #define MPT_ENABLE_FILEIO // External samples require disk file io #endif #if defined(NO_PLUGINS) // Any plugin type requires NO_PLUGINS to not be defined. #if defined(MPT_WITH_VST) #undef MPT_WITH_VST #endif #endif #if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT) && !defined(MPT_BUILD_WINESUPPORT_WRAPPER) #ifndef MPT_NO_NAMESPACE #define MPT_NO_NAMESPACE #endif #endif #if defined(MPT_NO_NAMESPACE) #ifdef OPENMPT_NAMESPACE #undef OPENMPT_NAMESPACE #endif #define OPENMPT_NAMESPACE #ifdef OPENMPT_NAMESPACE_BEGIN #undef OPENMPT_NAMESPACE_BEGIN #endif #define OPENMPT_NAMESPACE_BEGIN #ifdef OPENMPT_NAMESPACE_END #undef OPENMPT_NAMESPACE_END #endif #define OPENMPT_NAMESPACE_END #else #ifndef OPENMPT_NAMESPACE #define OPENMPT_NAMESPACE OpenMPT #endif #ifndef OPENMPT_NAMESPACE_BEGIN #define OPENMPT_NAMESPACE_BEGIN namespace OPENMPT_NAMESPACE { #endif #ifndef OPENMPT_NAMESPACE_END #define OPENMPT_NAMESPACE_END } #endif #endif #define MPT_CONFIGURATION_IO_READ_FILEDATA_NO_64BIT // platform configuration #if MPT_OS_WINDOWS #define WIN32_LEAN_AND_MEAN // windows.h excludes #define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines #ifndef NOMINMAX #define NOMINMAX // Macros min(a,b) and max(a,b) #endif #define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc. #define NOCOMM // COMM driver routines #define NOKANJI // Kanji support stuff. #define NOPROFILER // Profiler interface. #define NOMCX // Modem Configuration Extensions // mmsystem.h excludes #define MMNODRV //#define MMNOSOUND //#define MMNOWAVE //#define MMNOMIDI #define MMNOAUX #define MMNOMIXER //#define MMNOTIMER #define MMNOJOY #define MMNOMCI //#define MMNOMMIO //#define MMNOMMSYSTEM // mmreg.h excludes #define NOMMIDS //#define NONEWWAVE #define NONEWRIFF #define NOJPEGDIB #define NONEWIC #define NOBITMAP #endif // MPT_OS_WINDOWS // third-party library configuration #ifdef MPT_WITH_STBVORBIS #ifndef STB_VORBIS_HEADER_ONLY #define STB_VORBIS_HEADER_ONLY #endif #endif #ifdef MPT_WITH_VORBISFILE #ifndef OV_EXCLUDE_STATIC_CALLBACKS #define OV_EXCLUDE_STATIC_CALLBACKS #endif #endif #ifdef __cplusplus #include "mpt/base/namespace.hpp" OPENMPT_NAMESPACE_BEGIN namespace mpt { #ifndef MPT_NO_NAMESPACE using namespace ::mpt; #endif } // namespace mpt OPENMPT_NAMESPACE_END #endif libopenmpt-0.8.1+release.autotools/common/stdafx.h0000644000175000017500000000612614660143604017221 00000000000000/* * StdAfx.h * -------- * Purpose: Include file for standard system include files, or project specific include files that are used frequently, but are changed infrequently. Also includes the global build settings from openmpt/all/BuildSettings.hpp. * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once // has to be first #include "openmpt/all/BuildSettings.hpp" #include "openmpt/all/PlatformFixes.hpp" #if defined(MODPLUG_TRACKER) #if defined(MPT_WITH_MFC) // cppcheck-suppress missingInclude #include // MFC core // cppcheck-suppress missingInclude #include // MFC standard components // cppcheck-suppress missingInclude #include // MFC extensions // cppcheck-suppress missingInclude #include // MFC support for Windows Common Controls // cppcheck-suppress missingInclude #include // cppcheck-suppress missingInclude #include #ifndef _AFX_NO_MFC_CONTROLS_IN_DIALOGS // cppcheck-suppress missingInclude #include #endif // !_AFX_NO_MFC_CONTROLS_IN_DIALOGS // cppcheck-suppress missingInclude #include #endif // MPT_WITH_MFC #if MPT_OS_WINDOWS #include #include #include #include #endif // MPT_OS_WINDOWS #endif // MODPLUG_TRACKER #if MPT_COMPILER_MSVC #include #endif #include "mpt/check/compiler.hpp" #include "mpt/check/libc.hpp" #include "mpt/check/libcxx.hpp" #if defined(MPT_WITH_MFC) #include "mpt/check/mfc.hpp" #endif #if MPT_OS_WINDOWS #include "mpt/check/windows.hpp" #endif #include "mpt/base/span.hpp" #include "mpt/exception/exception.hpp" #include "mpt/exception/exception_text.hpp" #include "mpt/out_of_memory/out_of_memory.hpp" #include "mpt/string/types.hpp" #include "mpt/system_error/system_error.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/logging/Logger.hpp" #include #include // this will be available everywhere #include "../common/mptBaseMacros.h" // // // // // // #include "../common/mptBaseTypes.h" // "openmpt/base/Types.hpp" // "mptBaseMacros.h" // // // // #include "../common/mptAssert.h" // "mptBaseMacros.h" #include "../common/mptBaseUtils.h" // // // // // #include "../common/mptString.h" // // // // // // #include "../common/mptStringBuffer.h" #include "../common/mptStringFormat.h" // #include "../common/mptPathString.h" #include "../common/Logging.h" // "openmpt/logging/Logger.hpp" // #include "../common/misc_util.h" // // // // for std::abs #include #include #include #include //{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately before the previous line. libopenmpt-0.8.1+release.autotools/common/FileReader.h0000644000175000017500000003374714502511125017733 00000000000000/* * FileReader.h * ------------ * Purpose: A basic class for transparent reading of memory-based files. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/io_read/filecursor.hpp" #include "mpt/io_read/filecursor_filename_traits.hpp" #include "mpt/io_read/filecursor_traits_filedata.hpp" #include "mpt/io_read/filecursor_traits_memory.hpp" #include "mpt/io_read/filereader.hpp" #include "openmpt/base/Types.hpp" #include "mptPathString.h" #include "mptStringBuffer.h" #include #include #include #include #include #include #include #include #include "FileReaderFwd.h" OPENMPT_NAMESPACE_BEGIN namespace FileReaderExt { // Read a string of length srcSize into fixed-length char array destBuffer using a given read mode. // The file cursor is advanced by "srcSize" bytes. // Returns true if at least one byte could be read or 0 bytes were requested. template bool ReadString(TFileCursor &f, char (&destBuffer)[destSize], const std::size_t srcSize) { typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly. std::size_t realSrcSize = source.size(); // In case fewer bytes are available mpt::String::WriteAutoBuf(destBuffer) = mpt::String::ReadBuf(mode, mpt::byte_cast(source.data()), realSrcSize); return (realSrcSize > 0 || srcSize == 0); } // Read a string of length srcSize into a std::string dest using a given read mode. // The file cursor is advanced by "srcSize" bytes. // Returns true if at least one character could be read or 0 characters were requested. template bool ReadString(TFileCursor &f, std::string &dest, const std::size_t srcSize) { dest.clear(); typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly. std::size_t realSrcSize = source.size(); // In case fewer bytes are available dest = mpt::String::ReadBuf(mode, mpt::byte_cast(source.data()), realSrcSize); return (realSrcSize > 0 || srcSize == 0); } // Read a string of length srcSize into a mpt::charbuf dest using a given read mode. // The file cursor is advanced by "srcSize" bytes. // Returns true if at least one character could be read or 0 characters were requested. template bool ReadString(TFileCursor &f, mpt::charbuf &dest, const std::size_t srcSize) { typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly. std::size_t realSrcSize = source.size(); // In case fewer bytes are available dest = mpt::String::ReadBuf(mode, mpt::byte_cast(source.data()), realSrcSize); return (realSrcSize > 0 || srcSize == 0); } // Read a charset encoded string of length srcSize into a mpt::ustring dest using a given read mode. // The file cursor is advanced by "srcSize" bytes. // Returns true if at least one character could be read or 0 characters were requested. template bool ReadString(TFileCursor &f, mpt::ustring &dest, mpt::Charset charset, const std::size_t srcSize) { dest.clear(); typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly. std::size_t realSrcSize = source.size(); // In case fewer bytes are available dest = mpt::ToUnicode(charset, mpt::String::ReadBuf(mode, mpt::byte_cast(source.data()), realSrcSize)); return (realSrcSize > 0 || srcSize == 0); } // Read a string with a preprended length field of type Tsize (must be a packed<*,*> type) into a std::string dest using a given read mode. // The file cursor is advanced by the string length. // Returns true if the size field could be read and at least one character could be read or 0 characters were requested. template bool ReadSizedString(TFileCursor &f, char (&destBuffer)[destSize], const std::size_t maxLength = std::numeric_limits::max()) { static_assert(mpt::is_binary_safe::value); Tsize srcSize; if(!mpt::IO::FileReader::Read(f, srcSize)) { return false; } return FileReaderExt::ReadString(f, destBuffer, std::min(static_cast(srcSize), maxLength)); } // Read a string with a preprended length field of type Tsize (must be a packed<*,*> type) into a std::string dest using a given read mode. // The file cursor is advanced by the string length. // Returns true if the size field could be read and at least one character could be read or 0 characters were requested. template bool ReadSizedString(TFileCursor &f, std::string &dest, const std::size_t maxLength = std::numeric_limits::max()) { static_assert(mpt::is_binary_safe::value); Tsize srcSize; if(!mpt::IO::FileReader::Read(f, srcSize)) { return false; } return FileReaderExt::ReadString(f, dest, std::min(static_cast(srcSize), maxLength)); } // Read a string with a preprended length field of type Tsize (must be a packed<*,*> type) into a mpt::charbuf dest using a given read mode. // The file cursor is advanced by the string length. // Returns true if the size field could be read and at least one character could be read or 0 characters were requested. template bool ReadSizedString(TFileCursor &f, mpt::charbuf &dest, const std::size_t maxLength = std::numeric_limits::max()) { static_assert(mpt::is_binary_safe::value); Tsize srcSize; if(!mpt::IO::FileReader::Read(f, srcSize)) { return false; } return FileReaderExt::ReadString(f, dest, std::min(static_cast(srcSize), maxLength)); } } // namespace FileReaderExt namespace detail { template using FileCursor = mpt::IO::FileCursor; template class FileReader : public FileCursor { private: using traits_type = Ttraits; using filename_traits_type = Tfilenametraits; public: using pos_type = typename traits_type::pos_type; using data_type = typename traits_type::data_type; using ref_data_type = typename traits_type::ref_data_type; using shared_data_type = typename traits_type::shared_data_type; using value_data_type = typename traits_type::value_data_type; using shared_filename_type = typename filename_traits_type::shared_filename_type; public: // Initialize invalid file reader object. FileReader() { return; } FileReader(const FileCursor &other) : FileCursor(other) { return; } FileReader(FileCursor &&other) : FileCursor(std::move(other)) { return; } // Initialize file reader object with pointer to data and data length. template explicit FileReader(mpt::span bytedata, shared_filename_type filename = shared_filename_type{}) : FileCursor(bytedata, std::move(filename)) { return; } // Initialize file reader object based on an existing file reader object window. explicit FileReader(value_data_type other, shared_filename_type filename = shared_filename_type{}) : FileCursor(std::move(other), std::move(filename)) { return; } public: template bool Read(T &target) { return mpt::IO::FileReader::Read(*this, target); } template T ReadIntLE() { return mpt::IO::FileReader::ReadIntLE(*this); } template T ReadIntBE() { return mpt::IO::FileReader::ReadIntLE(*this); } template T ReadTruncatedIntLE(std::size_t size) { return mpt::IO::FileReader::ReadTruncatedIntLE(*this, size); } template T ReadSizedIntLE(std::size_t size) { return mpt::IO::FileReader::ReadSizedIntLE(*this, size); } uint32 ReadUint32LE() { return mpt::IO::FileReader::ReadUint32LE(*this); } uint32 ReadUint32BE() { return mpt::IO::FileReader::ReadUint32BE(*this); } int32 ReadInt32LE() { return mpt::IO::FileReader::ReadInt32LE(*this); } int32 ReadInt32BE() { return mpt::IO::FileReader::ReadInt32BE(*this); } uint32 ReadUint24LE() { return mpt::IO::FileReader::ReadUint24LE(*this); } uint32 ReadUint24BE() { return mpt::IO::FileReader::ReadUint24BE(*this); } uint16 ReadUint16LE() { return mpt::IO::FileReader::ReadUint16LE(*this); } uint16 ReadUint16BE() { return mpt::IO::FileReader::ReadUint16BE(*this); } int16 ReadInt16LE() { return mpt::IO::FileReader::ReadInt16LE(*this); } int16 ReadInt16BE() { return mpt::IO::FileReader::ReadInt16BE(*this); } char ReadChar() { return mpt::IO::FileReader::ReadChar(*this); } uint8 ReadUint8() { return mpt::IO::FileReader::ReadUint8(*this); } int8 ReadInt8() { return mpt::IO::FileReader::ReadInt8(*this); } float ReadFloatLE() { return mpt::IO::FileReader::ReadFloatLE(*this); } float ReadFloatBE() { return mpt::IO::FileReader::ReadFloatBE(*this); } double ReadDoubleLE() { return mpt::IO::FileReader::ReadDoubleLE(*this); } double ReadDoubleBE() { return mpt::IO::FileReader::ReadDoubleBE(*this); } template bool ReadStruct(T &target) { return mpt::IO::FileReader::ReadStruct(*this, target); } template std::size_t ReadStructPartial(T &target, std::size_t partialSize = sizeof(T)) { return mpt::IO::FileReader::ReadStructPartial(*this, target, partialSize); } bool ReadNullString(std::string &dest, const std::size_t maxLength = std::numeric_limits::max()) { return mpt::IO::FileReader::ReadNullString(*this, dest, maxLength); } bool ReadLine(std::string &dest, const std::size_t maxLength = std::numeric_limits::max()) { return mpt::IO::FileReader::ReadLine(*this, dest, maxLength); } template bool ReadArray(T (&destArray)[destSize]) { return mpt::IO::FileReader::ReadArray(*this, destArray); } template bool ReadArray(std::array &destArray) { return mpt::IO::FileReader::ReadArray(*this, destArray); } template std::array ReadArray() { return mpt::IO::FileReader::ReadArray(*this); } template bool ReadVector(std::vector &destVector, std::size_t destSize) { return mpt::IO::FileReader::ReadVector(*this, destVector, destSize); } template bool ReadMagic(const char (&magic)[N]) { return mpt::IO::FileReader::ReadMagic(*this, magic); } template bool ReadVarInt(T &target) { return mpt::IO::FileReader::ReadVarInt(*this, target); } template using Item = mpt::IO::FileReader::Chunk; template using ChunkList = mpt::IO::FileReader::ChunkList; template Item ReadNextChunk(pos_type alignment) { return mpt::IO::FileReader::ReadNextChunk(*this, alignment); } template ChunkList ReadChunks(pos_type alignment) { return mpt::IO::FileReader::ReadChunks(*this, alignment); } template ChunkList ReadChunksUntil(pos_type alignment, decltype(T().GetID()) stopAtID) { return mpt::IO::FileReader::ReadChunksUntil(*this, alignment, stopAtID); } template bool ReadString(char (&destBuffer)[destSize], const std::size_t srcSize) { return FileReaderExt::ReadString(*this, destBuffer, srcSize); } template bool ReadString(std::string &dest, const std::size_t srcSize) { return FileReaderExt::ReadString(*this, dest, srcSize); } template bool ReadString(mpt::charbuf &dest, const std::size_t srcSize) { return FileReaderExt::ReadString(*this, dest, srcSize); } template bool ReadString(mpt::ustring &dest, mpt::Charset charset, const std::size_t srcSize) { return FileReaderExt::ReadString(*this, dest, charset, srcSize); } template bool ReadSizedString(char (&destBuffer)[destSize], const std::size_t maxLength = std::numeric_limits::max()) { return FileReaderExt::ReadSizedString(*this, destBuffer, maxLength); } template bool ReadSizedString(std::string &dest, const std::size_t maxLength = std::numeric_limits::max()) { return FileReaderExt::ReadSizedString(*this, dest, maxLength); } template bool ReadSizedString(mpt::charbuf &dest, const std::size_t maxLength = std::numeric_limits::max()) { return FileReaderExt::ReadSizedString(*this, dest, maxLength); } }; } // namespace detail using FileCursor = detail::FileCursor>; using FileReader = detail::FileReader>; using ChunkReader = FileReader; using MemoryFileCursor = detail::FileCursor; using MemoryFileReader = detail::FileReader; OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/build-aux/0000755000175000017500000000000015023302361016223 500000000000000libopenmpt-0.8.1+release.autotools/build-aux/compile0000755000175000017500000001635015023302324017525 00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2021 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: libopenmpt-0.8.1+release.autotools/build-aux/missing0000755000175000017500000001533615023302324017551 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2021 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=https://www.perl.org/ flex_URL=https://github.com/westes/flex gnu_software_URL=https://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: libopenmpt-0.8.1+release.autotools/build-aux/ar-lib0000755000175000017500000001336315023302324017244 00000000000000#! /bin/sh # Wrapper for Microsoft lib.exe me=ar-lib scriptversion=2019-07-04.01; # UTC # Copyright (C) 2010-2021 Free Software Foundation, Inc. # Written by Peter Rosin . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . # func_error message func_error () { echo "$me: $1" 1>&2 exit 1 } file_conv= # func_file_conv build_file # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv in mingw) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin | msys) file=`cygpath -m "$file" || echo "$file"` ;; wine) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_at_file at_file operation archive # Iterate over all members in AT_FILE performing OPERATION on ARCHIVE # for each of them. # When interpreting the content of the @FILE, do NOT use func_file_conv, # since the user would need to supply preconverted file names to # binutils ar, at least for MinGW. func_at_file () { operation=$2 archive=$3 at_file_contents=`cat "$1"` eval set x "$at_file_contents" shift for member do $AR -NOLOGO $operation:"$member" "$archive" || exit $? done } case $1 in '') func_error "no command. Try '$0 --help' for more information." ;; -h | --h*) cat <. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x$basic_os != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os in linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ | linux-musl* | linux-relibc* | linux-uclibc* ) ;; uclinux-uclibc* ) ;; -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 exit 1 ;; kfreebsd*-gnu* | kopensolaris*-gnu*) ;; vxworks-simlinux | vxworks-simwindows | vxworks-spe) ;; nto-qnx*) ;; os2-emx) ;; *-eabi* | *-gnueabi*) ;; -*) # Blank kernel with real OS is always fine. ;; *-*) echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: libopenmpt-0.8.1+release.autotools/build-aux/config.guess0000755000175000017500000014051215023302324020465 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-01-09' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_X32 >/dev/null then LIBCABI=${LIBC}x32 fi fi GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; x86_64:Haiku:*:*) GUESS=x86_64-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: libopenmpt-0.8.1+release.autotools/build-aux/depcomp0000755000175000017500000005602015023302324017522 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: libopenmpt-0.8.1+release.autotools/build-aux/install-sh0000755000175000017500000003577615023302324020170 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Email bug reports to bug-automake@gnu.org. Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: libopenmpt-0.8.1+release.autotools/build-aux/ltmain.sh0000755000175000017500000121240115023302310017761 00000000000000#! /usr/bin/env sh ## DO NOT EDIT - This file generated from ./build-aux/ltmain.in ## by inline-source v2019-02-19.15 # libtool (GNU libtool) 2.4.7 # Provide generalized library-building support services. # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996-2019, 2021-2022 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.7 Debian-2.4.7-7~deb12u1" package_revision=2.4.7 ## ------ ## ## Usage. ## ## ------ ## # Run './libtool --help' for help with using this script from the # command line. ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # After configure completes, it has a better idea of some of the # shell tools we need than the defaults used by the functions shared # with bootstrap, so set those here where they can still be over- # ridden by the user, but otherwise take precedence. : ${AUTOCONF="autoconf"} : ${AUTOMAKE="automake"} ## -------------------------- ## ## Source external libraries. ## ## -------------------------- ## # Much of our low-level functionality needs to be sourced from external # libraries, which are installed to $pkgauxdir. # Set a version string for this script. scriptversion=2019-02-19.15; # UTC # General shell script boiler plate, and helper functions. # Written by Gary V. Vaughan, 2004 # This is free software. There is NO warranty; not even for # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Copyright (C) 2004-2019, 2021 Bootstrap Authors # # This file is dual licensed under the terms of the MIT license # , and GPL version 2 or later # . You must apply one of # these licenses when using or redistributing this software or any of # the files within it. See the URLs above, or the file `LICENSE` # included in the Bootstrap distribution for the full license texts. # Please report bugs or propose patches to: # ## ------ ## ## Usage. ## ## ------ ## # Evaluate this file near the top of your script to gain access to # the functions and variables defined here: # # . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh # # If you need to override any of the default environment variable # settings, do that before evaluating this file. ## -------------------- ## ## Shell normalisation. ## ## -------------------- ## # Some shells need a little help to be as Bourne compatible as possible. # Before doing anything else, make sure all that help has been provided! DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # NLS nuisances: We save the old values in case they are required later. _G_user_locale= _G_safe_locale= for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test set = \"\${$_G_var+set}\"; then save_$_G_var=\$$_G_var $_G_var=C export $_G_var _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" fi" done # These NLS vars are set unconditionally (bootstrap issue #24). Unset those # in case the environment reset is needed later and the $save_* variant is not # defined (see the code above). LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL # Make sure IFS has a sensible default sp=' ' nl=' ' IFS="$sp $nl" # There are apparently some retarded systems that use ';' as a PATH separator! if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # func_unset VAR # -------------- # Portably unset VAR. # In some shells, an 'unset VAR' statement leaves a non-zero return # status if VAR is already unset, which might be problematic if the # statement is used at the end of a function (thus poisoning its return # value) or when 'set -e' is active (causing even a spurious abort of # the script in this case). func_unset () { { eval $1=; (eval unset $1) >/dev/null 2>&1 && eval unset $1 || : ; } } # Make sure CDPATH doesn't cause `cd` commands to output the target dir. func_unset CDPATH # Make sure ${,E,F}GREP behave sanely. func_unset GREP_OPTIONS ## ------------------------- ## ## Locate command utilities. ## ## ------------------------- ## # func_executable_p FILE # ---------------------- # Check that FILE is an executable regular file. func_executable_p () { test -f "$1" && test -x "$1" } # func_path_progs PROGS_LIST CHECK_FUNC [PATH] # -------------------------------------------- # Search for either a program that responds to --version with output # containing "GNU", or else returned by CHECK_FUNC otherwise, by # trying all the directories in PATH with each of the elements of # PROGS_LIST. # # CHECK_FUNC should accept the path to a candidate program, and # set $func_check_prog_result if it truncates its output less than # $_G_path_prog_max characters. func_path_progs () { _G_progs_list=$1 _G_check_func=$2 _G_PATH=${3-"$PATH"} _G_path_prog_max=0 _G_path_prog_found=false _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} for _G_dir in $_G_PATH; do IFS=$_G_save_IFS test -z "$_G_dir" && _G_dir=. for _G_prog_name in $_G_progs_list; do for _exeext in '' .EXE; do _G_path_prog=$_G_dir/$_G_prog_name$_exeext func_executable_p "$_G_path_prog" || continue case `"$_G_path_prog" --version 2>&1` in *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; *) $_G_check_func $_G_path_prog func_path_progs_result=$func_check_prog_result ;; esac $_G_path_prog_found && break 3 done done done IFS=$_G_save_IFS test -z "$func_path_progs_result" && { echo "no acceptable sed could be found in \$PATH" >&2 exit 1 } } # We want to be able to use the functions in this file before configure # has figured out where the best binaries are kept, which means we have # to search for them ourselves - except when the results are already set # where we skip the searches. # Unless the user overrides by setting SED, search the path for either GNU # sed, or the sed that truncates its output the least. test -z "$SED" && { _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for _G_i in 1 2 3 4 5 6 7; do _G_sed_script=$_G_sed_script$nl$_G_sed_script done echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed _G_sed_script= func_check_prog_sed () { _G_path_prog=$1 _G_count=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo '' >> conftest.nl "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "sed gsed" func_check_prog_sed "$PATH:/usr/xpg4/bin" rm -f conftest.sed SED=$func_path_progs_result } # Unless the user overrides by setting GREP, search the path for either GNU # grep, or the grep that truncates its output the least. test -z "$GREP" && { func_check_prog_grep () { _G_path_prog=$1 _G_count=0 _G_path_prog_max=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo 'GREP' >> conftest.nl "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "grep ggrep" func_check_prog_grep "$PATH:/usr/xpg4/bin" GREP=$func_path_progs_result } ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # All uppercase variable names are used for environment variables. These # variables can be overridden by the user before calling a script that # uses them if a suitable command of that name is not already available # in the command search PATH. : ${CP="cp -f"} : ${ECHO="printf %s\n"} : ${EGREP="$GREP -E"} : ${FGREP="$GREP -F"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} ## -------------------- ## ## Useful sed snippets. ## ## -------------------- ## sed_dirname='s|/[^/]*$||' sed_basename='s|^.*/||' # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s|\([`"$\\]\)|\\\1|g' # Same as above, but do not quote variable references. sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' # Sed substitution that converts a w32 file name or path # that contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-'\' parameter expansions in output of sed_double_quote_subst that # were '\'-ed in input to the same. If an odd number of '\' preceded a # '$' in input to sed_double_quote_subst, that '$' was protected from # expansion. Since each input '\' is now two '\'s, look for any number # of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. _G_bs='\\' _G_bs2='\\\\' _G_bs4='\\\\\\\\' _G_dollar='\$' sed_double_backslash="\ s/$_G_bs4/&\\ /g s/^$_G_bs2$_G_dollar/$_G_bs&/ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g s/\n//g" # require_check_ifs_backslash # --------------------------- # Check if we can use backslash as IFS='\' separator, and set # $check_ifs_backshlash_broken to ':' or 'false'. require_check_ifs_backslash=func_require_check_ifs_backslash func_require_check_ifs_backslash () { _G_save_IFS=$IFS IFS='\' _G_check_ifs_backshlash='a\\b' for _G_i in $_G_check_ifs_backshlash do case $_G_i in a) check_ifs_backshlash_broken=false ;; '') break ;; *) check_ifs_backshlash_broken=: break ;; esac done IFS=$_G_save_IFS require_check_ifs_backslash=: } ## ----------------- ## ## Global variables. ## ## ----------------- ## # Except for the global variables explicitly listed below, the following # functions in the '^func_' namespace, and the '^require_' namespace # variables initialised in the 'Resource management' section, sourcing # this file will not pollute your global namespace with anything # else. There's no portable way to scope variables in Bourne shell # though, so actually running these functions will sometimes place # results into a variable named after the function, and often use # temporary variables in the '^_G_' namespace. If you are careful to # avoid using those namespaces casually in your sourcing script, things # should continue to work as you expect. And, of course, you can freely # overwrite any of the functions or variables defined here before # calling anything to customize them. EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. # Allow overriding, eg assuming that you follow the convention of # putting '$debug_cmd' at the start of all your functions, you can get # bash to show function call trace with: # # debug_cmd='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name debug_cmd=${debug_cmd-":"} exit_cmd=: # By convention, finish your script with: # # exit $exit_status # # so that you can set exit_status to non-zero if you want to indicate # something went wrong during execution without actually bailing out at # the point of failure. exit_status=$EXIT_SUCCESS # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath=$0 # The name of this program. progname=`$ECHO "$progpath" |$SED "$sed_basename"` # Make sure we have an absolute progpath for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` progdir=`cd "$progdir" && pwd` progpath=$progdir/$progname ;; *) _G_IFS=$IFS IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS=$_G_IFS test -x "$progdir/$progname" && break done IFS=$_G_IFS test -n "$progdir" || progdir=`pwd` progpath=$progdir/$progname ;; esac ## ----------------- ## ## Standard options. ## ## ----------------- ## # The following options affect the operation of the functions defined # below, and should be set appropriately depending on run-time para- # meters passed on the command line. opt_dry_run=false opt_quiet=false opt_verbose=false # Categories 'all' and 'none' are always available. Append any others # you will pass as the first argument to func_warning from your own # code. warning_categories= # By default, display warnings according to 'opt_warning_types'. Set # 'warning_func' to ':' to elide all warnings, or func_fatal_error to # treat the next displayed warning as a fatal error. warning_func=func_warn_and_continue # Set to 'all' to display all warnings, 'none' to suppress all # warnings, or a space delimited list of some subset of # 'warning_categories' to display only the listed warnings. opt_warning_types=all ## -------------------- ## ## Resource management. ## ## -------------------- ## # This section contains definitions for functions that each ensure a # particular resource (a file, or a non-empty configuration variable for # example) is available, and if appropriate to extract default values # from pertinent package files. Call them using their associated # 'require_*' variable to ensure that they are executed, at most, once. # # It's entirely deliberate that calling these functions can set # variables that don't obey the namespace limitations obeyed by the rest # of this file, in order that that they be as useful as possible to # callers. # require_term_colors # ------------------- # Allow display of bold text on terminals that support it. require_term_colors=func_require_term_colors func_require_term_colors () { $debug_cmd test -t 1 && { # COLORTERM and USE_ANSI_COLORS environment variables take # precedence, because most terminfo databases neglect to describe # whether color sequences are supported. test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} if test 1 = "$USE_ANSI_COLORS"; then # Standard ANSI escape sequences tc_reset='' tc_bold=''; tc_standout='' tc_red=''; tc_green='' tc_blue=''; tc_cyan='' else # Otherwise trust the terminfo database after all. test -n "`tput sgr0 2>/dev/null`" && { tc_reset=`tput sgr0` test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` tc_standout=$tc_bold test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` } fi } require_term_colors=: } ## ----------------- ## ## Function library. ## ## ----------------- ## # This section contains a variety of useful functions to call in your # scripts. Take note of the portable wrappers for features provided by # some modern shells, which will fall back to slower equivalents on # less featureful shells. # func_append VAR VALUE # --------------------- # Append VALUE onto the existing contents of VAR. # _G_HAVE_PLUSEQ_OP # Can be empty, in which case the shell is probed, "yes" if += is # useable or anything else if it does not work. if test -z "$_G_HAVE_PLUSEQ_OP" && \ __PLUSEQ_TEST="a" && \ __PLUSEQ_TEST+=" b" 2>/dev/null && \ test "a b" = "$__PLUSEQ_TEST"; then _G_HAVE_PLUSEQ_OP=yes fi if test yes = "$_G_HAVE_PLUSEQ_OP" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_append () { $debug_cmd eval "$1+=\$2" }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_append () { $debug_cmd eval "$1=\$$1\$2" } fi # func_append_quoted VAR VALUE # ---------------------------- # Quote VALUE and append to the end of shell variable VAR, separated # by a space. if test yes = "$_G_HAVE_PLUSEQ_OP"; then eval 'func_append_quoted () { $debug_cmd func_quote_arg pretty "$2" eval "$1+=\\ \$func_quote_arg_result" }' else func_append_quoted () { $debug_cmd func_quote_arg pretty "$2" eval "$1=\$$1\\ \$func_quote_arg_result" } fi # func_append_uniq VAR VALUE # -------------------------- # Append unique VALUE onto the existing contents of VAR, assuming # entries are delimited by the first character of VALUE. For example: # # func_append_uniq options " --another-option option-argument" # # will only append to $options if " --another-option option-argument " # is not already present somewhere in $options already (note spaces at # each end implied by leading space in second argument). func_append_uniq () { $debug_cmd eval _G_current_value='`$ECHO $'$1'`' _G_delim=`expr "$2" : '\(.\)'` case $_G_delim$_G_current_value$_G_delim in *"$2$_G_delim"*) ;; *) func_append "$@" ;; esac } # func_arith TERM... # ------------------ # Set func_arith_result to the result of evaluating TERMs. test -z "$_G_HAVE_ARITH_OP" \ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ && _G_HAVE_ARITH_OP=yes if test yes = "$_G_HAVE_ARITH_OP"; then eval 'func_arith () { $debug_cmd func_arith_result=$(( $* )) }' else func_arith () { $debug_cmd func_arith_result=`expr "$@"` } fi # func_basename FILE # ------------------ # Set func_basename_result to FILE with everything up to and including # the last / stripped. if test yes = "$_G_HAVE_XSI_OPS"; then # If this shell supports suffix pattern removal, then use it to avoid # forking. Hide the definitions single quotes in case the shell chokes # on unsupported syntax... _b='func_basename_result=${1##*/}' _d='case $1 in */*) func_dirname_result=${1%/*}$2 ;; * ) func_dirname_result=$3 ;; esac' else # ...otherwise fall back to using sed. _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` if test "X$func_dirname_result" = "X$1"; then func_dirname_result=$3 else func_append func_dirname_result "$2" fi' fi eval 'func_basename () { $debug_cmd '"$_b"' }' # func_dirname FILE APPEND NONDIR_REPLACEMENT # ------------------------------------------- # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. eval 'func_dirname () { $debug_cmd '"$_d"' }' # func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT # -------------------------------------------------------- # Perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # For efficiency, we do not delegate to the functions above but instead # duplicate the functionality here. eval 'func_dirname_and_basename () { $debug_cmd '"$_b"' '"$_d"' }' # func_echo ARG... # ---------------- # Echo program name prefixed message. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname: $_G_line" done IFS=$func_echo_IFS } # func_echo_all ARG... # -------------------- # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_echo_infix_1 INFIX ARG... # ------------------------------ # Echo program name, followed by INFIX on the first line, with any # additional lines not showing INFIX. func_echo_infix_1 () { $debug_cmd $require_term_colors _G_infix=$1; shift _G_indent=$_G_infix _G_prefix="$progname: $_G_infix: " _G_message=$* # Strip color escape sequences before counting printable length for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" do test -n "$_G_tc" && { _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` } done _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes func_echo_infix_1_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_infix_1_IFS $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 _G_prefix=$_G_indent done IFS=$func_echo_infix_1_IFS } # func_error ARG... # ----------------- # Echo program name prefixed message to standard error. func_error () { $debug_cmd $require_term_colors func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 } # func_fatal_error ARG... # ----------------------- # Echo program name prefixed message to standard error, and exit. func_fatal_error () { $debug_cmd func_error "$*" exit $EXIT_FAILURE } # func_grep EXPRESSION FILENAME # ----------------------------- # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $debug_cmd $GREP "$1" "$2" >/dev/null 2>&1 } # func_len STRING # --------------- # Set func_len_result to the length of STRING. STRING may not # start with a hyphen. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_len () { $debug_cmd func_len_result=${#1} }' else func_len () { $debug_cmd func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` } fi # func_mkdir_p DIRECTORY-PATH # --------------------------- # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { $debug_cmd _G_directory_path=$1 _G_dir_list= if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then # Protect directory names starting with '-' case $_G_directory_path in -*) _G_directory_path=./$_G_directory_path ;; esac # While some portion of DIR does not yet exist... while test ! -d "$_G_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. _G_dir_list=$_G_directory_path:$_G_dir_list # If the last portion added has no slash in it, the list is done case $_G_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` done _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` func_mkdir_p_IFS=$IFS; IFS=: for _G_dir in $_G_dir_list; do IFS=$func_mkdir_p_IFS # mkdir can fail with a 'File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$_G_dir" 2>/dev/null || : done IFS=$func_mkdir_p_IFS # Bail out if we (or some other process) failed to create a directory. test -d "$_G_directory_path" || \ func_fatal_error "Failed to create '$1'" fi } # func_mktempdir [BASENAME] # ------------------------- # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, BASENAME is the basename for that directory. func_mktempdir () { $debug_cmd _G_template=${TMPDIR-/tmp}/${1-$progname} if test : = "$opt_dry_run"; then # Return a directory name, but don't create it in dry-run mode _G_tmpdir=$_G_template-$$ else # If mktemp works, use that first and foremost _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` if test ! -d "$_G_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race _G_tmpdir=$_G_template-${RANDOM-0}$$ func_mktempdir_umask=`umask` umask 0077 $MKDIR "$_G_tmpdir" umask $func_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$_G_tmpdir" || \ func_fatal_error "cannot create temporary directory '$_G_tmpdir'" fi $ECHO "$_G_tmpdir" } # func_normal_abspath PATH # ------------------------ # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. func_normal_abspath () { $debug_cmd # These SED scripts presuppose an absolute path with a trailing slash. _G_pathcar='s|^/\([^/]*\).*$|\1|' _G_pathcdr='s|^/[^/]*||' _G_removedotparts=':dotsl s|/\./|/|g t dotsl s|/\.$|/|' _G_collapseslashes='s|/\{1,\}|/|g' _G_finalslash='s|/*$|/|' # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` while :; do # Processed it all yet? if test / = "$func_normal_abspath_tpath"; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result"; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_notquiet ARG... # -------------------- # Echo program name prefixed message only when not in quiet mode. func_notquiet () { $debug_cmd $opt_quiet || func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_relative_path SRCDIR DSTDIR # -------------------------------- # Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. func_relative_path () { $debug_cmd func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=$func_dirname_result if test -z "$func_relative_path_tlibdir"; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test -n "$func_stripname_result"; then func_append func_relative_path_result "/$func_stripname_result" fi # Normalisation. If bindir is libdir, return '.' else relative path. if test -n "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result" func_relative_path_result=$func_stripname_result fi test -n "$func_relative_path_result" || func_relative_path_result=. : } # func_quote_portable EVAL ARG # ---------------------------- # Internal function to portably implement func_quote_arg. Note that we still # keep attention to performance here so we as much as possible try to avoid # calling sed binary (so far O(N) complexity as long as func_append is O(1)). func_quote_portable () { $debug_cmd $require_check_ifs_backslash func_quote_portable_result=$2 # one-time-loop (easy break) while true do if $1; then func_quote_portable_result=`$ECHO "$2" | $SED \ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` break fi # Quote for eval. case $func_quote_portable_result in *[\\\`\"\$]*) # Fallback to sed for $func_check_bs_ifs_broken=:, or when the string # contains the shell wildcard characters. case $check_ifs_backshlash_broken$func_quote_portable_result in :*|*[\[\*\?]*) func_quote_portable_result=`$ECHO "$func_quote_portable_result" \ | $SED "$sed_quote_subst"` break ;; esac func_quote_portable_old_IFS=$IFS for _G_char in '\' '`' '"' '$' do # STATE($1) PREV($2) SEPARATOR($3) set start "" "" func_quote_portable_result=dummy"$_G_char$func_quote_portable_result$_G_char"dummy IFS=$_G_char for _G_part in $func_quote_portable_result do case $1 in quote) func_append func_quote_portable_result "$3$2" set quote "$_G_part" "\\$_G_char" ;; start) set first "" "" func_quote_portable_result= ;; first) set quote "$_G_part" "" ;; esac done done IFS=$func_quote_portable_old_IFS ;; *) ;; esac break done func_quote_portable_unquoted_result=$func_quote_portable_result case $func_quote_portable_result in # double-quote args containing shell metacharacters to delay # word splitting, command substitution and variable expansion # for a subsequent eval. # many bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_portable_result=\"$func_quote_portable_result\" ;; esac } # func_quotefast_eval ARG # ----------------------- # Quote one ARG (internal). This is equivalent to 'func_quote_arg eval ARG', # but optimized for speed. Result is stored in $func_quotefast_eval. if test xyes = `(x=; printf -v x %q yes; echo x"$x") 2>/dev/null`; then printf -v _GL_test_printf_tilde %q '~' if test '\~' = "$_GL_test_printf_tilde"; then func_quotefast_eval () { printf -v func_quotefast_eval_result %q "$1" } else # Broken older Bash implementations. Make those faster too if possible. func_quotefast_eval () { case $1 in '~'*) func_quote_portable false "$1" func_quotefast_eval_result=$func_quote_portable_result ;; *) printf -v func_quotefast_eval_result %q "$1" ;; esac } fi else func_quotefast_eval () { func_quote_portable false "$1" func_quotefast_eval_result=$func_quote_portable_result } fi # func_quote_arg MODEs ARG # ------------------------ # Quote one ARG to be evaled later. MODEs argument may contain zero or more # specifiers listed below separated by ',' character. This function returns two # values: # i) func_quote_arg_result # double-quoted (when needed), suitable for a subsequent eval # ii) func_quote_arg_unquoted_result # has all characters that are still active within double # quotes backslashified. Available only if 'unquoted' is specified. # # Available modes: # ---------------- # 'eval' (default) # - escape shell special characters # 'expand' # - the same as 'eval'; but do not quote variable references # 'pretty' # - request aesthetic output, i.e. '"a b"' instead of 'a\ b'. This might # be used later in func_quote to get output like: 'echo "a b"' instead # of 'echo a\ b'. This is slower than default on some shells. # 'unquoted' # - produce also $func_quote_arg_unquoted_result which does not contain # wrapping double-quotes. # # Examples for 'func_quote_arg pretty,unquoted string': # # string | *_result | *_unquoted_result # ------------+-----------------------+------------------- # " | \" | \" # a b | "a b" | a b # "a b" | "\"a b\"" | \"a b\" # * | "*" | * # z="${x-$y}" | "z=\"\${x-\$y}\"" | z=\"\${x-\$y}\" # # Examples for 'func_quote_arg pretty,unquoted,expand string': # # string | *_result | *_unquoted_result # --------------+---------------------+-------------------- # z="${x-$y}" | "z=\"${x-$y}\"" | z=\"${x-$y}\" func_quote_arg () { _G_quote_expand=false case ,$1, in *,expand,*) _G_quote_expand=: ;; esac case ,$1, in *,pretty,*|*,expand,*|*,unquoted,*) func_quote_portable $_G_quote_expand "$2" func_quote_arg_result=$func_quote_portable_result func_quote_arg_unquoted_result=$func_quote_portable_unquoted_result ;; *) # Faster quote-for-eval for some shells. func_quotefast_eval "$2" func_quote_arg_result=$func_quotefast_eval_result ;; esac } # func_quote MODEs ARGs... # ------------------------ # Quote all ARGs to be evaled later and join them into single command. See # func_quote_arg's description for more info. func_quote () { $debug_cmd _G_func_quote_mode=$1 ; shift func_quote_result= while test 0 -lt $#; do func_quote_arg "$_G_func_quote_mode" "$1" if test -n "$func_quote_result"; then func_append func_quote_result " $func_quote_arg_result" else func_append func_quote_result "$func_quote_arg_result" fi shift done } # func_stripname PREFIX SUFFIX NAME # --------------------------------- # strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_stripname () { $debug_cmd # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary variable first. func_stripname_result=$3 func_stripname_result=${func_stripname_result#"$1"} func_stripname_result=${func_stripname_result%"$2"} }' else func_stripname () { $debug_cmd case $2 in .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; esac } fi # func_show_eval CMD [FAIL_EXP] # ----------------------------- # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} func_quote_arg pretty,expand "$_G_cmd" eval "func_notquiet $func_quote_arg_result" $opt_dry_run || { eval "$_G_cmd" _G_status=$? if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_show_eval_locale CMD [FAIL_EXP] # ------------------------------------ # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} $opt_quiet || { func_quote_arg expand,pretty "$_G_cmd" eval "func_echo $func_quote_arg_result" } $opt_dry_run || { eval "$_G_user_locale $_G_cmd" _G_status=$? eval "$_G_safe_locale" if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_tr_sh # ---------- # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { $debug_cmd case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_verbose ARG... # ------------------- # Echo program name prefixed message in verbose mode only. func_verbose () { $debug_cmd $opt_verbose && func_echo "$*" : } # func_warn_and_continue ARG... # ----------------------------- # Echo program name prefixed warning message to standard error. func_warn_and_continue () { $debug_cmd $require_term_colors func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 } # func_warning CATEGORY ARG... # ---------------------------- # Echo program name prefixed warning message to standard error. Warning # messages can be filtered according to CATEGORY, where this function # elides messages where CATEGORY is not listed in the global variable # 'opt_warning_types'. func_warning () { $debug_cmd # CATEGORY must be in the warning_categories list! case " $warning_categories " in *" $1 "*) ;; *) func_internal_error "invalid warning category '$1'" ;; esac _G_category=$1 shift case " $opt_warning_types " in *" $_G_category "*) $warning_func ${1+"$@"} ;; esac } # func_sort_ver VER1 VER2 # ----------------------- # 'sort -V' is not generally available. # Note this deviates from the version comparison in automake # in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a # but this should suffice as we won't be specifying old # version formats or redundant trailing .0 in bootstrap.conf. # If we did want full compatibility then we should probably # use m4_version_compare from autoconf. func_sort_ver () { $debug_cmd printf '%s\n%s\n' "$1" "$2" \ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n } # func_lt_ver PREV CURR # --------------------- # Return true if PREV and CURR are in the correct order according to # func_sort_ver, otherwise false. Use it like this: # # func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." func_lt_ver () { $debug_cmd test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: #! /bin/sh # A portable, pluggable option parser for Bourne shell. # Written by Gary V. Vaughan, 2010 # This is free software. There is NO warranty; not even for # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Copyright (C) 2010-2019, 2021 Bootstrap Authors # # This file is dual licensed under the terms of the MIT license # , and GPL version 2 or later # . You must apply one of # these licenses when using or redistributing this software or any of # the files within it. See the URLs above, or the file `LICENSE` # included in the Bootstrap distribution for the full license texts. # Please report bugs or propose patches to: # # Set a version string for this script. scriptversion=2019-02-19.15; # UTC ## ------ ## ## Usage. ## ## ------ ## # This file is a library for parsing options in your shell scripts along # with assorted other useful supporting features that you can make use # of too. # # For the simplest scripts you might need only: # # #!/bin/sh # . relative/path/to/funclib.sh # . relative/path/to/options-parser # scriptversion=1.0 # func_options ${1+"$@"} # eval set dummy "$func_options_result"; shift # ...rest of your script... # # In order for the '--version' option to work, you will need to have a # suitably formatted comment like the one at the top of this file # starting with '# Written by ' and ending with '# Copyright'. # # For '-h' and '--help' to work, you will also need a one line # description of your script's purpose in a comment directly above the # '# Written by ' line, like the one at the top of this file. # # The default options also support '--debug', which will turn on shell # execution tracing (see the comment above debug_cmd below for another # use), and '--verbose' and the func_verbose function to allow your script # to display verbose messages only when your user has specified # '--verbose'. # # After sourcing this file, you can plug in processing for additional # options by amending the variables from the 'Configuration' section # below, and following the instructions in the 'Option parsing' # section further down. ## -------------- ## ## Configuration. ## ## -------------- ## # You should override these variables in your script after sourcing this # file so that they reflect the customisations you have added to the # option parser. # The usage line for option parsing errors and the start of '-h' and # '--help' output messages. You can embed shell variables for delayed # expansion at the time the message is displayed, but you will need to # quote other shell meta-characters carefully to prevent them being # expanded when the contents are evaled. usage='$progpath [OPTION]...' # Short help message in response to '-h' and '--help'. Add to this or # override it after sourcing this library to reflect the full set of # options your script accepts. usage_message="\ --debug enable verbose shell tracing -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -v, --verbose verbosely report processing --version print version information and exit -h, --help print short or long help message and exit " # Additional text appended to 'usage_message' in response to '--help'. long_help_message=" Warning categories include: 'all' show all warnings 'none' turn off all the warnings 'error' warnings are treated as fatal errors" # Help message printed before fatal option parsing errors. fatal_help="Try '\$progname --help' for more information." ## ------------------------- ## ## Hook function management. ## ## ------------------------- ## # This section contains functions for adding, removing, and running hooks # in the main code. A hook is just a list of function names that can be # run in order later on. # func_hookable FUNC_NAME # ----------------------- # Declare that FUNC_NAME will run hooks added with # 'func_add_hook FUNC_NAME ...'. func_hookable () { $debug_cmd func_append hookable_fns " $1" } # func_add_hook FUNC_NAME HOOK_FUNC # --------------------------------- # Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must # first have been declared "hookable" by a call to 'func_hookable'. func_add_hook () { $debug_cmd case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not accept hook functions." ;; esac eval func_append ${1}_hooks '" $2"' } # func_remove_hook FUNC_NAME HOOK_FUNC # ------------------------------------ # Remove HOOK_FUNC from the list of hook functions to be called by # FUNC_NAME. func_remove_hook () { $debug_cmd eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' } # func_propagate_result FUNC_NAME_A FUNC_NAME_B # --------------------------------------------- # If the *_result variable of FUNC_NAME_A _is set_, assign its value to # *_result variable of FUNC_NAME_B. func_propagate_result () { $debug_cmd func_propagate_result_result=: if eval "test \"\${${1}_result+set}\" = set" then eval "${2}_result=\$${1}_result" else func_propagate_result_result=false fi } # func_run_hooks FUNC_NAME [ARG]... # --------------------------------- # Run all hook functions registered to FUNC_NAME. # It's assumed that the list of hook functions contains nothing more # than a whitespace-delimited list of legal shell function names, and # no effort is wasted trying to catch shell meta-characters or preserve # whitespace. func_run_hooks () { $debug_cmd _G_rc_run_hooks=false case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not support hook functions." ;; esac eval _G_hook_fns=\$$1_hooks; shift for _G_hook in $_G_hook_fns; do func_unset "${_G_hook}_result" eval $_G_hook '${1+"$@"}' func_propagate_result $_G_hook func_run_hooks if $func_propagate_result_result; then eval set dummy "$func_run_hooks_result"; shift fi done } ## --------------- ## ## Option parsing. ## ## --------------- ## # In order to add your own option parsing hooks, you must accept the # full positional parameter list from your hook function. You may remove # or edit any options that you action, and then pass back the remaining # unprocessed options in '_result', escaped # suitably for 'eval'. # # The '_result' variable is automatically unset # before your hook gets called; for best performance, only set the # *_result variable when necessary (i.e. don't call the 'func_quote' # function unnecessarily because it can be an expensive operation on some # machines). # # Like this: # # my_options_prep () # { # $debug_cmd # # # Extend the existing usage message. # usage_message=$usage_message' # -s, --silent don'\''t print informational messages # ' # # No change in '$@' (ignored completely by this hook). Leave # # my_options_prep_result variable intact. # } # func_add_hook func_options_prep my_options_prep # # # my_silent_option () # { # $debug_cmd # # args_changed=false # # # Note that, for efficiency, we parse as many options as we can # # recognise in a loop before passing the remainder back to the # # caller on the first unrecognised argument we encounter. # while test $# -gt 0; do # opt=$1; shift # case $opt in # --silent|-s) opt_silent=: # args_changed=: # ;; # # Separate non-argument short options: # -s*) func_split_short_opt "$_G_opt" # set dummy "$func_split_short_opt_name" \ # "-$func_split_short_opt_arg" ${1+"$@"} # shift # args_changed=: # ;; # *) # Make sure the first unrecognised option "$_G_opt" # # is added back to "$@" in case we need it later, # # if $args_changed was set to 'true'. # set dummy "$_G_opt" ${1+"$@"}; shift; break ;; # esac # done # # # Only call 'func_quote' here if we processed at least one argument. # if $args_changed; then # func_quote eval ${1+"$@"} # my_silent_option_result=$func_quote_result # fi # } # func_add_hook func_parse_options my_silent_option # # # my_option_validation () # { # $debug_cmd # # $opt_silent && $opt_verbose && func_fatal_help "\ # '--silent' and '--verbose' options are mutually exclusive." # } # func_add_hook func_validate_options my_option_validation # # You'll also need to manually amend $usage_message to reflect the extra # options you parse. It's preferable to append if you can, so that # multiple option parsing hooks can be added safely. # func_options_finish [ARG]... # ---------------------------- # Finishing the option parse loop (call 'func_options' hooks ATM). func_options_finish () { $debug_cmd func_run_hooks func_options ${1+"$@"} func_propagate_result func_run_hooks func_options_finish } # func_options [ARG]... # --------------------- # All the functions called inside func_options are hookable. See the # individual implementations for details. func_hookable func_options func_options () { $debug_cmd _G_options_quoted=false for my_func in options_prep parse_options validate_options options_finish do func_unset func_${my_func}_result func_unset func_run_hooks_result eval func_$my_func '${1+"$@"}' func_propagate_result func_$my_func func_options if $func_propagate_result_result; then eval set dummy "$func_options_result"; shift _G_options_quoted=: fi done $_G_options_quoted || { # As we (func_options) are top-level options-parser function and # nobody quoted "$@" for us yet, we need to do it explicitly for # caller. func_quote eval ${1+"$@"} func_options_result=$func_quote_result } } # func_options_prep [ARG]... # -------------------------- # All initialisations required before starting the option parse loop. # Note that when calling hook functions, we pass through the list of # positional parameters. If a hook function modifies that list, and # needs to propagate that back to rest of this script, then the complete # modified list must be put in 'func_run_hooks_result' before returning. func_hookable func_options_prep func_options_prep () { $debug_cmd # Option defaults: opt_verbose=false opt_warning_types= func_run_hooks func_options_prep ${1+"$@"} func_propagate_result func_run_hooks func_options_prep } # func_parse_options [ARG]... # --------------------------- # The main option parsing loop. func_hookable func_parse_options func_parse_options () { $debug_cmd _G_parse_options_requote=false # this just eases exit handling while test $# -gt 0; do # Defer to hook functions for initial option parsing, so they # get priority in the event of reusing an option name. func_run_hooks func_parse_options ${1+"$@"} func_propagate_result func_run_hooks func_parse_options if $func_propagate_result_result; then eval set dummy "$func_parse_options_result"; shift # Even though we may have changed "$@", we passed the "$@" array # down into the hook and it quoted it for us (because we are in # this if-branch). No need to quote it again. _G_parse_options_requote=false fi # Break out of the loop if we already parsed every option. test $# -gt 0 || break # We expect that one of the options parsed in this function matches # and thus we remove _G_opt from "$@" and need to re-quote. _G_match_parse_options=: _G_opt=$1 shift case $_G_opt in --debug|-x) debug_cmd='set -x' func_echo "enabling shell trace mode" >&2 $debug_cmd ;; --no-warnings|--no-warning|--no-warn) set dummy --warnings none ${1+"$@"} shift ;; --warnings|--warning|-W) if test $# = 0 && func_missing_arg $_G_opt; then _G_parse_options_requote=: break fi case " $warning_categories $1" in *" $1 "*) # trailing space prevents matching last $1 above func_append_uniq opt_warning_types " $1" ;; *all) opt_warning_types=$warning_categories ;; *none) opt_warning_types=none warning_func=: ;; *error) opt_warning_types=$warning_categories warning_func=func_fatal_error ;; *) func_fatal_error \ "unsupported warning category: '$1'" ;; esac shift ;; --verbose|-v) opt_verbose=: ;; --version) func_version ;; -\?|-h) func_usage ;; --help) func_help ;; # Separate optargs to long options (plugins may need this): --*=*) func_split_equals "$_G_opt" set dummy "$func_split_equals_lhs" \ "$func_split_equals_rhs" ${1+"$@"} shift ;; # Separate optargs to short options: -W*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "$func_split_short_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-v*|-x*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) _G_parse_options_requote=: ; break ;; -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; *) set dummy "$_G_opt" ${1+"$@"}; shift _G_match_parse_options=false break ;; esac if $_G_match_parse_options; then _G_parse_options_requote=: fi done if $_G_parse_options_requote; then # save modified positional parameters for caller func_quote eval ${1+"$@"} func_parse_options_result=$func_quote_result fi } # func_validate_options [ARG]... # ------------------------------ # Perform any sanity checks on option settings and/or unconsumed # arguments. func_hookable func_validate_options func_validate_options () { $debug_cmd # Display all warnings if -W was not given. test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" func_run_hooks func_validate_options ${1+"$@"} func_propagate_result func_run_hooks func_validate_options # Bail if the options were screwed! $exit_cmd $EXIT_FAILURE } ## ----------------- ## ## Helper functions. ## ## ----------------- ## # This section contains the helper functions used by the rest of the # hookable option parser framework in ascii-betical order. # func_fatal_help ARG... # ---------------------- # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { $debug_cmd eval \$ECHO \""Usage: $usage"\" eval \$ECHO \""$fatal_help"\" func_error ${1+"$@"} exit $EXIT_FAILURE } # func_help # --------- # Echo long help message to standard output and exit. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message" exit 0 } # func_missing_arg ARGNAME # ------------------------ # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $debug_cmd func_error "Missing argument for '$1'." exit_cmd=exit } # func_split_equals STRING # ------------------------ # Set func_split_equals_lhs and func_split_equals_rhs shell variables # after splitting STRING at the '=' sign. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_equals () { $debug_cmd func_split_equals_lhs=${1%%=*} func_split_equals_rhs=${1#*=} if test "x$func_split_equals_lhs" = "x$1"; then func_split_equals_rhs= fi }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_equals () { $debug_cmd func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` func_split_equals_rhs= test "x$func_split_equals_lhs=" = "x$1" \ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` } fi #func_split_equals # func_split_short_opt SHORTOPT # ----------------------------- # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_short_opt () { $debug_cmd func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"} }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_short_opt () { $debug_cmd func_split_short_opt_name=`expr "x$1" : 'x\(-.\)'` func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` } fi #func_split_short_opt # func_usage # ---------- # Echo short help message to standard output and exit. func_usage () { $debug_cmd func_usage_message $ECHO "Run '$progname --help |${PAGER-more}' for full usage" exit 0 } # func_usage_message # ------------------ # Echo short help message to standard output. func_usage_message () { $debug_cmd eval \$ECHO \""Usage: $usage"\" echo $SED -n 's|^# || /^Written by/{ x;p;x } h /^Written by/q' < "$progpath" echo eval \$ECHO \""$usage_message"\" } # func_version # ------------ # Echo version message to standard output and exit. # The version message is extracted from the calling file's header # comments, with leading '# ' stripped: # 1. First display the progname and version # 2. Followed by the header comment line matching /^# Written by / # 3. Then a blank line followed by the first following line matching # /^# Copyright / # 4. Immediately followed by any lines between the previous matches, # except lines preceding the intervening completely blank line. # For example, see the header comments of this file. func_version () { $debug_cmd printf '%s\n' "$progname $scriptversion" $SED -n ' /^# Written by /!b s|^# ||; p; n :fwd2blnk /./ { n b fwd2blnk } p; n :holdwrnt s|^# || s|^# *$|| /^Copyright /!{ /./H n b holdwrnt } s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| G s|\(\n\)\n*|\1|g p; q' < "$progpath" exit $? } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "30/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: # Set a version string. scriptversion='(GNU libtool) 2.4.7' # func_echo ARG... # ---------------- # Libtool also displays the current mode in messages, so override # funclib.sh func_echo with this custom definition. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" done IFS=$func_echo_IFS } # func_warning ARG... # ------------------- # Libtool warnings are not categorized, so override funclib.sh # func_warning with this simpler definition. func_warning () { $debug_cmd $warning_func ${1+"$@"} } ## ---------------- ## ## Options parsing. ## ## ---------------- ## # Hook in the functions to make sure our own options are parsed during # the option parsing loop. usage='$progpath [OPTION]... [MODE-ARG]...' # Short help message in response to '-h'. usage_message="Options: --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --mode=MODE use operation mode MODE --no-warnings equivalent to '-Wnone' --preserve-dup-deps don't remove duplicate dependency libraries --quiet, --silent don't print informational messages --tag=TAG use configuration variables from tag TAG -v, --verbose print more informational messages than default --version print version information -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -h, --help, --help-all print short, long, or detailed help message " # Additional text appended to 'usage_message' in response to '--help'. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message MODE must be one of the following: clean remove files from the build directory compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. When passed as first option, '--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. Try '$progname --help --mode=MODE' for a more detailed description of MODE. When reporting a bug, please describe a test case to reproduce it and include the following information: host-triplet: $host shell: $SHELL compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) version: $progname $scriptversion Debian-2.4.7-7~deb12u1 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to . GNU libtool home page: . General help using GNU software: ." exit 0 } # func_lo2o OBJECT-NAME # --------------------- # Transform OBJECT-NAME from a '.lo' suffix to the platform specific # object suffix. lo2o=s/\\.lo\$/.$objext/ o2lo=s/\\.$objext\$/.lo/ if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_lo2o () { case $1 in *.lo) func_lo2o_result=${1%.lo}.$objext ;; * ) func_lo2o_result=$1 ;; esac }' # func_xform LIBOBJ-OR-SOURCE # --------------------------- # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) # suffix to a '.lo' libtool-object suffix. eval 'func_xform () { func_xform_result=${1%.*}.lo }' else # ...otherwise fall back to using sed. func_lo2o () { func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` } func_xform () { func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` } fi # func_fatal_configuration ARG... # ------------------------------- # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_fatal_error ${1+"$@"} \ "See the $PACKAGE documentation for more information." \ "Fatal configuration error." } # func_config # ----------- # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # ------------- # Display the features supported by this script. func_features () { echo "host: $host" if test yes = "$build_libtool_libs"; then echo "enable shared libraries" else echo "disable shared libraries" fi if test yes = "$build_old_libs"; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag TAGNAME # ----------------------- # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname=$1 re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf=/$re_begincf/,/$re_endcf/p # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # ------------------------ # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # libtool_options_prep [ARG]... # ----------------------------- # Preparation for options parsed by libtool. libtool_options_prep () { $debug_mode # Option defaults: opt_config=false opt_dlopen= opt_dry_run=false opt_help=false opt_mode= opt_preserve_dup_deps=false opt_quiet=false nonopt= preserve_args= _G_rc_lt_options_prep=: _G_rc_lt_options_prep=: # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; *) _G_rc_lt_options_prep=false ;; esac if $_G_rc_lt_options_prep; then # Pass back the list of options. func_quote eval ${1+"$@"} libtool_options_prep_result=$func_quote_result fi } func_add_hook func_options_prep libtool_options_prep # libtool_parse_options [ARG]... # --------------------------------- # Provide handling for libtool specific options. libtool_parse_options () { $debug_cmd _G_rc_lt_parse_options=false # Perform our own loop to consume as many options as possible in # each iteration. while test $# -gt 0; do _G_match_lt_parse_options=: _G_opt=$1 shift case $_G_opt in --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) func_config ;; --dlopen|-dlopen) opt_dlopen="${opt_dlopen+$opt_dlopen }$1" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) func_features ;; --finish) set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $_G_opt && break opt_mode=$1 case $1 in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $_G_opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_quiet=false func_append preserve_args " $_G_opt" ;; --no-warnings|--no-warning|--no-warn) opt_warning=false func_append preserve_args " $_G_opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $_G_opt" ;; --silent|--quiet) opt_quiet=: opt_verbose=false func_append preserve_args " $_G_opt" ;; --tag) test $# = 0 && func_missing_arg $_G_opt && break opt_tag=$1 func_append preserve_args " $_G_opt $1" func_enable_tag "$1" shift ;; --verbose|-v) opt_quiet=false opt_verbose=: func_append preserve_args " $_G_opt" ;; # An option not handled by this hook function: *) set dummy "$_G_opt" ${1+"$@"} ; shift _G_match_lt_parse_options=false break ;; esac $_G_match_lt_parse_options && _G_rc_lt_parse_options=: done if $_G_rc_lt_parse_options; then # save modified positional parameters for caller func_quote eval ${1+"$@"} libtool_parse_options_result=$func_quote_result fi } func_add_hook func_parse_options libtool_parse_options # libtool_validate_options [ARG]... # --------------------------------- # Perform any sanity checks on option settings and/or unconsumed # arguments. libtool_validate_options () { # save first non-option argument if test 0 -lt $#; then nonopt=$1 shift fi # preserve --debug test : = "$debug_cmd" || func_append preserve_args " --debug" case $host in # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match test yes != "$build_libtool_libs" \ && test yes != "$build_old_libs" \ && func_fatal_configuration "not configured to build any kind of library" # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test execute != "$opt_mode"; then func_error "unrecognized option '-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help=$help help="Try '$progname --help --mode=$opt_mode' for more information." } # Pass back the unparsed argument list func_quote eval ${1+"$@"} libtool_validate_options_result=$func_quote_result } func_add_hook func_validate_options libtool_validate_options # Process options as early as possible so that --help and --version # can return quickly. func_options ${1+"$@"} eval set dummy "$func_options_result"; shift ## ----------- ## ## Main. ## ## ----------- ## magic='%%%MAGIC variable%%%' magic_exe='%%%MAGIC EXE variable%%%' # Global variables. extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # func_generated_by_libtool # True iff stdin has been generated by Libtool. This function is only # a basic sanity check; it will hardly flush out determined imposters. func_generated_by_libtool_p () { $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p } # func_lalib_unsafe_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if 'file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case $lalib_p_line in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test yes = "$lalib_p" } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { test -f "$1" && $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $debug_cmd save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # 'FILE.' does not work on cygwin managed mounts. func_source () { $debug_cmd case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case $lt_sysroot:$1 in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result='='$func_stripname_result ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $debug_cmd if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with '--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=$1 if test yes = "$build_libtool_libs"; then write_lobj=\'$2\' else write_lobj=none fi if test yes = "$build_old_libs"; then write_oldobj=\'$3\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $debug_cmd # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result= if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result"; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $debug_cmd if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $debug_cmd # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $debug_cmd if test -z "$2" && test -n "$1"; then func_error "Could not determine host file name corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result=$1 fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $debug_cmd if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " '$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result=$3 fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $debug_cmd case $4 in $1 ) func_to_host_path_result=$3$func_to_host_path_result ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via '$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $debug_cmd $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $debug_cmd case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result=$1 } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result=$func_convert_core_msys_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result=$func_convert_core_file_wine_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via '$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $debug_cmd if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd=func_convert_path_$func_stripname_result fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $debug_cmd func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result=$1 } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_msys_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_path_wine_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_dll_def_p FILE # True iff FILE is a Windows DLL '.def' file. # Keep in sync with _LT_DLL_DEF_P in libtool.m4 func_dll_def_p () { $debug_cmd func_dll_def_p_tmp=`$SED -n \ -e 's/^[ ]*//' \ -e '/^\(;.*\)*$/d' \ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ -e q \ "$1"` test DEF = "$func_dll_def_p_tmp" } # func_mode_compile arg... func_mode_compile () { $debug_cmd # Get the compilation command and the source file. base_compile= srcfile=$nonopt # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg=$arg arg_mode=normal ;; target ) libobj=$arg arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify '-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs=$IFS; IFS=, for arg in $args; do IFS=$save_ifs func_append_quoted lastarg "$arg" done IFS=$save_ifs func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg=$srcfile srcfile=$arg ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with '-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj=$func_basename_result } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from '$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test yes = "$build_libtool_libs" \ || func_fatal_configuration "cannot build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_arg pretty "$libobj" test "X$libobj" != "X$func_quote_arg_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name '$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname=$func_basename_result xdir=$func_dirname_result lobj=$xdir$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test yes = "$build_old_libs"; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test no = "$compiler_c_o"; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext lockfile=$output_obj.lock else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test yes = "$need_locks"; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test warn = "$need_locks"; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_arg pretty "$srcfile" qsrcfile=$func_quote_arg_result # Only build a PIC object if we are building libtool libraries. if test yes = "$build_libtool_libs"; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test no != "$pic_mode"; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test yes = "$suppress_opt"; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test yes = "$build_old_libs"; then if test yes != "$pic_mode"; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test yes = "$compiler_c_o"; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test no != "$need_locks"; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test compile = "$opt_mode" && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a '.o' file suitable for static linking -static only build a '.o' file suitable for static linking -Wc,FLAG -Xcompiler FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a 'standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix '.c' with the library object suffix, '.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to '-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the '--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the 'install' or 'cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE use a list of object files found in FILE to specify objects -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wa,FLAG -Xassembler FLAG pass linker-specific FLAG directly to the assembler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with '-') are ignored. Every other argument is treated as a filename. Files ending in '.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in '.la', then a libtool library is created, only library objects ('.lo' files) may be specified, and '-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created using 'ar' and 'ranlib', or on Windows using 'lib'. If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode '$opt_mode'" ;; esac echo $ECHO "Try '$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test : = "$opt_help"; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | $SED -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | $SED '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $debug_cmd # The first argument is the command name. cmd=$nonopt test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "'$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "'$file' was not linked with '-export-dynamic'" continue fi func_dirname "$file" "" "." dir=$func_dirname_result if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir=$func_dirname_result ;; *) func_warning "'-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir=$absdir # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic=$magic # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file=$progdir/$program elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file=$progdir/$program fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if $opt_dry_run; then # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS else if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd=\$cmd$args fi } test execute = "$opt_mode" && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $debug_cmd libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "'$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument '$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and '=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_quiet && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the '-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the '$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the '$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the '$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test finish = "$opt_mode" && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $debug_cmd # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac then # Aesthetically quote it. func_quote_arg pretty "$nonopt" install_prog="$func_quote_arg_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_arg pretty "$arg" func_append install_prog "$func_quote_arg_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=false stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=: ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test X-m = "X$prev" && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_arg pretty "$arg" func_append install_prog " $func_quote_arg_result" if test -n "$arg2"; then func_quote_arg pretty "$arg2" fi func_append install_shared_prog " $func_quote_arg_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the '$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_arg pretty "$install_override_mode" func_append install_shared_prog " -m $func_quote_arg_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=: if $isdir; then destdir=$dest destname= else func_dirname_and_basename "$dest" "" "." destdir=$func_dirname_result destname=$func_basename_result # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "'$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "'$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir=$func_dirname_result func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking '$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname=$1 shift srcname=$realname test -n "$relink_command" && srcname=${realname}T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme=$stripme case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme= ;; esac ;; os2*) case $realname in *_dll.a) tstripme= ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try 'ln -sf' first, because the 'ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib=$destdir/$realname func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name=$func_basename_result instname=$dir/${name}i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest=$destfile destfile= ;; *) func_fatal_help "cannot copy a libtool object to '$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test yes = "$build_old_libs"; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext= case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=.exe fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script '$wrapper'" finalize=: for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` if test -n "$libdir" && test ! -f "$libfile"; then func_warning "'$lib' has not been installed in '$libdir'" finalize=false fi done relink_command= func_source "$wrapper" outputname= if test no = "$fast_install" && test -n "$relink_command"; then $opt_dry_run || { if $finalize; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file=$func_basename_result outputname=$tmpdir/$file # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_quiet || { func_quote_arg expand,pretty "$relink_command" eval "func_echo $func_quote_arg_result" } if eval "$relink_command"; then : else func_error "error: relink '$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file=$outputname else func_warning "cannot relink '$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name=$func_basename_result # Set up the ranlib parameters. oldlib=$destdir/$name func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run '$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test install = "$opt_mode" && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $debug_cmd my_outputname=$1 my_originator=$2 my_pic_p=${3-false} my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms=${my_outputname}S.c else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist=$output_objdir/$my_outputname.nm func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* External symbol declarations for the compiler. */\ " if test yes = "$dlself"; then func_verbose "generating symbol list for '$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from '$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols=$output_objdir/$outputname.exp $opt_dry_run || { $RM $export_symbols eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from '$dlprefile'" func_basename "$dlprefile" name=$func_basename_result case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename= if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname"; then func_basename "$dlprefile_dlname" dlprefile_dlbasename=$func_basename_result else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename"; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi func_show_eval '$RM "${nlist}I"' if test -n "$global_symbol_to_import"; then eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[];\ " if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ static void lt_syminit(void) { LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; for (; symbol->name; ++symbol) {" $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" echo >> "$output_objdir/$my_dlsyms" "\ } }" fi echo >> "$output_objdir/$my_dlsyms" "\ LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = { {\"$my_originator\", (void *) 0}," if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ {\"@INIT@\", (void *) <_syminit}," fi case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) $my_pic_p && pic_flag_for_symtable=" $pic_flag" ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' # Transform the symbol file into the correct name. symfileobj=$output_objdir/${my_outputname}S.$objext case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for '$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $debug_cmd win32_libid_type=unknown win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then case $nm_interface in "MS dumpbin") if func_cygming_ms_implib_p "$1" || func_cygming_gnu_implib_p "$1" then win32_nmres=import else win32_nmres= fi ;; *) func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s|.*|import| p q } }'` ;; esac case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $debug_cmd sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $debug_cmd match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive that possess that section. Heuristic: eliminate # all those that have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $debug_cmd if func_cygming_gnu_implib_p "$1"; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1"; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result= fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $debug_cmd f_ex_an_ar_dir=$1; shift f_ex_an_ar_oldlib=$1 if test yes = "$lock_old_archive_extraction"; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test yes = "$lock_old_archive_extraction"; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $debug_cmd my_gentop=$1; shift my_oldlibs=${1+"$@"} my_oldobjs= my_xlib= my_xabs= my_xdir= for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib=$func_basename_result my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir=$my_gentop/$my_xlib_u func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` func_basename "$darwin_archive" darwin_base_archive=$func_basename_result darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches; do func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" cd "unfat-$$/$darwin_base_archive-$darwin_arch" func_extract_an_archive "`pwd`" "$darwin_base_archive" cd "$darwin_curdir" $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result=$my_oldobjs } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory where it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" func_quote_arg pretty "$ECHO" qECHO=$func_quote_arg_result $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=$qECHO fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ that is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options that match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test yes = "$fast_install"; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else \$ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* declarations of non-ANSI functions */ #if defined __MINGW32__ # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined __CYGWIN__ # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined other_platform || defined ... */ #endif /* portability defines, excluding path handling macros */ #if defined _MSC_VER # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC #elif defined __MINGW32__ # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined __CYGWIN__ # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined other platforms ... */ #endif #if defined PATH_MAX # define LT_PATHMAX PATH_MAX #elif defined MAXPATHLEN # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ defined __OS2__ # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free (stale); stale = 0; } \ } while (0) #if defined LT_DEBUGWRAPPER static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; size_t tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined HAVE_DOS_BASED_FILE_SYSTEM if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined HAVE_DOS_BASED_FILE_SYSTEM } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = (size_t) (q - p); p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (STREQ (str, pat)) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else size_t len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { size_t orig_value_len = strlen (orig_value); size_t add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ size_t len = strlen (new_value); while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[--len] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $debug_cmd case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_suncc_cstd_abi # !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! # Several compiler flags select an ABI that is incompatible with the # Cstd library. Avoid specifying it if any are in CXXFLAGS. func_suncc_cstd_abi () { $debug_cmd case " $compile_command " in *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) suncc_use_cstd_abi=no ;; *) suncc_use_cstd_abi=yes ;; esac } # func_mode_link arg... func_mode_link () { $debug_cmd case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # what system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll that has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= os2dllname= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=false prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module=$wl-single_module func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test yes != "$build_libtool_libs" \ && func_fatal_configuration "cannot build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg=$1 shift func_quote_arg pretty,unquoted "$arg" qarg=$func_quote_arg_unquoted_result func_append libtool_args " $func_quote_arg_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir=$arg prev= continue ;; dlfiles|dlprefiles) $preload || { # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=: } case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test no = "$dlself"; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test dlprefiles = "$prev"; then dlself=yes elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test dlfiles = "$prev"; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols=$arg test -f "$arg" \ || func_fatal_error "symbol file '$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex=$arg prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir=$arg prev= continue ;; mllvm) # Clang does not use LLVM to link, so we can simply discard any # '-mllvm $arg' options when doing the link step. prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result if test none != "$pic_object"; then # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object fi # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file '$arg' does not exist" fi arg=$save_arg prev= continue ;; os2dllname) os2dllname=$arg prev= continue ;; precious_regex) precious_files_regex=$arg prev= continue ;; release) release=-$arg prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test rpath = "$prev"; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds=$arg prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xassembler) func_append compiler_flags " -Xassembler $qarg" prev= func_append compile_command " -Xassembler $qarg" func_append finalize_command " -Xassembler $qarg" continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg=$arg case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "'-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test X-export-symbols = "X$arg"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between '-L' and '$1'" else func_fatal_error "need path for '-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of '$dir'" dir=$absdir ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test X-lc = "X$arg" || test X-lm = "X$arg"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test X-lc = "X$arg" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*) # Do not include libc due to us having libc/libc_r. test X-lc = "X$arg" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test X-lc = "X$arg" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test X-lc = "X$arg" && continue ;; esac elif test X-lc_r = "X$arg"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -mllvm) prev=mllvm continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; # Solaris ld rejects as of 11.4. Refer to Oracle bug 22985199. -pthread) case $host in *solaris2*) ;; *) case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac ;; esac continue ;; -mt|-mthreads|-kthread|-Kthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module=$wl-multi_module continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "'-no-install' is ignored for $host" func_warning "assuming '-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -os2dllname) prev=os2dllname continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_arg pretty "$flag" func_append arg " $func_quote_arg_result" func_append compiler_flags " $func_quote_arg_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_arg pretty "$flag" func_append arg " $wl$func_quote_arg_result" func_append compiler_flags " $wl$func_quote_arg_result" func_append linker_flags " $func_quote_arg_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xassembler) prev=xassembler continue ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_arg pretty "$arg" arg=$func_quote_arg_result ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # -fstack-protector* stack protector flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization # -specs=* GCC specs files # -stdlib=* select c++ std lib with clang # -fsanitize=* Clang/GCC memory and address sanitizer # -fuse-ld=* Linker select flags for GCC # -static-* direct GCC to link specific libraries statically # -fcilkplus Cilk Plus language extension features for C/C++ # -Wa,* Pass flags directly to the assembler -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus|-Wa,*) func_quote_arg pretty "$arg" arg=$func_quote_arg_result func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; -Z*) if test os2 = "`expr $host : '.*\(os2\)'`"; then # OS/2 uses -Zxxx to specify OS/2-specific options compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case $arg in -Zlinker | -Zstack) prev=xcompiler ;; esac continue else # Otherwise treat like 'Some other compiler flag' below func_quote_arg pretty "$arg" arg=$func_quote_arg_result fi ;; # Some other compiler flag. -* | +*) func_quote_arg pretty "$arg" arg=$func_quote_arg_result ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result test none = "$pic_object" || { # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object } # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test dlfiles = "$prev"; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test dlprefiles = "$prev"; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_arg pretty "$arg" arg=$func_quote_arg_result ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the '$prevarg' option requires an argument" if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname=$func_basename_result libobjs_save=$libobjs if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" # Definition is injected by LT_CONFIG during libtool generation. func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" func_dirname "$output" "/" "" output_objdir=$func_dirname_result$objdir func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test lib = "$linkmode"; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=false newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test lib,link = "$linkmode,$pass"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs=$tmp_deplibs fi if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass"; then libs=$deplibs deplibs= fi if test prog = "$linkmode"; then case $pass in dlopen) libs=$dlfiles ;; dlpreopen) libs=$dlprefiles ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test lib,dlpreopen = "$linkmode,$pass"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs=$dlprefiles fi if test dlopen = "$pass"; then # Collect dlpreopened libraries save_deplibs=$deplibs deplibs= fi for deplib in $libs; do lib= found=false case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test lib != "$linkmode" && test prog != "$linkmode"; then func_warning "'-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test lib = "$linkmode"; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib=$searchdir/lib$name$search_ext if test -f "$lib"; then if test .la = "$search_ext"; then found=: else found=false fi break 2 fi done done if $found; then # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll=$l done if test "X$ll" = "X$old_library"; then # only static version available found=false func_dirname "$lib" "" "." ladir=$func_dirname_result lib=$ladir/$old_library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi else # deplib doesn't seem to be a libtool library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi ;; # -l *.ltframework) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test conv = "$pass" && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi if test scan = "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "'-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test link = "$pass"; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=false case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=: fi ;; pass_all) valid_a_lib=: ;; esac if $valid_a_lib; then echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" else echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." fi ;; esac continue ;; prog) if test link != "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test conv = "$pass"; then deplibs="$deplib $deplibs" elif test prog = "$linkmode"; then if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=: continue ;; esac # case $deplib $found || test -f "$lib" \ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "'$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir=$func_dirname_result dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass" || { test prog != "$linkmode" && test lib != "$linkmode"; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test conv = "$pass"; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for '$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test prog != "$linkmode" && test lib != "$linkmode"; then func_fatal_error "'$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test yes = "$prefer_static_libs" || test built,no = "$prefer_static_libs,$installed"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib=$l done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for '$lib'" fi # This library was specified with -dlopen. if test dlopen = "$pass"; then test -z "$libdir" \ && func_fatal_error "cannot -dlopen a convenience library: '$lib'" if test -z "$dlname" || test yes != "$dlopen_support" || test no = "$build_libtool_libs" then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of '$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir=$ladir fi ;; esac func_basename "$lib" laname=$func_basename_result # Find the relevant object directory and library name. if test yes = "$installed"; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library '$lib' was moved." dir=$ladir absdir=$abs_ladir libdir=$abs_ladir else dir=$lt_sysroot$libdir absdir=$lt_sysroot$libdir fi test yes = "$hardcode_automatic" && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir=$ladir absdir=$abs_ladir # Remove this search path later func_append notinst_path " $abs_ladir" else dir=$ladir/$objdir absdir=$abs_ladir/$objdir # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test dlpreopen = "$pass"; then if test -z "$libdir" && test prog = "$linkmode"; then func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" fi case $host in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test lib = "$linkmode"; then deplibs="$dir/$old_library $deplibs" elif test prog,link = "$linkmode,$pass"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test prog = "$linkmode" && test link != "$pass"; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=false if test no != "$link_all_deplibs" || test -z "$library_names" || test no = "$build_libtool_libs"; then linkalldeplibs=: fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if $linkalldeplibs; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test prog,link = "$linkmode,$pass"; then if test -n "$library_names" && { { test no = "$prefer_static_libs" || test built,yes = "$prefer_static_libs,$installed"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then # Make sure the rpath contains only unique directories. case $temp_rpath: in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if $alldeplibs && { test pass_all = "$deplibs_check_method" || { test yes = "$build_libtool_libs" && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test built = "$use_static_libs" && test yes = "$installed"; then use_static_libs=no fi if test -n "$library_names" && { test no = "$use_static_libs" || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc* | *os2*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test no = "$installed"; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule= for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule=$dlpremoduletest break fi done if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then echo if test prog = "$linkmode"; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test lib = "$linkmode" && test yes = "$hardcode_into_libs"; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname=$1 shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname=$dlname elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc* | *os2*) func_arith $current - $age major=$func_arith_result versuffix=-$major ;; esac eval soname=\"$soname_spec\" else soname=$realname fi # Make a new name for the extract_expsyms_cmds to use soroot=$soname func_basename "$soroot" soname=$func_basename_result func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from '$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for '$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test prog = "$linkmode" || test relink != "$opt_mode"; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test no = "$hardcode_direct"; then add=$dir/$linklib case $host in *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;; *-*-sysv4*uw2*) add_dir=-L$dir ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir=-L$dir ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we cannot # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library"; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add=$dir/$old_library fi elif test -n "$old_library"; then add=$dir/$old_library fi fi esac elif test no = "$hardcode_minus_L"; then case $host in *-*-sunos*) add_shlibpath=$dir ;; esac add_dir=-L$dir add=-l$name elif test no = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; relink) if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$dir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$absdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name elif test yes = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; *) lib_linked=no ;; esac if test yes != "$lib_linked"; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test prog = "$linkmode"; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test yes != "$hardcode_direct" && test yes != "$hardcode_minus_L" && test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test prog = "$linkmode" || test relink = "$opt_mode"; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$libdir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$libdir add=-l$name elif test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add=-l$name elif test yes = "$hardcode_automatic"; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib"; then add=$inst_prefix_dir$libdir/$linklib else add=$libdir/$linklib fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir=-L$libdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name fi if test prog = "$linkmode"; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test prog = "$linkmode"; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test unsupported != "$hardcode_direct"; then test -n "$old_library" && linklib=$old_library compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test yes = "$build_libtool_libs"; then # Not a shared library if test pass_all != "$deplibs_check_method"; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system cannot link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test yes = "$module"; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test lib = "$linkmode"; then if test -n "$dependency_libs" && { test yes != "$hardcode_into_libs" || test yes = "$build_old_libs" || test yes = "$link_static"; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs=$temp_deplibs fi func_append newlib_search_path " $absdir" # Link against this library test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test no != "$link_all_deplibs"; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path=$deplib ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of '$dir'" absdir=$dir fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names"; then for tmp in $deplibrary_names; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl"; then depdepl=$absdir/$objdir/$depdepl darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" path= fi fi ;; *) path=-L$absdir/$objdir ;; esac else eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "'$deplib' seems to be moved" path=-L$absdir fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test link = "$pass"; then if test prog = "$linkmode"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs=$newdependency_libs if test dlpreopen = "$pass"; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test dlopen != "$pass"; then test conv = "$pass" || { # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= } if test prog,link = "$linkmode,$pass"; then vars="compile_deplibs finalize_deplibs" else vars=deplibs fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Add Sun CC postdeps if required: test CXX = "$tagname" && { case $host_os in linux*) case `$CC -V 2>&1 | $SED 5q` in *Sun\ C*) # Sun C++ 5.9 func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; solaris*) func_cc_basename "$CC" case $func_cc_basename_result in CC* | sunCC*) func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; esac } # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i= ;; esac if test -n "$i"; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test prog = "$linkmode"; then dlfiles=$newdlfiles fi if test prog = "$linkmode" || test lib = "$linkmode"; then dlprefiles=$newdlprefiles fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "'-R' is ignored for archives" test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "'-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "'-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs=$output func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form 'libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test no = "$module" \ && func_fatal_help "libtool library '$output' must begin with 'lib'" if test no != "$need_lib_prefix"; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test pass_all != "$deplibs_check_method"; then func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test no = "$dlself" \ || func_warning "'-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test 1 -lt "$#" \ && func_warning "ignoring multiple '-rpath's for a libtool library" install_libdir=$1 oldlibs= if test -z "$rpath"; then if test yes = "$build_libtool_libs"; then # Building a libtool convenience library. # Some compilers have problems with a '.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "'-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs=$IFS; IFS=: set dummy $vinfo 0 0 0 shift IFS=$save_ifs test -n "$7" && \ func_fatal_help "too many parameters to '-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major=$1 number_minor=$2 number_revision=$3 # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # that has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|freebsd-elf|linux|midnightbsd-elf|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_revision ;; freebsd-aout|qnx|sunos) current=$number_major revision=$number_minor age=0 ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_minor lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type '$version_type'" ;; esac ;; no) current=$1 revision=$2 age=$3 ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT '$current' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION '$revision' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE '$age' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE '$age' is greater than the current interface number '$current'" func_fatal_error "'$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" # On Darwin other compilers case $CC in nagfor*) verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" ;; *) verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; esac ;; freebsd-aout) major=.$current versuffix=.$current.$revision ;; freebsd-elf | midnightbsd-elf) func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; irix | nonstopux) if test no = "$lt_irix_increment"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring=$verstring_prefix$major.$revision # Add in all the interfaces that we are compatible with. loop=$revision while test 0 -ne "$loop"; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring_prefix$major.$iface:$verstring done # Before this point, $major must not contain '.'. major=.$major versuffix=$major.$revision ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=.$current.$age.$revision verstring=$current.$age.$revision # Add in all the interfaces that we are compatible with. loop=$age while test 0 -ne "$loop"; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring:$iface.0 done # Make executables depend on our current version. func_append verstring ":$current.0" ;; qnx) major=.$current versuffix=.$current ;; sco) major=.$current versuffix=.$current ;; sunos) major=.$current versuffix=.$current.$revision ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 file systems. func_arith $current - $age major=$func_arith_result versuffix=-$major ;; *) func_fatal_configuration "unknown library version type '$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring=0.0 ;; esac if test no = "$need_version"; then versuffix= else versuffix=.0.0 fi fi # Remove version info from name if versioning should be avoided if test yes,no = "$avoid_version,$need_version"; then major= versuffix= verstring= fi # Check to see if the archive will have undefined symbols. if test yes = "$allow_undefined"; then if test unsupported = "$allow_undefined_flag"; then if test yes = "$build_old_libs"; then func_warning "undefined symbols not allowed in $host shared libraries; building static only" build_libtool_libs=no else func_fatal_error "can't build $host shared library unless -no-undefined is specified" fi fi else # Don't allow undefined symbols. allow_undefined_flag=$no_undefined_flag fi fi func_generate_dlsyms "$libname" "$libname" : func_append libobjs " $symfileobj" test " " = "$libobjs" && libobjs= if test relink != "$opt_mode"; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) if test -n "$precious_files_regex"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles=$dlfiles dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles=$dlprefiles dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test yes = "$build_libtool_libs"; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test yes = "$build_libtool_need_lc"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release= versuffix= major= newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib=$potent_lib while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | $SED 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;; *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib= ;; esac fi if test -n "$a_deplib"; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib=$potent_lib # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs= tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test yes = "$allow_libtool_libs_with_static_runtimes"; then for i in $predeps $postdeps; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test none = "$deplibs_check_method"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test yes = "$droppeddeps"; then if test yes = "$module"; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test no = "$allow_undefined"; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs=$new_libs # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test yes = "$build_libtool_libs"; then # Remove $wl instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test yes = "$hardcode_into_libs"; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath=$finalize_rpath test relink = "$opt_mode" || rpath=$compile_rpath$rpath for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath=$finalize_shlibpath test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname=$1 shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname=$realname fi if test -z "$dlname"; then dlname=$soname fi lib=$output_objdir/$realname linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols=$output_objdir/$libname.uexp func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile func_dll_def_p "$export_symbols" || { # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols=$export_symbols export_symbols= always_export_symbols=yes } fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs=$IFS; IFS='~' for cmd1 in $cmds; do IFS=$save_ifs # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test yes = "$try_normal_branch" \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=$output_objdir/$output_la.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS=$save_ifs if test -n "$export_symbols_regex" && test : != "$skipped_export"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test : != "$skipped_export" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs=$tmp_deplibs if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test yes = "$compiler_needs_object" && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test : != "$skipped_export" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then output=$output_objdir/$output_la.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then output=$output_objdir/$output_la.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test yes = "$compiler_needs_object"; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-$k.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test -z "$objlist" || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test 1 -eq "$k"; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-$k.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-$k.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi ${skipped_export-false} && { func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi } test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs=$IFS; IFS='~' for cmd in $concat_cmds; do IFS=$save_ifs $opt_quiet || { func_quote_arg expand,pretty "$cmd" eval "func_echo $func_quote_arg_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi ${skipped_export-false} && { if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi } libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs=$IFS; IFS='~' for cmd in $cmds; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs $opt_quiet || { func_quote_arg expand,pretty "$cmd" eval "func_echo $func_quote_arg_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs # Restore the uninstalled library and exit if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test yes = "$module" || test yes = "$export_dynamic"; then # On all known operating systems, these are identical. dlname=$soname fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "'-R' is ignored for objects" test -n "$vinfo" && \ func_warning "'-version-info' is ignored for objects" test -n "$release" && \ func_warning "'-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object '$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj=$output ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # if reload_cmds runs $LD directly, get rid of -Wl from # whole_archive_flag_spec and hope we can get by with turning comma # into space. case $reload_cmds in *\$LD[\ \$]*) wl= ;; esac if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags else gentop=$output_objdir/${obj}x func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test yes = "$build_libtool_libs" || libobjs=$non_pic_objects # Create the old-style object. reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs output=$obj func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi test yes = "$build_libtool_libs" || { if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS } if test -n "$pic_flag" || test default != "$pic_mode"; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output=$libobj func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "'-version-info' is ignored for programs" test -n "$release" && \ func_warning "'-release' is ignored for programs" $preload \ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test CXX = "$tagname"; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " $wl-bind_at_load" func_append finalize_command " $wl-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs=$new_libs func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath=$rpath rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath=$rpath if test -n "$libobjs" && test yes = "$build_old_libs"; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" false # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=: case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=false ;; *cygwin* | *mingw* ) test yes = "$build_libtool_libs" || wrappers_required=false ;; *) if test no = "$need_relink" || test yes != "$build_libtool_libs"; then wrappers_required=false fi ;; esac $wrappers_required || { # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command=$compile_command$compile_rpath # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.$objext"; then func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' fi exit $exit_status } if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test yes = "$no_install"; then # We don't need to create a wrapper script. link_command=$compile_var$compile_command$compile_rpath # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi case $hardcode_action,$fast_install in relink,*) # Fast installation is not supported link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath func_warning "this platform does not like uninstalled shared libraries" func_warning "'$output' will be relinked during installation" ;; *,yes) link_command=$finalize_var$compile_command$finalize_rpath relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` ;; *,no) link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath ;; *,needless) link_command=$finalize_var$compile_command$finalize_rpath relink_command= ;; esac # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_arg pretty "$var_value" relink_command="$var=$func_quote_arg_result; export $var; $relink_command" fi done func_quote eval cd "`pwd`" func_quote_arg pretty,unquoted "($func_quote_result; $relink_command)" relink_command=$func_quote_arg_unquoted_result fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource=$output_path/$objdir/lt-$output_name.c cwrapper=$output_path/$output_name.exe $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host"; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do case $build_libtool_libs in convenience) oldobjs="$libobjs_save $symfileobj" addlibs=$convenience build_libtool_libs=no ;; module) oldobjs=$libobjs_save addlibs=$old_convenience build_libtool_libs=no ;; *) oldobjs="$old_deplibs $non_pic_objects" $preload && test -f "$symfileobj" \ && func_append oldobjs " $symfileobj" addlibs=$old_convenience ;; esac if test -n "$addlibs"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase=$func_basename_result case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj"; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test -z "$oldobjs"; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test yes = "$build_old_libs" && old_library=$libname.$libext func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_arg pretty,unquoted "$var_value" relink_command="$var=$func_quote_arg_unquoted_result; export $var; $relink_command" fi done # Quote the link command for shipping. func_quote eval cd "`pwd`" relink_command="($func_quote_result; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" func_quote_arg pretty,unquoted "$relink_command" relink_command=$func_quote_arg_unquoted_result if test yes = "$hardcode_automatic"; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test yes = "$installed"; then if test -z "$install_libdir"; then break fi output=$output_objdir/${outputname}i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name=$func_basename_result func_resolve_sysroot "$deplib" eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs=$newdependency_libs newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles=$newdlprefiles else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles=$newdlprefiles fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test -n "$bindir"; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result/$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that cannot go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test no,yes = "$installed,$need_relink"; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } if test link = "$opt_mode" || test relink = "$opt_mode"; then func_mode_link ${1+"$@"} fi # func_mode_uninstall arg... func_mode_uninstall () { $debug_cmd RM=$nonopt files= rmforce=false exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic for arg do case $arg in -f) func_append RM " $arg"; rmforce=: ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir=$func_dirname_result if test . = "$dir"; then odir=$objdir else odir=$dir/$objdir fi func_basename "$file" name=$func_basename_result test uninstall = "$opt_mode" && odir=$dir # Remember odir for removal later, being careful to avoid duplicates if test clean = "$opt_mode"; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif $rmforce; then continue fi rmfiles=$file case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case $opt_mode in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test none != "$pic_object"; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test none != "$non_pic_object"; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test clean = "$opt_mode"; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.$objext" if test yes = "$fast_install" && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name"; then func_append rmfiles " $odir/lt-$noexename.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the $objdir's in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then func_mode_uninstall ${1+"$@"} fi test -z "$opt_mode" && { help=$generic_help func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode '$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # where we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: libopenmpt-0.8.1+release.autotools/build-aux/test-driver0000755000175000017500000001141715023302326020346 00000000000000#! /bin/sh # test-driver - basic testsuite driver script. scriptversion=2018-03-07.03; # UTC # Copyright (C) 2011-2021 Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u usage_error () { echo "$0: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat <"$log_file" "$@" >>"$log_file" 2>&1 estatus=$? if test $enable_hard_errors = no && test $estatus -eq 99; then tweaked_estatus=1 else tweaked_estatus=$estatus fi case $tweaked_estatus:$expect_failure in 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 0:*) col=$grn res=PASS recheck=no gcopy=no;; 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; *:*) col=$red res=FAIL recheck=yes gcopy=yes;; esac # Report the test outcome and exit status in the logs, so that one can # know whether the test passed or failed simply by looking at the '.log' # file, without the need of also peaking into the corresponding '.trs' # file (automake bug#11814). echo "$res $test_name (exit status: $estatus)" >>"$log_file" # Report outcome to console. echo "${col}${res}${std}: $test_name" # Register the test result, and other relevant metadata. echo ":test-result: $res" > $trs_file echo ":global-test-result: $res" >> $trs_file echo ":recheck: $recheck" >> $trs_file echo ":copy-in-global-log: $gcopy" >> $trs_file # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: libopenmpt-0.8.1+release.autotools/man/0000755000175000017500000000000015023302363015106 500000000000000libopenmpt-0.8.1+release.autotools/man/openmpt123.10000644000175000017500000001177315023302261017026 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. .TH OPENMPT123 "1" "June 2025" "openmpt123 v0.8.1" "User Commands" .SH NAME openmpt123 - command line module music player based on libopenmpt .SH SYNOPSIS .B openmpt123 [\fI\,options\/\fR] [\fI\,--\/\fR] \fI\,file1 \/\fR[\fI\,file2\/\fR] ... .SH DESCRIPTION openmpt123 v0.8.1, libopenmpt 0.8.1+r23497 (OpenMPT 1.32.01.04\-r23497 https://source.openmpt.org/svn/openmpt/tags/libopenmpt\-0.8.1@23497 (2025\-06\-14T13:04:39.042416Z) clean) Copyright \(co 2013\-2025 OpenMPT Project Developers and Contributors .PP openmpt123 plays module music files. .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR Show help .TP \fB\-\-help\-keyboard\fR Show keyboard hotkeys in ui mode .TP \fB\-q\fR, \fB\-\-quiet\fR Suppress non\-error screen output .TP \fB\-v\fR, \fB\-\-verbose\fR Show more screen output .TP \fB\-\-version\fR Show version information and exit .TP \fB\-\-short\-version\fR Show version number and nothing else .TP \fB\-\-long\-version\fR Show long version information and exit .TP \fB\-\-credits\fR Show elaborate contributors list .TP \fB\-\-license\fR Show license .TP \fB\-\-probe\fR Probe each file whether it is a supported file format .TP \fB\-\-info\fR Display information about each file .TP \fB\-\-ui\fR Interactively play each file .TP \fB\-\-batch\fR Play each file .TP \fB\-\-render\fR Render each file to individual PCM data files .TP \fB\-\-banner\fR n openmpt123 banner style [0=hide,1=show,2=verbose] [default: 1] .TP \fB\-\-assume\-terminal\fR Skip checking whether stdin/stderr are a terminal, and always allow UI [default: 0] .TP \fB\-\-terminal\-width\fR n Assume terminal is n characters wide [default: \fB\-1]\fR .TP \fB\-\-terminal\-height\fR n Assume terminal is n characters high [default: \fB\-1]\fR .TP \fB\-\-[no\-]progress\fR Show playback progress [default: 1] .TP \fB\-\-[no\-]meters\fR Show peak meters [default: 1] .TP \fB\-\-[no\-]channel\-meters\fR Show channel peak meters (EXPERIMENTAL) [default: 0] .TP \fB\-\-[no\-]pattern\fR Show pattern (EXPERIMENTAL) [default: 0] .TP \fB\-\-[no\-]details\fR Show song details [default: 1] .TP \fB\-\-[no\-]message\fR Show song message [default: 0] .TP \fB\-\-update\fR n Set output update interval to n ms [default: \fB\-1]\fR .TP \fB\-\-samplerate\fR n Set samplerate to n Hz [default: 48000] .TP \fB\-\-channels\fR n use n [1,2,4] output channels [default: 2] .TP \fB\-\-[no\-]float\fR Output 32bit floating point instead of 16bit integer [default: 1] .TP \fB\-\-gain\fR n Set output gain to n dB [default: 0] .TP \fB\-\-stereo\fR n Set stereo separation to n % [default: 100] .TP \fB\-\-filter\fR n Set interpolation filter taps to n [1,2,4,8] [default: 8] .TP \fB\-\-ramping\fR n Set volume ramping strength n [0..5] [default: \fB\-1]\fR .TP \fB\-\-tempo\fR f Set tempo factor f [default: 1] .TP \fB\-\-pitch\fR f Set pitch factor f [default: 1] .TP \fB\-\-dither\fR n Dither type to use (if applicable for selected output format): [0=off,1=auto,2=0.5bit,3=1bit] [default: 1] .TP \fB\-\-playlist\fR file Load playlist from file .TP \fB\-\-[no\-]randomize\fR Randomize playlist [default: 0] .TP \fB\-\-[no\-]shuffle\fR Shuffle through playlist [default: 0] .TP \fB\-\-[no\-]restart\fR Restart playlist when finished [default: 0] .TP \fB\-\-subsong\fR n Select subsong n (\fB\-1\fR means play all subsongs consecutively) [default: \fB\-1]\fR .TP \fB\-\-repeat\fR n Repeat song n times (\fB\-1\fR means forever) [default: 0] .TP \fB\-\-seek\fR n Seek to n seconds on start [default: 0] .TP \fB\-\-end\-time\fR n Play until position is n seconds (0 means until the end) [default: 0] .TP \fB\-\-ctl\fR c=v Set libopenmpt ctl c to value v .TP \fB\-\-driver\fR n Set output driver [default: default], .TP \fB\-\-device\fR n Set output device [default: default], use \fB\-\-device\fR help to show available devices .TP \fB\-\-buffer\fR n Set output buffer size to n ms [default: \fB\-1]\fR .TP \fB\-\-period\fR n Set output period size to n ms [default: \fB\-1]\fR .TP \fB\-\-stdout\fR Write raw audio data to stdout [default: 0] .TP \fB\-\-output\-type\fR t Use output format t when writing to a individual PCM files (only applies to \fB\-\-render\fR mode) [default: auto] .TP \fB\-o\fR, \fB\-\-output\fR f Write PCM output to file f instead of streaming to audio device (only applies to \fB\-\-ui\fR and \fB\-\-batch\fR modes) [default: ] .TP \fB\-\-force\fR Force overwriting of output file [default: 0] .TP \fB\-\-\fR Interpret further arguments as filenames .PP Keyboard hotkeys (use 'openmpt123 \fB\-\-ui\fR'): .TP [q] quit .TP [ ] pause / unpause .TP [N] skip 10 files backward .TP [n] prev file .TP [m] next file .TP [M] skip 10 files forward .TP [h] seek 10 seconds backward .TP [j] seek 1 seconds backward .TP [k] seek 1 seconds forward .TP [l] seek 10 seconds forward .TP [u]|[i] +/\- tempo .TP [o]|[p] +/\- pitch .TP [3]|[4] +/\- gain .TP [5]|[6] +/\- stereo separation .TP [7]|[8] +/\- filter taps .TP [9]|[0] +/\- volume ramping .SH COPYRIGHT Copyright \(co 2013\-2025 OpenMPT Project Developers and Contributors libopenmpt-0.8.1+release.autotools/libopenmpt/0000755000175000017500000000000015023302363016504 500000000000000libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_ext_impl.cpp0000644000175000017500000003322114717154075023221 00000000000000/* * libopenmpt_ext_impl.cpp * ----------------------- * Purpose: libopenmpt extensions - implementation * Notes : * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "common/stdafx.h" #include "libopenmpt_internal.h" #include "libopenmpt_ext.hpp" #include "libopenmpt_ext_impl.hpp" #include "mpt/base/saturate_round.hpp" #include "soundlib/Sndfile.h" // assume OPENMPT_NAMESPACE is OpenMPT namespace openmpt { module_ext_impl::module_ext_impl( callback_stream_wrapper stream, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : module_impl( stream, std::move(log), ctls ) { ctor(); } module_ext_impl::module_ext_impl( std::istream & stream, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : module_impl( stream, std::move(log), ctls ) { ctor(); } module_ext_impl::module_ext_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : module_impl( data, std::move(log), ctls ) { ctor(); } module_ext_impl::module_ext_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : module_impl( data, std::move(log), ctls ) { ctor(); } module_ext_impl::module_ext_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : module_impl( data, std::move(log), ctls ) { ctor(); } module_ext_impl::module_ext_impl( const std::byte * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : module_impl( data, size, std::move(log), ctls ) { ctor(); } module_ext_impl::module_ext_impl( const std::uint8_t * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : module_impl( data, size, std::move(log), ctls ) { ctor(); } module_ext_impl::module_ext_impl( const char * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : module_impl( data, size, std::move(log), ctls ) { ctor(); } module_ext_impl::module_ext_impl( const void * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : module_impl( data, size, std::move(log), ctls ) { ctor(); } void module_ext_impl::ctor() { /* add stuff here */ } module_ext_impl::~module_ext_impl() { /* add stuff here */ } void * module_ext_impl::get_interface( const std::string & interface_id ) { if ( interface_id.empty() ) { return 0; } else if ( interface_id == ext::pattern_vis_id ) { return dynamic_cast< ext::pattern_vis * >( this ); } else if ( interface_id == ext::interactive_id ) { return dynamic_cast< ext::interactive * >( this ); } else if ( interface_id == ext::interactive2_id ) { return dynamic_cast< ext::interactive2 * >( this ); } else if ( interface_id == ext::interactive3_id ) { return dynamic_cast< ext::interactive3 * >( this ); /* add stuff here */ } else { return 0; } } // pattern_vis module_ext_impl::effect_type module_ext_impl::get_pattern_row_channel_volume_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const { auto volcmd = static_cast( get_pattern_row_channel_command( pattern, row, channel, module::command_volumeffect ) ); switch ( OpenMPT::ModCommand::GetVolumeEffectType( volcmd ) ) { case OpenMPT::EffectType::Normal : return effect_general; break; case OpenMPT::EffectType::Global : return effect_global ; break; case OpenMPT::EffectType::Volume : return effect_volume ; break; case OpenMPT::EffectType::Panning: return effect_panning; break; case OpenMPT::EffectType::Pitch : return effect_pitch ; break; default: return effect_unknown; break; } } module_ext_impl::effect_type module_ext_impl::get_pattern_row_channel_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const { auto command = static_cast( get_pattern_row_channel_command( pattern, row, channel, module::command_effect ) ); switch (OpenMPT::ModCommand::GetEffectType( command ) ) { case OpenMPT::EffectType::Normal : return effect_general; break; case OpenMPT::EffectType::Global : return effect_global ; break; case OpenMPT::EffectType::Volume : return effect_volume ; break; case OpenMPT::EffectType::Panning: return effect_panning; break; case OpenMPT::EffectType::Pitch : return effect_pitch ; break; default: return effect_unknown; break; } } // interactive void module_ext_impl::set_current_speed( std::int32_t speed ) { if ( speed < 1 || speed > 65535 ) { throw openmpt::exception("invalid tick count"); } m_sndFile->m_PlayState.m_nMusicSpeed = speed; } void module_ext_impl::set_current_tempo( std::int32_t tempo ) { if ( tempo < 32 || tempo > 512 ) { throw openmpt::exception("invalid tempo"); } m_sndFile->m_PlayState.m_nMusicTempo.Set( tempo ); } void module_ext_impl::set_tempo_factor( double factor ) { if ( factor <= 0.0 || factor > 4.0 ) { throw openmpt::exception("invalid tempo factor"); } m_sndFile->m_nTempoFactor = mpt::saturate_round( 65536.0 / factor ); m_sndFile->RecalculateSamplesPerTick(); } double module_ext_impl::get_tempo_factor( ) const { return 65536.0 / m_sndFile->m_nTempoFactor; } void module_ext_impl::set_pitch_factor( double factor ) { if ( factor <= 0.0 || factor > 4.0 ) { throw openmpt::exception("invalid pitch factor"); } m_sndFile->m_nFreqFactor = mpt::saturate_round( 65536.0 * factor ); m_sndFile->RecalculateSamplesPerTick(); } double module_ext_impl::get_pitch_factor( ) const { return m_sndFile->m_nFreqFactor / 65536.0; } void module_ext_impl::set_global_volume( double volume ) { if ( volume < 0.0 || volume > 1.0 ) { throw openmpt::exception("invalid global volume"); } m_sndFile->m_PlayState.m_nGlobalVolume = mpt::saturate_round( volume * OpenMPT::MAX_GLOBAL_VOLUME ); } double module_ext_impl::get_global_volume( ) const { return m_sndFile->m_PlayState.m_nGlobalVolume / static_cast( OpenMPT::MAX_GLOBAL_VOLUME ); } void module_ext_impl::set_channel_volume( std::int32_t channel, double volume ) { if ( channel < 0 || channel >= get_num_channels() ) { throw openmpt::exception("invalid channel"); } if ( volume < 0.0 || volume > 1.0 ) { throw openmpt::exception("invalid global volume"); } m_sndFile->m_PlayState.Chn[channel].nGlobalVol = mpt::saturate_round(volume * 64.0); } double module_ext_impl::get_channel_volume( std::int32_t channel ) const { if ( channel < 0 || channel >= get_num_channels() ) { throw openmpt::exception("invalid channel"); } return m_sndFile->m_PlayState.Chn[channel].nGlobalVol / 64.0; } void module_ext_impl::set_channel_mute_status( std::int32_t channel, bool mute ) { if ( channel < 0 || channel >= get_num_channels() ) { throw openmpt::exception("invalid channel"); } m_sndFile->ChnSettings[channel].dwFlags.set( OpenMPT::CHN_MUTE | OpenMPT::CHN_SYNCMUTE , mute ); m_sndFile->m_PlayState.Chn[channel].dwFlags.set( OpenMPT::CHN_MUTE | OpenMPT::CHN_SYNCMUTE , mute ); // Also update NNA channels for ( OpenMPT::CHANNELINDEX i = m_sndFile->GetNumChannels(); i < OpenMPT::MAX_CHANNELS; i++) { if ( m_sndFile->m_PlayState.Chn[i].nMasterChn == channel + 1) { m_sndFile->m_PlayState.Chn[i].dwFlags.set( OpenMPT::CHN_MUTE | OpenMPT::CHN_SYNCMUTE, mute ); } } } bool module_ext_impl::get_channel_mute_status( std::int32_t channel ) const { if ( channel < 0 || channel >= get_num_channels() ) { throw openmpt::exception("invalid channel"); } return m_sndFile->m_PlayState.Chn[channel].dwFlags[OpenMPT::CHN_MUTE | OpenMPT::CHN_SYNCMUTE]; } void module_ext_impl::set_instrument_mute_status( std::int32_t instrument, bool mute ) { const bool instrument_mode = get_num_instruments() != 0; const std::int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples(); if ( instrument < 0 || instrument >= max_instrument ) { throw openmpt::exception("invalid instrument"); } if ( instrument_mode ) { if ( m_sndFile->Instruments[instrument + 1] != nullptr ) { m_sndFile->Instruments[instrument + 1]->dwFlags.set( OpenMPT::INS_MUTE, mute ); } } else { m_sndFile->GetSample( static_cast( instrument + 1 ) ).uFlags.set( OpenMPT::CHN_MUTE, mute ) ; } } bool module_ext_impl::get_instrument_mute_status( std::int32_t instrument ) const { const bool instrument_mode = get_num_instruments() != 0; const std::int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples(); if ( instrument < 0 || instrument >= max_instrument ) { throw openmpt::exception("invalid instrument"); } if ( instrument_mode ) { if ( m_sndFile->Instruments[instrument + 1] != nullptr ) { return m_sndFile->Instruments[instrument + 1]->dwFlags[OpenMPT::INS_MUTE]; } return true; } else { return m_sndFile->GetSample( static_cast( instrument + 1 ) ).uFlags[OpenMPT::CHN_MUTE]; } } std::int32_t module_ext_impl::play_note( std::int32_t instrument, std::int32_t note, double volume, double panning ) { const bool instrument_mode = get_num_instruments() != 0; const std::int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples(); if ( instrument < 0 || instrument >= max_instrument ) { throw openmpt::exception("invalid instrument"); } note += OpenMPT::NOTE_MIN; if ( note < OpenMPT::NOTE_MIN || note > OpenMPT::NOTE_MAX ) { throw openmpt::exception("invalid note"); } // Find a free channel OpenMPT::CHANNELINDEX free_channel = m_sndFile->GetNNAChannel( OpenMPT::CHANNELINDEX_INVALID ); if ( free_channel == OpenMPT::CHANNELINDEX_INVALID ) { free_channel = OpenMPT::MAX_CHANNELS - 1; } OpenMPT::ModChannel &chn = m_sndFile->m_PlayState.Chn[free_channel]; chn.Reset( OpenMPT::ModChannel::resetTotal, *m_sndFile, OpenMPT::CHANNELINDEX_INVALID, OpenMPT::CHN_MUTE ); chn.nMasterChn = 0; // remove NNA association chn.nNewNote = chn.nLastNote = static_cast(note); chn.ResetEnvelopes(); m_sndFile->InstrumentChange(chn, instrument + 1); chn.nFadeOutVol = 0x10000; m_sndFile->NoteChange(chn, note, false, true, true); chn.nPan = mpt::saturate_round( OpenMPT::Clamp( panning * 128.0, -128.0, 128.0 ) + 128.0 ); chn.nVolume = mpt::saturate_round( OpenMPT::Clamp( volume * 256.0, 0.0, 256.0 ) ); // Remove channel from list of mixed channels to fix https://bugs.openmpt.org/view.php?id=209 // This is required because a previous note on the same channel might have just stopped playing, // but the channel is still in the mix list. // Since the channel volume / etc is only updated every tick in CSoundFile::ReadNote, and we // do not want to duplicate mixmode-dependant logic here, CSoundFile::CreateStereoMix may already // try to mix our newly set up channel at volume 0 if we don't remove it from the list. auto mix_begin = std::begin( m_sndFile->m_PlayState.ChnMix ); auto mix_end = std::remove( mix_begin, mix_begin + m_sndFile->m_nMixChannels, free_channel ); m_sndFile->m_nMixChannels = static_cast( std::distance( mix_begin, mix_end ) ); return free_channel; } void module_ext_impl::stop_note( std::int32_t channel ) { if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) { throw openmpt::exception("invalid channel"); } auto & chn = m_sndFile->m_PlayState.Chn[channel]; chn.nLength = 0; chn.pCurrentSample = nullptr; } void module_ext_impl::note_off(int32_t channel ) { if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) { throw openmpt::exception( "invalid channel" ); } auto & chn = m_sndFile->m_PlayState.Chn[channel]; chn.dwFlags |= OpenMPT::CHN_KEYOFF; } void module_ext_impl::note_fade(int32_t channel ) { if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) { throw openmpt::exception( "invalid channel" ); } auto & chn = m_sndFile->m_PlayState.Chn[channel]; chn.dwFlags |= OpenMPT::CHN_NOTEFADE; } void module_ext_impl::set_channel_panning( int32_t channel, double panning ) { if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) { throw openmpt::exception( "invalid channel" ); } auto & chn = m_sndFile->m_PlayState.Chn[channel]; chn.nPan = mpt::saturate_round( std::clamp( panning, -1.0, 1.0 ) * 128.0 + 128.0 ); } double module_ext_impl::get_channel_panning( int32_t channel ) { if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) { throw openmpt::exception( "invalid channel" ); } auto & chn = m_sndFile->m_PlayState.Chn[channel]; return ( chn.nPan - 128 ) / 128.0; } void module_ext_impl::set_note_finetune( int32_t channel, double finetune ) { if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) { throw openmpt::exception( "invalid channel" ); } auto & chn = m_sndFile->m_PlayState.Chn[channel]; chn.microTuning = mpt::saturate_round( finetune * 32768.0 ); } double module_ext_impl::get_note_finetune( int32_t channel ) { if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) { throw openmpt::exception( "invalid channel" ); } auto & chn = m_sndFile->m_PlayState.Chn[channel]; return chn.microTuning / 32768.0; } void module_ext_impl::set_current_tempo2( double tempo ) { if ( tempo < 32.0 || tempo > 512.0 ) { throw openmpt::exception("invalid tempo"); } m_sndFile->m_PlayState.m_nMusicTempo = decltype( m_sndFile->m_PlayState.m_nMusicTempo )( tempo ); } /* add stuff here */ } // namespace openmpt libopenmpt-0.8.1+release.autotools/libopenmpt/.clang-format0000644000175000017500000001141114275750533021013 00000000000000# clang-format 14 Language: Cpp Standard: c++20 AccessModifierOffset: -2 #? AlignAfterOpenBracket: AlwaysBreak AlignArrayOfStructures: Left AlignConsecutiveAssignments: false AlignConsecutiveBitFields: false AlignConsecutiveDeclarations: false AlignConsecutiveMacros: true AlignEscapedNewlines: DontAlign AlignOperands: AlignAfterOperator AlignTrailingComments: true AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: Never AllowShortCaseLabelsOnASingleLine: false AllowShortEnumsOnASingleLine: false AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: false AllowShortLambdasOnASingleLine: Inline AllowShortLoopsOnASingleLine: false AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: Yes AttributeMacros: [] BinPackArguments: true BinPackParameters: false BitFieldColonSpacing: Both BraceWrapping: AfterCaseLabel: true AfterClass: false AfterControlStatement: MultiLine AfterEnum: false AfterFunction: false AfterNamespace: false #AfterObjCDeclaration AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false BeforeLambdaBody: true BeforeWhile: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: false SplitEmptyNamespace: true #BreakAfterJavaFieldAnnotations BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Custom BreakBeforeConceptDeclarations: true BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeComma BreakInheritanceList: BeforeComma BreakStringLiterals: false ColumnLimit: 0 CommentPragmas: '' #? CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 2 #? ContinuationIndentWidth: 2 #? Cpp11BracedListStyle: true DeriveLineEnding: true DerivePointerAlignment: false EmptyLineAfterAccessModifier: Leave EmptyLineBeforeAccessModifier: Leave FixNamespaceComments: true ForEachMacros: [] IfMacros: ['MPT_MAYBE_CONSTANT_IF'] IncludeBlocks: Preserve IncludeCategories: [] #? IncludeIsMainRegex: '' #? IncludeIsMainSourceRegex: '' #? IndentAccessModifiers: false IndentCaseBlocks: true IndentCaseLabels: true IndentExternBlock: NoIndent IndentGotoLabels: false IndentPPDirectives: None #IndentRequiresClause: true #BeforeHash IndentWidth: 2 IndentWrappedFunctionNames: true InsertTrailingCommas: None #JavaImportGroups #JavaScriptQuotes #JavaScriptWrapImports KeepEmptyLinesAtTheStartOfBlocks: true LambdaBodyIndentation: OuterScope MacroBlockBegin: '' #? MacroBlockEnd: '' #? MaxEmptyLinesToKeep: 3 NamespaceIndentation: None NamespaceMacros: [] #? #ObjCBinPackProtocolList #ObjCBlockIndentWidth #ObjCBreakBeforeNestedBlockParam #ObjCSpaceAfterProperty #ObjCSpaceBeforeProtocolList PackConstructorInitializers: Never #PenaltyBreakAssignment #PenaltyBreakBeforeFirstCallParameter #PenaltyBreakComment #PenaltyBreakFirstLessLess #PenaltyBreakOpenParenthesis #PenaltyBreakString #PenaltyBreakTemplateDeclaration #PenaltyExcessCharacter #PenaltyIndentedWhitespace #PenaltyReturnTypeOnItsOwnLine PointerAlignment: Middle PPIndentWidth: -1 #RawStringFormats QualifierAlignment: Leave #QualifierOrder: ['static', 'inline', 'constexpr', 'volatile', 'const', 'restrict', 'type'] ReferenceAlignment: Pointer ReflowComments: false RemoveBracesLLVM: false SeparateDefinitionBlocks: Leave ShortNamespaceLines: 1 SortIncludes: false #SortJavaStaticImport SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true SpaceAroundPointerQualifiers: Default SpaceBeforeAssignmentOperators: true SpaceBeforeCaseColon: false SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeParensOptions: AfterControlStatements: true AfterForeachMacros: true AfterFunctionDeclarationName: false AfterFunctionDefinitionName: false AfterIfMacros: true AfterOverloadedOperator: false #AfterRequiresInClause: false #AfterRequiresInExpression: false BeforeNonEmptyParentheses: false SpaceBeforeRangeBasedForLoopColon: true SpaceBeforeSquareBrackets: false SpaceInEmptyBlock: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInConditionalStatement: true SpacesInContainerLiterals: true SpacesInLineCommentPrefix: Minimum: 1 Maximum: -1 SpacesInParentheses: true SpacesInSquareBrackets: false StatementAttributeLikeMacros: [] StatementMacros: [ 'MPT_WARNING', 'MPT_TEST_GROUP_INLINE_IDENTIFIER', 'MPT_TEST_GROUP_INLINE', 'MPT_TEST_GROUP_STATIC' ] #? TabWidth: 2 TypenameMacros: [] #? UseCRLF: false UseTab: ForContinuationAndIndentation WhitespaceSensitiveMacros: - MPT_PP_STRINGIFY libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_ext_impl.hpp0000644000175000017500000000753414201775654023236 00000000000000/* * libopenmpt_ext_impl.hpp * ----------------------- * Purpose: libopenmpt extensions - implementation header * Notes : * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_EXT_IMPL_HPP #define LIBOPENMPT_EXT_IMPL_HPP #include "libopenmpt_internal.h" #include "libopenmpt_impl.hpp" #include "libopenmpt_ext.hpp" namespace openmpt { class module_ext_impl : public module_impl , public ext::pattern_vis , public ext::interactive , public ext::interactive2 , public ext::interactive3 /* add stuff here */ { public: module_ext_impl( callback_stream_wrapper stream, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_ext_impl( std::istream & stream, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_ext_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_ext_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_ext_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_ext_impl( const std::byte * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_ext_impl( const std::uint8_t * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_ext_impl( const char * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_ext_impl( const void * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); private: /* add stuff here */ private: void ctor(); public: ~module_ext_impl(); public: void * get_interface( const std::string & interface_id ); // pattern_vis effect_type get_pattern_row_channel_volume_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const override; effect_type get_pattern_row_channel_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const override; // interactive void set_current_speed( std::int32_t speed ) override; void set_current_tempo( std::int32_t tempo ) override; void set_tempo_factor( double factor ) override; double get_tempo_factor( ) const override; void set_pitch_factor( double factor ) override; double get_pitch_factor( ) const override; void set_global_volume( double volume ) override; double get_global_volume( ) const override; void set_channel_volume( std::int32_t channel, double volume ) override; double get_channel_volume( std::int32_t channel ) const override; void set_channel_mute_status( std::int32_t channel, bool mute ) override; bool get_channel_mute_status( std::int32_t channel ) const override; void set_instrument_mute_status( std::int32_t instrument, bool mute ) override; bool get_instrument_mute_status( std::int32_t instrument ) const override; std::int32_t play_note( std::int32_t instrument, std::int32_t note, double volume, double panning ) override; void stop_note( std::int32_t channel ) override; void note_off( std::int32_t channel ) override; void note_fade( std::int32_t channel ) override; void set_channel_panning( std::int32_t channel, double panning ) override; double get_channel_panning( std::int32_t channel ) override; void set_note_finetune( std::int32_t channel, double finetune ) override; double get_note_finetune( std::int32_t channel ) override; void set_current_tempo2(double tempo) override; /* add stuff here */ }; // class module_ext_impl } // namespace openmpt #endif // LIBOPENMPT_EXT_IMPL_HPP libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_c.cpp0000644000175000017500000017122014754140332021614 00000000000000/* * libopenmpt_c.cpp * ---------------- * Purpose: libopenmpt C interface implementation * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "openmpt/all/BuildSettings.hpp" #if defined(__MINGW32__) && !defined(__MINGW64__) #include #endif #include "libopenmpt_internal.h" #include "libopenmpt.h" #include "libopenmpt_ext.h" #include "libopenmpt_impl.hpp" #include "libopenmpt_ext_impl.hpp" #include #include #include #include #include #include #include #include #if defined(_MSC_VER) #pragma warning(disable:4702) /* unreachable code */ #endif namespace openmpt { static const char * strdup( const char * src ) { char * dst = (char*)std::calloc( std::strlen( src ) + 1, sizeof( char ) ); if ( !dst ) { return NULL; } std::strcpy( dst, src ); return dst; } class logfunc_logger : public log_interface { private: openmpt_log_func m_logfunc; void * m_user; public: logfunc_logger( openmpt_log_func func, void * user ) : m_logfunc(func), m_user(user) { return; } void log( const std::string & message ) const override { if ( m_logfunc ) { m_logfunc( message.c_str(), m_user ); } else { openmpt_log_func_default( message.c_str(), m_user ); } } }; // class logfunc_logger namespace interface { class invalid_module_pointer : public openmpt::exception { public: invalid_module_pointer() : openmpt::exception("module * not valid") { return; } invalid_module_pointer(const invalid_module_pointer&) = default; virtual ~invalid_module_pointer() noexcept = default; }; class argument_null_pointer : public openmpt::exception { public: argument_null_pointer() : openmpt::exception("argument null pointer") { return; } argument_null_pointer(const argument_null_pointer&) = default; virtual ~argument_null_pointer() noexcept = default; }; } // namespace interface static std::string format_exception( const char * const function ) { std::string err; try { // cppcheck false-positive // cppcheck-suppress rethrowNoCurrentException throw; } catch ( const openmpt::exception & e ) { err += function; err += ": "; err += "ERROR: "; const char * what = e.what(); err += what ? what : ""; } catch ( const std::bad_alloc & e ) { err += function; err += ": "; err += "OUT OF MEMORY: "; const char * what = e.what(); err += what ? what : ""; } catch ( const std::exception & e ) { err += function; err += ": "; err += "INTERNAL ERROR: "; const char * what = e.what(); err += what ? what : ""; } catch ( ... ) { err += function; err += ": "; err += "UNKNOWN INTERNAL ERROR"; } return err; } static void error_message_from_exception( const char * * error_message, const std::exception & e ) { if ( error_message ) { const char * what = e.what(); *error_message = ( what ? openmpt::strdup( what ) : openmpt::strdup( "" ) ); } } static int error_from_exception( const char * * error_message ) { int error = 0; if ( error_message ) { if ( *error_message ) { openmpt_free_string( *error_message ); *error_message = NULL; } } try { // cppcheck false-positive // cppcheck-suppress rethrowNoCurrentException throw; } catch ( const std::bad_alloc & e ) { error = OPENMPT_ERROR_OUT_OF_MEMORY; error_message_from_exception( error_message, e ); } catch ( const openmpt::interface::invalid_module_pointer & e ) { error = OPENMPT_ERROR_INVALID_MODULE_POINTER; error_message_from_exception( error_message, e ); } catch ( const openmpt::interface::argument_null_pointer & e ) { error = OPENMPT_ERROR_ARGUMENT_NULL_POINTER; error_message_from_exception( error_message, e ); } catch ( const openmpt::exception & e ) { error = OPENMPT_ERROR_GENERAL; error_message_from_exception( error_message, e ); } catch ( const std::invalid_argument & e ) { error = OPENMPT_ERROR_INVALID_ARGUMENT; error_message_from_exception( error_message, e ); } catch ( const std::out_of_range & e ) { error = OPENMPT_ERROR_OUT_OF_RANGE; error_message_from_exception( error_message, e ); } catch ( const std::length_error & e ) { error = OPENMPT_ERROR_LENGTH; error_message_from_exception( error_message, e ); } catch ( const std::domain_error & e ) { error = OPENMPT_ERROR_DOMAIN; error_message_from_exception( error_message, e ); } catch ( const std::logic_error & e ) { error = OPENMPT_ERROR_LOGIC; error_message_from_exception( error_message, e ); } catch ( const std::underflow_error & e ) { error = OPENMPT_ERROR_UNDERFLOW; error_message_from_exception( error_message, e ); } catch ( const std::overflow_error & e ) { error = OPENMPT_ERROR_OVERFLOW; error_message_from_exception( error_message, e ); } catch ( const std::range_error & e ) { error = OPENMPT_ERROR_RANGE; error_message_from_exception( error_message, e ); } catch ( const std::runtime_error & e ) { error = OPENMPT_ERROR_RUNTIME; error_message_from_exception( error_message, e ); } catch ( const std::exception & e ) { error = OPENMPT_ERROR_EXCEPTION; error_message_from_exception( error_message, e ); } catch ( ... ) { error = OPENMPT_ERROR_UNKNOWN; } return error; } } // namespace openmpt extern "C" { struct openmpt_module { openmpt_log_func logfunc; void * loguser; openmpt_error_func errfunc; void * erruser; int error; const char * error_message; openmpt::module_impl * impl; }; struct openmpt_module_ext { openmpt_module mod; openmpt::module_ext_impl * impl; }; } // extern "C" namespace openmpt { static void do_report_exception( const char * const function, openmpt_log_func const logfunc = 0, void * const loguser = 0, openmpt_error_func errfunc = 0, void * const erruser = 0, openmpt::module_impl * const impl = 0, openmpt_module * const mod = 0, int * const err = 0, const char * * err_msg = 0 ) { int error = OPENMPT_ERROR_OK; const char * error_message = NULL; int error_func_result = OPENMPT_ERROR_FUNC_RESULT_DEFAULT; if ( errfunc || mod || err || err_msg ) { error = error_from_exception( mod ? &error_message : NULL ); } if ( errfunc ) { error_func_result = errfunc( error, erruser ); } if ( mod && ( error_func_result & OPENMPT_ERROR_FUNC_RESULT_STORE ) ) { mod->error = error; mod->error_message = ( error_message ? openmpt::strdup( error_message ) : openmpt::strdup( "" ) ); } if ( err ) { *err = error; } if ( err_msg ) { *err_msg = ( error_message ? openmpt::strdup( error_message ) : openmpt::strdup( "" ) ); } if ( error_message ) { openmpt_free_string( error_message ); error_message = NULL; } if ( error_func_result & OPENMPT_ERROR_FUNC_RESULT_LOG ) { try { const std::string message = format_exception( function ); if ( impl ) { impl->PushToCSoundFileLog( message ); } else if ( logfunc ) { logfunc( message.c_str(), loguser ); } else { openmpt_log_func_default( message.c_str(), NULL ); } } catch ( ... ) { fprintf( stderr, "openmpt: %s:%i: UNKNOWN INTERNAL ERROR in error handling: function='%s', logfunc=%p, loguser=%p, errfunc=%p, erruser=%p, impl=%p\n", __FILE__, static_cast( __LINE__ ), function ? function : "", reinterpret_cast( logfunc ), loguser, reinterpret_cast( errfunc ), erruser, static_cast( impl ) ); fflush( stderr ); } } } static void report_exception( const char * const function, openmpt_module * mod = 0, int * error = 0, const char * * error_message = 0 ) { do_report_exception( function, mod ? mod->logfunc : NULL, mod ? mod->loguser : NULL, mod ? mod->errfunc : NULL, mod ? mod->erruser : NULL, mod ? mod->impl : 0, mod ? mod : NULL, error ? error : NULL, error_message ? error_message : NULL ); } static void report_exception( const char * const function, openmpt_log_func const logfunc, void * const loguser, openmpt_error_func errfunc, void * const erruser, int * error, const char * * error_message ) { do_report_exception( function, logfunc, loguser, errfunc, erruser, 0, 0, error, error_message ); } namespace interface { template < typename T > void check_soundfile( T * mod ) { if ( !mod ) { throw openmpt::interface::invalid_module_pointer(); } } template < typename T > void check_pointer( T * p ) { if ( !p ) { throw openmpt::interface::argument_null_pointer(); } } } // namespace interface } // namespace openmpt extern "C" { uint32_t openmpt_get_library_version(void) { try { return openmpt::get_library_version(); } catch ( ... ) { openmpt::report_exception( __func__ ); } return 0; } uint32_t openmpt_get_core_version(void) { try { return openmpt::get_core_version(); } catch ( ... ) { openmpt::report_exception( __func__ ); } return 0; } void openmpt_free_string( const char * str ) { try { std::free( const_cast< char * >( str ) ); } catch ( ... ) { openmpt::report_exception( __func__ ); } return; } const char * openmpt_get_string( const char * key ) { try { if ( !key ) { return openmpt::strdup( "" ); } return openmpt::strdup( openmpt::string::get( key ).c_str() ); } catch ( ... ) { openmpt::report_exception( __func__ ); } return NULL; } const char * openmpt_get_supported_extensions(void) { try { std::string retval; bool first = true; std::vector supported_extensions = openmpt::module_impl::get_supported_extensions(); for ( std::vector::iterator i = supported_extensions.begin(); i != supported_extensions.end(); ++i ) { if ( first ) { first = false; } else { retval += ";"; } retval += *i; } return openmpt::strdup( retval.c_str() ); } catch ( ... ) { openmpt::report_exception( __func__ ); } return NULL; } int openmpt_is_extension_supported( const char * extension ) { try { if ( !extension ) { return 0; } return openmpt::module_impl::is_extension_supported( extension ) ? 1 : 0; } catch ( ... ) { openmpt::report_exception( __func__ ); } return 0; } void openmpt_log_func_default( const char * message, void * /*user*/ ) { fprintf( stderr, "openmpt: %s\n", message ); fflush( stderr ); } void openmpt_log_func_silent( const char * /*message*/ , void * /*user*/ ) { return; } int openmpt_error_is_transient( int error ) { int result = 0; switch ( error ) { case OPENMPT_ERROR_OUT_OF_MEMORY: result = 1; break; default: result = 0; break; } return result; } const char * openmpt_error_string( int error ) { const char * text = "unknown error"; switch ( error ) { case OPENMPT_ERROR_OK: text = ""; break; case OPENMPT_ERROR_UNKNOWN: text = "unknown internal error"; break; case OPENMPT_ERROR_EXCEPTION: text = "unknown exception "; break; case OPENMPT_ERROR_OUT_OF_MEMORY: text = "out of memory"; break; case OPENMPT_ERROR_RUNTIME: text = "runtime error"; break; case OPENMPT_ERROR_RANGE: text = "range error"; break; case OPENMPT_ERROR_OVERFLOW: text = "arithmetic overflow"; break; case OPENMPT_ERROR_UNDERFLOW: text = "arithmetic underflow"; break; case OPENMPT_ERROR_LOGIC: text = "logic error"; break; case OPENMPT_ERROR_DOMAIN: text = "value domain error"; break; case OPENMPT_ERROR_LENGTH: text = "maximum supported size exceeded"; break; case OPENMPT_ERROR_OUT_OF_RANGE: text = "argument out of range"; break; case OPENMPT_ERROR_INVALID_ARGUMENT: text = "invalid argument"; break; case OPENMPT_ERROR_GENERAL: text = "libopenmpt error"; break; } return openmpt::strdup( text ); } int openmpt_error_func_default( int error, void * /* user */ ) { (void)error; return OPENMPT_ERROR_FUNC_RESULT_DEFAULT; } int openmpt_error_func_log( int error, void * /* user */ ) { (void)error; return OPENMPT_ERROR_FUNC_RESULT_LOG; } int openmpt_error_func_store( int error, void * /* user */ ) { (void)error; return OPENMPT_ERROR_FUNC_RESULT_STORE; } int openmpt_error_func_ignore( int error, void * /* user */ ) { (void)error; return OPENMPT_ERROR_FUNC_RESULT_NONE; } int openmpt_error_func_errno( int error, void * user ) { int * e = (int *)user; if ( !e ) { return OPENMPT_ERROR_FUNC_RESULT_DEFAULT; } *e = error; return OPENMPT_ERROR_FUNC_RESULT_NONE; } void * openmpt_error_func_errno_userdata( int * error ) { return (void *)error; } double openmpt_could_open_probability( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * loguser ) { return openmpt_could_open_probability2( stream_callbacks, stream, effort, logfunc, loguser, NULL, NULL, NULL, NULL ); } double openmpt_could_open_propability( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * loguser ) { return openmpt_could_open_probability2( stream_callbacks, stream, effort, logfunc, loguser, NULL, NULL, NULL, NULL ); } double openmpt_could_open_probability2( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ) { try { openmpt::callback_stream_wrapper istream = { stream, stream_callbacks.read, stream_callbacks.seek, stream_callbacks.tell }; return openmpt::module_impl::could_open_probability( istream, effort, openmpt::helper::make_unique( logfunc ? logfunc : openmpt_log_func_default, loguser ) ); } catch ( ... ) { openmpt::report_exception( __func__, logfunc, loguser, errfunc, erruser, error, error_message ); } return 0.0; } size_t openmpt_probe_file_header_get_recommended_size(void) { try { return openmpt::module_impl::probe_file_header_get_recommended_size(); } catch ( ... ) { openmpt::report_exception( __func__ ); } return 0; } int openmpt_probe_file_header( uint64_t flags, const void * data, size_t size, uint64_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ) { try { return openmpt::module_impl::probe_file_header( flags, data, size, filesize ); } catch ( ... ) { openmpt::report_exception( __func__, logfunc, loguser, errfunc, erruser, error, error_message ); } return OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR; } int openmpt_probe_file_header_without_filesize( uint64_t flags, const void * data, size_t size, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ) { try { return openmpt::module_impl::probe_file_header( flags, data, size ); } catch ( ... ) { openmpt::report_exception( __func__, logfunc, loguser, errfunc, erruser, error, error_message ); } return OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR; } int openmpt_probe_file_header_from_stream( uint64_t flags, openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ) { try { openmpt::callback_stream_wrapper istream = { stream, stream_callbacks.read, stream_callbacks.seek, stream_callbacks.tell }; return openmpt::module_impl::probe_file_header( flags, istream ); } catch ( ... ) { openmpt::report_exception( __func__, logfunc, loguser, errfunc, erruser, error, error_message ); } return OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR; } openmpt_module * openmpt_module_create( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * user, const openmpt_module_initial_ctl * ctls ) { return openmpt_module_create2( stream_callbacks, stream, logfunc, user, NULL, NULL, NULL, NULL, ctls ); } openmpt_module * openmpt_module_create2( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ) { try { openmpt_module * mod = (openmpt_module*)std::calloc( 1, sizeof( openmpt_module ) ); if ( !mod ) { throw std::bad_alloc(); } std::memset( mod, 0, sizeof( openmpt_module ) ); mod->logfunc = logfunc ? logfunc : openmpt_log_func_default; mod->loguser = loguser; mod->errfunc = errfunc ? errfunc : NULL; mod->erruser = erruser; mod->error = OPENMPT_ERROR_OK; mod->error_message = NULL; mod->impl = 0; try { std::map< std::string, std::string > ctls_map; if ( ctls ) { for ( const openmpt_module_initial_ctl * it = ctls; it->ctl; ++it ) { if ( it->value ) { ctls_map[ it->ctl ] = it->value; } else { ctls_map.erase( it->ctl ); } } } openmpt::callback_stream_wrapper istream = { stream, stream_callbacks.read, stream_callbacks.seek, stream_callbacks.tell }; mod->impl = new openmpt::module_impl( istream, openmpt::helper::make_unique( mod->logfunc, mod->loguser ), ctls_map ); return mod; } catch ( ... ) { #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:6001) // false-positive: Using uninitialized memory 'mod'. #endif // _MSC_VER openmpt::report_exception( __func__, mod, error, error_message ); #if defined(_MSC_VER) #pragma warning(pop) #endif // _MSC_VER } delete mod->impl; mod->impl = 0; if ( mod->error_message ) { openmpt_free_string( mod->error_message ); mod->error_message = NULL; } std::free( (void*)mod ); mod = NULL; } catch ( ... ) { openmpt::report_exception( __func__, 0, error, error_message ); } return NULL; } openmpt_module * openmpt_module_create_from_memory( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * user, const openmpt_module_initial_ctl * ctls ) { return openmpt_module_create_from_memory2( filedata, filesize, logfunc, user, NULL, NULL, NULL, NULL, ctls ); } openmpt_module * openmpt_module_create_from_memory2( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ) { try { openmpt_module * mod = (openmpt_module*)std::calloc( 1, sizeof( openmpt_module ) ); if ( !mod ) { throw std::bad_alloc(); } std::memset( mod, 0, sizeof( openmpt_module ) ); mod->logfunc = logfunc ? logfunc : openmpt_log_func_default; mod->loguser = loguser; mod->errfunc = errfunc ? errfunc : NULL; mod->erruser = erruser; mod->error = OPENMPT_ERROR_OK; mod->error_message = NULL; mod->impl = 0; try { std::map< std::string, std::string > ctls_map; if ( ctls ) { for ( const openmpt_module_initial_ctl * it = ctls; it->ctl; ++it ) { if ( it->value ) { ctls_map[ it->ctl ] = it->value; } else { ctls_map.erase( it->ctl ); } } } mod->impl = new openmpt::module_impl( filedata, filesize, openmpt::helper::make_unique( mod->logfunc, mod->loguser ), ctls_map ); return mod; } catch ( ... ) { #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:6001) // false-positive: Using uninitialized memory 'mod'. #endif // _MSC_VER openmpt::report_exception( __func__, mod, error, error_message ); #if defined(_MSC_VER) #pragma warning(pop) #endif // _MSC_VER } delete mod->impl; mod->impl = 0; if ( mod->error_message ) { openmpt_free_string( mod->error_message ); mod->error_message = NULL; } std::free( (void*)mod ); mod = NULL; } catch ( ... ) { openmpt::report_exception( __func__, 0, error, error_message ); } return NULL; } void openmpt_module_destroy( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); delete mod->impl; mod->impl = 0; if ( mod->error_message ) { openmpt_free_string( mod->error_message ); mod->error_message = NULL; } std::free( (void*)mod ); mod = NULL; return; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return; } void openmpt_module_set_log_func( openmpt_module * mod, openmpt_log_func logfunc, void * loguser ) { try { openmpt::interface::check_soundfile( mod ); mod->logfunc = logfunc ? logfunc : openmpt_log_func_default; mod->loguser = loguser; return; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return; } void openmpt_module_set_error_func( openmpt_module * mod, openmpt_error_func errfunc, void * erruser ) { try { openmpt::interface::check_soundfile( mod ); mod->errfunc = errfunc ? errfunc : NULL; mod->erruser = erruser; mod->error = OPENMPT_ERROR_OK; return; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return; } int openmpt_module_error_get_last( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->error; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return -1; } const char * openmpt_module_error_get_last_message( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->error_message ? openmpt::strdup( mod->error_message ) : openmpt::strdup( "" ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } void openmpt_module_error_set_last( openmpt_module * mod, int error ) { try { openmpt::interface::check_soundfile( mod ); mod->error = error; if ( mod->error_message ) { openmpt_free_string( mod->error_message ); mod->error_message = NULL; } return; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return; } void openmpt_module_error_clear( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); mod->error = OPENMPT_ERROR_OK; if ( mod->error_message ) { openmpt_free_string( mod->error_message ); mod->error_message = NULL; } return; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return; } int openmpt_module_select_subsong( openmpt_module * mod, int32_t subsong ) { try { openmpt::interface::check_soundfile( mod ); mod->impl->select_subsong( subsong ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_selected_subsong( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_selected_subsong(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return -1; } int32_t openmpt_module_get_restart_order( openmpt_module * mod, int32_t subsong ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_restart_order( subsong ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return -1; } int32_t openmpt_module_get_restart_row( openmpt_module * mod, int32_t subsong ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_restart_row( subsong ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return -1; } int openmpt_module_set_repeat_count( openmpt_module * mod, int32_t repeat_count ) { try { openmpt::interface::check_soundfile( mod ); mod->impl->set_repeat_count( repeat_count ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_repeat_count( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_repeat_count(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } double openmpt_module_get_duration_seconds( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_duration_seconds(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0.0; } double openmpt_module_get_time_at_position( openmpt_module * mod, int32_t order, int32_t row ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_time_at_position( order, row ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return -1.0; } double openmpt_module_set_position_seconds( openmpt_module * mod, double seconds ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->set_position_seconds( seconds ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0.0; } double openmpt_module_get_position_seconds( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_position_seconds(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0.0; } double openmpt_module_set_position_order_row( openmpt_module * mod, int32_t order, int32_t row ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->set_position_order_row( order, row ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0.0; } int openmpt_module_get_render_param( openmpt_module * mod, int param, int32_t * value ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( value ); *value = mod->impl->get_render_param( (openmpt::module::render_param)param ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int openmpt_module_set_render_param( openmpt_module * mod, int param, int32_t value ) { try { openmpt::interface::check_soundfile( mod ); mod->impl->set_render_param( (openmpt::module::render_param)param, value ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } size_t openmpt_module_read_mono( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * mono ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->read( samplerate, count, mono ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } size_t openmpt_module_read_stereo( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * left, int16_t * right ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->read( samplerate, count, left, right ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } size_t openmpt_module_read_quad( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * left, int16_t * right, int16_t * rear_left, int16_t * rear_right ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->read( samplerate, count, left, right, rear_left, rear_right ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } size_t openmpt_module_read_float_mono( openmpt_module * mod, int32_t samplerate, size_t count, float * mono ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->read( samplerate, count, mono ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } size_t openmpt_module_read_float_stereo( openmpt_module * mod, int32_t samplerate, size_t count, float * left, float * right ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->read( samplerate, count, left, right ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } size_t openmpt_module_read_float_quad( openmpt_module * mod, int32_t samplerate, size_t count, float * left, float * right, float * rear_left, float * rear_right ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->read( samplerate, count, left, right, rear_left, rear_right ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } size_t openmpt_module_read_interleaved_stereo( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * interleaved_stereo ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->read_interleaved_stereo( samplerate, count, interleaved_stereo ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } size_t openmpt_module_read_interleaved_quad( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * interleaved_quad ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->read_interleaved_quad( samplerate, count, interleaved_quad ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } size_t openmpt_module_read_interleaved_float_stereo( openmpt_module * mod, int32_t samplerate, size_t count, float * interleaved_stereo ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->read_interleaved_stereo( samplerate, count, interleaved_stereo ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } size_t openmpt_module_read_interleaved_float_quad( openmpt_module * mod, int32_t samplerate, size_t count, float * interleaved_quad ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->read_interleaved_quad( samplerate, count, interleaved_quad ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } const char * openmpt_module_get_metadata_keys( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); std::string retval; bool first = true; std::vector metadata_keys = mod->impl->get_metadata_keys(); for ( std::vector::iterator i = metadata_keys.begin(); i != metadata_keys.end(); ++i ) { if ( first ) { first = false; } else { retval += ";"; } retval += *i; } return openmpt::strdup( retval.c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } const char * openmpt_module_get_metadata( openmpt_module * mod, const char * key ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( key ); return openmpt::strdup( mod->impl->get_metadata( key ).c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } double openmpt_module_get_current_estimated_bpm( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_estimated_bpm(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0.0; } int32_t openmpt_module_get_current_speed( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_speed(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_current_tempo( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_tempo(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } double openmpt_module_get_current_tempo2( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_tempo2(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_current_order( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_order(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_current_pattern( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_pattern(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_current_row( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_row(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_current_playing_channels( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_playing_channels(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } float openmpt_module_get_current_channel_vu_mono( openmpt_module * mod, int32_t channel ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_channel_vu_mono( channel ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0.0; } float openmpt_module_get_current_channel_vu_left( openmpt_module * mod, int32_t channel ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_channel_vu_left( channel ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0.0; } float openmpt_module_get_current_channel_vu_right( openmpt_module * mod, int32_t channel ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_channel_vu_right( channel ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0.0; } float openmpt_module_get_current_channel_vu_rear_left( openmpt_module * mod, int32_t channel ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_channel_vu_rear_left( channel ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0.0; } float openmpt_module_get_current_channel_vu_rear_right( openmpt_module * mod, int32_t channel ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_current_channel_vu_rear_right( channel ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0.0; } int32_t openmpt_module_get_num_subsongs( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_num_subsongs(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_num_channels( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_num_channels(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_num_orders( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_num_orders(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_num_patterns( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_num_patterns(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_num_instruments( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_num_instruments(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_num_samples( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_num_samples(); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } const char * openmpt_module_get_subsong_name( openmpt_module * mod, int32_t index ) { try { openmpt::interface::check_soundfile( mod ); std::vector names = mod->impl->get_subsong_names(); if ( names.size() >= (std::size_t)std::numeric_limits::max() ) { throw std::runtime_error("too many names"); } if ( index < 0 || index >= (int32_t)names.size() ) { return openmpt::strdup( "" ); } return openmpt::strdup( names[index].c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } const char * openmpt_module_get_channel_name( openmpt_module * mod, int32_t index ) { try { openmpt::interface::check_soundfile( mod ); std::vector names = mod->impl->get_channel_names(); if ( names.size() >= (std::size_t)std::numeric_limits::max() ) { throw std::runtime_error("too many names"); } if ( index < 0 || index >= (int32_t)names.size() ) { return openmpt::strdup( "" ); } return openmpt::strdup( names[index].c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } const char * openmpt_module_get_order_name( openmpt_module * mod, int32_t index ) { try { openmpt::interface::check_soundfile( mod ); std::vector names = mod->impl->get_order_names(); if ( names.size() >= (std::size_t)std::numeric_limits::max() ) { throw std::runtime_error("too many names"); } if ( index < 0 || index >= (int32_t)names.size() ) { return openmpt::strdup( "" ); } return openmpt::strdup( names[index].c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } const char * openmpt_module_get_pattern_name( openmpt_module * mod, int32_t index ) { try { openmpt::interface::check_soundfile( mod ); std::vector names = mod->impl->get_pattern_names(); if ( names.size() >= (std::size_t)std::numeric_limits::max() ) { throw std::runtime_error("too many names"); } if ( index < 0 || index >= (int32_t)names.size() ) { return openmpt::strdup( "" ); } return openmpt::strdup( names[index].c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } const char * openmpt_module_get_instrument_name( openmpt_module * mod, int32_t index ) { try { openmpt::interface::check_soundfile( mod ); std::vector names = mod->impl->get_instrument_names(); if ( names.size() >= (std::size_t)std::numeric_limits::max() ) { throw std::runtime_error("too many names"); } if ( index < 0 || index >= (int32_t)names.size() ) { return openmpt::strdup( "" ); } return openmpt::strdup( names[index].c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } const char * openmpt_module_get_sample_name( openmpt_module * mod, int32_t index ) { try { openmpt::interface::check_soundfile( mod ); std::vector names = mod->impl->get_sample_names(); if ( names.size() >= (std::size_t)std::numeric_limits::max() ) { throw std::runtime_error("too many names"); } if ( index < 0 || index >= (int32_t)names.size() ) { return openmpt::strdup( "" ); } return openmpt::strdup( names[index].c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } int32_t openmpt_module_get_order_pattern( openmpt_module * mod, int32_t order ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_order_pattern( order ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int openmpt_module_is_order_skip_entry( openmpt_module * mod, int32_t order ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->is_order_skip_entry( order ) ? 1 : 0; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int openmpt_module_is_pattern_skip_item( openmpt_module * mod, int32_t pattern ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->is_pattern_skip_item( pattern ) ? 1 : 0; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int openmpt_module_is_order_stop_entry( openmpt_module * mod, int32_t order ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->is_order_stop_entry( order ) ? 1 : 0; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int openmpt_module_is_pattern_stop_item( openmpt_module * mod, int32_t pattern ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->is_pattern_stop_item( pattern ) ? 1 : 0; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_pattern_num_rows( openmpt_module * mod, int32_t pattern ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_pattern_num_rows( pattern ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_pattern_rows_per_beat( openmpt_module * mod, int32_t pattern ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_pattern_rows_per_beat( pattern ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int32_t openmpt_module_get_pattern_rows_per_measure( openmpt_module * mod, int32_t pattern ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_pattern_rows_per_measure( pattern ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } uint8_t openmpt_module_get_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command ) { try { openmpt::interface::check_soundfile( mod ); return mod->impl->get_pattern_row_channel_command( pattern, row, channel, command ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } const char * openmpt_module_format_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command ) { try { openmpt::interface::check_soundfile( mod ); return openmpt::strdup( mod->impl->format_pattern_row_channel_command( pattern, row, channel, command ).c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } const char * openmpt_module_highlight_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command ) { try { openmpt::interface::check_soundfile( mod ); return openmpt::strdup( mod->impl->highlight_pattern_row_channel_command( pattern, row, channel, command ).c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } const char * openmpt_module_format_pattern_row_channel( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, size_t width, int pad ) { try { openmpt::interface::check_soundfile( mod ); return openmpt::strdup( mod->impl->format_pattern_row_channel( pattern, row, channel, width, pad ? true : false ).c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } const char * openmpt_module_highlight_pattern_row_channel( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, size_t width, int pad ) { try { openmpt::interface::check_soundfile( mod ); return openmpt::strdup( mod->impl->highlight_pattern_row_channel( pattern, row, channel, width, pad ? true : false ).c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } const char * openmpt_module_get_ctls( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); std::string retval; bool first = true; std::vector ctls = mod->impl->get_ctls(); for ( std::vector::iterator i = ctls.begin(); i != ctls.end(); ++i ) { if ( first ) { first = false; } else { retval += ";"; } retval += *i; } return openmpt::strdup( retval.c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } const char * openmpt_module_ctl_get( openmpt_module * mod, const char * ctl ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( ctl ); return openmpt::strdup( mod->impl->ctl_get( ctl ).c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } int openmpt_module_ctl_get_boolean( openmpt_module * mod, const char * ctl ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( ctl ); return mod->impl->ctl_get_boolean( ctl ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int64_t openmpt_module_ctl_get_integer( openmpt_module * mod, const char * ctl ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( ctl ); return mod->impl->ctl_get_integer( ctl ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } double openmpt_module_ctl_get_floatingpoint( openmpt_module * mod, const char * ctl ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( ctl ); return mod->impl->ctl_get_floatingpoint( ctl ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0.0; } const char * openmpt_module_ctl_get_text( openmpt_module * mod, const char * ctl ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( ctl ); return openmpt::strdup( mod->impl->ctl_get_text( ctl ).c_str() ); } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return NULL; } int openmpt_module_ctl_set( openmpt_module * mod, const char * ctl, const char * value ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( ctl ); openmpt::interface::check_pointer( value ); mod->impl->ctl_set( ctl, value ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int openmpt_module_ctl_set_boolean( openmpt_module * mod, const char * ctl, int value ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( ctl ); mod->impl->ctl_set_boolean( ctl, value ? true : false ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int openmpt_module_ctl_set_integer( openmpt_module * mod, const char * ctl, int64_t value ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( ctl ); mod->impl->ctl_set_integer( ctl, value ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int openmpt_module_ctl_set_floatingpoint( openmpt_module * mod, const char * ctl, double value ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( ctl ); mod->impl->ctl_set_floatingpoint( ctl, value ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } int openmpt_module_ctl_set_text( openmpt_module * mod, const char * ctl, const char * value ) { try { openmpt::interface::check_soundfile( mod ); openmpt::interface::check_pointer( ctl ); openmpt::interface::check_pointer( value ); mod->impl->ctl_set_text( ctl, value ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod ); } return 0; } openmpt_module_ext * openmpt_module_ext_create( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ) { try { openmpt_module_ext * mod_ext = (openmpt_module_ext*)std::calloc( 1, sizeof( openmpt_module_ext ) ); if ( !mod_ext ) { throw std::bad_alloc(); } std::memset( mod_ext, 0, sizeof( openmpt_module_ext ) ); openmpt_module * mod = &mod_ext->mod; std::memset( mod, 0, sizeof( openmpt_module ) ); mod_ext->impl = 0; mod->logfunc = logfunc ? logfunc : openmpt_log_func_default; mod->loguser = loguser; mod->errfunc = errfunc ? errfunc : NULL; mod->erruser = erruser; mod->error = OPENMPT_ERROR_OK; mod->error_message = NULL; mod->impl = 0; try { std::map< std::string, std::string > ctls_map; if ( ctls ) { for ( const openmpt_module_initial_ctl * it = ctls; it->ctl; ++it ) { if ( it->value ) { ctls_map[ it->ctl ] = it->value; } else { ctls_map.erase( it->ctl ); } } } openmpt::callback_stream_wrapper istream = { stream, stream_callbacks.read, stream_callbacks.seek, stream_callbacks.tell }; mod_ext->impl = new openmpt::module_ext_impl( istream, openmpt::helper::make_unique( mod->logfunc, mod->loguser ), ctls_map ); mod->impl = mod_ext->impl; return mod_ext; } catch ( ... ) { openmpt::report_exception( __func__, mod, error, error_message ); } #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:6001) // false-positive: Using uninitialized memory 'mod_ext'. #endif // _MSC_VER delete mod_ext->impl; #if defined(_MSC_VER) #pragma warning(pop) #endif // _MSC_VER mod_ext->impl = 0; mod->impl = 0; if ( mod->error_message ) { openmpt_free_string( mod->error_message ); mod->error_message = NULL; } std::free( (void*)mod_ext ); mod_ext = NULL; } catch ( ... ) { openmpt::report_exception( __func__, 0, error, error_message ); } return NULL; } openmpt_module_ext * openmpt_module_ext_create_from_memory( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ) { try { openmpt_module_ext * mod_ext = (openmpt_module_ext*)std::calloc( 1, sizeof( openmpt_module_ext ) ); if ( !mod_ext ) { throw std::bad_alloc(); } std::memset( mod_ext, 0, sizeof( openmpt_module_ext ) ); openmpt_module * mod = &mod_ext->mod; std::memset( mod, 0, sizeof( openmpt_module ) ); mod_ext->impl = 0; mod->logfunc = logfunc ? logfunc : openmpt_log_func_default; mod->loguser = loguser; mod->errfunc = errfunc ? errfunc : NULL; mod->erruser = erruser; mod->error = OPENMPT_ERROR_OK; mod->error_message = NULL; mod->impl = 0; try { std::map< std::string, std::string > ctls_map; if ( ctls ) { for ( const openmpt_module_initial_ctl * it = ctls; it->ctl; ++it ) { if ( it->value ) { ctls_map[ it->ctl ] = it->value; } else { ctls_map.erase( it->ctl ); } } } mod_ext->impl = new openmpt::module_ext_impl( filedata, filesize, openmpt::helper::make_unique( mod->logfunc, mod->loguser ), ctls_map ); mod->impl = mod_ext->impl; return mod_ext; } catch ( ... ) { openmpt::report_exception( __func__, mod, error, error_message ); } #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:6001) // false-positive: Using uninitialized memory 'mod_ext'. #endif // _MSC_VER delete mod_ext->impl; #if defined(_MSC_VER) #pragma warning(pop) #endif // _MSC_VER mod_ext->impl = 0; mod->impl = 0; if ( mod->error_message ) { openmpt_free_string( mod->error_message ); mod->error_message = NULL; } std::free( (void*)mod_ext ); mod_ext = NULL; } catch ( ... ) { openmpt::report_exception( __func__, 0, error, error_message ); } return NULL; } void openmpt_module_ext_destroy( openmpt_module_ext * mod_ext ) { try { openmpt::interface::check_soundfile( mod_ext ); openmpt_module * mod = &mod_ext->mod; mod->impl = 0; delete mod_ext->impl; mod_ext->impl = 0; if ( mod->error_message ) { openmpt_free_string( mod->error_message ); mod->error_message = NULL; } std::free( (void*)mod_ext ); mod_ext = NULL; return; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return; } openmpt_module * openmpt_module_ext_get_module( openmpt_module_ext * mod_ext ) { try { openmpt::interface::check_soundfile( mod_ext ); openmpt_module * mod = &mod_ext->mod; return mod; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return NULL; } static int get_pattern_row_channel_volume_effect_type( openmpt_module_ext * mod_ext, int32_t pattern, int32_t row, int32_t channel ) { try { openmpt::interface::check_soundfile( mod_ext ); return mod_ext->impl->get_pattern_row_channel_volume_effect_type( pattern, row, channel ); } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return -1; } static int get_pattern_row_channel_effect_type( openmpt_module_ext * mod_ext, int32_t pattern, int32_t row, int32_t channel ) { try { openmpt::interface::check_soundfile( mod_ext ); return mod_ext->impl->get_pattern_row_channel_effect_type( pattern, row, channel ); } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return -1; } static int set_current_speed( openmpt_module_ext * mod_ext, int32_t speed ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->set_current_speed( speed ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static int set_current_tempo( openmpt_module_ext * mod_ext, int32_t tempo ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->set_current_tempo( tempo ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static int set_tempo_factor( openmpt_module_ext * mod_ext, double factor ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->set_tempo_factor( factor ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static double get_tempo_factor( openmpt_module_ext * mod_ext ) { try { openmpt::interface::check_soundfile( mod_ext ); return mod_ext->impl->get_tempo_factor(); } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0.0; } static int set_pitch_factor( openmpt_module_ext * mod_ext, double factor ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->set_pitch_factor( factor ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static double get_pitch_factor( openmpt_module_ext * mod_ext ) { try { openmpt::interface::check_soundfile( mod_ext ); return mod_ext->impl->get_pitch_factor(); } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0.0; } static int set_global_volume( openmpt_module_ext * mod_ext, double volume ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->set_global_volume( volume ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static double get_global_volume( openmpt_module_ext * mod_ext ) { try { openmpt::interface::check_soundfile( mod_ext ); return mod_ext->impl->get_global_volume(); } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0.0; } static int set_channel_volume( openmpt_module_ext * mod_ext, int32_t channel, double volume ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->set_channel_volume( channel, volume ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static double get_channel_volume( openmpt_module_ext * mod_ext, int32_t channel ) { try { openmpt::interface::check_soundfile( mod_ext ); return mod_ext->impl->get_channel_volume( channel ); } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0.0; } static int set_channel_mute_status( openmpt_module_ext * mod_ext, int32_t channel, int mute ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->set_channel_mute_status( channel, mute ? true : false ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static int get_channel_mute_status( openmpt_module_ext * mod_ext, int32_t channel ) { try { openmpt::interface::check_soundfile( mod_ext ); return mod_ext->impl->get_channel_mute_status( channel ) ? 1 : 0; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return -1; } static int set_instrument_mute_status( openmpt_module_ext * mod_ext, int32_t instrument, int mute ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->set_instrument_mute_status( instrument, mute ? true : false ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static int get_instrument_mute_status( openmpt_module_ext * mod_ext, int32_t instrument ) { try { openmpt::interface::check_soundfile( mod_ext ); return mod_ext->impl->get_instrument_mute_status( instrument ) ? 1 : 0; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return -1; } static int32_t play_note( openmpt_module_ext * mod_ext, int32_t instrument, int32_t note, double volume, double panning ) { try { openmpt::interface::check_soundfile( mod_ext ); return mod_ext->impl->play_note( instrument, note, volume, panning ); } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return -1; } static int stop_note( openmpt_module_ext * mod_ext, int32_t channel ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->stop_note( channel ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static int note_off( openmpt_module_ext * mod_ext, int32_t channel ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->note_off(channel ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static int note_fade( openmpt_module_ext * mod_ext, int32_t channel ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->note_fade(channel ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static int set_channel_panning( openmpt_module_ext * mod_ext, int32_t channel, double panning ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->set_channel_panning( channel, panning ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static double get_channel_panning( openmpt_module_ext * mod_ext, int32_t channel ) { try { openmpt::interface::check_soundfile( mod_ext ); return mod_ext->impl->get_channel_panning( channel ); } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0.0; } static int set_note_finetune( openmpt_module_ext * mod_ext, int32_t channel, double finetune ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->set_note_finetune( channel, finetune ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } static double get_note_finetune( openmpt_module_ext * mod_ext, int32_t channel ) { try { openmpt::interface::check_soundfile( mod_ext ); return mod_ext->impl->get_note_finetune( channel ); } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0.0; } static int set_current_tempo2( openmpt_module_ext * mod_ext, double tempo ) { try { openmpt::interface::check_soundfile( mod_ext ); mod_ext->impl->set_current_tempo2( tempo ); return 1; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } /* add stuff here */ int openmpt_module_ext_get_interface( openmpt_module_ext * mod_ext, const char * interface_id, void * interface, size_t interface_size ) { try { openmpt::interface::check_soundfile( mod_ext ); openmpt::interface::check_pointer( interface_id ); openmpt::interface::check_pointer( interface ); std::memset( interface, 0, interface_size ); int result = 0; std::string_view interface_id_sv = interface_id; if ( interface_id_sv == "" ) { result = 0; } else if ( ( interface_id_sv == LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS ) && ( interface_size == sizeof( openmpt_module_ext_interface_pattern_vis ) ) ) { openmpt_module_ext_interface_pattern_vis * i = static_cast< openmpt_module_ext_interface_pattern_vis * >( interface ); i->get_pattern_row_channel_volume_effect_type = &get_pattern_row_channel_volume_effect_type; i->get_pattern_row_channel_effect_type = &get_pattern_row_channel_effect_type; result = 1; } else if ( ( interface_id_sv == LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE ) && ( interface_size == sizeof( openmpt_module_ext_interface_interactive ) ) ) { openmpt_module_ext_interface_interactive * i = static_cast< openmpt_module_ext_interface_interactive * >( interface ); i->set_current_speed = &set_current_speed; i->set_current_tempo = &set_current_tempo; i->set_tempo_factor = &set_tempo_factor; i->get_tempo_factor = &get_tempo_factor; i->set_pitch_factor = &set_pitch_factor; i->get_pitch_factor = &get_pitch_factor; i->set_global_volume = &set_global_volume; i->get_global_volume = &get_global_volume; i->set_channel_volume = &set_channel_volume; i->get_channel_volume = &get_channel_volume; i->set_channel_mute_status = &set_channel_mute_status; i->get_channel_mute_status = &get_channel_mute_status; i->set_instrument_mute_status = &set_instrument_mute_status; i->get_instrument_mute_status = &get_instrument_mute_status; i->play_note = &play_note; i->stop_note = &stop_note; result = 1; } else if ( ( interface_id_sv == LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE2 ) && ( interface_size == sizeof( openmpt_module_ext_interface_interactive2 ) ) ) { openmpt_module_ext_interface_interactive2 * i = static_cast< openmpt_module_ext_interface_interactive2 * >( interface ); i->note_off = ¬e_off; i->note_fade = ¬e_fade; i->set_channel_panning = &set_channel_panning; i->get_channel_panning = &get_channel_panning; i->set_note_finetune = &set_note_finetune; i->get_note_finetune = &get_note_finetune; result = 1; } else if ( ( interface_id_sv == LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE3 ) && ( interface_size == sizeof( openmpt_module_ext_interface_interactive3 ) ) ) { openmpt_module_ext_interface_interactive3 * i = static_cast< openmpt_module_ext_interface_interactive3 * >( interface ); i->set_current_tempo2 = &set_current_tempo2; result = 1; /* add stuff here */ } else { result = 0; } return result; } catch ( ... ) { openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); } return 0; } } // extern "C" libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_stream_callbacks_buffer.h0000644000175000017500000002121414173267003025657 00000000000000/* * libopenmpt_stream_callbacks_buffer.h * ------------------------------------ * Purpose: libopenmpt public c interface * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_STREAM_CALLBACKS_BUFFER_H #define LIBOPENMPT_STREAM_CALLBACKS_BUFFER_H #include "libopenmpt.h" #include #include #include /*! \addtogroup libopenmpt_c * @{ */ #ifdef __cplusplus extern "C" { #endif typedef struct openmpt_stream_buffer { const void * file_data; /* or prefix data IFF prefix_size < file_size */ int64_t file_size; int64_t file_pos; int64_t prefix_size; int overflow; } openmpt_stream_buffer; static LIBOPENMPT_C_INLINE size_t openmpt_stream_buffer_read_func( void * stream, void * dst, size_t bytes ) { openmpt_stream_buffer * s = (openmpt_stream_buffer*)stream; int64_t offset = 0; int64_t begpos = 0; int64_t endpos = 0; size_t valid_bytes = 0; if ( !s ) { return 0; } offset = bytes; begpos = s->file_pos; endpos = s->file_pos; valid_bytes = 0; endpos = (uint64_t)endpos + (uint64_t)offset; if ( ( offset > 0 ) && !( (uint64_t)endpos > (uint64_t)begpos ) ) { /* integer wrapped */ return 0; } if ( bytes == 0 ) { return 0; } if ( begpos >= s->file_size ) { return 0; } if ( endpos > s->file_size ) { /* clip to eof */ bytes = bytes - (size_t)( endpos - s->file_size ); endpos = endpos - ( endpos - s->file_size ); } memset( dst, 0, bytes ); if ( begpos >= s->prefix_size ) { s->overflow = 1; valid_bytes = 0; } else if ( endpos > s->prefix_size ) { s->overflow = 1; valid_bytes = bytes - (size_t)( endpos - s->prefix_size ); } else { valid_bytes = bytes; } memcpy( dst, (const char*)s->file_data + s->file_pos, valid_bytes ); s->file_pos = s->file_pos + bytes; return bytes; } static LIBOPENMPT_C_INLINE int openmpt_stream_buffer_seek_func( void * stream, int64_t offset, int whence ) { openmpt_stream_buffer * s = (openmpt_stream_buffer*)stream; int result = -1; if ( !s ) { return -1; } switch ( whence ) { case OPENMPT_STREAM_SEEK_SET: if ( offset < 0 ) { return -1; } if ( offset > s->file_size ) { return -1; } s->file_pos = offset; result = 0; break; case OPENMPT_STREAM_SEEK_CUR: do { int64_t oldpos = s->file_pos; int64_t pos = s->file_pos; pos = (uint64_t)pos + (uint64_t)offset; if ( ( offset > 0 ) && !( (uint64_t)pos > (uint64_t)oldpos ) ) { /* integer wrapped */ return -1; } if ( ( offset < 0 ) && !( (uint64_t)pos < (uint64_t)oldpos ) ) { /* integer wrapped */ return -1; } s->file_pos = pos; } while(0); result = 0; break; case OPENMPT_STREAM_SEEK_END: if ( offset > 0 ) { return -1; } do { int64_t oldpos = s->file_pos; int64_t pos = s->file_pos; pos = s->file_size; pos = (uint64_t)pos + (uint64_t)offset; if ( ( offset < 0 ) && !( (uint64_t)pos < (uint64_t)oldpos ) ) { /* integer wrapped */ return -1; } s->file_pos = pos; } while(0); result = 0; break; } return result; } static LIBOPENMPT_C_INLINE int64_t openmpt_stream_buffer_tell_func( void * stream ) { openmpt_stream_buffer * s = (openmpt_stream_buffer*)stream; if ( !s ) { return -1; } return s->file_pos; } LIBOPENMPT_DEPRECATED static LIBOPENMPT_C_INLINE void openmpt_stream_buffer_init( openmpt_stream_buffer * buffer, const void * file_data, int64_t file_size ) { memset( buffer, 0, sizeof( openmpt_stream_buffer ) ); buffer->file_data = file_data; buffer->file_size = file_size; buffer->file_pos = 0; buffer->prefix_size = file_size; buffer->overflow = 0; } #define openmpt_stream_buffer_init_prefix_only( buffer_, prefix_data_, prefix_size_, file_size_ ) do { \ openmpt_stream_buffer_init( (buffer_), (prefix_data_), (file_size_) ); \ (buffer_)->prefix_size = (prefix_size_); \ } while(0) #define openmpt_stream_buffer_overflowed( buffer_ ) ( (buffer_)->overflow ) /*! \brief Provide openmpt_stream_callbacks for in-memoy buffers * * Fills openmpt_stream_callbacks suitable for passing an in-memory buffer as a stream parameter to functions doing file input/output. * A suitable openmpt_stream_buffer object may be initialized with openmpt_stream_buffer_init(). * * \remarks The stream argument must be passed as `(void*)(openmpt_stream_buffer*)stream_buffer`. * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \sa openmpt_could_open_probability2 * \sa openmpt_probe_file_header_from_stream * \sa openmpt_module_create2 * \sa openmpt_stream_buffer_init * \deprecated Please use openmpt_stream_get_buffer_callbacks2(). */ LIBOPENMPT_DEPRECATED static LIBOPENMPT_C_INLINE openmpt_stream_callbacks openmpt_stream_get_buffer_callbacks(void) { openmpt_stream_callbacks retval; memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); retval.read = openmpt_stream_buffer_read_func; retval.seek = openmpt_stream_buffer_seek_func; retval.tell = openmpt_stream_buffer_tell_func; return retval; } typedef struct openmpt_stream_buffer2 { const void * file_data; int64_t file_size; int64_t file_pos; } openmpt_stream_buffer2; static size_t openmpt_stream_buffer_read_func2( void * stream, void * dst, size_t bytes ) { openmpt_stream_buffer2 * s = (openmpt_stream_buffer2*)stream; int64_t offset = 0; int64_t begpos = 0; int64_t endpos = 0; if ( !s ) { return 0; } offset = bytes; begpos = s->file_pos; endpos = s->file_pos; endpos = (uint64_t)endpos + (uint64_t)offset; if ( ( offset > 0 ) && !( (uint64_t)endpos > (uint64_t)begpos ) ) { /* integer wrapped */ return 0; } if ( bytes == 0 ) { return 0; } if ( begpos >= s->file_size ) { return 0; } if ( endpos > s->file_size ) { /* clip to eof */ bytes = bytes - (size_t)( endpos - s->file_size ); endpos = endpos - ( endpos - s->file_size ); } memcpy( dst, (const char*)s->file_data + s->file_pos, bytes ); s->file_pos = s->file_pos + bytes; return bytes; } static int openmpt_stream_buffer_seek_func2( void * stream, int64_t offset, int whence ) { openmpt_stream_buffer2 * s = (openmpt_stream_buffer2*)stream; int result = -1; if ( !s ) { return -1; } switch ( whence ) { case OPENMPT_STREAM_SEEK_SET: if ( offset < 0 ) { return -1; } if ( offset > s->file_size ) { return -1; } s->file_pos = offset; result = 0; break; case OPENMPT_STREAM_SEEK_CUR: do { int64_t oldpos = s->file_pos; int64_t pos = s->file_pos; pos = (uint64_t)pos + (uint64_t)offset; if ( ( offset > 0 ) && !( (uint64_t)pos > (uint64_t)oldpos ) ) { /* integer wrapped */ return -1; } if ( ( offset < 0 ) && !( (uint64_t)pos < (uint64_t)oldpos ) ) { /* integer wrapped */ return -1; } s->file_pos = pos; } while(0); result = 0; break; case OPENMPT_STREAM_SEEK_END: if ( offset > 0 ) { return -1; } do { int64_t oldpos = s->file_pos; int64_t pos = s->file_pos; pos = s->file_size; pos = (uint64_t)pos + (uint64_t)offset; if ( ( offset < 0 ) && !( (uint64_t)pos < (uint64_t)oldpos ) ) { /* integer wrapped */ return -1; } s->file_pos = pos; } while(0); result = 0; break; } return result; } static int64_t openmpt_stream_buffer_tell_func2( void * stream ) { openmpt_stream_buffer2 * s = (openmpt_stream_buffer2*)stream; if ( !s ) { return -1; } return s->file_pos; } static void openmpt_stream_buffer_init2( openmpt_stream_buffer2 * buffer, const void * file_data, int64_t file_size ) { memset( buffer, 0, sizeof( openmpt_stream_buffer2 ) ); buffer->file_data = file_data; buffer->file_size = file_size; buffer->file_pos = 0; } /*! \brief Provide openmpt_stream_callbacks for in-memoy buffers * * Fills openmpt_stream_callbacks suitable for passing an in-memory buffer as a stream parameter to functions doing file input/output. * A suitable openmpt_stream_buffer2 object can be initialized with openmpt_stream_buffer_init2(). * * \remarks The stream argument must be passed as `(void*)(openmpt_stream_buffer2*)stream_buffer`. * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \sa openmpt_could_open_probability2 * \sa openmpt_probe_file_header_from_stream * \sa openmpt_module_create2 * \sa openmpt_stream_buffer_init2 * \since 0.7.0 */ static openmpt_stream_callbacks openmpt_stream_get_buffer_callbacks2(void) { openmpt_stream_callbacks retval; memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); retval.read = openmpt_stream_buffer_read_func2; retval.seek = openmpt_stream_buffer_seek_func2; retval.tell = openmpt_stream_buffer_tell_func2; return retval; } #ifdef __cplusplus } #endif /*! * @} */ #endif /* LIBOPENMPT_STREAM_CALLBACKS_BUFFER_H */ libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt.h0000644000175000017500000027630114705211733020765 00000000000000/* * libopenmpt.h * ------------ * Purpose: libopenmpt public c interface * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_H #define LIBOPENMPT_H #include "libopenmpt_config.h" #include #include /*! * \page libopenmpt_c_overview C API * * \section libopenmpt_c_error Error Handling * * - Functions with no return value in the corresponding C++ API return 0 on * failure and 1 on success. * - Functions that return a string in the corresponding C++ API return a * dynamically allocated const char *. In case of failure or memory allocation * failure, a NULL pointer is returned. * - Functions that return integer values signal error condition by returning * an invalid value (-1 in most cases, 0 in some cases). * - All functions that work on an \ref openmpt_module object will call an * \ref openmpt_error_func and depending on the value returned by this function * log the error code and/xor/or store it inside the openmpt_module object. * Stored error codes can be accessed with the openmpt_module_error_get_last() * and openmpt_module_error_get_last_message(). Stored errors will not get * cleared automatically and should be reset with openmpt_module_error_clear(). * - Some functions not directly related to an \ref openmpt_module object take * an explicit \ref openmpt_error_func error function callback and a pointer to * an int and behave analog to the functions working on an \ref openmpt_module * object. * * \section libopenmpt_c_strings Strings * * - All strings returned from libopenmpt are encoded in UTF-8. * - All strings passed to libopenmpt should also be encoded in UTF-8. * Behaviour in case of invalid UTF-8 is unspecified. * - libopenmpt does not enforce or expect any particular Unicode * normalization form. * - All strings returned from libopenmpt are dynamically allocated and must * be freed with openmpt_free_string(). Do NOT use the C standard library * free() for libopenmpt strings as that would make your code invalid on * windows when dynamically linking against libopenmpt which itself statically * links to the C runtime. * - All strings passed to libopenmpt are copied. No ownership is assumed or * transferred. * * \section libopenmpt_c_fileio File I/O * * libopenmpt can use 3 different strategies for file I/O. * * - openmpt_module_create_from_memory2() will load the module from the provided * memory buffer, which will require loading all data upfront by the library * caller. * - openmpt_module_create2() with a seekable stream will load the module via * callbacks to the stream interface. libopenmpt will not implement an * additional buffering layer in this case which means the callbacks are assumed * to be performant even with small i/o sizes. * - openmpt_module_create2() with an unseekable stream will load the module via * callbacks to the stream interface. libopempt will make an internal copy as * it goes along, and sometimes have to pre-cache the whole file in case it * needs to know the complete file size. This strategy is intended to be used * if the file is located on a high latency network. * * | create function | speed | memory consumption | * | ----------------------------------------------: | :----: | :----------------: | * | openmpt_module_create_from_memory2() |

fast

|

medium

| * | openmpt_module_create2() with seekable stream |

slow

|

low

| * | openmpt_module_create2() with unseekable stream |

medium

|

high

| * * In all cases, the data or stream passed to the create function is no longer * needed after the openmpt_module has been created and can be freed by the * caller. * * \section libopenmpt_c_outputformat Output Format * * libopenmpt supports a wide range of PCM output formats: * [8000..192000]/[mono|stereo|quad]/[f32|i16]. * * Unless you have some very specific requirements demanding a particular aspect * of the output format, you should always prefer 48000/stereo/f32 as the * libopenmpt PCM format. * * - Please prefer 48000Hz unless the user explicitly demands something else. * Practically all audio equipment and file formats use 48000Hz nowadays. * - Practically all module formats are made for stereo output. Mono will not * give you any measurable speed improvements and can trivially be obtained from * the stereo output anyway. Quad is not expected by almost all modules and even * if they do use surround effects, they expect the effects to be mixed to * stereo. * - Floating point output provides headroom instead of hard clipping if the * module is louder than 0dBFs, will give you a better signal-to-noise ratio * than int16 output, and avoid the need to apply an additional dithering to the * output by libopenmpt. Unless your platform has no floating point unit at all, * floating point will thus also be slightly faster. * * \section libopenmpt_c_threads libopenmpt in multi-threaded environments * * - libopenmpt is thread-aware. * - Individual libopenmpt objects are not thread-safe. * - libopenmpt itself does not spawn any user-visible threads but may spawn * threads for internal use. * - You must ensure to only ever access a particular libopenmpt object from a * single thread at a time. * - Consecutive accesses can happen from different threads. * - Different objects can be accessed concurrently from different threads. * * \section libopenmpt_c_staticlinking Statically linking to libopenmpt * * libopenmpt is implemented in C++. This implies that linking to libopenmpt * statically requires linking to the C++ runtime and standard library. The * **highly preferred and recommended** way to do this is by using the C++ * compiler instead of the platform linker to do the linking. This will do all * necessary things that are C++ specific (in particular, it will pull in the * appropriate runtime and/or library). If for whatever reason it is not * possible to use the C++ compiler for statically linking against libopenmpt, * the libopenmpt build system can list the required libraries in the pkg-config * file `libopenmpt.pc`. However, there is no reliable way to determine the name * of the required library or libraries from within the build system. The * libopenmpt autotools `configure` and plain `Makefile` honor the custom * variable `CXXSTDLIB_PCLIBSPRIVATE` which serves the sole purpose of listing * the standard library (or libraries) required for static linking. The contents * of this variable will be put in `libopenmpt.pc` `Libs.private` and used for * nothing else. * * This problem is inherent to libraries implemented in C++ that can also be used * without a C++ compiler. Other libraries try to solve that by listing * `-lstdc++` unconditionally in `Libs.private`. However, that will break * platforms that use a different C++ standard library (in particular FreeBSD). * * See https://lists.freedesktop.org/archives/pkg-config/2016-August/001055.html . * * Dymically linking to libopenmpt does not require anything special and will * work as usual (and exactly as done for libraries implemented in C). * * Note: This section does not apply when using Microsoft Visual Studio or * Andriod NDK ndk-build build systems. * * \section libopenmpt_c_detailed Detailed documentation * * \ref libopenmpt_c * * In case a function is not documented here, you might want to look at the * \ref libopenmpt_cpp documentation. The C and C++ APIs are kept semantically * as close as possible. * * \section libopenmpt_c_examples Examples * * \subsection libopenmpt_c_example_unsafe Unsafe, simplified example without any error checking to get a first idea of the API * \include libopenmpt_example_c_unsafe.c * \subsection libopenmpt_c_example_file FILE* * \include libopenmpt_example_c.c * \subsection libopenmpt_c_example_inmemory in memory * \include libopenmpt_example_c_mem.c * \subsection libopenmpt_c_example_stdout reading FILE* and writing PCM data to STDOUT (usable without PortAudio) * \include libopenmpt_example_c_stdout.c * */ /*! \defgroup libopenmpt_c libopenmpt C */ /*! \addtogroup libopenmpt_c * @{ */ #ifdef __cplusplus extern "C" { #endif /*! \brief Get the libopenmpt version number * * Returns the libopenmpt version number. * \return The value represents (major << 24 + minor << 16 + patch << 0). * \remarks libopenmpt < 0.3.0-pre used the following scheme: (major << 24 + minor << 16 + revision). */ LIBOPENMPT_API uint32_t openmpt_get_library_version(void); /*! \brief Get the core version number * * Return the OpenMPT core version number. * \return The value represents (majormajor << 24 + major << 16 + minor << 8 + minorminor). */ LIBOPENMPT_API uint32_t openmpt_get_core_version(void); /*! Return a verbose library version string from openmpt_get_string(). \deprecated Please use `"library_version"` directly. */ #define OPENMPT_STRING_LIBRARY_VERSION LIBOPENMPT_DEPRECATED_STRING( "library_version" ) /*! Return a verbose library features string from openmpt_get_string(). \deprecated Please use `"library_features"` directly. */ #define OPENMPT_STRING_LIBRARY_FEATURES LIBOPENMPT_DEPRECATED_STRING( "library_features" ) /*! Return a verbose OpenMPT core version string from openmpt_get_string(). \deprecated Please use `"core_version"` directly. */ #define OPENMPT_STRING_CORE_VERSION LIBOPENMPT_DEPRECATED_STRING( "core_version" ) /*! Return information about the current build (e.g. the build date or compiler used) from openmpt_get_string(). \deprecated Please use `"build"` directly. */ #define OPENMPT_STRING_BUILD LIBOPENMPT_DEPRECATED_STRING( "build" ) /*! Return all contributors from openmpt_get_string(). \deprecated Please use `"credits"` directly. */ #define OPENMPT_STRING_CREDITS LIBOPENMPT_DEPRECATED_STRING( "credits" ) /*! Return contact information about libopenmpt from openmpt_get_string(). \deprecated Please use `"contact"` directly. */ #define OPENMPT_STRING_CONTACT LIBOPENMPT_DEPRECATED_STRING( "contact" ) /*! Return the libopenmpt license from openmpt_get_string(). \deprecated Please use `"license"` directly. */ #define OPENMPT_STRING_LICENSE LIBOPENMPT_DEPRECATED_STRING( "license" ) /*! \brief Free a string returned by libopenmpt * * Frees any string that got returned by libopenmpt. */ LIBOPENMPT_API void openmpt_free_string( const char * str ); /*! \brief Get library related metadata. * * \param key Key to query. * Possible keys are: * - "library_version": verbose library version string * - "library_version_is_release": "1" if the version is an officially released version * - "library_features": verbose library features string * - "core_version": verbose OpenMPT core version string * - "source_url": original source code URL * - "source_date": original source code date * - "source_revision": original source code revision * - "source_is_modified": "1" if the original source has been modified * - "source_has_mixed_revisions": "1" if the original source has been compiled from different various revision * - "source_is_package": "1" if the original source has been obtained from a source pacakge instead of source code version control * - "build": information about the current build (e.g. the build date or compiler used) * - "build_compiler": information about the compiler used to build libopenmpt * - "credits": all contributors * - "contact": contact information about libopenmpt * - "license": the libopenmpt license * - "url": libopenmpt website URL * - "support_forum_url": libopenmpt support and discussions forum URL * - "bugtracker_url": libopenmpt bug and issue tracker URL * \return A (possibly multi-line) string containing the queried information. If no information is available, the string is empty. */ LIBOPENMPT_API const char * openmpt_get_string( const char * key ); /*! \brief Get a list of supported file extensions * * \return The semicolon-separated list of extensions supported by this libopenmpt build. The extensions are returned lower-case without a leading dot. */ LIBOPENMPT_API const char * openmpt_get_supported_extensions(void); /*! \brief Query whether a file extension is supported * * \param extension file extension to query without a leading dot. The case is ignored. * \return 1 if the extension is supported by libopenmpt, 0 otherwise. */ LIBOPENMPT_API int openmpt_is_extension_supported( const char * extension ); /*! Seek to the given offset relative to the beginning of the file. */ #define OPENMPT_STREAM_SEEK_SET 0 /*! Seek to the given offset relative to the current position in the file. */ #define OPENMPT_STREAM_SEEK_CUR 1 /*! Seek to the given offset relative to the end of the file. */ #define OPENMPT_STREAM_SEEK_END 2 /*! \brief Read bytes from stream * * Read bytes data from stream to dst. * \param stream Stream to read data from * \param dst Target where to copy data. * \param bytes Number of bytes to read. * \return Number of bytes actually read and written to dst. * \retval 0 End of stream or error. * \remarks Short reads are allowed as long as they return at least 1 byte if EOF is not reached. */ typedef size_t (*openmpt_stream_read_func)( void * stream, void * dst, size_t bytes ); /*! \brief Seek stream position * * Seek to stream position offset at whence. * \param stream Stream to operate on. * \param offset Offset to seek to. * \param whence OPENMPT_STREAM_SEEK_SET, OPENMPT_STREAM_SEEK_CUR, OPENMPT_STREAM_SEEK_END. See C89 documentation. * \return Returns 0 on success. * \retval 0 Success. * \retval -1 Failure. Position does not get updated. * \remarks libopenmpt will not try to seek beyond the file size, thus it is not important whether you allow for virtual positioning after the file end, or return an error in that case. The position equal to the file size needs to be seekable to. */ typedef int (*openmpt_stream_seek_func)( void * stream, int64_t offset, int whence ); /*! \brief Tell stream position * * Tell position of stream. * \param stream Stream to operate on. * \return Current position in stream. * \retval -1 Failure. */ typedef int64_t (*openmpt_stream_tell_func)( void * stream ); /*! \brief Stream callbacks * * Stream callbacks used by libopenmpt for stream operations. * \sa openmpt_stream_get_file_callbacks * \sa openmpt_stream_get_fd_callbacks * \sa openmpt_stream_get_buffer_callbacks */ typedef struct openmpt_stream_callbacks { /*! \brief Read callback. * * \sa openmpt_stream_read_func */ openmpt_stream_read_func read; /*! \brief Seek callback. * * Seek callback can be NULL if seeking is not supported. * \sa openmpt_stream_seek_func */ openmpt_stream_seek_func seek; /*! \brief Tell callback. * * Tell callback can be NULL if seeking is not supported. * \sa openmpt_stream_tell_func */ openmpt_stream_tell_func tell; } openmpt_stream_callbacks; /*! \brief Logging function * * \param message UTF-8 encoded log message. * \param user User context that was passed to openmpt_module_create2(), openmpt_module_create_from_memory2() or openmpt_could_open_probability2(). */ typedef void (*openmpt_log_func)( const char * message, void * user ); /*! \brief Default logging function * * Default logging function that logs anything to stderr. */ LIBOPENMPT_API void openmpt_log_func_default( const char * message, void * user ); /*! \brief Silent logging function * * Silent logging function that throws any log message away. */ LIBOPENMPT_API void openmpt_log_func_silent( const char * message, void * user ); /*! No error. \since 0.3.0 */ #define OPENMPT_ERROR_OK 0 /*! Lowest value libopenmpt will use for any of its own error codes. \since 0.3.0 */ #define OPENMPT_ERROR_BASE 256 /*! Unknown internal error. \since 0.3.0 */ #define OPENMPT_ERROR_UNKNOWN ( OPENMPT_ERROR_BASE + 1 ) /*! Unknown internal C++ exception. \since 0.3.0 */ #define OPENMPT_ERROR_EXCEPTION ( OPENMPT_ERROR_BASE + 11 ) /*! Out of memory. \since 0.3.0 */ #define OPENMPT_ERROR_OUT_OF_MEMORY ( OPENMPT_ERROR_BASE + 21 ) /*! Runtime error. \since 0.3.0 */ #define OPENMPT_ERROR_RUNTIME ( OPENMPT_ERROR_BASE + 30 ) /*! Range error. \since 0.3.0 */ #define OPENMPT_ERROR_RANGE ( OPENMPT_ERROR_BASE + 31 ) /*! Arithmetic overflow. \since 0.3.0 */ #define OPENMPT_ERROR_OVERFLOW ( OPENMPT_ERROR_BASE + 32 ) /*! Arithmetic underflow. \since 0.3.0 */ #define OPENMPT_ERROR_UNDERFLOW ( OPENMPT_ERROR_BASE + 33 ) /*! Logic error. \since 0.3.0 */ #define OPENMPT_ERROR_LOGIC ( OPENMPT_ERROR_BASE + 40 ) /*! Value domain error. \since 0.3.0 */ #define OPENMPT_ERROR_DOMAIN ( OPENMPT_ERROR_BASE + 41 ) /*! Maximum supported size exceeded. \since 0.3.0 */ #define OPENMPT_ERROR_LENGTH ( OPENMPT_ERROR_BASE + 42 ) /*! Argument out of range. \since 0.3.0 */ #define OPENMPT_ERROR_OUT_OF_RANGE ( OPENMPT_ERROR_BASE + 43 ) /*! Invalid argument. \since 0.3.0 */ #define OPENMPT_ERROR_INVALID_ARGUMENT ( OPENMPT_ERROR_BASE + 44 ) /*! General libopenmpt error. \since 0.3.0 */ #define OPENMPT_ERROR_GENERAL ( OPENMPT_ERROR_BASE + 101 ) /*! openmpt_module * is invalid. \since 0.3.0 */ #define OPENMPT_ERROR_INVALID_MODULE_POINTER ( OPENMPT_ERROR_BASE + 102 ) /*! NULL pointer argument. \since 0.3.0 */ #define OPENMPT_ERROR_ARGUMENT_NULL_POINTER ( OPENMPT_ERROR_BASE + 103 ) /*! \brief Check whether the error is transient * * Checks whether an error code represents a transient error which may not occur again in a later try if for example memory has been freed up after an out-of-memory error. * \param error Error code. * \retval 0 Error is not transient. * \retval 1 Error is transient. * \sa OPENMPT_ERROR_OUT_OF_MEMORY * \since 0.3.0 */ LIBOPENMPT_API int openmpt_error_is_transient( int error ); /*! \brief Convert error code to text * * Converts an error code into a text string describing the error. * \param error Error code. * \return Allocated string describing the error. * \retval NULL Not enough memory to allocate the string. * \since 0.3.0 */ LIBOPENMPT_API const char * openmpt_error_string( int error ); /*! Do not log or store the error. \since 0.3.0 */ #define OPENMPT_ERROR_FUNC_RESULT_NONE 0 /*! Log the error. \since 0.3.0 */ #define OPENMPT_ERROR_FUNC_RESULT_LOG ( 1 << 0 ) /*! Store the error. \since 0.3.0 */ #define OPENMPT_ERROR_FUNC_RESULT_STORE ( 1 << 1 ) /*! Log and store the error. \since 0.3.0 */ #define OPENMPT_ERROR_FUNC_RESULT_DEFAULT ( OPENMPT_ERROR_FUNC_RESULT_LOG | OPENMPT_ERROR_FUNC_RESULT_STORE ) /*! \brief Error function * * \param error Error code. * \param user User context that was passed to openmpt_module_create2(), openmpt_module_create_from_memory2() or openmpt_could_open_probability2(). * \return Mask of OPENMPT_ERROR_FUNC_RESULT_LOG and OPENMPT_ERROR_FUNC_RESULT_STORE. * \retval OPENMPT_ERROR_FUNC_RESULT_NONE Do not log or store the error. * \retval OPENMPT_ERROR_FUNC_RESULT_LOG Log the error. * \retval OPENMPT_ERROR_FUNC_RESULT_STORE Store the error. * \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT Log and store the error. * \sa OPENMPT_ERROR_FUNC_RESULT_NONE * \sa OPENMPT_ERROR_FUNC_RESULT_LOG * \sa OPENMPT_ERROR_FUNC_RESULT_STORE * \sa OPENMPT_ERROR_FUNC_RESULT_DEFAULT * \sa openmpt_error_func_default * \sa openmpt_error_func_log * \sa openmpt_error_func_store * \sa openmpt_error_func_ignore * \sa openmpt_error_func_errno * \since 0.3.0 */ typedef int (*openmpt_error_func)( int error, void * user ); /*! \brief Default error function * * Causes all errors to be logged and stored. * \param error Error code. * \param user Ignored. * \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT Always. * \since 0.3.0 */ LIBOPENMPT_API int openmpt_error_func_default( int error, void * user ); /*! \brief Log error function * * Causes all errors to be logged. * \param error Error code. * \param user Ignored. * \retval OPENMPT_ERROR_FUNC_RESULT_LOG Always. * \since 0.3.0 */ LIBOPENMPT_API int openmpt_error_func_log( int error, void * user ); /*! \brief Store error function * * Causes all errors to be stored. * \param error Error code. * \param user Ignored. * \retval OPENMPT_ERROR_FUNC_RESULT_STORE Always. * \since 0.3.0 */ LIBOPENMPT_API int openmpt_error_func_store( int error, void * user ); /*! \brief Ignore error function * * Causes all errors to be neither logged nor stored. * \param error Error code. * \param user Ignored. * \retval OPENMPT_ERROR_FUNC_RESULT_NONE Always. * \since 0.3.0 */ LIBOPENMPT_API int openmpt_error_func_ignore( int error, void * user ); /*! \brief Errno error function * * Causes all errors to be stored in the pointer passed in as user. * \param error Error code. * \param user Pointer to an int as generated by openmpt_error_func_errno_userdata. * \retval OPENMPT_ERROR_FUNC_RESULT_NONE user is not NULL. * \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT user is NULL. * \since 0.3.0 */ LIBOPENMPT_API int openmpt_error_func_errno( int error, void * user ); /*! \brief User pointer for openmpt_error_func_errno * * Provides a suitable user pointer argument for openmpt_error_func_errno. * \param error Pointer to an integer value to be used as output by openmpt_error_func_errno. * \retval (void*)error. * \since 0.3.0 */ LIBOPENMPT_API void * openmpt_error_func_errno_userdata( int * error ); /*! \brief Roughly scan the input stream to find out whether libopenmpt might be able to open it * * \param stream_callbacks Input stream callback operations. * \param stream Input stream to scan. * \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file. * \param logfunc Logging function where warning and errors are written. May be NULL. * \param user Logging function user context. Used to pass any user-defined data associated with this module to the logging function. * \return Probability between 0.0 and 1.0. * \remarks openmpt_could_open_probability() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.). * \remarks openmpt_could_open_probability() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_probability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_probability() returned 0.5. * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \deprecated Please use openmpt_could_open_probability2(). * \since 0.3.0 */ LIBOPENMPT_API LIBOPENMPT_DEPRECATED double openmpt_could_open_probability( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * user ); /*! \brief Roughly scan the input stream to find out whether libopenmpt might be able to open it * * \param stream_callbacks Input stream callback operations. * \param stream Input stream to scan. * \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file. * \param logfunc Logging function where warning and errors are written. May be NULL. * \param user Logging function user context. Used to pass any user-defined data associated with this module to the logging function. * \return Probability between 0.0 and 1.0. * \remarks openmpt_could_open_probability() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.). * \remarks openmpt_could_open_probability() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_probability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_probability() returned 0.5. * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \deprecated Please use openmpt_could_open_probability2(). */ LIBOPENMPT_API LIBOPENMPT_DEPRECATED double openmpt_could_open_propability( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * user ); /*! \brief Roughly scan the input stream to find out whether libopenmpt might be able to open it * * \param stream_callbacks Input stream callback operations. * \param stream Input stream to scan. * \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file. * \param logfunc Logging function where warning and errors are written. May be NULL. * \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. * \param errfunc Error function to define error behaviour. May be NULL. * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function. * \param error Pointer to an integer where an error may get stored. May be NULL. * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. * \return Probability between 0.0 and 1.0. * \remarks openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize() provide a simpler and faster interface that fits almost all use cases better. It is recommended to use openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize() instead of openmpt_could_open_probability(). * \remarks openmpt_could_open_probability2() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.). * \remarks openmpt_could_open_probability2() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_probability2() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_probability2() returned 0.5. \include libopenmpt_example_c_probe.c * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \sa openmpt_probe_file_header * \sa openmpt_probe_file_header_without_filesize * \since 0.3.0 */ LIBOPENMPT_API double openmpt_could_open_probability2( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ); /*! \brief Get recommended header size for successfull format probing * * \sa openmpt_probe_file_header() * \sa openmpt_probe_file_header_without_filesize() * \since 0.3.0 */ LIBOPENMPT_API size_t openmpt_probe_file_header_get_recommended_size(void); /*! Probe for module formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES 0x1ull /*! Probe for module-specific container formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS 0x2ull /*! Probe for the default set of formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT ( OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES | OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS ) /*! Probe for no formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_FLAGS_NONE 0x0ull /*! Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): The file will most likely be supported by libopenmpt. \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS 1 /*! Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): The file is not supported by libopenmpt. \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE 0 /*! Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): An answer could not be determined with the amount of data provided. \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA (-1) /*! Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): An internal error occurred. \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR (-255) /*! \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it * * \param flags Bit mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT. * \param data Beginning of the file data. * \param size Size of the beginning of the file data. * \param filesize Full size of the file data on disk. * \param logfunc Logging function where warning and errors are written. May be NULL. * \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. * \param errfunc Error function to define error behaviour. May be NULL. * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function. * \param error Pointer to an integer where an error may get stored. May be NULL. * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. * \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size and filesize to the file's size. * \remarks openmpt_could_open_probability2() provides a more elaborate interface that might be required for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred. * \sa openmpt_probe_file_header_get_recommended_size() * \sa openmpt_probe_file_header_without_filesize() * \sa openmpt_probe_file_header_from_stream() * \sa openmpt_could_open_probability2() * \since 0.3.0 */ LIBOPENMPT_API int openmpt_probe_file_header( uint64_t flags, const void * data, size_t size, uint64_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ); /*! \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it * * \param flags Bit mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT. * \param data Beginning of the file data. * \param size Size of the beginning of the file data. * \param logfunc Logging function where warning and errors are written. May be NULL. * \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. * \param errfunc Error function to define error behaviour. May be NULL. * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function. * \param error Pointer to an integer where an error may get stored. May be NULL. * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. * \remarks It is recommended to use openmpt_probe_file_header() and provide the acutal file's size as a parameter if at all possible. libopenmpt can provide more accurate answers if the filesize is known. * \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size to the file's size. * \remarks openmpt_could_open_probability2() provides a more elaborate interface that might be required for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred. * \sa openmpt_probe_file_header_get_recommended_size() * \sa openmpt_probe_file_header() * \sa openmpt_probe_file_header_from_stream() * \sa openmpt_could_open_probability2() * \since 0.3.0 */ LIBOPENMPT_API int openmpt_probe_file_header_without_filesize( uint64_t flags, const void * data, size_t size, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ); /*! \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it * * \param flags Bit mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT. * \param stream_callbacks Input stream callback operations. * \param stream Input stream to scan. * \param logfunc Logging function where warning and errors are written. May be NULL. * \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. * \param errfunc Error function to define error behaviour. May be NULL. * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function. * \param error Pointer to an integer where an error may get stored. May be NULL. * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. * \remarks The stream is left in an unspecified state when this function returns. * \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size and filesize to the file's size. * \remarks openmpt_could_open_probability2() provides a more elaborate interface that might be required for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided. * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred. * \sa openmpt_probe_file_header_get_recommended_size() * \sa openmpt_probe_file_header() * \sa openmpt_probe_file_header_without_filesize() * \sa openmpt_could_open_probability2() * \since 0.3.0 */ LIBOPENMPT_API int openmpt_probe_file_header_from_stream( uint64_t flags, openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ); /*! \brief Opaque type representing a libopenmpt module */ typedef struct openmpt_module openmpt_module; typedef struct openmpt_module_initial_ctl { const char * ctl; const char * value; } openmpt_module_initial_ctl; /*! \brief Construct an openmpt_module * * \param stream_callbacks Input stream callback operations. * \param stream Input stream to load the module from. * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. May be NULL. * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) * \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set. * \return A pointer to the constructed openmpt_module, or NULL on failure. * \remarks The input data can be discarded after an openmpt_module has been constructed successfully. * \sa openmpt_stream_callbacks * \sa \ref libopenmpt_c_fileio * \deprecated Please use openmpt_module_create2(). */ LIBOPENMPT_API LIBOPENMPT_DEPRECATED openmpt_module * openmpt_module_create( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, const openmpt_module_initial_ctl * ctls ); /*! \brief Construct an openmpt_module * * \param stream_callbacks Input stream callback operations. * \param stream Input stream to load the module from. * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. May be NULL. * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) * \param errfunc Error function to define error behaviour. May be NULL. * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function. * \param error Pointer to an integer where an error may get stored. May be NULL. * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. * \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set. * \return A pointer to the constructed openmpt_module, or NULL on failure. * \remarks The input data can be discarded after an openmpt_module has been constructed successfully. * \sa openmpt_stream_callbacks * \sa \ref libopenmpt_c_fileio * \since 0.3.0 */ LIBOPENMPT_API openmpt_module * openmpt_module_create2( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ); /*! \brief Construct an openmpt_module * * \param filedata Data to load the module from. * \param filesize Amount of data available. * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) * \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set. * \return A pointer to the constructed openmpt_module, or NULL on failure. * \remarks The input data can be discarded after an openmpt_module has been constructed successfully. * \sa \ref libopenmpt_c_fileio * \deprecated Please use openmpt_module_create_from_memory2(). */ LIBOPENMPT_API LIBOPENMPT_DEPRECATED openmpt_module * openmpt_module_create_from_memory( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * loguser, const openmpt_module_initial_ctl * ctls ); /*! \brief Construct an openmpt_module * * \param filedata Data to load the module from. * \param filesize Amount of data available. * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) * \param errfunc Error function to define error behaviour. May be NULL. * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function. * \param error Pointer to an integer where an error may get stored. May be NULL. * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. * \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set. * \return A pointer to the constructed openmpt_module, or NULL on failure. * \remarks The input data can be discarded after an openmpt_module has been constructed successfully. * \sa \ref libopenmpt_c_fileio * \since 0.3.0 */ LIBOPENMPT_API openmpt_module * openmpt_module_create_from_memory2( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ); /*! \brief Unload a previously created openmpt_module from memory. * * \param mod The module to unload. */ LIBOPENMPT_API void openmpt_module_destroy( openmpt_module * mod ); /*! \brief Set logging function. * * Set the logging function of an already constructed openmpt_module. * \param mod The module handle to work on. * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) * \since 0.3.0 */ LIBOPENMPT_API void openmpt_module_set_log_func( openmpt_module * mod, openmpt_log_func logfunc, void * loguser ); /*! \brief Set error function. * * Set the error function of an already constructed openmpt_module. * \param mod The module handle to work on. * \param errfunc Error function to define error behaviour. May be NULL. * \param erruser Error function user context. * \since 0.3.0 */ LIBOPENMPT_API void openmpt_module_set_error_func( openmpt_module * mod, openmpt_error_func errfunc, void * erruser ); /*! \brief Get last error. * * Return the error currently stored in an openmpt_module. The stored error is not cleared. * \param mod The module handle to work on. * \return The error currently stored. * \sa openmpt_module_error_get_last_message * \sa openmpt_module_error_set_last * \sa openmpt_module_error_clear * \since 0.3.0 */ LIBOPENMPT_API int openmpt_module_error_get_last( openmpt_module * mod ); /*! \brief Get last error message. * * Return the error message currently stored in an openmpt_module. The stored error is not cleared. * \param mod The module handle to work on. * \return The error message currently stored. * \sa openmpt_module_error_set_last * \sa openmpt_module_error_clear * \since 0.3.0 */ LIBOPENMPT_API const char * openmpt_module_error_get_last_message( openmpt_module * mod ); /*! \brief Set last error. * * Set the error currently stored in an openmpt_module. * \param mod The module handle to work on. * \param error Error to be stored. * \sa openmpt_module_error_get_last * \sa openmpt_module_error_clear * \since 0.3.0 */ LIBOPENMPT_API void openmpt_module_error_set_last( openmpt_module * mod, int error ); /*! \brief Clear last error. * * Set the error currently stored in an openmpt_module to OPPENMPT_ERROR_OK. * \param mod The module handle to work on. * \sa openmpt_module_error_get_last * \sa openmpt_module_error_set_last * \since 0.3.0 */ LIBOPENMPT_API void openmpt_module_error_clear( openmpt_module * mod ); /** * \defgroup openmpt_module_render_param Render param indices * * \brief Parameter index to use with openmpt_module_get_render_param() and openmpt_module_set_render_param() * @{ */ /*! \brief Master Gain * * The related value represents a relative gain in milliBel.\n * The default value is 0.\n * The supported value range is unlimited.\n */ #define OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL 1 /*! \brief Stereo Separation * * The related value represents the stereo separation generated by the libopenmpt mixer in percent.\n * The default value is 100.\n * The supported value range is [0,200].\n */ #define OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT 2 /*! \brief Interpolation Filter * * The related value represents the interpolation filter length used by the libopenmpt mixer.\n * The default value is 0, which indicates a recommended default value.\n * The supported value range is [0,inf). Values greater than the implementation limit are clamped to the maximum supported value.\n * Currently supported values: * - 0: internal default * - 1: no interpolation (zero order hold) * - 2: linear interpolation * - 4: cubic interpolation * - 8: windowed sinc with 8 taps */ #define OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH 3 /*! \brief Volume Ramping Strength * * The related value represents the amount of volume ramping done by the libopenmpt mixer.\n * The default value is -1, which indicates a recommended default value.\n * The meaningful value range is [-1..10].\n * A value of 0 completely disables volume ramping. This might cause clicks in sound output.\n * Higher values imply slower/softer volume ramps. */ #define OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH 4 /** @}*/ /** * \defgroup openmpt_module_command_index Pattern cell indices * * \brief Parameter index to use with openmpt_module_get_pattern_row_channel_command(), openmpt_module_format_pattern_row_channel_command() and openmpt_module_highlight_pattern_row_channel_command() * @{ */ #define OPENMPT_MODULE_COMMAND_NOTE 0 #define OPENMPT_MODULE_COMMAND_INSTRUMENT 1 #define OPENMPT_MODULE_COMMAND_VOLUMEEFFECT 2 #define OPENMPT_MODULE_COMMAND_EFFECT 3 #define OPENMPT_MODULE_COMMAND_VOLUME 4 #define OPENMPT_MODULE_COMMAND_PARAMETER 5 /** @}*/ /*! \brief Select a sub-song from a multi-song module * * \param mod The module handle to work on. * \param subsong Index of the sub-song. -1 plays all sub-songs consecutively. * \return 1 on success, 0 on failure. * \sa openmpt_module_get_num_subsongs, openmpt_module_get_selected_subsong, openmpt_module_get_subsong_name * \remarks Whether subsong -1 (all subsongs consecutively), subsong 0 or some other subsong is selected by default, is an implementation detail and subject to change. If you do not want to care about subsongs, it is recommended to just not call openmpt_module_select_subsong() at all. */ LIBOPENMPT_API int openmpt_module_select_subsong( openmpt_module * mod, int32_t subsong ); /*! \brief Get currently selected sub-song from a multi-song module * * \param mod The module handle to work on. * \return Currently selected sub-song. -1 for all subsongs consecutively, 0 or greater for the current sub-song index. * \sa openmpt_module_get_num_subsongs, openmpt_module_select_subsong, openmpt_module_get_subsong_name * \since 0.3.0 */ LIBOPENMPT_API int32_t openmpt_module_get_selected_subsong( openmpt_module * mod ); /*! \brief Get the restart order of the specified sub-song * * \param mod The module handle to work on. * \param subsong Index of the sub-song to retrieve the restart position from. * \return The restart order of the specified sub-song. This is the order to which playback returns after the last pattern row of the song has been played. -1 is returned if if sub-song is not in range [0,openmpt_module_get_num_subsongs()[ * \sa openmpt_module_get_restart_row * \since 0.8.0 */ LIBOPENMPT_API int32_t openmpt_module_get_restart_order( openmpt_module * mod, int32_t subsong ); /*! \brief Get the restart row of the specified sub-song * * \param mod The module handle to work on. * \param subsong Index of the sub-song to retrieve the restart position from. * \return The restart row of the specified sub-song. This is the first played row of the order to which playback returns after the last pattern row of the song has been played. -1 is returned if if sub-song is not in range [0,openmpt_module_get_num_subsongs()[ * \sa openmpt_module_get_restart_order * \since 0.8.0 */ LIBOPENMPT_API int32_t openmpt_module_get_restart_row( openmpt_module * mod, int32_t subsong ); /*! \brief Set Repeat Count * * \param mod The module handle to work on. * \param repeat_count Repeat Count * - -1: repeat forever * - 0: play once, repeat zero times (the default) * - n>0: play once and repeat n times after that * \return 1 on success, 0 on failure. * \sa openmpt_module_get_repeat_count */ LIBOPENMPT_API int openmpt_module_set_repeat_count( openmpt_module * mod, int32_t repeat_count ); /*! \brief Get Repeat Count * * \param mod The module handle to work on. * \return Repeat Count * - -1: repeat forever * - 0: play once, repeat zero times (the default) * - n>0: play once and repeat n times after that * \sa openmpt_module_set_repeat_count */ LIBOPENMPT_API int32_t openmpt_module_get_repeat_count( openmpt_module * mod ); /*! \brief approximate song duration * * \param mod The module handle to work on. * \return Approximate duration of current sub-song in seconds. * \remarks The function may return infinity if the pattern data is too complex to evaluate. */ LIBOPENMPT_API double openmpt_module_get_duration_seconds( openmpt_module * mod ); /*! \brief Get approximate playback time in seconds at given position * * \param mod The module handle to work on. * \param order The order position at which the time should be retrieved. * \param row The pattern row number at which the time should be retrieved. * \return Approximate playback time in seconds of current sub-song at the start of the given order and row combination. Negative if the position does not exist, or the pattern data is too complex to evaluate. * \remarks If an order / row combination is played multiple times (e.g. due the pattern loops), the first occurence of this position is returned. * \since 0.8.0 */ LIBOPENMPT_API double openmpt_module_get_time_at_position( openmpt_module * mod, int32_t order, int32_t row ); /*! \brief Set approximate current song position * * \param mod The module handle to work on. * \param seconds Seconds to seek to. If seconds is out of range, the position gets set to song start or end respectively. * \return Approximate new song position in seconds. * \sa openmpt_module_get_position_seconds */ LIBOPENMPT_API double openmpt_module_set_position_seconds( openmpt_module * mod, double seconds ); /*! \brief Get current song position * * \param mod The module handle to work on. * \return Current song position in seconds. * \sa openmpt_module_set_position_seconds */ LIBOPENMPT_API double openmpt_module_get_position_seconds( openmpt_module * mod ); /*! \brief Set approximate current song position * * If order or row are out of range, to position is not modified and the current position is returned. * \param mod The module handle to work on. * \param order Pattern order number to seek to. * \param row Pattern row number to seek to. * \return Approximate new song position in seconds. * \sa openmpt_module_set_position_seconds * \sa openmpt_module_get_position_seconds */ LIBOPENMPT_API double openmpt_module_set_position_order_row( openmpt_module * mod, int32_t order, int32_t row ); /*! \brief Get render parameter * * \param mod The module handle to work on. * \param param Parameter to query. See \ref openmpt_module_render_param * \param value Pointer to the variable that receives the current value of the parameter. * \return 1 on success, 0 on failure (invalid param or value is NULL). * \sa OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL * \sa OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT * \sa OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH * \sa OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH * \sa openmpt_module_set_render_param */ LIBOPENMPT_API int openmpt_module_get_render_param( openmpt_module * mod, int param, int32_t * value ); /*! \brief Set render parameter * * \param mod The module handle to work on. * \param param Parameter to set. See \ref openmpt_module_render_param * \param value The value to set param to. * \return 1 on success, 0 on failure (invalid param). * \sa OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL * \sa OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT * \sa OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH * \sa OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH * \sa openmpt_module_get_render_param */ LIBOPENMPT_API int openmpt_module_set_render_param( openmpt_module * mod, int param, int32_t value ); /*@{*/ /*! \brief Render audio data * * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. * \param mono Pointer to a buffer of at least count elements that receives the mono/center output. * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. * \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. * \sa \ref libopenmpt_c_outputformat */ LIBOPENMPT_API size_t openmpt_module_read_mono( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * mono ); /*! \brief Render audio data * * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. * \param left Pointer to a buffer of at least count elements that receives the left output. * \param right Pointer to a buffer of at least count elements that receives the right output. * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. * \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. * \sa \ref libopenmpt_c_outputformat */ LIBOPENMPT_API size_t openmpt_module_read_stereo( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * left, int16_t * right ); /*! \brief Render audio data * * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. * \param left Pointer to a buffer of at least count elements that receives the left output. * \param right Pointer to a buffer of at least count elements that receives the right output. * \param rear_left Pointer to a buffer of at least count elements that receives the rear left output. * \param rear_right Pointer to a buffer of at least count elements that receives the rear right output. * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. * \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. * \sa \ref libopenmpt_c_outputformat */ LIBOPENMPT_API size_t openmpt_module_read_quad( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * left, int16_t * right, int16_t * rear_left, int16_t * rear_right ); /*! \brief Render audio data * * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. * \param mono Pointer to a buffer of at least count elements that receives the mono/center output. * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. * \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. * \sa \ref libopenmpt_c_outputformat */ LIBOPENMPT_API size_t openmpt_module_read_float_mono( openmpt_module * mod, int32_t samplerate, size_t count, float * mono ); /*! \brief Render audio data * * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. * \param left Pointer to a buffer of at least count elements that receives the left output. * \param right Pointer to a buffer of at least count elements that receives the right output. * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. * \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. * \sa \ref libopenmpt_c_outputformat */ LIBOPENMPT_API size_t openmpt_module_read_float_stereo( openmpt_module * mod, int32_t samplerate, size_t count, float * left, float * right ); /*! \brief Render audio data * * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. * \param left Pointer to a buffer of at least count elements that receives the left output. * \param right Pointer to a buffer of at least count elements that receives the right output. * \param rear_left Pointer to a buffer of at least count elements that receives the rear left output. * \param rear_right Pointer to a buffer of at least count elements that receives the rear right output. * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. * \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. * \sa \ref libopenmpt_c_outputformat */ LIBOPENMPT_API size_t openmpt_module_read_float_quad( openmpt_module * mod, int32_t samplerate, size_t count, float * left, float * right, float * rear_left, float * rear_right ); /*! \brief Render audio data * * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. * \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R). * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. * \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. * \sa \ref libopenmpt_c_outputformat */ LIBOPENMPT_API size_t openmpt_module_read_interleaved_stereo( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * interleaved_stereo ); /*! \brief Render audio data * * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. * \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. * \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. * \sa \ref libopenmpt_c_outputformat */ LIBOPENMPT_API size_t openmpt_module_read_interleaved_quad( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * interleaved_quad ); /*! \brief Render audio data * * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. * \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R). * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. * \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. * \sa \ref libopenmpt_c_outputformat */ LIBOPENMPT_API size_t openmpt_module_read_interleaved_float_stereo( openmpt_module * mod, int32_t samplerate, size_t count, float * interleaved_stereo ); /*! \brief Render audio data * * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. * \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. * \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. * \sa \ref libopenmpt_c_outputformat */ LIBOPENMPT_API size_t openmpt_module_read_interleaved_float_quad( openmpt_module * mod, int32_t samplerate, size_t count, float * interleaved_quad ); /*@}*/ /*! \brief Get the list of supported metadata item keys * * \param mod The module handle to work on. * \return Metadata item keys supported by openmpt_module_get_metadata, as a semicolon-separated list. * \sa openmpt_module_get_metadata */ LIBOPENMPT_API const char * openmpt_module_get_metadata_keys( openmpt_module * mod ); /*! \brief Get a metadata item value * * \param mod The module handle to work on. * \param key Metadata item key to query. Use openmpt_module_get_metadata_keys to check for available keys. * Possible keys are: * - type: Module format extension (e.g. it) or another similar identifier for modules formats that typically do not use a file extension * - type_long: Format name associated with the module format (e.g. Impulse Tracker) * - originaltype: Module format extension (e.g. it) of the original module in case the actual type is a converted format (e.g. mo3 or gdm) * - originaltype_long: Format name associated with the module format (e.g. Impulse Tracker) of the original module in case the actual type is a converted format (e.g. mo3 or gdm) * - container: Container format the module file is embedded in, if any (e.g. umx) * - container_long: Full container name if the module is embedded in a container (e.g. Unreal Music) * - tracker: Tracker that was (most likely) used to save the module file, if known * - artist: Author of the module * - title: Module title * - date: Date the module was last saved, in ISO-8601 format. * - message: Song message. If the song message is empty or the module format does not support song messages, a list of instrument and sample names is returned instead. * - message_raw: Song message. If the song message is empty or the module format does not support song messages, an empty string is returned. * - warnings: A list of warnings that were generated while loading the module. * \return The associated value for key. * \sa openmpt_module_get_metadata_keys */ LIBOPENMPT_API const char * openmpt_module_get_metadata( openmpt_module * mod, const char * key ); /*! Get the current estimated beats per minute (BPM). * * \param mod The module handle to work on. * \remarks Many module formats lack time signature metadata. It is common that this estimate is off by a factor of two, but other multipliers are also possible. * \remarks Due to the nature of how module tempo works, the estimate may change slightly after switching libopenmpt's output to a different sample rate. * \return The current estimated BPM. */ LIBOPENMPT_API double openmpt_module_get_current_estimated_bpm( openmpt_module * mod ); /*! \brief Get the current speed * * \param mod The module handle to work on. * \return The current speed in ticks per row. */ LIBOPENMPT_API int32_t openmpt_module_get_current_speed( openmpt_module * mod ); /*! \brief Get the current tempo * * \param mod The module handle to work on. * \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. * \deprecated Please use openmpt_module_get_current_tempo2(). */ LIBOPENMPT_API LIBOPENMPT_DEPRECATED int32_t openmpt_module_get_current_tempo( openmpt_module * mod ); /*! \brief Get the current tempo * * \param mod The module handle to work on. * \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. * \since 0.7.0 */ LIBOPENMPT_API double openmpt_module_get_current_tempo2( openmpt_module * mod ); /*! \brief Get the current order * * \param mod The module handle to work on. * \return The current order at which the module is being played back. */ LIBOPENMPT_API int32_t openmpt_module_get_current_order( openmpt_module * mod ); /*! \brief Get the current pattern * * \param mod The module handle to work on. * \return The current pattern that is being played. */ LIBOPENMPT_API int32_t openmpt_module_get_current_pattern( openmpt_module * mod ); /*! \brief Get the current row * * \param mod The module handle to work on. * \return The current row at which the current pattern is being played. */ LIBOPENMPT_API int32_t openmpt_module_get_current_row( openmpt_module * mod ); /*! \brief Get the current amount of playing channels. * * \param mod The module handle to work on. * \return The amount of sample channels that are currently being rendered. */ LIBOPENMPT_API int32_t openmpt_module_get_current_playing_channels( openmpt_module * mod ); /*! \brief Get an approximate indication of the channel volume. * * \param mod The module handle to work on. * \param channel The channel whose volume should be retrieved. * \return The approximate channel volume. * \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ LIBOPENMPT_API float openmpt_module_get_current_channel_vu_mono( openmpt_module * mod, int32_t channel ); /*! \brief Get an approximate indication of the channel volume on the front-left speaker. * * \param mod The module handle to work on. * \param channel The channel whose volume should be retrieved. * \return The approximate channel volume. * \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ LIBOPENMPT_API float openmpt_module_get_current_channel_vu_left( openmpt_module * mod, int32_t channel ); /*! \brief Get an approximate indication of the channel volume on the front-right speaker. * * \param mod The module handle to work on. * \param channel The channel whose volume should be retrieved. * \return The approximate channel volume. * \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ LIBOPENMPT_API float openmpt_module_get_current_channel_vu_right( openmpt_module * mod, int32_t channel ); /*! \brief Get an approximate indication of the channel volume on the rear-left speaker. * * \param mod The module handle to work on. * \param channel The channel whose volume should be retrieved. * \return The approximate channel volume. * \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ LIBOPENMPT_API float openmpt_module_get_current_channel_vu_rear_left( openmpt_module * mod, int32_t channel ); /*! \brief Get an approximate indication of the channel volume on the rear-right speaker. * * \param mod The module handle to work on. * \param channel The channel whose volume should be retrieved. * \return The approximate channel volume. * \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ LIBOPENMPT_API float openmpt_module_get_current_channel_vu_rear_right( openmpt_module * mod, int32_t channel ); /*! \brief Get the number of sub-songs * * \param mod The module handle to work on. * \return The number of sub-songs in the module. This includes any "hidden" songs (songs that share the same sequence, but start at different order indices) and "normal" sub-songs or "sequences" (if the format supports them). * \sa openmpt_module_get_subsong_name, openmpt_module_select_subsong, openmpt_module_get_selected_subsong */ LIBOPENMPT_API int32_t openmpt_module_get_num_subsongs( openmpt_module * mod ); /*! \brief Get the number of pattern channels * * \param mod The module handle to work on. * \return The number of pattern channels in the module. Not all channels do necessarily contain data. * \remarks The number of pattern channels is completely independent of the number of output channels. libopenmpt can render modules in mono, stereo or quad surround, but the choice of which of the three modes to use must not be made based on the return value of this function, which may be any positive integer amount. Only use this function for informational purposes. */ LIBOPENMPT_API int32_t openmpt_module_get_num_channels( openmpt_module * mod ); /*! \brief Get the number of orders * * \param mod The module handle to work on. * \return The number of orders in the current sequence of the module. */ LIBOPENMPT_API int32_t openmpt_module_get_num_orders( openmpt_module * mod ); /*! \brief Get the number of patterns * * \param mod The module handle to work on. * \return The number of distinct patterns in the module. */ LIBOPENMPT_API int32_t openmpt_module_get_num_patterns( openmpt_module * mod ); /*! \brief Get the number of instruments * * \param mod The module handle to work on. * \return The number of instrument slots in the module. Instruments are a layer on top of samples, and are not supported by all module formats. */ LIBOPENMPT_API int32_t openmpt_module_get_num_instruments( openmpt_module * mod ); /*! \brief Get the number of samples * * \param mod The module handle to work on. * \return The number of sample slots in the module. */ LIBOPENMPT_API int32_t openmpt_module_get_num_samples( openmpt_module * mod ); /*! \brief Get a sub-song name * * \param mod The module handle to work on. * \param index The sub-song whose name should be retrieved * \return The sub-song name. * \sa openmpt_module_get_num_subsongs, openmpt_module_select_subsong, openmpt_module_get_selected_subsong */ LIBOPENMPT_API const char * openmpt_module_get_subsong_name( openmpt_module * mod, int32_t index ); /*! \brief Get a channel name * * \param mod The module handle to work on. * \param index The channel whose name should be retrieved * \return The channel name. * \sa openmpt_module_get_num_channels */ LIBOPENMPT_API const char * openmpt_module_get_channel_name( openmpt_module * mod, int32_t index ); /*! \brief Get an order name * * \param mod The module handle to work on. * \param index The order whose name should be retrieved * \return The order name. * \sa openmpt_module_get_num_orders */ LIBOPENMPT_API const char * openmpt_module_get_order_name( openmpt_module * mod, int32_t index ); /*! \brief Get a pattern name * * \param mod The module handle to work on. * \param index The pattern whose name should be retrieved * \return The pattern name. * \sa openmpt_module_get_num_patterns */ LIBOPENMPT_API const char * openmpt_module_get_pattern_name( openmpt_module * mod, int32_t index ); /*! \brief Get an instrument name * * \param mod The module handle to work on. * \param index The instrument whose name should be retrieved * \return The instrument name. * \sa openmpt_module_get_num_instruments */ LIBOPENMPT_API const char * openmpt_module_get_instrument_name( openmpt_module * mod, int32_t index ); /*! \brief Get a sample name * * \param mod The module handle to work on. * \param index The sample whose name should be retrieved * \return The sample name. * \sa openmpt_module_get_num_samples */ LIBOPENMPT_API const char * openmpt_module_get_sample_name( openmpt_module * mod, int32_t index ); /*! \brief Get pattern at order position * * \param mod The module handle to work on. * \param order The order item whose pattern index should be retrieved. * \return The pattern index found at the given order position of the current sequence. */ LIBOPENMPT_API int32_t openmpt_module_get_order_pattern( openmpt_module * mod, int32_t order ); /*! \brief Check if specified order is a skip ("+++") item * * \param mod The module handle to work on. * \param order The order index to check. * \return Returns non-zero value if the pattern index at the given order position represents a skip item. During playback, this item is ignored and playback resumes at the next order list item. * \sa openmpt_module_is_order_stop_entry, openmpt_module_is_pattern_skip_item * \since 0.8.0 */ LIBOPENMPT_API int openmpt_module_is_order_skip_entry( openmpt_module * mod, int32_t order ); /*! \brief Check if specified pattern index is a skip ("+++") item * * \param mod The module handle to work on. * \param pattern The pattern index to check. * \return Returns non-zero value if the pattern index represents a skip item. During playback, this item is ignored and playback resumes at the next order list item. * \sa openmpt_module_is_pattern_stop_item, openmpt_module_is_order_skip_entry, openmpt_module_get_order_pattern * \since 0.8.0 */ LIBOPENMPT_API int openmpt_module_is_pattern_skip_item( openmpt_module * mod, int32_t pattern ); /*! \brief Check if specified order is a stop ("---") item * * \param mod The module handle to work on. * \param order The order index to check. * \return Returns non-zero value if the pattern index at the given order position represents a stop item. When this item is reached, playback continues at the restart position of the current sub-song. * \sa openmpt_module_is_order_skip_entry, openmpt_module_is_pattern_stop_item * \since 0.8.0 */ LIBOPENMPT_API int openmpt_module_is_order_stop_entry( openmpt_module * mod, int32_t order ); /*! \brief Check if specified pattern index is a stop ("---") item * * \param mod The module handle to work on. * \param pattern The pattern index to check. * \return Returns non-zero value if the pattern index represents a stop item. When this item is reached, playback continues at the restart position of the current sub-song. * \sa openmpt_module_is_pattern_skip_item, openmpt_module_is_order_stop_entry, openmpt_module_get_order_pattern * \since 0.8.0 */ LIBOPENMPT_API int openmpt_module_is_pattern_stop_item( openmpt_module * mod, int32_t pattern ); /*! \brief Get the number of rows in a pattern * * \param mod The module handle to work on. * \param pattern The pattern whose row count should be retrieved. * \return The number of rows in the given pattern. If the pattern does not exist, 0 is returned. */ LIBOPENMPT_API int32_t openmpt_module_get_pattern_num_rows( openmpt_module * mod, int32_t pattern ); /*! \brief Get the rows per beat of a pattern * * \param mod The module handle to work on. * \param pattern The pattern whose time signature should be retrieved. * \return The rows per beat of the given pattern. If the pattern does not exist or the time signature is not defined, 0 is returned. * \remarks Many module formats lack time signature metadata. In this case, the returned value may be an incorrect estimation. * \since 0.8.0 */ LIBOPENMPT_API int32_t openmpt_module_get_pattern_rows_per_beat( openmpt_module * mod, int32_t pattern ); /*! \brief Get the rows per measure of a pattern * * \param mod The module handle to work on. * \param pattern The pattern whose time signature should be retrieved. * \return The rows per measure of the given pattern. If the pattern does not exist or the time signature is not defined, 0 is returned. * \remarks Many module formats lack time signature metadata. In this case, the returned value may be an incorrect estimation. */ LIBOPENMPT_API int32_t openmpt_module_get_pattern_rows_per_measure( openmpt_module * mod, int32_t pattern ); /*! \brief Get raw pattern content * * \param mod The module handle to work on. * \param pattern The pattern whose data should be retrieved. * \param row The row from which the data should be retrieved. * \param channel The channel from which the data should be retrieved. * \param command The cell index at which the data should be retrieved. See \ref openmpt_module_command_index * \return The internal, raw pattern data at the given pattern position. */ LIBOPENMPT_API uint8_t openmpt_module_get_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command ); /*! \brief Get formatted (human-readable) pattern content * * \param mod The module handle to work on. * \param pattern The pattern whose data should be retrieved. * \param row The row from which the data should be retrieved. * \param channel The channel from which the data should be retrieved. * \param command The cell index at which the data should be retrieved. * \return The formatted pattern data at the given pattern position. See \ref openmpt_module_command_index * \sa openmpt_module_highlight_pattern_row_channel_command */ LIBOPENMPT_API const char * openmpt_module_format_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command ); /*! \brief Get highlighting information for formatted pattern content * * \param mod The module handle to work on. * \param pattern The pattern whose data should be retrieved. * \param row The row from which the data should be retrieved. * \param channel The channel from which the data should be retrieved. * \param command The cell index at which the data should be retrieved. See \ref openmpt_module_command_index * \return The highlighting string for the formatted pattern data as retrieved by openmpt_module_get_pattern_row_channel_command at the given pattern position. * \remarks The returned string will map each character position of the string returned by openmpt_module_get_pattern_row_channel_command to a highlighting instruction. * Possible highlighting characters are: * - " " : empty/space * - "." : empty/dot * - "n" : generic note * - "m" : special note * - "i" : generic instrument * - "u" : generic volume column effect * - "v" : generic volume column parameter * - "e" : generic effect column effect * - "f" : generic effect column parameter * \sa openmpt_module_get_pattern_row_channel_command */ LIBOPENMPT_API const char * openmpt_module_highlight_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command ); /*! \brief Get formatted (human-readable) pattern content * * \param mod The module handle to work on. * \param pattern The pattern whose data should be retrieved. * \param row The row from which the data should be retrieved. * \param channel The channel from which the data should be retrieved. * \param width The maximum number of characters the string should contain. 0 means no limit. * \param pad If true, the string will be resized to the exact length provided in the width parameter. * \return The formatted pattern data at the given pattern position. * \sa openmpt_module_highlight_pattern_row_channel */ LIBOPENMPT_API const char * openmpt_module_format_pattern_row_channel( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, size_t width, int pad ); /*! \brief Get highlighting information for formatted pattern content * * \param mod The module handle to work on. * \param pattern The pattern whose data should be retrieved. * \param row The row from which the data should be retrieved. * \param channel The channel from which the data should be retrieved. * \param width The maximum number of characters the string should contain. 0 means no limit. * \param pad If true, the string will be resized to the exact length provided in the width parameter. * \return The highlighting string for the formatted pattern data as retrieved by openmpt_module_format_pattern_row_channel at the given pattern position. * \sa openmpt_module_format_pattern_row_channel */ LIBOPENMPT_API const char * openmpt_module_highlight_pattern_row_channel( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, size_t width, int pad ); /*! \brief Retrieve supported ctl keys * * \param mod The module handle to work on. * \return A semicolon-separated list containing all supported ctl keys. * \remarks Currently supported ctl values are: * - load.skip_samples (boolean): Set to "1" to avoid loading samples into memory * - load.skip_patterns (boolean): Set to "1" to avoid loading patterns into memory * - load.skip_plugins (boolean): Set to "1" to avoid loading plugins * - load.skip_subsongs_init (boolean): Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking. * - seek.sync_samples (boolean): Set to "0" to not sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row. * - subsong (integer): The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong. * - play.at_end (text): Chooses the behaviour when the end of song is reached. The song end is considered to be reached after the number of reptitions set by openmpt_module_set_repeat_count was played, so if the song is set to repeat infinitely, its end is never considered to be reached. * - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames. * - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the loop start (if the song is not programmed to loop, playback resumed from the song start). * - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames. * - play.tempo_factor (floatingpoint): Set a floating point tempo factor. "1.0" is the default tempo. * - play.pitch_factor (floatingpoint): Set a floating point pitch factor. "1.0" is the default pitch. * - render.resampler.emulate_amiga (boolean): Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. * - render.resampler.emulate_amiga_type (string): Configures the filter type to use for the Amiga resampler. Supported values are: * - "auto": Filter type is chosen by the library and might change. This is the default. * - "a500": Amiga A500 filter. * - "a1200": Amiga A1200 filter. * - "unfiltered": BLEP synthesis without model-specific filters. The LED filter is ignored by this setting. This filter mode is considered to be experimental and might change in the future. * - render.opl.volume_factor (floatingpoint): Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume. * - dither (integer): Set the dither algorithm that is used for the 16 bit versions of openmpt_module_read. Supported values are: * - 0: No dithering. * - 1: Default mode. Chosen by OpenMPT code, might change. * - 2: Rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker). * - 3: Rectangular, 1 bit depth, simple 1st order noise shaping */ LIBOPENMPT_API const char * openmpt_module_get_ctls( openmpt_module * mod ); /*! \brief Get current ctl value * * \param mod The module handle to work on. * \param ctl The ctl key whose value should be retrieved. * \return The associated ctl value, or NULL on failure. * \sa openmpt_module_get_ctls * \deprecated Please use openmpt_module_ctl_get_boolean(), openmpt_module_ctl_get_integer(), openmpt_module_ctl_get_floatingpoint(), or openmpt_module_ctl_get_text(). */ LIBOPENMPT_API LIBOPENMPT_DEPRECATED const char * openmpt_module_ctl_get( openmpt_module * mod, const char * ctl ); /*! \brief Get current ctl boolean value * * \param mod The module handle to work on. * \param ctl The ctl key whose value should be retrieved. * \return The associated ctl value, or NULL on failure. * \sa openmpt_module_get_ctls * \since 0.5.0 */ LIBOPENMPT_API int openmpt_module_ctl_get_boolean( openmpt_module * mod, const char * ctl ); /*! \brief Get current ctl integer value * * \param mod The module handle to work on. * \param ctl The ctl key whose value should be retrieved. * \return The associated ctl value, or NULL on failure. * \sa openmpt_module_get_ctls * \since 0.5.0 */ LIBOPENMPT_API int64_t openmpt_module_ctl_get_integer( openmpt_module * mod, const char * ctl ); /*! \brief Get current ctl floatingpoint value * * \param mod The module handle to work on. * \param ctl The ctl key whose value should be retrieved. * \return The associated ctl value, or NULL on failure. * \sa openmpt_module_get_ctls * \since 0.5.0 */ LIBOPENMPT_API double openmpt_module_ctl_get_floatingpoint( openmpt_module * mod, const char * ctl ); /*! \brief Get current ctl string value * * \param mod The module handle to work on. * \param ctl The ctl key whose value should be retrieved. * \return The associated ctl value, or NULL on failure. * \sa openmpt_module_get_ctls * \since 0.5.0 */ LIBOPENMPT_API const char * openmpt_module_ctl_get_text( openmpt_module * mod, const char * ctl ); /*! \brief Set ctl value * * \param mod The module handle to work on. * \param ctl The ctl key whose value should be set. * \param value The value that should be set. * \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized. * \sa openmpt_module_get_ctls * \deprecated Please use openmpt_module_ctl_set_boolean(), openmpt_module_ctl_set_integer(), openmpt_module_ctl_set_floatingpoint(), or openmpt_module_ctl_set_text(). */ LIBOPENMPT_API LIBOPENMPT_DEPRECATED int openmpt_module_ctl_set( openmpt_module * mod, const char * ctl, const char * value ); /*! \brief Set ctl boolean value * * \param mod The module handle to work on. * \param ctl The ctl key whose value should be set. * \param value The value that should be set. * \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized. * \sa openmpt_module_get_ctls * \since 0.5.0 */ LIBOPENMPT_API int openmpt_module_ctl_set_boolean( openmpt_module * mod, const char * ctl, int value ); /*! \brief Set ctl integer value * * \param mod The module handle to work on. * \param ctl The ctl key whose value should be set. * \param value The value that should be set. * \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized. * \sa openmpt_module_get_ctls * \since 0.5.0 */ LIBOPENMPT_API int openmpt_module_ctl_set_integer( openmpt_module * mod, const char * ctl, int64_t value ); /*! \brief Set ctl floatingpoint value * * \param mod The module handle to work on. * \param ctl The ctl key whose value should be set. * \param value The value that should be set. * \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized. * \sa openmpt_module_get_ctls * \since 0.5.0 */ LIBOPENMPT_API int openmpt_module_ctl_set_floatingpoint( openmpt_module * mod, const char * ctl, double value ); /*! \brief Set ctl string value * * \param mod The module handle to work on. * \param ctl The ctl key whose value should be set. * \param value The value that should be set. * \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized. * \sa openmpt_module_get_ctls * \since 0.5.0 */ LIBOPENMPT_API int openmpt_module_ctl_set_text( openmpt_module * mod, const char * ctl, const char * value ); /* remember to add new functions to both C and C++ interfaces and to increase OPENMPT_API_VERSION_MINOR */ #ifdef __cplusplus } #endif /*! * @} */ #endif /* LIBOPENMPT_H */ libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt.pc.in0000644000175000017500000000047112740237634021543 00000000000000 prefix=@prefix@ exec_prefix=@exec_prefix@ includedir=@includedir@ libdir=@libdir@ Name: libopenmpt Description: Tracker module player based on OpenMPT Version: @VERSION@ Requires.private: @LIBOPENMPT_REQUIRES_PRIVATE@ Libs: -L${libdir} -lopenmpt Libs.private: @LIBOPENMPT_LIBS_PRIVATE@ Cflags: -I${includedir} libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_config.h0000644000175000017500000002760314320233106022300 00000000000000/* * libopenmpt_config.h * ------------------- * Purpose: libopenmpt public interface configuration * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_CONFIG_H #define LIBOPENMPT_CONFIG_H /* clang-format off */ /*! \defgroup libopenmpt libopenmpt */ /*! \addtogroup libopenmpt @{ */ /* provoke warnings if already defined */ #define LIBOPENMPT_API #undef LIBOPENMPT_API #define LIBOPENMPT_CXX_API #undef LIBOPENMPT_CXX_API /*! @} */ /*! \addtogroup libopenmpt_c @{ */ /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_buffer.h exists. * \remarks * Use the following to check for availability: * \code * #include * #if defined(LIBOPENMPT_STREAM_CALLBACKS_BUFFER) * #include * #endif * \endcode */ #define LIBOPENMPT_STREAM_CALLBACKS_BUFFER /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_fd.h exists. * \since 0.3.0 * \remarks * Use the following to check for availability: * \code * #include * #if defined(LIBOPENMPT_STREAM_CALLBACKS_FD) || ((OPENMPT_API_VERSION_MAJOR == 0) && ((OPENMPT_API_VERSION_MINOR == 2) || (OPENMPT_API_VERSION_MINOR == 1))) * #include * #endif * \endcode */ #define LIBOPENMPT_STREAM_CALLBACKS_FD /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_file.h exists. * \since 0.3.0 * \remarks * Use the following to check for availability: * \code * #include * #if defined(LIBOPENMPT_STREAM_CALLBACKS_FILE) || ((OPENMPT_API_VERSION_MAJOR == 0) && ((OPENMPT_API_VERSION_MINOR == 2) || (OPENMPT_API_VERSION_MINOR == 1))) * #include * #endif * \endcode */ #define LIBOPENMPT_STREAM_CALLBACKS_FILE /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_file_mingw.h exists. * \since 0.7.0 * \remarks * This macro does not determine if the interfaces required to use libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h are available. * It is the libopenmpt user's responsibility to check for availability of the _off64_t, _ftelli64(), and _fseeki64(). * Use the following to check for availability: * \code * #include * #if defined(LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW) * #include * #endif * \endcode */ #define LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h exists. * \since 0.7.0 * \remarks * This macro does not determine if the interfaces required to use libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h are available. * It is the libopenmpt user's responsibility to check for availability of the __int64, _ftelli64(), and _fseeki64(). * Use the following to check for availability: * \code * #include * #if defined(LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT) * #include * #endif * \endcode */ #define LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_file_posix.h exists. * \since 0.7.0 * \remarks * This macro does not determine if the interfaces required to use libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h are available. * It is the libopenmpt user's responsibility to check for availability of the _off_t, ftello(), and fseeko(). * Use the following to check for availability: * \code * #include * #if defined(LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW) * #include * #endif * \endcode */ #define LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h exists. * \since 0.7.0 * \remarks * This macro does not determine if the interfaces required to use libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h are available. * It is the libopenmpt user's responsibility to check for availability of the off64_t, ftello64(), and fseeko64(). * Use the following to check for availability: * \code * #include * #if defined(LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_LFS64) * #include * #endif * \endcode */ #define LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_LFS64 /*! @} */ /*! \addtogroup libopenmpt @{ */ #if defined(__DOXYGEN__) #define LIBOPENMPT_API_HELPER_EXPORT #define LIBOPENMPT_API_HELPER_IMPORT #define LIBOPENMPT_API_HELPER_PUBLIC #define LIBOPENMPT_API_HELPER_LOCAL #elif defined(_MSC_VER) #define LIBOPENMPT_API_HELPER_EXPORT __declspec(dllexport) #define LIBOPENMPT_API_HELPER_IMPORT __declspec(dllimport) #define LIBOPENMPT_API_HELPER_PUBLIC #define LIBOPENMPT_API_HELPER_LOCAL #ifdef __cplusplus #define LIBOPENMPT_API_HELPER_EXPORT_CLASS __declspec(dllexport) #define LIBOPENMPT_API_HELPER_IMPORT_CLASS __declspec(dllimport) #define LIBOPENMPT_API_HELPER_PUBLIC_CLASS #define LIBOPENMPT_API_HELPER_LOCAL_CLASS #endif #elif defined(__EMSCRIPTEN__) #define LIBOPENMPT_API_HELPER_EXPORT __attribute__((visibility("default"))) __attribute__((used)) #define LIBOPENMPT_API_HELPER_IMPORT __attribute__((visibility("default"))) __attribute__((used)) #define LIBOPENMPT_API_HELPER_PUBLIC __attribute__((visibility("default"))) __attribute__((used)) #define LIBOPENMPT_API_HELPER_LOCAL __attribute__((visibility("hidden"))) #ifdef __cplusplus #define LIBOPENMPT_API_HELPER_EXPORT_CLASS __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_IMPORT_CLASS __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_PUBLIC_CLASS __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_LOCAL_CLASS __attribute__((visibility("hidden"))) #define LIBOPENMPT_API_HELPER_EXPORT_MEMBER __attribute__((visibility("default"))) __attribute__((used)) #define LIBOPENMPT_API_HELPER_IMPORT_MEMBER __attribute__((visibility("default"))) __attribute__((used)) #define LIBOPENMPT_API_HELPER_PUBLIC_MEMBER __attribute__((visibility("default"))) __attribute__((used)) #define LIBOPENMPT_API_HELPER_LOCAL_MEMBER __attribute__((visibility("hidden"))) #endif #elif (defined(__GNUC__) || defined(__clang__)) && defined(_WIN32) #define LIBOPENMPT_API_HELPER_EXPORT __declspec(dllexport) #define LIBOPENMPT_API_HELPER_IMPORT __declspec(dllimport) #define LIBOPENMPT_API_HELPER_PUBLIC __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_LOCAL __attribute__((visibility("hidden"))) #ifdef __cplusplus #define LIBOPENMPT_API_HELPER_EXPORT_CLASS __declspec(dllexport) #define LIBOPENMPT_API_HELPER_IMPORT_CLASS __declspec(dllimport) #define LIBOPENMPT_API_HELPER_PUBLIC_CLASS __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_LOCAL_CLASS __attribute__((visibility("hidden"))) #endif #elif defined(__GNUC__) || defined(__clang__) #define LIBOPENMPT_API_HELPER_EXPORT __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_IMPORT __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_PUBLIC __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_LOCAL __attribute__((visibility("hidden"))) #ifdef __cplusplus #define LIBOPENMPT_API_HELPER_EXPORT_CLASS __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_IMPORT_CLASS __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_PUBLIC_CLASS __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_LOCAL_CLASS __attribute__((visibility("hidden"))) #endif #elif defined(_WIN32) #define LIBOPENMPT_API_HELPER_EXPORT __declspec(dllexport) #define LIBOPENMPT_API_HELPER_IMPORT __declspec(dllimport) #define LIBOPENMPT_API_HELPER_PUBLIC #define LIBOPENMPT_API_HELPER_LOCAL #ifdef __cplusplus #define LIBOPENMPT_API_HELPER_EXPORT_CLASS __declspec(dllexport) #define LIBOPENMPT_API_HELPER_IMPORT_CLASS __declspec(dllimport) #define LIBOPENMPT_API_HELPER_PUBLIC_CLASS #define LIBOPENMPT_API_HELPER_LOCAL_CLASS #endif #else #define LIBOPENMPT_API_HELPER_EXPORT #define LIBOPENMPT_API_HELPER_IMPORT #define LIBOPENMPT_API_HELPER_PUBLIC #define LIBOPENMPT_API_HELPER_LOCAL #endif #ifdef __cplusplus #ifndef LIBOPENMPT_API_HELPER_EXPORT_CLASS #define LIBOPENMPT_API_HELPER_EXPORT_CLASS #endif #ifndef LIBOPENMPT_API_HELPER_EXPORT_MEMBER #define LIBOPENMPT_API_HELPER_EXPORT_MEMBER #endif #ifndef LIBOPENMPT_API_HELPER_IMPORT_CLASS #define LIBOPENMPT_API_HELPER_IMPORT_CLASS #endif #ifndef LIBOPENMPT_API_HELPER_IMPORT_MEMBER #define LIBOPENMPT_API_HELPER_IMPORT_MEMBER #endif #ifndef LIBOPENMPT_API_HELPER_PUBLIC_CLASS #define LIBOPENMPT_API_HELPER_PUBLIC_CLASS #endif #ifndef LIBOPENMPT_API_HELPER_PUBLIC_MEMBER #define LIBOPENMPT_API_HELPER_PUBLIC_MEMBER #endif #ifndef LIBOPENMPT_API_HELPER_LOCAL_CLASS #define LIBOPENMPT_API_HELPER_LOCAL_CLASS #endif #ifndef LIBOPENMPT_API_HELPER_LOCAL_MEMBER #define LIBOPENMPT_API_HELPER_LOCAL_MEMBER #endif #endif #if defined(LIBOPENMPT_BUILD_DLL) #define LIBOPENMPT_API LIBOPENMPT_API_HELPER_EXPORT #elif defined(LIBOPENMPT_USE_DLL) #define LIBOPENMPT_API LIBOPENMPT_API_HELPER_IMPORT #else #define LIBOPENMPT_API LIBOPENMPT_API_HELPER_PUBLIC #endif #ifdef __cplusplus #if defined(LIBOPENMPT_BUILD_DLL) #define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_EXPORT #define LIBOPENMPT_CXX_API_CLASS LIBOPENMPT_API_HELPER_EXPORT_CLASS #define LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_API_HELPER_EXPORT_MEMBER #elif defined(LIBOPENMPT_USE_DLL) #define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_IMPORT #define LIBOPENMPT_CXX_API_CLASS LIBOPENMPT_API_HELPER_IMPORT_CLASS #define LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_API_HELPER_IMPORT_MEMBER #else #define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_PUBLIC #define LIBOPENMPT_CXX_API_CLASS LIBOPENMPT_API_HELPER_PUBLIC_CLASS #define LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_API_HELPER_PUBLIC_MEMBER #endif #if defined(LIBOPENMPT_USE_DLL) #if defined(_MSC_VER) && !defined(_DLL) #error "C++ interface is disabled if libopenmpt is built as a DLL and the runtime is statically linked. This is not supported by microsoft and cannot possibly work. Ever." #undef LIBOPENMPT_CXX_API #define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_LOCAL #undef LIBOPENMPT_CXX_API_CLASS #define LIBOPENMPT_CXX_API_CLASS LIBOPENMPT_API_HELPER_LOCAL_CLASS #undef LIBOPENMPT_CXX_API_MEMBER #define LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_API_HELPER_LOCAL_MEMBER #endif #endif #endif /*! @} */ /* C */ #if !defined(LIBOPENMPT_NO_DEPRECATE) #if defined(__clang__) #define LIBOPENMPT_DEPRECATED __attribute__((deprecated)) #elif defined(__GNUC__) #define LIBOPENMPT_DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) #define LIBOPENMPT_DEPRECATED __declspec(deprecated) #else #define LIBOPENMPT_DEPRECATED #endif #else #define LIBOPENMPT_DEPRECATED #endif #ifndef __cplusplus #if !defined(LIBOPENMPT_NO_DEPRECATE) LIBOPENMPT_DEPRECATED static const int LIBOPENMPT_DEPRECATED_STRING_CONSTANT = 0; #define LIBOPENMPT_DEPRECATED_STRING( str ) ( LIBOPENMPT_DEPRECATED_STRING_CONSTANT ? ( str ) : ( str ) ) #else #define LIBOPENMPT_DEPRECATED_STRING( str ) str #endif #else #define LIBOPENMPT_DEPRECATED_STRING( str ) str #endif #if defined(__STDC__) && (__STDC__ == 1) #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) #define LIBOPENMPT_C_INLINE inline #else #define LIBOPENMPT_C_INLINE #endif #else #define LIBOPENMPT_C_INLINE #endif /* C++ */ #ifdef __cplusplus #if defined(LIBOPENMPT_ASSUME_CPLUSPLUS) #endif #if !defined(LIBOPENMPT_NO_DEPRECATE) #define LIBOPENMPT_ATTR_DEPRECATED [[deprecated]] #else #define LIBOPENMPT_ATTR_DEPRECATED #endif #endif /* clang-format on */ #include "libopenmpt_version.h" #endif /* LIBOPENMPT_CONFIG_H */ libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h0000644000175000017500000000510714172232041026717 00000000000000/* * libopenmpt_stream_callbacks_file_msvcrt.h * ----------------------------------------- * Purpose: libopenmpt public c interface * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT_H #define LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT_H #include "libopenmpt.h" #include #include #include /*! \addtogroup libopenmpt_c * @{ */ #ifdef __cplusplus extern "C" { #endif static size_t openmpt_stream_file_msvcrt_read_func( void * stream, void * dst, size_t bytes ) { FILE * f = 0; size_t retval = 0; f = (FILE*)stream; if ( !f ) { return 0; } retval = fread( dst, 1, bytes, f ); if ( retval <= 0 ) { return 0; } return retval; } static int openmpt_stream_file_msvcrt_seek_func( void * stream, int64_t offset, int whence ) { FILE * f = 0; int fwhence = 0; f = (FILE*)stream; if ( !f ) { return -1; } switch ( whence ) { case OPENMPT_STREAM_SEEK_SET: fwhence = SEEK_SET; break; case OPENMPT_STREAM_SEEK_CUR: fwhence = SEEK_CUR; break; case OPENMPT_STREAM_SEEK_END: fwhence = SEEK_END; break; default: return -1; break; } if ( (__int64)offset != offset ) { return -1; } return _fseeki64( f, (__int64)offset, fwhence ) ? -1 : 0; } static int64_t openmpt_stream_file_msvcrt_tell_func( void * stream ) { FILE * f = 0; __int64 result = 0; int64_t retval = 0; f = (FILE*)stream; if ( !f ) { return -1; } result = _ftelli64( f ); if ( (int64_t)result != result ) { return -1; } retval = (int64_t)result; if ( retval < 0 ) { return -1; } return retval; } /*! \brief Provide openmpt_stream_callbacks for standard C FILE objects * * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. * * \remarks The stream argument must be passed as `(void*)(FILE*)file`. * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \sa openmpt_could_open_probability2 * \sa openmpt_probe_file_header_from_stream * \sa openmpt_module_create2 */ static openmpt_stream_callbacks openmpt_stream_get_file_msvcrt_callbacks(void) { openmpt_stream_callbacks retval; memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); retval.read = openmpt_stream_file_msvcrt_read_func; retval.seek = openmpt_stream_file_msvcrt_seek_func; retval.tell = openmpt_stream_file_msvcrt_tell_func; return retval; } #ifdef __cplusplus } #endif /*! * @} */ #endif /* LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT_H */ libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_test/0000755000175000017500000000000015023302363021714 500000000000000libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_test/libopenmpt_test.cpp0000644000175000017500000000353714730570477025601 00000000000000/* * libopenmpt_test.cpp * ------------------- * Purpose: libopenmpt test suite driver * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "openmpt/all/BuildSettings.hpp" #include "openmpt/all/PlatformFixes.hpp" #include "mpt/base/integer.hpp" #include "mpt/main/main.hpp" #include "../../libopenmpt/libopenmpt_internal.h" #include "../../test/test.h" #include #include #include #include #if defined(__EMSCRIPTEN__) #include #endif /* __EMSCRIPTEN__ */ namespace libopenmpt_test { static mpt::uint8 main() { #if defined(__EMSCRIPTEN__) EM_ASM( FS.mkdir('/test'); FS.mount(NODEFS, {'root': '../test/'}, '/test'); FS.mkdir('/libopenmpt'); FS.mount(NODEFS, {'root': '../libopenmpt/'}, '/libopenmpt'); ); #endif /* __EMSCRIPTEN__ */ try { using namespace OpenMPT; Test::PrintHeader(); // run test with "C" / classic() locale Test::DoTests(); // try setting the C locale to the user locale setlocale( LC_ALL, "" ); // run all tests again with a set C locale Test::DoTests(); // try to set the C and C++ locales to the user locale try { std::locale old = std::locale::global( std::locale( "" ) ); static_cast( old ); } catch ( ... ) { // Setting c++ global locale does not work. // This is no problem for libopenmpt, just continue. } // and now, run all tests once again Test::DoTests(); Test::PrintFooter(); } catch ( const std::exception & e ) { std::cerr << "TEST ERROR: exception: " << ( e.what() ? e.what() : "" ) << std::endl; return 255; } catch ( ... ) { std::cerr << "TEST ERROR: unknown exception" << std::endl; return 255; } return 0; } } // namespace libopenmpt_test MPT_MAIN_IMPLEMENT_MAIN_NO_ARGS(libopenmpt_test) libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_stream_callbacks_file_mingw.h0000644000175000017500000000507414172232041026525 00000000000000/* * libopenmpt_stream_callbacks_file_mingw.h * ---------------------------------------- * Purpose: libopenmpt public c interface * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW_H #define LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW_H #include "libopenmpt.h" #include #include #include /*! \addtogroup libopenmpt_c * @{ */ #ifdef __cplusplus extern "C" { #endif static size_t openmpt_stream_file_mingw_read_func( void * stream, void * dst, size_t bytes ) { FILE * f = 0; size_t retval = 0; f = (FILE*)stream; if ( !f ) { return 0; } retval = fread( dst, 1, bytes, f ); if ( retval <= 0 ) { return 0; } return retval; } static int openmpt_stream_file_mingw_seek_func( void * stream, int64_t offset, int whence ) { FILE * f = 0; int fwhence = 0; f = (FILE*)stream; if ( !f ) { return -1; } switch ( whence ) { case OPENMPT_STREAM_SEEK_SET: fwhence = SEEK_SET; break; case OPENMPT_STREAM_SEEK_CUR: fwhence = SEEK_CUR; break; case OPENMPT_STREAM_SEEK_END: fwhence = SEEK_END; break; default: return -1; break; } if ( (_off64_t)offset != offset ) { return -1; } return fseeko64( f, (_off64_t)offset, fwhence ) ? -1 : 0; } static int64_t openmpt_stream_file_mingw_tell_func( void * stream ) { FILE * f = 0; _off64_t result = 0; int64_t retval = 0; f = (FILE*)stream; if ( !f ) { return -1; } result = ftello64( f ); if ( (int64_t)result != result ) { return -1; } retval = (int64_t)result; if ( retval < 0 ) { return -1; } return retval; } /*! \brief Provide openmpt_stream_callbacks for standard C FILE objects * * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. * * \remarks The stream argument must be passed as `(void*)(FILE*)file`. * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \sa openmpt_could_open_probability2 * \sa openmpt_probe_file_header_from_stream * \sa openmpt_module_create2 */ static openmpt_stream_callbacks openmpt_stream_get_file_mingw_callbacks(void) { openmpt_stream_callbacks retval; memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); retval.read = openmpt_stream_file_mingw_read_func; retval.seek = openmpt_stream_file_mingw_seek_func; retval.tell = openmpt_stream_file_mingw_tell_func; return retval; } #ifdef __cplusplus } #endif /*! * @} */ #endif /* LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW_H */ libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_impl.cpp0000644000175000017500000026021315015401723022327 00000000000000/* * libopenmpt_impl.cpp * ------------------- * Purpose: libopenmpt private interface implementation * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "common/stdafx.h" #include "libopenmpt_internal.h" #include "libopenmpt.hpp" #include "libopenmpt_impl.hpp" #include #include #include #include #include #include #include #include #include #include "mpt/audio/span.hpp" #include "mpt/base/algorithm.hpp" #include "mpt/base/detect.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/base/saturate_round.hpp" #include "mpt/format/default_integer.hpp" #include "mpt/format/default_floatingpoint.hpp" #include "mpt/format/default_string.hpp" #include "mpt/format/join.hpp" #include "mpt/io_read/callbackstream.hpp" #include "mpt/io_read/filecursor_callbackstream.hpp" #include "mpt/io_read/filecursor_memory.hpp" #include "mpt/io_read/filecursor_stdstream.hpp" #include "mpt/mutex/mutex.hpp" #include "mpt/parse/parse.hpp" #include "mpt/string/types.hpp" #include "mpt/string/utility.hpp" #include "mpt/string_transcode/transcode.hpp" #include "common/version.h" #include "common/misc_util.h" #include "common/FileReader.h" #include "common/Logging.h" #include "soundlib/Sndfile.h" #include "soundlib/mod_specifications.h" #include "soundlib/AudioReadTarget.h" #if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT #include #endif // MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT OPENMPT_NAMESPACE_BEGIN #if !defined(MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS) #if MPT_WINRT_BEFORE(MPT_WIN_8) MPT_WARNING("Warning: libopenmpt for WinRT is built with reduced functionality. Please #define NTDDI_VERSION 0x0602000.") #endif // MPT_WINRT_BEFORE(MPT_WIN_8) #if MPT_PLATFORM_MULTITHREADED && MPT_MUTEX_NONE MPT_WARNING("Warning: libopenmpt built in non thread-safe mode because mutexes are not supported by the C++ standard library available.") #endif // MPT_MUTEX_NONE #if MPT_OS_WINDOWS && (defined(__MINGW32__) || defined(__MINGW64__)) && MPT_LIBCXX_GNU && !defined(_GLIBCXX_HAS_GTHREADS) MPT_WARNING("Warning: Platform (Windows) supports multi-threading, however the toolchain (MinGW/GCC) does not. The resulting libopenmpt may not be thread-safe. This is a MinGW/GCC issue. You can avoid this warning by using a MinGW toolchain built with posix threading model as opposed to win32 threading model.") #endif // MINGW #if MPT_CLANG_AT_LEAST(5,0,0) && MPT_CLANG_BEFORE(11,0,0) && defined(__powerpc__) && !defined(__powerpc64__) MPT_WARNING("Warning: libopenmpt is known to trigger bad code generation with Clang 5..10 on powerpc (32bit) when using -O3. See .") #endif #if defined(ENABLE_TESTS) #if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR) #if MPT_GCC_BEFORE(9,1,0) MPT_WARNING("Warning: MinGW with GCC earlier than 9.1 detected. Standard library does neither provide std::fstream wchar_t overloads nor std::filesystem with wchar_t support. Unicode filename support is thus unavailable.") #endif // MPT_GCC_AT_LEAST(9,1,0) #endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR #endif // ENABLE_TESTS #endif // !MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS #if defined(MPT_ASSERT_HANDLER_NEEDED) && !defined(ENABLE_TESTS) MPT_NOINLINE void AssertHandler(const mpt::source_location &loc, const char *expr, const char *msg) { if(msg) { mpt::log::GlobalLogger().SendLogMessage(loc, LogError, "ASSERT", MPT_USTRING("ASSERTION FAILED: ") + mpt::transcode(mpt::source_encoding, msg) + MPT_USTRING(" (") + mpt::transcode(mpt::source_encoding, expr) + MPT_USTRING(")") ); } else { mpt::log::GlobalLogger().SendLogMessage(loc, LogError, "ASSERT", MPT_USTRING("ASSERTION FAILED: ") + mpt::transcode(mpt::source_encoding, expr) ); } #if defined(MPT_BUILD_FATAL_ASSERTS) std::abort(); #endif // MPT_BUILD_FATAL_ASSERTS } #endif // MPT_ASSERT_HANDLER_NEEDED && !ENABLE_TESTS OPENMPT_NAMESPACE_END // assume OPENMPT_NAMESPACE is OpenMPT namespace openmpt { namespace version { std::uint32_t get_library_version() { return OPENMPT_API_VERSION; } std::uint32_t get_core_version() { return OpenMPT::Version::Current().GetRawVersion(); } static std::string get_library_version_string() { std::string str; const OpenMPT::SourceInfo sourceInfo = OpenMPT::SourceInfo::Current(); str += mpt::format_value_default(OPENMPT_API_VERSION_MAJOR); str += "."; str += mpt::format_value_default(OPENMPT_API_VERSION_MINOR); str += "."; str += mpt::format_value_default(OPENMPT_API_VERSION_PATCH); if ( std::string(OPENMPT_API_VERSION_PREREL).length() > 0 ) { str += OPENMPT_API_VERSION_PREREL; } std::vector fields; if ( sourceInfo.Revision() ) { fields.push_back( "r" + mpt::format_value_default( sourceInfo.Revision() ) ); } if ( sourceInfo.IsDirty() ) { fields.push_back( "modified" ); } else if ( sourceInfo.HasMixedRevisions() ) { fields.push_back( "mixed" ); } if ( sourceInfo.IsPackage() ) { fields.push_back( "pkg" ); } if ( !fields.empty() ) { str += "+"; str += OpenMPT::mpt::join_format( fields, std::string(".") ); } return str; } static std::string get_library_features_string() { return mpt::transcode( mpt::common_encoding::utf8, mpt::trim( OpenMPT::Build::GetBuildFeaturesString() ) ); } static std::string get_core_version_string() { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetVersionStringExtended() ); } static std::string get_source_url_string() { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::SourceInfo::Current().GetUrlWithRevision() ); } static std::string get_source_date_string() { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::SourceInfo::Current().Date() ); } static std::string get_source_revision_string() { const OpenMPT::SourceInfo sourceInfo = OpenMPT::SourceInfo::Current(); return sourceInfo.Revision() ? mpt::format_value_default( sourceInfo.Revision() ) : std::string(); } static std::string get_build_string() { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetBuildDateString() ); } static std::string get_build_compiler_string() { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetBuildCompilerString() ); } static std::string get_credits_string() { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetFullCreditsString() ); } static std::string get_contact_string() { return mpt::transcode( mpt::common_encoding::utf8, MPT_USTRING("Forum: ") + OpenMPT::Build::GetURL( OpenMPT::Build::Url::Forum ) ); } static std::string get_license_string() { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetLicenseString() ); } static std::string get_url_string() { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetURL( OpenMPT::Build::Url::Website ) ); } static std::string get_support_forum_url_string() { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetURL( OpenMPT::Build::Url::Forum ) ); } static std::string get_bugtracker_url_string() { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetURL( OpenMPT::Build::Url::Bugtracker ) ); } std::string get_string( const std::string & key ) { if ( key == "" ) { return std::string(); } else if ( key == "library_version" ) { return get_library_version_string(); } else if ( key == "library_version_major" ) { return mpt::format_value_default(OPENMPT_API_VERSION_MAJOR); } else if ( key == "library_version_minor" ) { return mpt::format_value_default(OPENMPT_API_VERSION_MINOR); } else if ( key == "library_version_patch" ) { return mpt::format_value_default(OPENMPT_API_VERSION_PATCH); } else if ( key == "library_version_prerel" ) { return mpt::format_value_default(OPENMPT_API_VERSION_PREREL); } else if ( key == "library_version_is_release" ) { return ( std::string(OPENMPT_API_VERSION_PREREL).length() == 0 ) ? "1" : "0"; } else if ( key == "library_features" ) { return get_library_features_string(); } else if ( key == "core_version" ) { return get_core_version_string(); } else if ( key == "source_url" ) { return get_source_url_string(); } else if ( key == "source_date" ) { return get_source_date_string(); } else if ( key == "source_revision" ) { return get_source_revision_string(); } else if ( key == "source_is_modified" ) { return OpenMPT::SourceInfo::Current().IsDirty() ? "1" : "0"; } else if ( key == "source_has_mixed_revisions" ) { return OpenMPT::SourceInfo::Current().HasMixedRevisions() ? "1" : "0"; } else if ( key == "source_is_package" ) { return OpenMPT::SourceInfo::Current().IsPackage() ? "1" : "0"; } else if ( key == "build" ) { return get_build_string(); } else if ( key == "build_compiler" ) { return get_build_compiler_string(); } else if ( key == "credits" ) { return get_credits_string(); } else if ( key == "contact" ) { return get_contact_string(); } else if ( key == "license" ) { return get_license_string(); } else if ( key == "url" ) { return get_url_string(); } else if ( key == "support_forum_url" ) { return get_support_forum_url_string(); } else if ( key == "bugtracker_url" ) { return get_bugtracker_url_string(); } else { return std::string(); } } } // namespace version log_interface::log_interface() { return; } log_interface::~log_interface() { return; } std_ostream_log::std_ostream_log( std::ostream & dst ) : destination(dst) { return; } std_ostream_log::~std_ostream_log() { return; } void std_ostream_log::log( const std::string & message ) const { destination.flush(); destination << message << std::endl; destination.flush(); } class log_forwarder : public OpenMPT::ILog { private: log_interface & destination; public: log_forwarder( log_interface & dest ) : destination(dest) { return; } private: void AddToLog( OpenMPT::LogLevel level, const mpt::ustring & text ) const override { destination.log( mpt::transcode( mpt::common_encoding::utf8, LogLevelToString( level ) + MPT_USTRING(": ") + text ) ); } }; // class log_forwarder class loader_log : public OpenMPT::ILog { private: mutable std::vector > m_Messages; public: std::vector > GetMessages() const; private: void AddToLog( OpenMPT::LogLevel level, const mpt::ustring & text ) const override; }; // class loader_log std::vector > loader_log::GetMessages() const { return m_Messages; } void loader_log::AddToLog( OpenMPT::LogLevel level, const mpt::ustring & text ) const { m_Messages.push_back( std::make_pair( level, mpt::transcode( mpt::common_encoding::utf8, text ) ) ); } void module_impl::PushToCSoundFileLog( const std::string & text ) const { m_sndFile->AddToLog( OpenMPT::LogError, mpt::transcode( mpt::common_encoding::utf8, text ) ); } void module_impl::PushToCSoundFileLog( int loglevel, const std::string & text ) const { m_sndFile->AddToLog( static_cast( loglevel ), mpt::transcode( mpt::common_encoding::utf8, text ) ); } module_impl::subsong_data::subsong_data( double duration, std::int32_t start_row, std::int32_t start_order, std::int32_t sequence, std::int32_t restart_row, std::int32_t restart_order ) : duration(duration) , start_row(start_row) , start_order(start_order) , sequence(sequence) , restart_row(restart_row) , restart_order(restart_order) { return; } static OpenMPT::ResamplingMode filterlength_to_resamplingmode(std::int32_t length) { OpenMPT::ResamplingMode result = OpenMPT::SRCMODE_SINC8LP; if ( length == 0 ) { result = OpenMPT::SRCMODE_SINC8LP; } else if ( length >= 8 ) { result = OpenMPT::SRCMODE_SINC8LP; } else if ( length >= 3 ) { result = OpenMPT::SRCMODE_CUBIC; } else if ( length >= 2 ) { result = OpenMPT::SRCMODE_LINEAR; } else if ( length >= 1 ) { result = OpenMPT::SRCMODE_NEAREST; } else { throw openmpt::exception("negative filter length"); } return result; } static std::int32_t resamplingmode_to_filterlength(OpenMPT::ResamplingMode mode) { switch ( mode ) { case OpenMPT::SRCMODE_NEAREST: return 1; break; case OpenMPT::SRCMODE_LINEAR: return 2; break; case OpenMPT::SRCMODE_CUBIC: return 4; break; case OpenMPT::SRCMODE_SINC8: case OpenMPT::SRCMODE_SINC8LP: case OpenMPT::SRCMODE_DEFAULT: return 8; default: throw openmpt::exception("unknown interpolation filter length set internally"); break; } } template < typename sample_type > static inline std::size_t valid_channels( sample_type * const * buffers, std::size_t max_channels ) { std::size_t channel; for ( channel = 0; channel < max_channels; ++channel ) { if ( !buffers[ channel ] ) { break; } } return channel; } static OpenMPT::Resampling::AmigaFilter translate_amiga_filter_type( module_impl::amiga_filter_type amiga_type ) { switch (amiga_type ) { case module_impl::amiga_filter_type::a500: return OpenMPT::Resampling::AmigaFilter::A500; case module_impl::amiga_filter_type::a1200: case module_impl::amiga_filter_type::auto_filter: default: return OpenMPT::Resampling::AmigaFilter::A1200; case module_impl::amiga_filter_type::unfiltered: return OpenMPT::Resampling::AmigaFilter::Unfiltered; } } static void ramping_to_mixersettings( OpenMPT::MixerSettings & settings, int ramping ) { if ( ramping == -1 ) { settings.SetVolumeRampUpMicroseconds( OpenMPT::MixerSettings().GetVolumeRampUpMicroseconds() ); settings.SetVolumeRampDownMicroseconds( OpenMPT::MixerSettings().GetVolumeRampDownMicroseconds() ); } else if ( ramping <= 0 ) { settings.SetVolumeRampUpMicroseconds( 0 ); settings.SetVolumeRampDownMicroseconds( 0 ); } else { settings.SetVolumeRampUpMicroseconds( ramping * 1000 ); settings.SetVolumeRampDownMicroseconds( ramping * 1000 ); } } static void mixersettings_to_ramping( int & ramping, const OpenMPT::MixerSettings & settings ) { std::int32_t ramp_us = std::max( settings.GetVolumeRampUpMicroseconds(), settings.GetVolumeRampDownMicroseconds() ); if ( ( settings.GetVolumeRampUpMicroseconds() == OpenMPT::MixerSettings().GetVolumeRampUpMicroseconds() ) && ( settings.GetVolumeRampDownMicroseconds() == OpenMPT::MixerSettings().GetVolumeRampDownMicroseconds() ) ) { ramping = -1; } else if ( ramp_us <= 0 ) { ramping = 0; } else { ramping = ( ramp_us + 500 ) / 1000; } } std::string module_impl::mod_string_to_utf8( const std::string & encoded ) const { return OpenMPT::mpt::ToCharset( OpenMPT::mpt::Charset::UTF8, m_sndFile->GetCharsetInternal(), encoded ); } void module_impl::apply_mixer_settings( std::int32_t samplerate, int channels ) { bool samplerate_changed = static_cast( m_sndFile->m_MixerSettings.gdwMixingFreq ) != samplerate; bool channels_changed = static_cast( m_sndFile->m_MixerSettings.gnChannels ) != channels; if ( samplerate_changed || channels_changed ) { OpenMPT::MixerSettings mixersettings = m_sndFile->m_MixerSettings; std::int32_t volrampin_us = mixersettings.GetVolumeRampUpMicroseconds(); std::int32_t volrampout_us = mixersettings.GetVolumeRampDownMicroseconds(); mixersettings.gdwMixingFreq = samplerate; mixersettings.gnChannels = channels; mixersettings.SetVolumeRampUpMicroseconds( volrampin_us ); mixersettings.SetVolumeRampDownMicroseconds( volrampout_us ); m_sndFile->SetMixerSettings( mixersettings ); } else if ( !m_mixer_initialized ) { m_sndFile->InitPlayer( true ); } if ( samplerate_changed ) { m_sndFile->SuspendPlugins(); m_sndFile->ResumePlugins(); } m_mixer_initialized = true; } void module_impl::apply_libopenmpt_defaults() { set_render_param( module::RENDER_STEREOSEPARATION_PERCENT, 100 ); m_sndFile->Order.SetSequence( 0 ); } module_impl::subsongs_type module_impl::get_subsongs() const { std::vector subsongs; if ( m_sndFile->Order.GetNumSequences() == 0 ) { throw openmpt::exception("module contains no songs"); } for ( OpenMPT::SEQUENCEINDEX seq = 0; seq < m_sndFile->Order.GetNumSequences(); ++seq ) { const std::vector lengths = m_sndFile->GetLength( OpenMPT::eNoAdjust, OpenMPT::GetLengthTarget( true ).StartPos( seq, 0, 0 ) ); for ( const auto & l : lengths ) { subsongs.push_back( subsong_data( l.duration, l.startRow, l.startOrder, seq, l.restartRow, l.restartOrder ) ); } } return subsongs; } void module_impl::init_subsongs( subsongs_type & subsongs ) const { subsongs = get_subsongs(); } bool module_impl::has_subsongs_inited() const { return !m_subsongs.empty(); } void module_impl::ctor( const std::map< std::string, std::string > & ctls ) { m_sndFile = std::make_unique(); m_loaded = false; m_mixer_initialized = false; m_Dithers = std::make_unique( OpenMPT::mpt::global_prng(), OpenMPT::DithersWrapperOpenMPT::DefaultDither, 4 ); m_LogForwarder = std::make_unique( *m_Log ); m_sndFile->SetCustomLog( m_LogForwarder.get() ); m_current_subsong = 0; m_currentPositionSeconds = 0.0; m_Gain = 1.0f; m_ctl_play_at_end = song_end_action::fadeout_song; m_ctl_load_skip_samples = false; m_ctl_load_skip_patterns = false; m_ctl_load_skip_plugins = false; m_ctl_load_skip_subsongs_init = false; m_ctl_seek_sync_samples = true; // init member variables that correspond to ctls for ( const auto & ctl : ctls ) { ctl_set( ctl.first, ctl.second, false ); } } void module_impl::load( const OpenMPT::FileCursor & file, const std::map< std::string, std::string > & ctls ) { loader_log loaderlog; m_sndFile->SetCustomLog( &loaderlog ); { int load_flags = OpenMPT::CSoundFile::loadCompleteModule; if ( m_ctl_load_skip_samples ) { load_flags &= ~OpenMPT::CSoundFile::loadSampleData; } if ( m_ctl_load_skip_patterns ) { load_flags &= ~OpenMPT::CSoundFile::loadPatternData; } if ( m_ctl_load_skip_plugins ) { load_flags &= ~(OpenMPT::CSoundFile::loadPluginData | OpenMPT::CSoundFile::loadPluginInstance); } if ( !m_sndFile->Create( file, static_cast( load_flags ) ) ) { throw openmpt::exception("error loading file"); } if ( !m_ctl_load_skip_subsongs_init ) { init_subsongs( m_subsongs ); } m_loaded = true; } m_sndFile->SetCustomLog( m_LogForwarder.get() ); std::vector > loaderMessages = loaderlog.GetMessages(); for ( const auto & msg : loaderMessages ) { PushToCSoundFileLog( msg.first, msg.second ); m_loaderMessages.push_back( mpt::transcode( mpt::common_encoding::utf8, LogLevelToString( msg.first ) ) + std::string(": ") + msg.second ); } // init CSoundFile state that corresponds to ctls for ( const auto & ctl : ctls ) { ctl_set( ctl.first, ctl.second, false ); } } bool module_impl::is_loaded() const { return m_loaded; } std::size_t module_impl::read_wrapper( std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right ) { m_sndFile->ResetMixStat(); m_sndFile->m_bIsRendering = ( m_ctl_play_at_end != song_end_action::fadeout_song ); std::size_t count_read = 0; std::int16_t * const buffers[4] = { left, right, rear_left, rear_right }; OpenMPT::AudioTargetBufferWithGain> target( mpt::audio_span_planar( buffers, valid_channels( buffers, std::size( buffers ) ), count ), *m_Dithers, m_Gain ); while ( count > 0 ) { std::size_t count_chunk = m_sndFile->Read( static_cast( std::min( static_cast( count ), static_cast( std::numeric_limits::max() / 2 / 4 / 4 ) ) ), // safety margin / samplesize / channels target ); if ( count_chunk == 0 ) { break; } count -= count_chunk; count_read += count_chunk; } if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) { // This is the song end, but allow the song or loop to restart on the next call m_sndFile->m_PlayState.m_flags.reset(OpenMPT::SONG_ENDREACHED); } return count_read; } std::size_t module_impl::read_wrapper( std::size_t count, float * left, float * right, float * rear_left, float * rear_right ) { m_sndFile->ResetMixStat(); m_sndFile->m_bIsRendering = ( m_ctl_play_at_end != song_end_action::fadeout_song ); std::size_t count_read = 0; float * const buffers[4] = { left, right, rear_left, rear_right }; OpenMPT::AudioTargetBufferWithGain> target( mpt::audio_span_planar( buffers, valid_channels( buffers, std::size( buffers ) ), count ), *m_Dithers, m_Gain ); while ( count > 0 ) { std::size_t count_chunk = m_sndFile->Read( static_cast( std::min( static_cast( count ), static_cast( std::numeric_limits::max() / 2 / 4 / 4 ) ) ), // safety margin / samplesize / channels target ); if ( count_chunk == 0 ) { break; } count -= count_chunk; count_read += count_chunk; } if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) { // This is the song end, but allow the song or loop to restart on the next call m_sndFile->m_PlayState.m_flags.reset(OpenMPT::SONG_ENDREACHED); } return count_read; } std::size_t module_impl::read_interleaved_wrapper( std::size_t count, std::size_t channels, std::int16_t * interleaved ) { m_sndFile->ResetMixStat(); m_sndFile->m_bIsRendering = ( m_ctl_play_at_end != song_end_action::fadeout_song ); std::size_t count_read = 0; OpenMPT::AudioTargetBufferWithGain> target( mpt::audio_span_interleaved( interleaved, channels, count ), *m_Dithers, m_Gain ); while ( count > 0 ) { std::size_t count_chunk = m_sndFile->Read( static_cast( std::min( static_cast( count ), static_cast( std::numeric_limits::max() / 2 / 4 / 4 ) ) ), // safety margin / samplesize / channels target ); if ( count_chunk == 0 ) { break; } count -= count_chunk; count_read += count_chunk; } if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) { // This is the song end, but allow the song or loop to restart on the next call m_sndFile->m_PlayState.m_flags.reset(OpenMPT::SONG_ENDREACHED); } return count_read; } std::size_t module_impl::read_interleaved_wrapper( std::size_t count, std::size_t channels, float * interleaved ) { m_sndFile->ResetMixStat(); m_sndFile->m_bIsRendering = ( m_ctl_play_at_end != song_end_action::fadeout_song ); std::size_t count_read = 0; OpenMPT::AudioTargetBufferWithGain> target( mpt::audio_span_interleaved( interleaved, channels, count ), *m_Dithers, m_Gain ); while ( count > 0 ) { std::size_t count_chunk = m_sndFile->Read( static_cast( std::min( static_cast( count ), static_cast( std::numeric_limits::max() / 2 / 4 / 4 ) ) ), // safety margin / samplesize / channels target ); if ( count_chunk == 0 ) { break; } count -= count_chunk; count_read += count_chunk; } if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) { // This is the song end, but allow the song or loop to restart on the next call m_sndFile->m_PlayState.m_flags.reset(OpenMPT::SONG_ENDREACHED); } return count_read; } std::vector module_impl::get_supported_extensions() { std::vector retval; std::vector extensions = OpenMPT::CSoundFile::GetSupportedExtensions( false ); std::copy( extensions.begin(), extensions.end(), std::back_insert_iterator >( retval ) ); return retval; } bool module_impl::is_extension_supported( std::string_view extension ) { return OpenMPT::CSoundFile::IsExtensionSupported( extension ); } double module_impl::could_open_probability( const OpenMPT::FileCursor & file, double effort, std::unique_ptr log ) { try { if ( effort >= 0.8 ) { std::unique_ptr sndFile = std::make_unique(); std::unique_ptr logForwarder = std::make_unique( *log ); sndFile->SetCustomLog( logForwarder.get() ); if ( !sndFile->Create( file, OpenMPT::CSoundFile::loadCompleteModule ) ) { return 0.0; } sndFile->Destroy(); return 1.0; } else if ( effort >= 0.6 ) { std::unique_ptr sndFile = std::make_unique(); std::unique_ptr logForwarder = std::make_unique( *log ); sndFile->SetCustomLog( logForwarder.get() ); if ( !sndFile->Create( file, OpenMPT::CSoundFile::loadNoPatternOrPluginData ) ) { return 0.0; } sndFile->Destroy(); return 0.8; } else if ( effort >= 0.2 ) { std::unique_ptr sndFile = std::make_unique(); std::unique_ptr logForwarder = std::make_unique( *log ); sndFile->SetCustomLog( logForwarder.get() ); if ( !sndFile->Create( file, OpenMPT::CSoundFile::onlyVerifyHeader ) ) { return 0.0; } sndFile->Destroy(); return 0.6; } else if ( effort >= 0.1 ) { OpenMPT::FileCursor::PinnedView view = file.GetPinnedView( probe_file_header_get_recommended_size() ); int probe_file_header_result = probe_file_header( probe_file_header_flags_default2, view.data(), view.size(), file.GetLength() ); double result = 0.0; switch ( probe_file_header_result ) { case probe_file_header_result_success: result = 0.6; break; case probe_file_header_result_failure: result = 0.0; break; case probe_file_header_result_wantmoredata: result = 0.3; break; default: throw openmpt::exception(""); break; } return result; } else { return 0.2; } } catch ( ... ) { return 0.0; } } double module_impl::could_open_probability( callback_stream_wrapper stream, double effort, std::unique_ptr log ) { mpt::IO::CallbackStream fstream; fstream.stream = stream.stream; fstream.read = stream.read; fstream.seek = stream.seek; fstream.tell = stream.tell; return could_open_probability( mpt::IO::make_FileCursor( fstream ), effort, std::move(log) ); } double module_impl::could_open_probability( std::istream & stream, double effort, std::unique_ptr log ) { return could_open_probability(mpt::IO::make_FileCursor( stream ), effort, std::move(log) ); } std::size_t module_impl::probe_file_header_get_recommended_size() { return OpenMPT::CSoundFile::ProbeRecommendedSize; } int module_impl::probe_file_header( std::uint64_t flags, const std::byte * data, std::size_t size, std::uint64_t filesize ) { int result = 0; switch ( OpenMPT::CSoundFile::Probe( static_cast( flags ), mpt::span( data, size ), &filesize ) ) { case OpenMPT::CSoundFile::ProbeSuccess: result = probe_file_header_result_success; break; case OpenMPT::CSoundFile::ProbeFailure: result = probe_file_header_result_failure; break; case OpenMPT::CSoundFile::ProbeWantMoreData: result = probe_file_header_result_wantmoredata; break; default: throw exception("internal error"); break; } return result; } int module_impl::probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size, std::uint64_t filesize ) { int result = 0; switch ( OpenMPT::CSoundFile::Probe( static_cast( flags ), mpt::span( mpt::byte_cast( data ), size ), &filesize ) ) { case OpenMPT::CSoundFile::ProbeSuccess: result = probe_file_header_result_success; break; case OpenMPT::CSoundFile::ProbeFailure: result = probe_file_header_result_failure; break; case OpenMPT::CSoundFile::ProbeWantMoreData: result = probe_file_header_result_wantmoredata; break; default: throw exception("internal error"); break; } return result; } int module_impl::probe_file_header( std::uint64_t flags, const void * data, std::size_t size, std::uint64_t filesize ) { int result = 0; switch ( OpenMPT::CSoundFile::Probe( static_cast( flags ), mpt::span( mpt::void_cast( data ), size ), &filesize ) ) { case OpenMPT::CSoundFile::ProbeSuccess: result = probe_file_header_result_success; break; case OpenMPT::CSoundFile::ProbeFailure: result = probe_file_header_result_failure; break; case OpenMPT::CSoundFile::ProbeWantMoreData: result = probe_file_header_result_wantmoredata; break; default: throw exception("internal error"); break; } return result; } int module_impl::probe_file_header( std::uint64_t flags, const std::byte * data, std::size_t size ) { int result = 0; switch ( OpenMPT::CSoundFile::Probe( static_cast( flags ), mpt::span( data, size ), nullptr ) ) { case OpenMPT::CSoundFile::ProbeSuccess: result = probe_file_header_result_success; break; case OpenMPT::CSoundFile::ProbeFailure: result = probe_file_header_result_failure; break; case OpenMPT::CSoundFile::ProbeWantMoreData: result = probe_file_header_result_wantmoredata; break; default: throw exception("internal error"); break; } return result; } int module_impl::probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size ) { int result = 0; switch ( OpenMPT::CSoundFile::Probe( static_cast( flags ), mpt::span( mpt::byte_cast( data ), size ), nullptr ) ) { case OpenMPT::CSoundFile::ProbeSuccess: result = probe_file_header_result_success; break; case OpenMPT::CSoundFile::ProbeFailure: result = probe_file_header_result_failure; break; case OpenMPT::CSoundFile::ProbeWantMoreData: result = probe_file_header_result_wantmoredata; break; default: throw exception("internal error"); break; } return result; } int module_impl::probe_file_header( std::uint64_t flags, const void * data, std::size_t size ) { int result = 0; switch ( OpenMPT::CSoundFile::Probe( static_cast( flags ), mpt::span( mpt::void_cast( data ), size ), nullptr ) ) { case OpenMPT::CSoundFile::ProbeSuccess: result = probe_file_header_result_success; break; case OpenMPT::CSoundFile::ProbeFailure: result = probe_file_header_result_failure; break; case OpenMPT::CSoundFile::ProbeWantMoreData: result = probe_file_header_result_wantmoredata; break; default: throw exception("internal error"); break; } return result; } int module_impl::probe_file_header( std::uint64_t flags, std::istream & stream ) { int result = 0; char buffer[ PROBE_RECOMMENDED_SIZE ]; OpenMPT::MemsetZero( buffer ); std::size_t size_read = 0; std::size_t size_toread = OpenMPT::CSoundFile::ProbeRecommendedSize; if ( stream.bad() ) { throw exception("error reading stream"); } const bool seekable = mpt::IO::FileDataStdStream::IsSeekable( stream ); const std::uint64_t filesize = ( seekable ? mpt::IO::FileDataStdStream::GetLength( stream ) : 0 ); while ( ( size_toread > 0 ) && stream ) { stream.read( buffer + size_read, size_toread ); if ( stream.bad() ) { throw exception("error reading stream"); } else if ( stream.eof() ) { // normal } else if ( stream.fail() ) { throw exception("error reading stream"); } else { // normal } std::size_t read_count = static_cast( stream.gcount() ); size_read += read_count; size_toread -= read_count; } switch ( OpenMPT::CSoundFile::Probe( static_cast( flags ), mpt::span( mpt::byte_cast( buffer ), size_read ), seekable ? &filesize : nullptr ) ) { case OpenMPT::CSoundFile::ProbeSuccess: result = probe_file_header_result_success; break; case OpenMPT::CSoundFile::ProbeFailure: result = probe_file_header_result_failure; break; case OpenMPT::CSoundFile::ProbeWantMoreData: result = probe_file_header_result_wantmoredata; break; default: throw exception("internal error"); break; } return result; } int module_impl::probe_file_header( std::uint64_t flags, callback_stream_wrapper stream ) { int result = 0; char buffer[ PROBE_RECOMMENDED_SIZE ]; OpenMPT::MemsetZero( buffer ); std::size_t size_read = 0; std::size_t size_toread = OpenMPT::CSoundFile::ProbeRecommendedSize; if ( !stream.read ) { throw exception("error reading stream"); } mpt::IO::CallbackStream fstream; fstream.stream = stream.stream; fstream.read = stream.read; fstream.seek = stream.seek; fstream.tell = stream.tell; const bool seekable = mpt::IO::FileDataCallbackStream::IsSeekable( fstream ); const std::uint64_t filesize = ( seekable ? mpt::IO::FileDataCallbackStream::GetLength( fstream ) : 0 ); while ( size_toread > 0 ) { std::size_t read_count = stream.read( stream.stream, buffer + size_read, size_toread ); size_read += read_count; size_toread -= read_count; if ( read_count == 0 ) { // eof break; } } switch ( OpenMPT::CSoundFile::Probe( static_cast( flags ), mpt::span( mpt::byte_cast( buffer ), size_read ), seekable ? &filesize : nullptr ) ) { case OpenMPT::CSoundFile::ProbeSuccess: result = probe_file_header_result_success; break; case OpenMPT::CSoundFile::ProbeFailure: result = probe_file_header_result_failure; break; case OpenMPT::CSoundFile::ProbeWantMoreData: result = probe_file_header_result_wantmoredata; break; default: throw exception("internal error"); break; } return result; } module_impl::module_impl( callback_stream_wrapper stream, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) { ctor( ctls ); mpt::IO::CallbackStream fstream; fstream.stream = stream.stream; fstream.read = stream.read; fstream.seek = stream.seek; fstream.tell = stream.tell; load( mpt::IO::make_FileCursor( fstream ), ctls ); apply_libopenmpt_defaults(); } module_impl::module_impl( std::istream & stream, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) { ctor( ctls ); load( mpt::IO::make_FileCursor( stream ), ctls ); apply_libopenmpt_defaults(); } module_impl::module_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) { ctor( ctls ); load( mpt::IO::make_FileCursor( mpt::as_span( data ) ), ctls ); apply_libopenmpt_defaults(); } module_impl::module_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) { ctor( ctls ); load( mpt::IO::make_FileCursor( mpt::as_span( data ) ), ctls ); apply_libopenmpt_defaults(); } module_impl::module_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) { ctor( ctls ); load( mpt::IO::make_FileCursor( mpt::byte_cast< mpt::span< const std::byte > >( mpt::as_span( data ) ) ), ctls ); apply_libopenmpt_defaults(); } module_impl::module_impl( const std::byte * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) { ctor( ctls ); load( mpt::IO::make_FileCursor( mpt::as_span( data, size ) ), ctls ); apply_libopenmpt_defaults(); } module_impl::module_impl( const std::uint8_t * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) { ctor( ctls ); load( mpt::IO::make_FileCursor( mpt::as_span( data, size ) ), ctls ); apply_libopenmpt_defaults(); } module_impl::module_impl( const char * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) { ctor( ctls ); load( mpt::IO::make_FileCursor( mpt::byte_cast< mpt::span< const std::byte > >( mpt::as_span( data, size ) ) ), ctls ); apply_libopenmpt_defaults(); } module_impl::module_impl( const void * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) { ctor( ctls ); load( mpt::IO::make_FileCursor( mpt::as_span( mpt::void_cast< const std::byte * >( data ), size ) ), ctls ); apply_libopenmpt_defaults(); } module_impl::~module_impl() { m_sndFile->Destroy(); } std::int32_t module_impl::get_render_param( int param ) const { std::int32_t result = 0; switch ( param ) { case module::RENDER_MASTERGAIN_MILLIBEL: { result = static_cast( 1000.0f * 2.0f * std::log10( m_Gain ) ); } break; case module::RENDER_STEREOSEPARATION_PERCENT: { result = m_sndFile->m_MixerSettings.m_nStereoSeparation * 100 / OpenMPT::MixerSettings::StereoSeparationScale; } break; case module::RENDER_INTERPOLATIONFILTER_LENGTH: { result = resamplingmode_to_filterlength( m_sndFile->m_Resampler.m_Settings.SrcMode ); } break; case module::RENDER_VOLUMERAMPING_STRENGTH: { int ramping = 0; mixersettings_to_ramping( ramping, m_sndFile->m_MixerSettings ); result = ramping; } break; default: throw openmpt::exception("unknown render param"); break; } return result; } void module_impl::set_render_param( int param, std::int32_t value ) { switch ( param ) { case module::RENDER_MASTERGAIN_MILLIBEL: { m_Gain = std::pow( 10.0f, static_cast( value ) * 0.001f * 0.5f ); } break; case module::RENDER_STEREOSEPARATION_PERCENT: { std::int32_t newvalue = value * OpenMPT::MixerSettings::StereoSeparationScale / 100; if ( newvalue != static_cast( m_sndFile->m_MixerSettings.m_nStereoSeparation ) ) { OpenMPT::MixerSettings settings = m_sndFile->m_MixerSettings; settings.m_nStereoSeparation = newvalue; m_sndFile->SetMixerSettings( settings ); } } break; case module::RENDER_INTERPOLATIONFILTER_LENGTH: { OpenMPT::CResamplerSettings newsettings = m_sndFile->m_Resampler.m_Settings; newsettings.SrcMode = filterlength_to_resamplingmode( value ); if ( newsettings != m_sndFile->m_Resampler.m_Settings ) { m_sndFile->SetResamplerSettings( newsettings ); } } break; case module::RENDER_VOLUMERAMPING_STRENGTH: { OpenMPT::MixerSettings newsettings = m_sndFile->m_MixerSettings; ramping_to_mixersettings( newsettings, value ); if ( m_sndFile->m_MixerSettings.VolumeRampUpMicroseconds != newsettings.VolumeRampUpMicroseconds || m_sndFile->m_MixerSettings.VolumeRampDownMicroseconds != newsettings.VolumeRampDownMicroseconds ) { m_sndFile->SetMixerSettings( newsettings ); } } break; default: throw openmpt::exception("unknown render param"); break; } } std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, std::int16_t * mono ) { if ( !mono ) { throw openmpt::exception("null pointer"); } apply_mixer_settings( samplerate, 1 ); count = read_wrapper( count, mono, nullptr, nullptr, nullptr ); m_currentPositionSeconds += static_cast( count ) / static_cast( samplerate ); return count; } std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right ) { if ( !left || !right ) { throw openmpt::exception("null pointer"); } apply_mixer_settings( samplerate, 2 ); count = read_wrapper( count, left, right, nullptr, nullptr ); m_currentPositionSeconds += static_cast( count ) / static_cast( samplerate ); return count; } std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right ) { if ( !left || !right || !rear_left || !rear_right ) { throw openmpt::exception("null pointer"); } apply_mixer_settings( samplerate, 4 ); count = read_wrapper( count, left, right, rear_left, rear_right ); m_currentPositionSeconds += static_cast( count ) / static_cast( samplerate ); return count; } std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, float * mono ) { if ( !mono ) { throw openmpt::exception("null pointer"); } apply_mixer_settings( samplerate, 1 ); count = read_wrapper( count, mono, nullptr, nullptr, nullptr ); m_currentPositionSeconds += static_cast( count ) / static_cast( samplerate ); return count; } std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, float * left, float * right ) { if ( !left || !right ) { throw openmpt::exception("null pointer"); } apply_mixer_settings( samplerate, 2 ); count = read_wrapper( count, left, right, nullptr, nullptr ); m_currentPositionSeconds += static_cast( count ) / static_cast( samplerate ); return count; } std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, float * left, float * right, float * rear_left, float * rear_right ) { if ( !left || !right || !rear_left || !rear_right ) { throw openmpt::exception("null pointer"); } apply_mixer_settings( samplerate, 4 ); count = read_wrapper( count, left, right, rear_left, rear_right ); m_currentPositionSeconds += static_cast( count ) / static_cast( samplerate ); return count; } std::size_t module_impl::read_interleaved_stereo( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_stereo ) { if ( !interleaved_stereo ) { throw openmpt::exception("null pointer"); } apply_mixer_settings( samplerate, 2 ); count = read_interleaved_wrapper( count, 2, interleaved_stereo ); m_currentPositionSeconds += static_cast( count ) / static_cast( samplerate ); return count; } std::size_t module_impl::read_interleaved_quad( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_quad ) { if ( !interleaved_quad ) { throw openmpt::exception("null pointer"); } apply_mixer_settings( samplerate, 4 ); count = read_interleaved_wrapper( count, 4, interleaved_quad ); m_currentPositionSeconds += static_cast( count ) / static_cast( samplerate ); return count; } std::size_t module_impl::read_interleaved_stereo( std::int32_t samplerate, std::size_t count, float * interleaved_stereo ) { if ( !interleaved_stereo ) { throw openmpt::exception("null pointer"); } apply_mixer_settings( samplerate, 2 ); count = read_interleaved_wrapper( count, 2, interleaved_stereo ); m_currentPositionSeconds += static_cast( count ) / static_cast( samplerate ); return count; } std::size_t module_impl::read_interleaved_quad( std::int32_t samplerate, std::size_t count, float * interleaved_quad ) { if ( !interleaved_quad ) { throw openmpt::exception("null pointer"); } apply_mixer_settings( samplerate, 4 ); count = read_interleaved_wrapper( count, 4, interleaved_quad ); m_currentPositionSeconds += static_cast( count ) / static_cast( samplerate ); return count; } double module_impl::get_duration_seconds() const { std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; if ( m_current_subsong == all_subsongs ) { // Play all subsongs consecutively. double total_duration = 0.0; for ( const auto & subsong : subsongs ) { total_duration += subsong.duration; } return total_duration; } return subsongs[m_current_subsong].duration; } double module_impl::get_time_at_position( std::int32_t order, std::int32_t row ) const { const auto t = m_sndFile->GetLength( OpenMPT::eNoAdjust, OpenMPT::GetLengthTarget( static_cast( order ), static_cast( row ) ) ).back(); if ( t.targetReached ) return t.duration; else return -1.0; } void module_impl::select_subsong( std::int32_t subsong ) { std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; if ( subsong != all_subsongs && ( subsong < 0 || subsong >= static_cast( subsongs.size() ) ) ) { throw openmpt::exception("invalid subsong"); } m_current_subsong = subsong; m_sndFile->m_SongFlags.set( OpenMPT::SONG_PLAYALLSONGS, subsong == all_subsongs ); if ( subsong == all_subsongs ) { subsong = 0; } m_sndFile->Order.SetSequence( static_cast( subsongs[subsong].sequence ) ); set_position_order_row( subsongs[subsong].start_order, subsongs[subsong].start_row ); m_currentPositionSeconds = 0.0; } std::int32_t module_impl::get_selected_subsong() const { return m_current_subsong; } std::int32_t module_impl::get_restart_order( std::int32_t subsong ) const { std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; if ( subsong < 0 || subsong >= static_cast( subsongs.size() ) ) { throw openmpt::exception( "invalid subsong" ); } return subsongs[subsong].restart_order; } std::int32_t module_impl::get_restart_row( std::int32_t subsong ) const { std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; if ( subsong < 0 || subsong >= static_cast( subsongs.size() ) ) { throw openmpt::exception( "invalid subsong" ); } return subsongs[subsong].restart_row; } void module_impl::set_repeat_count( std::int32_t repeat_count ) { m_sndFile->SetRepeatCount( repeat_count ); } std::int32_t module_impl::get_repeat_count() const { return m_sndFile->GetRepeatCount(); } double module_impl::get_position_seconds() const { return m_currentPositionSeconds; } double module_impl::set_position_seconds( double seconds ) { std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; const subsong_data * subsong = 0; double base_seconds = 0.0; if ( m_current_subsong == all_subsongs ) { // When playing all subsongs, find out which subsong this time would belong to. subsong = &subsongs.back(); for ( std::size_t i = 0; i < subsongs.size(); ++i ) { if ( base_seconds + subsongs[i].duration > seconds ) { subsong = &subsongs[i]; break; } base_seconds += subsongs[i].duration; } seconds -= base_seconds; } else { subsong = &subsongs[m_current_subsong]; } m_sndFile->SetCurrentOrder( static_cast( subsong->start_order ) ); OpenMPT::GetLengthType t = m_sndFile->GetLength( m_ctl_seek_sync_samples ? OpenMPT::eAdjustSamplePositions : OpenMPT::eAdjust, OpenMPT::GetLengthTarget( seconds ).StartPos( static_cast( subsong->sequence ), static_cast( subsong->start_order ), static_cast( subsong->start_row ) ) ).back(); m_sndFile->m_PlayState.m_nNextOrder = m_sndFile->m_PlayState.m_nCurrentOrder = t.targetReached ? t.restartOrder : t.endOrder; m_sndFile->m_PlayState.m_nNextRow = t.targetReached ? t.restartRow : t.endRow; m_sndFile->m_PlayState.m_nTickCount = OpenMPT::CSoundFile::TICKS_ROW_FINISHED; m_currentPositionSeconds = base_seconds + t.duration; return m_currentPositionSeconds; } double module_impl::set_position_order_row( std::int32_t order, std::int32_t row ) { if ( order < 0 || order >= m_sndFile->Order().GetLengthTailTrimmed() ) { return m_currentPositionSeconds; } OpenMPT::PATTERNINDEX pattern = m_sndFile->Order()[order]; if ( m_sndFile->Patterns.IsValidIndex( pattern ) ) { if ( row < 0 || row >= static_cast( m_sndFile->Patterns[pattern].GetNumRows() ) ) { return m_currentPositionSeconds; } } else { row = 0; } m_sndFile->m_PlayState.m_nCurrentOrder = static_cast( order ); m_sndFile->SetCurrentOrder( static_cast( order ) ); m_sndFile->m_PlayState.m_nNextRow = static_cast( row ); m_sndFile->m_PlayState.m_nTickCount = OpenMPT::CSoundFile::TICKS_ROW_FINISHED; m_currentPositionSeconds = m_sndFile->GetLength( m_ctl_seek_sync_samples ? OpenMPT::eAdjustSamplePositions : OpenMPT::eAdjust, OpenMPT::GetLengthTarget( static_cast( order ), static_cast( row ) ) ).back().duration; return m_currentPositionSeconds; } std::vector module_impl::get_metadata_keys() const { return { "type", "type_long", "originaltype", "originaltype_long", "container", "container_long", "tracker", "artist", "title", "date", "message", "message_raw", "warnings", }; } std::string module_impl::get_message_instruments() const { std::string retval; std::string tmp; bool valid = false; for ( OpenMPT::INSTRUMENTINDEX i = 1; i <= m_sndFile->GetNumInstruments(); ++i ) { std::string instname = m_sndFile->GetInstrumentName( i ); if ( !instname.empty() ) { valid = true; } tmp += instname; tmp += "\n"; } if ( valid ) { retval = tmp; } return retval; } std::string module_impl::get_message_samples() const { std::string retval; std::string tmp; bool valid = false; for ( OpenMPT::SAMPLEINDEX i = 1; i <= m_sndFile->GetNumSamples(); ++i ) { std::string samplename = m_sndFile->GetSampleName( i ); if ( !samplename.empty() ) { valid = true; } tmp += samplename; tmp += "\n"; } if ( valid ) { retval = tmp; } return retval; } std::string module_impl::get_metadata( const std::string & key ) const { if ( key == std::string("type") ) { return mpt::transcode( mpt::common_encoding::utf8, m_sndFile->m_modFormat.type ); } else if ( key == std::string("type_long") ) { return mpt::transcode( mpt::common_encoding::utf8, m_sndFile->m_modFormat.formatName ); } else if ( key == std::string("originaltype") ) { return mpt::transcode( mpt::common_encoding::utf8, m_sndFile->m_modFormat.originalType ); } else if ( key == std::string("originaltype_long") ) { return mpt::transcode( mpt::common_encoding::utf8, m_sndFile->m_modFormat.originalFormatName ); } else if ( key == std::string("container") ) { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::CSoundFile::ModContainerTypeToString( m_sndFile->GetContainerType() ) ); } else if ( key == std::string("container_long") ) { return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::CSoundFile::ModContainerTypeToTracker( m_sndFile->GetContainerType() ) ); } else if ( key == std::string("tracker") ) { return mpt::transcode( mpt::common_encoding::utf8, m_sndFile->m_modFormat.madeWithTracker ); } else if ( key == std::string("artist") ) { return mpt::transcode( mpt::common_encoding::utf8, m_sndFile->m_songArtist ); } else if ( key == std::string("title") ) { return mod_string_to_utf8( m_sndFile->GetTitle() ); } else if ( key == std::string("date") ) { if ( m_sndFile->GetFileHistory().empty() || !m_sndFile->GetFileHistory().back().HasValidDate() ) { return std::string(); } return mpt::transcode( mpt::common_encoding::utf8, m_sndFile->GetFileHistory().back().AsISO8601( m_sndFile->GetTimezoneInternal() ) ); } else if ( key == std::string("message") ) { std::string retval = m_sndFile->m_songMessage.GetFormatted( OpenMPT::SongMessage::leLF ); if ( retval.empty() ) { switch ( m_sndFile->GetMessageHeuristic() ) { case OpenMPT::ModMessageHeuristicOrder::Instruments: retval = get_message_instruments(); break; case OpenMPT::ModMessageHeuristicOrder::Samples: retval = get_message_samples(); break; case OpenMPT::ModMessageHeuristicOrder::InstrumentsSamples: if ( retval.empty() ) { retval = get_message_instruments(); } if ( retval.empty() ) { retval = get_message_samples(); } break; case OpenMPT::ModMessageHeuristicOrder::SamplesInstruments: if ( retval.empty() ) { retval = get_message_samples(); } if ( retval.empty() ) { retval = get_message_instruments(); } break; case OpenMPT::ModMessageHeuristicOrder::BothInstrumentsSamples: { std::string message_instruments = get_message_instruments(); std::string message_samples = get_message_samples(); if ( !message_instruments.empty() ) { retval += std::move( message_instruments ); } if ( !message_samples.empty() ) { retval += std::move( message_samples ); } } break; case OpenMPT::ModMessageHeuristicOrder::BothSamplesInstruments: { std::string message_instruments = get_message_instruments(); std::string message_samples = get_message_samples(); if ( !message_samples.empty() ) { retval += std::move( message_samples ); } if ( !message_instruments.empty() ) { retval += std::move( message_instruments ); } } break; } } return mod_string_to_utf8( retval ); } else if ( key == std::string("message_raw") ) { std::string retval = m_sndFile->m_songMessage.GetFormatted( OpenMPT::SongMessage::leLF ); return mod_string_to_utf8( retval ); } else if ( key == std::string("warnings") ) { std::string retval; bool first = true; for ( const auto & msg : m_loaderMessages ) { if ( !first ) { retval += "\n"; } else { first = false; } retval += msg; } return retval; } return ""; } double module_impl::get_current_estimated_bpm() const { return m_sndFile->GetCurrentBPM(); } std::int32_t module_impl::get_current_speed() const { return m_sndFile->m_PlayState.m_nMusicSpeed; } std::int32_t module_impl::get_current_tempo() const { return static_cast( m_sndFile->m_PlayState.m_nMusicTempo.GetInt() ); } double module_impl::get_current_tempo2() const { return m_sndFile->m_PlayState.m_nMusicTempo.ToDouble(); } std::int32_t module_impl::get_current_order() const { return m_sndFile->GetCurrentOrder(); } std::int32_t module_impl::get_current_pattern() const { std::int32_t order = m_sndFile->GetCurrentOrder(); if ( order < 0 || order >= m_sndFile->Order().GetLengthTailTrimmed() ) { return m_sndFile->GetCurrentPattern(); } std::int32_t pattern = m_sndFile->Order()[order]; if ( !m_sndFile->Patterns.IsValidIndex( static_cast( pattern ) ) ) { return -1; } return pattern; } std::int32_t module_impl::get_current_row() const { return m_sndFile->m_PlayState.m_nRow; } std::int32_t module_impl::get_current_playing_channels() const { return m_sndFile->GetMixStat(); } float module_impl::get_current_channel_vu_mono( std::int32_t channel ) const { if ( channel < 0 || channel >= m_sndFile->GetNumChannels() ) { return 0.0f; } const float left = m_sndFile->m_PlayState.Chn[channel].nLeftVU * (1.0f/128.0f); const float right = m_sndFile->m_PlayState.Chn[channel].nRightVU * (1.0f/128.0f); return std::sqrt(left*left + right*right); } float module_impl::get_current_channel_vu_left( std::int32_t channel ) const { if ( channel < 0 || channel >= m_sndFile->GetNumChannels() ) { return 0.0f; } return m_sndFile->m_PlayState.Chn[channel].dwFlags[OpenMPT::CHN_SURROUND] ? 0.0f : m_sndFile->m_PlayState.Chn[channel].nLeftVU * (1.0f/128.0f); } float module_impl::get_current_channel_vu_right( std::int32_t channel ) const { if ( channel < 0 || channel >= m_sndFile->GetNumChannels() ) { return 0.0f; } return m_sndFile->m_PlayState.Chn[channel].dwFlags[OpenMPT::CHN_SURROUND] ? 0.0f : m_sndFile->m_PlayState.Chn[channel].nRightVU * (1.0f/128.0f); } float module_impl::get_current_channel_vu_rear_left( std::int32_t channel ) const { if ( channel < 0 || channel >= m_sndFile->GetNumChannels() ) { return 0.0f; } return m_sndFile->m_PlayState.Chn[channel].dwFlags[OpenMPT::CHN_SURROUND] ? m_sndFile->m_PlayState.Chn[channel].nLeftVU * (1.0f/128.0f) : 0.0f; } float module_impl::get_current_channel_vu_rear_right( std::int32_t channel ) const { if ( channel < 0 || channel >= m_sndFile->GetNumChannels() ) { return 0.0f; } return m_sndFile->m_PlayState.Chn[channel].dwFlags[OpenMPT::CHN_SURROUND] ? m_sndFile->m_PlayState.Chn[channel].nRightVU * (1.0f/128.0f) : 0.0f; } std::int32_t module_impl::get_num_subsongs() const { std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; return static_cast( subsongs.size() ); } std::int32_t module_impl::get_num_channels() const { return m_sndFile->GetNumChannels(); } std::int32_t module_impl::get_num_orders() const { return m_sndFile->Order().GetLengthTailTrimmed(); } std::int32_t module_impl::get_num_patterns() const { return m_sndFile->Patterns.GetNumPatterns(); } std::int32_t module_impl::get_num_instruments() const { return m_sndFile->GetNumInstruments(); } std::int32_t module_impl::get_num_samples() const { return m_sndFile->GetNumSamples(); } std::vector module_impl::get_subsong_names() const { std::vector retval; std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; retval.reserve( subsongs.size() ); for ( const auto & subsong : subsongs ) { const auto & order = m_sndFile->Order( static_cast( subsong.sequence ) ); retval.push_back( mpt::transcode( mpt::common_encoding::utf8, order.GetName() ) ); if ( retval.back().empty() ) { // use first pattern name instead if ( order.IsValidPat( static_cast( subsong.start_order ) ) ) retval.back() = OpenMPT::mpt::ToCharset( OpenMPT::mpt::Charset::UTF8, m_sndFile->GetCharsetInternal(), m_sndFile->Patterns[ order[ subsong.start_order ] ].GetName() ); } } return retval; } std::vector module_impl::get_channel_names() const { std::vector retval; for ( OpenMPT::CHANNELINDEX i = 0; i < m_sndFile->GetNumChannels(); ++i ) { retval.push_back( mod_string_to_utf8( m_sndFile->ChnSettings[i].szName ) ); } return retval; } std::vector module_impl::get_order_names() const { std::vector retval; OpenMPT::ORDERINDEX num_orders = m_sndFile->Order().GetLengthTailTrimmed(); retval.reserve( num_orders ); for ( OpenMPT::ORDERINDEX i = 0; i < num_orders; ++i ) { OpenMPT::PATTERNINDEX pat = m_sndFile->Order()[i]; if ( m_sndFile->Patterns.IsValidIndex( pat ) ) { retval.push_back( mod_string_to_utf8( m_sndFile->Patterns[ m_sndFile->Order()[i] ].GetName() ) ); } else { if ( pat == OpenMPT::PATTERNINDEX_SKIP ) { retval.push_back( "+++ skip" ); } else if ( pat == OpenMPT::PATTERNINDEX_INVALID ) { retval.push_back( "--- stop" ); } else { retval.push_back( "???" ); } } } return retval; } std::vector module_impl::get_pattern_names() const { std::vector retval; retval.reserve( m_sndFile->Patterns.GetNumPatterns() ); for ( OpenMPT::PATTERNINDEX i = 0; i < m_sndFile->Patterns.GetNumPatterns(); ++i ) { retval.push_back( mod_string_to_utf8( m_sndFile->Patterns[i].GetName() ) ); } return retval; } std::vector module_impl::get_instrument_names() const { std::vector retval; retval.reserve( m_sndFile->GetNumInstruments() ); for ( OpenMPT::INSTRUMENTINDEX i = 1; i <= m_sndFile->GetNumInstruments(); ++i ) { retval.push_back( mod_string_to_utf8( m_sndFile->GetInstrumentName( i ) ) ); } return retval; } std::vector module_impl::get_sample_names() const { std::vector retval; retval.reserve( m_sndFile->GetNumSamples() ); for ( OpenMPT::SAMPLEINDEX i = 1; i <= m_sndFile->GetNumSamples(); ++i ) { retval.push_back( mod_string_to_utf8( m_sndFile->GetSampleName( i ) ) ); } return retval; } std::int32_t module_impl::get_order_pattern( std::int32_t o ) const { if ( o < 0 || o >= m_sndFile->Order().GetLengthTailTrimmed() ) { return -1; } return m_sndFile->Order()[o]; } bool module_impl::is_order_skip_entry( std::int32_t order ) const { if ( order < 0 || order >= m_sndFile->Order().GetLengthTailTrimmed() ) { return false; } return is_pattern_skip_item( m_sndFile->Order()[order] ); } bool module_impl::is_pattern_skip_item( std::int32_t pattern ) { return pattern == OpenMPT::PATTERNINDEX_SKIP; } bool module_impl::is_order_stop_entry( std::int32_t order ) const { if ( order < 0 || order >= m_sndFile->Order().GetLengthTailTrimmed() ) { return false; } return is_pattern_stop_item( m_sndFile->Order()[order] ); } bool module_impl::is_pattern_stop_item( std::int32_t pattern ) { return pattern == OpenMPT::PATTERNINDEX_INVALID; } std::int32_t module_impl::get_pattern_num_rows( std::int32_t p ) const { if ( !mpt::is_in_range( p, std::numeric_limits::min(), std::numeric_limits::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast( p ) ) ) { return 0; } return m_sndFile->Patterns[p].GetNumRows(); } std::int32_t module_impl::get_pattern_rows_per_beat( std::int32_t p ) const { if ( !mpt::is_in_range( p, std::numeric_limits::min(), std::numeric_limits::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast( p ) ) ) { return 0; } if ( m_sndFile->Patterns[p].GetOverrideSignature() ) { return m_sndFile->Patterns[p].GetRowsPerBeat(); } return m_sndFile->m_nDefaultRowsPerBeat; } std::int32_t module_impl::get_pattern_rows_per_measure( std::int32_t p ) const { if ( !mpt::is_in_range( p, std::numeric_limits::min(), std::numeric_limits::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast( p ) ) ) { return 0; } if ( m_sndFile->Patterns[p].GetOverrideSignature() ) { return m_sndFile->Patterns[p].GetRowsPerMeasure(); } return m_sndFile->m_nDefaultRowsPerMeasure; } std::uint8_t module_impl::get_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const { if ( !mpt::is_in_range( p, std::numeric_limits::min(), std::numeric_limits::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast( p ) ) ) { return 0; } const OpenMPT::CPattern & pattern = m_sndFile->Patterns[p]; if ( r < 0 || r >= static_cast( pattern.GetNumRows() ) ) { return 0; } if ( c < 0 || c >= m_sndFile->GetNumChannels() ) { return 0; } if ( cmd < module::command_note || cmd > module::command_parameter ) { return 0; } const OpenMPT::ModCommand & cell = *pattern.GetpModCommand( static_cast( r ), static_cast( c ) ); switch ( cmd ) { case module::command_note: return cell.note; break; case module::command_instrument: return cell.instr; break; case module::command_volumeffect: return cell.volcmd; break; case module::command_effect: return cell.command; break; case module::command_volume: return cell.vol; break; case module::command_parameter: return cell.param; break; } return 0; } /* highlight chars explained: : empty/space . : empty/dot n : generic note m : special note i : generic instrument u : generic volume column effect v : generic volume column parameter e : generic effect column effect f : generic effect column parameter */ std::pair< std::string, std::string > module_impl::format_and_highlight_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const { if ( !mpt::is_in_range( p, std::numeric_limits::min(), std::numeric_limits::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast( p ) ) ) { return std::make_pair( std::string(), std::string() ); } const OpenMPT::CPattern & pattern = m_sndFile->Patterns[p]; if ( r < 0 || r >= static_cast( pattern.GetNumRows() ) ) { return std::make_pair( std::string(), std::string() ); } if ( c < 0 || c >= m_sndFile->GetNumChannels() ) { return std::make_pair( std::string(), std::string() ); } if ( cmd < module::command_note || cmd > module::command_parameter ) { return std::make_pair( std::string(), std::string() ); } const OpenMPT::ModCommand & cell = *pattern.GetpModCommand( static_cast( r ), static_cast( c ) ); // clang-format off switch ( cmd ) { case module::command_note: return std::make_pair( ( cell.IsNote() || cell.IsSpecialNote() ) ? mpt::transcode( mpt::common_encoding::utf8, m_sndFile->GetNoteName( cell.note, cell.instr ) ) : std::string("...") , ( cell.IsNote() ) ? std::string("nnn") : cell.IsSpecialNote() ? std::string("mmm") : std::string("...") ); break; case module::command_instrument: return std::make_pair( cell.instr ? OpenMPT::mpt::afmt::HEX0<2>( cell.instr ) : std::string("..") , cell.instr ? std::string("ii") : std::string("..") ); break; case module::command_volumeffect: return std::make_pair( cell.IsPcNote() ? std::string(" ") : std::string( 1, OpenMPT::CModSpecifications::GetGenericVolEffectLetter( cell.volcmd ) ) , cell.IsPcNote() ? std::string(" ") : cell.volcmd != OpenMPT::VOLCMD_NONE ? std::string("u") : std::string(" ") ); break; case module::command_volume: return std::make_pair( cell.IsPcNote() ? OpenMPT::mpt::afmt::HEX0<2>( cell.GetValueVolCol() & 0xff ) : cell.volcmd != OpenMPT::VOLCMD_NONE ? OpenMPT::mpt::afmt::HEX0<2>( cell.vol ) : std::string("..") , cell.IsPcNote() ? std::string("vv") : cell.volcmd != OpenMPT::VOLCMD_NONE ? std::string("vv") : std::string("..") ); break; case module::command_effect: return std::make_pair( cell.IsPcNote() ? OpenMPT::mpt::afmt::HEX0<1>( ( cell.GetValueEffectCol() & 0x0f00 ) > 16 ) : cell.command != OpenMPT::CMD_NONE ? std::string( 1, m_sndFile->GetModSpecifications().GetEffectLetter( cell.command ) ) : std::string(".") , cell.IsPcNote() ? std::string("e") : cell.command != OpenMPT::CMD_NONE ? std::string("e") : std::string(".") ); break; case module::command_parameter: return std::make_pair( cell.IsPcNote() ? OpenMPT::mpt::afmt::HEX0<2>( cell.GetValueEffectCol() & 0x00ff ) : cell.command != OpenMPT::CMD_NONE ? OpenMPT::mpt::afmt::HEX0<2>( cell.param ) : std::string("..") , cell.IsPcNote() ? std::string("ff") : cell.command != OpenMPT::CMD_NONE ? std::string("ff") : std::string("..") ); break; } // clang-format on return std::make_pair( std::string(), std::string() ); } std::string module_impl::format_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const { return format_and_highlight_pattern_row_channel_command( p, r, c, cmd ).first; } std::string module_impl::highlight_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const { return format_and_highlight_pattern_row_channel_command( p, r, c, cmd ).second; } std::pair< std::string, std::string > module_impl::format_and_highlight_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const { std::string text = pad ? std::string( width, ' ' ) : std::string(); std::string high = pad ? std::string( width, ' ' ) : std::string(); if ( !mpt::is_in_range( p, std::numeric_limits::min(), std::numeric_limits::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast( p ) ) ) { return std::make_pair( text, high ); } const OpenMPT::CPattern & pattern = m_sndFile->Patterns[p]; if ( r < 0 || r >= static_cast( pattern.GetNumRows() ) ) { return std::make_pair( text, high ); } if ( c < 0 || c >= m_sndFile->GetNumChannels() ) { return std::make_pair( text, high ); } // 0000000001111 // 1234567890123 // "NNN IIvVV EFF" const OpenMPT::ModCommand & cell = *pattern.GetpModCommand( static_cast( r ), static_cast( c ) ); text.clear(); high.clear(); // clang-format off text += ( cell.IsNote() || cell.IsSpecialNote() ) ? mpt::transcode( mpt::common_encoding::utf8, m_sndFile->GetNoteName( cell.note, cell.instr ) ) : std::string("..."); high += ( cell.IsNote() ) ? std::string("nnn") : cell.IsSpecialNote() ? std::string("mmm") : std::string("..."); if ( ( width == 0 ) || ( width >= 6 ) ) { text += std::string(" "); high += std::string(" "); text += cell.instr ? OpenMPT::mpt::afmt::HEX0<2>( cell.instr ) : std::string(".."); high += cell.instr ? std::string("ii") : std::string(".."); } if ( ( width == 0 ) || ( width >= 9 ) ) { text += cell.IsPcNote() ? std::string(" ") + OpenMPT::mpt::afmt::HEX0<2>( cell.GetValueVolCol() & 0xff ) : cell.volcmd != OpenMPT::VOLCMD_NONE ? std::string( 1, OpenMPT::CModSpecifications::GetGenericVolEffectLetter( cell.volcmd ) ) + OpenMPT::mpt::afmt::HEX0<2>( cell.vol ) : std::string(" .."); high += cell.IsPcNote() ? std::string(" vv") : cell.volcmd != OpenMPT::VOLCMD_NONE ? std::string("uvv") : std::string(" .."); } if ( ( width == 0 ) || ( width >= 13 ) ) { text += std::string(" "); high += std::string(" "); text += cell.IsPcNote() ? OpenMPT::mpt::afmt::HEX0<3>( cell.GetValueEffectCol() & 0x0fff ) : cell.command != OpenMPT::CMD_NONE ? std::string( 1, m_sndFile->GetModSpecifications().GetEffectLetter( cell.command ) ) + OpenMPT::mpt::afmt::HEX0<2>( cell.param ) : std::string("..."); high += cell.IsPcNote() ? std::string("eff") : cell.command != OpenMPT::CMD_NONE ? std::string("eff") : std::string("..."); } if ( ( width != 0 ) && ( text.length() > width ) ) { text = text.substr( 0, width ); } else if ( ( width != 0 ) && pad ) { text += std::string( width - text.length(), ' ' ); } if ( ( width != 0 ) && ( high.length() > width ) ) { high = high.substr( 0, width ); } else if ( ( width != 0 ) && pad ) { high += std::string( width - high.length(), ' ' ); } // clang-format on return std::make_pair( text, high ); } std::string module_impl::format_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const { return format_and_highlight_pattern_row_channel( p, r, c, width, pad ).first; } std::string module_impl::highlight_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const { return format_and_highlight_pattern_row_channel( p, r, c, width, pad ).second; } std::pair module_impl::get_ctl_infos() const { static constexpr ctl_info ctl_infos[] = { { "load.skip_samples", ctl_type::boolean }, { "load.skip_patterns", ctl_type::boolean }, { "load.skip_plugins", ctl_type::boolean }, { "load.skip_subsongs_init", ctl_type::boolean }, { "seek.sync_samples", ctl_type::boolean }, { "subsong", ctl_type::integer }, { "play.tempo_factor", ctl_type::floatingpoint }, { "play.pitch_factor", ctl_type::floatingpoint }, { "play.at_end", ctl_type::text }, { "render.resampler.emulate_amiga", ctl_type::boolean }, { "render.resampler.emulate_amiga_type", ctl_type::text }, { "render.opl.volume_factor", ctl_type::floatingpoint }, { "dither", ctl_type::integer } }; return std::make_pair(std::begin(ctl_infos), std::end(ctl_infos)); } std::vector module_impl::get_ctls() const { std::vector result; auto ctl_infos = get_ctl_infos(); result.reserve(std::distance(ctl_infos.first, ctl_infos.second)); for ( std::ptrdiff_t i = 0; i < std::distance(ctl_infos.first, ctl_infos.second); ++i ) { result.push_back(ctl_infos.first[i].name); } return result; } std::string module_impl::ctl_get( std::string ctl, bool throw_if_unknown ) const { if ( !ctl.empty() ) { // cppcheck false-positive // cppcheck-suppress containerOutOfBounds char rightmost = ctl.back(); if ( rightmost == '!' || rightmost == '?' ) { if ( rightmost == '!' ) { throw_if_unknown = true; } else if ( rightmost == '?' ) { throw_if_unknown = false; } ctl = ctl.substr( 0, ctl.length() - 1 ); } } auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; }); if ( found_ctl == get_ctl_infos().second ) { if ( ctl == "" ) { throw openmpt::exception("empty ctl"); } else if ( throw_if_unknown ) { throw openmpt::exception("unknown ctl: " + ctl); } else { return std::string(); } } std::string result; switch ( found_ctl->type ) { case ctl_type::boolean: return mpt::format_value_default( ctl_get_boolean( ctl, throw_if_unknown ) ); break; case ctl_type::integer: return mpt::format_value_default( ctl_get_integer( ctl, throw_if_unknown ) ); break; case ctl_type::floatingpoint: return mpt::format_value_default( ctl_get_floatingpoint( ctl, throw_if_unknown ) ); break; case ctl_type::text: return ctl_get_text( ctl, throw_if_unknown ); break; } return result; } bool module_impl::ctl_get_boolean( std::string_view ctl, bool throw_if_unknown ) const { if ( !ctl.empty() ) { // cppcheck false-positive // cppcheck-suppress containerOutOfBounds char rightmost = ctl.back(); if ( rightmost == '!' || rightmost == '?' ) { if ( rightmost == '!' ) { throw_if_unknown = true; } else if ( rightmost == '?' ) { throw_if_unknown = false; } ctl = ctl.substr( 0, ctl.length() - 1 ); } } auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; }); if ( found_ctl == get_ctl_infos().second ) { if ( ctl == "" ) { throw openmpt::exception("empty ctl"); } else if ( throw_if_unknown ) { throw openmpt::exception("unknown ctl: " + std::string(ctl)); } else { return false; } } if ( found_ctl->type != ctl_type::boolean ) { throw openmpt::exception("wrong ctl value type"); } if ( ctl == "" ) { throw openmpt::exception("empty ctl"); } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) { return m_ctl_load_skip_samples; } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) { return m_ctl_load_skip_patterns; } else if ( ctl == "load.skip_plugins" ) { return m_ctl_load_skip_plugins; } else if ( ctl == "load.skip_subsongs_init" ) { return m_ctl_load_skip_subsongs_init; } else if ( ctl == "seek.sync_samples" ) { return m_ctl_seek_sync_samples; } else if ( ctl == "render.resampler.emulate_amiga" ) { return ( m_sndFile->m_Resampler.m_Settings.emulateAmiga != OpenMPT::Resampling::AmigaFilter::Off ); } else { MPT_ASSERT_NOTREACHED(); return false; } } std::int64_t module_impl::ctl_get_integer( std::string_view ctl, bool throw_if_unknown ) const { if ( !ctl.empty() ) { // cppcheck false-positive // cppcheck-suppress containerOutOfBounds char rightmost = ctl.back(); if ( rightmost == '!' || rightmost == '?' ) { if ( rightmost == '!' ) { throw_if_unknown = true; } else if ( rightmost == '?' ) { throw_if_unknown = false; } ctl = ctl.substr( 0, ctl.length() - 1 ); } } auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; }); if ( found_ctl == get_ctl_infos().second ) { if ( ctl == "" ) { throw openmpt::exception("empty ctl"); } else if ( throw_if_unknown ) { throw openmpt::exception("unknown ctl: " + std::string(ctl)); } else { return 0; } } if ( found_ctl->type != ctl_type::integer ) { throw openmpt::exception("wrong ctl value type"); } if ( ctl == "" ) { throw openmpt::exception("empty ctl"); } else if ( ctl == "subsong" ) { return get_selected_subsong(); } else if ( ctl == "dither" ) { return static_cast( m_Dithers->GetMode() ); } else { MPT_ASSERT_NOTREACHED(); return 0; } } double module_impl::ctl_get_floatingpoint( std::string_view ctl, bool throw_if_unknown ) const { if ( !ctl.empty() ) { // cppcheck false-positive // cppcheck-suppress containerOutOfBounds char rightmost = ctl.back(); if ( rightmost == '!' || rightmost == '?' ) { if ( rightmost == '!' ) { throw_if_unknown = true; } else if ( rightmost == '?' ) { throw_if_unknown = false; } ctl = ctl.substr( 0, ctl.length() - 1 ); } } auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; }); if ( found_ctl == get_ctl_infos().second ) { if ( ctl == "" ) { throw openmpt::exception("empty ctl"); } else if ( throw_if_unknown ) { throw openmpt::exception("unknown ctl: " + std::string(ctl)); } else { return 0.0; } } if ( found_ctl->type != ctl_type::floatingpoint ) { throw openmpt::exception("wrong ctl value type"); } if ( ctl == "" ) { throw openmpt::exception("empty ctl"); } else if ( ctl == "play.tempo_factor" ) { if ( !is_loaded() ) { return 1.0; } return 65536.0 / m_sndFile->m_nTempoFactor; } else if ( ctl == "play.pitch_factor" ) { if ( !is_loaded() ) { return 1.0; } return m_sndFile->m_nFreqFactor / 65536.0; } else if ( ctl == "render.opl.volume_factor" ) { return static_cast( m_sndFile->m_OPLVolumeFactor ) / static_cast( OpenMPT::CSoundFile::m_OPLVolumeFactorScale ); } else { MPT_ASSERT_NOTREACHED(); return 0.0; } } std::string module_impl::ctl_get_text( std::string_view ctl, bool throw_if_unknown ) const { if ( !ctl.empty() ) { // cppcheck false-positive // cppcheck-suppress containerOutOfBounds char rightmost = ctl.back(); if ( rightmost == '!' || rightmost == '?' ) { if ( rightmost == '!' ) { throw_if_unknown = true; } else if ( rightmost == '?' ) { throw_if_unknown = false; } ctl = ctl.substr( 0, ctl.length() - 1 ); } } auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; }); if ( found_ctl == get_ctl_infos().second ) { if ( ctl == "" ) { throw openmpt::exception("empty ctl"); } else if ( throw_if_unknown ) { throw openmpt::exception("unknown ctl: " + std::string(ctl)); } else { return std::string(); } } if ( ctl == "" ) { throw openmpt::exception("empty ctl"); } else if ( ctl == "play.at_end" ) { switch ( m_ctl_play_at_end ) { case song_end_action::fadeout_song: return "fadeout"; case song_end_action::continue_song: return "continue"; case song_end_action::stop_song: return "stop"; default: return std::string(); } } else if ( ctl == "render.resampler.emulate_amiga_type" ) { switch ( m_ctl_render_resampler_emulate_amiga_type ) { case amiga_filter_type::a500: return "a500"; case amiga_filter_type::a1200: return "a1200"; case amiga_filter_type::unfiltered: return "unfiltered"; case amiga_filter_type::auto_filter: return "auto"; default: return std::string(); } } else { MPT_ASSERT_NOTREACHED(); return std::string(); } } void module_impl::ctl_set( std::string ctl, const std::string & value, bool throw_if_unknown ) { if ( !ctl.empty() ) { // cppcheck false-positive // cppcheck-suppress containerOutOfBounds char rightmost = ctl.back(); if ( rightmost == '!' || rightmost == '?' ) { if ( rightmost == '!' ) { throw_if_unknown = true; } else if ( rightmost == '?' ) { throw_if_unknown = false; } ctl = ctl.substr( 0, ctl.length() - 1 ); } } auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; }); if ( found_ctl == get_ctl_infos().second ) { if ( ctl == "" ) { throw openmpt::exception("empty ctl: := " + value); } else if ( throw_if_unknown ) { throw openmpt::exception("unknown ctl: " + ctl + " := " + value); } else { return; } } switch ( found_ctl->type ) { case ctl_type::boolean: ctl_set_boolean( ctl, mpt::parse( value ), throw_if_unknown ); break; case ctl_type::integer: ctl_set_integer( ctl, mpt::parse( value ), throw_if_unknown ); break; case ctl_type::floatingpoint: ctl_set_floatingpoint( ctl, mpt::parse( value ), throw_if_unknown ); break; case ctl_type::text: ctl_set_text( ctl, value, throw_if_unknown ); break; } } void module_impl::ctl_set_boolean( std::string_view ctl, bool value, bool throw_if_unknown ) { if ( !ctl.empty() ) { // cppcheck false-positive // cppcheck-suppress containerOutOfBounds char rightmost = ctl.back(); if ( rightmost == '!' || rightmost == '?' ) { if ( rightmost == '!' ) { throw_if_unknown = true; } else if ( rightmost == '?' ) { throw_if_unknown = false; } ctl = ctl.substr( 0, ctl.length() - 1 ); } } auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; }); if ( found_ctl == get_ctl_infos().second ) { if ( ctl == "" ) { throw openmpt::exception("empty ctl: := " + mpt::format_value_default( value ) ); } else if ( throw_if_unknown ) { throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + mpt::format_value_default(value)); } else { return; } } if ( ctl == "" ) { throw openmpt::exception("empty ctl: := " + mpt::format_value_default( value ) ); } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) { m_ctl_load_skip_samples = value; } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) { m_ctl_load_skip_patterns = value; } else if ( ctl == "load.skip_plugins" ) { m_ctl_load_skip_plugins = value; } else if ( ctl == "load.skip_subsongs_init" ) { m_ctl_load_skip_subsongs_init = value; } else if ( ctl == "seek.sync_samples" ) { m_ctl_seek_sync_samples = value; } else if ( ctl == "render.resampler.emulate_amiga" ) { OpenMPT::CResamplerSettings newsettings = m_sndFile->m_Resampler.m_Settings; const bool enabled = value; if ( enabled ) newsettings.emulateAmiga = translate_amiga_filter_type( m_ctl_render_resampler_emulate_amiga_type ); else newsettings.emulateAmiga = OpenMPT::Resampling::AmigaFilter::Off; if ( newsettings != m_sndFile->m_Resampler.m_Settings ) { m_sndFile->SetResamplerSettings( newsettings ); } } else { MPT_ASSERT_NOTREACHED(); } } void module_impl::ctl_set_integer( std::string_view ctl, std::int64_t value, bool throw_if_unknown ) { if ( !ctl.empty() ) { // cppcheck false-positive // cppcheck-suppress containerOutOfBounds char rightmost = ctl.back(); if ( rightmost == '!' || rightmost == '?' ) { if ( rightmost == '!' ) { throw_if_unknown = true; } else if ( rightmost == '?' ) { throw_if_unknown = false; } ctl = ctl.substr( 0, ctl.length() - 1 ); } } auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; }); if ( found_ctl == get_ctl_infos().second ) { if ( ctl == "" ) { throw openmpt::exception("empty ctl: := " + mpt::format_value_default( value ) ); } else if ( throw_if_unknown ) { throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + mpt::format_value_default(value)); } else { return; } } if ( ctl == "" ) { throw openmpt::exception("empty ctl: := " + mpt::format_value_default( value ) ); } else if ( ctl == "subsong" ) { select_subsong( mpt::saturate_cast( value ) ); } else if ( ctl == "dither" ) { std::size_t dither = mpt::saturate_cast( value ); if ( dither >= OpenMPT::DithersOpenMPT::GetNumDithers() ) { dither = OpenMPT::DithersOpenMPT::GetDefaultDither(); } m_Dithers->SetMode( dither ); } else { MPT_ASSERT_NOTREACHED(); } } void module_impl::ctl_set_floatingpoint( std::string_view ctl, double value, bool throw_if_unknown ) { if ( !ctl.empty() ) { // cppcheck false-positive // cppcheck-suppress containerOutOfBounds char rightmost = ctl.back(); if ( rightmost == '!' || rightmost == '?' ) { if ( rightmost == '!' ) { throw_if_unknown = true; } else if ( rightmost == '?' ) { throw_if_unknown = false; } ctl = ctl.substr( 0, ctl.length() - 1 ); } } auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; }); if ( found_ctl == get_ctl_infos().second ) { if ( ctl == "" ) { throw openmpt::exception("empty ctl: := " + mpt::format_value_default( value ) ); } else if ( throw_if_unknown ) { throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + mpt::format_value_default(value)); } else { return; } } if ( ctl == "" ) { throw openmpt::exception("empty ctl: := " + mpt::format_value_default( value ) ); } else if ( ctl == "play.tempo_factor" ) { if ( !is_loaded() ) { return; } double factor = value; if ( factor <= 0.0 || factor > 4.0 ) { throw openmpt::exception("invalid tempo factor"); } m_sndFile->m_nTempoFactor = mpt::saturate_round( 65536.0 / factor ); m_sndFile->RecalculateSamplesPerTick(); } else if ( ctl == "play.pitch_factor" ) { if ( !is_loaded() ) { return; } double factor = value; if ( factor <= 0.0 || factor > 4.0 ) { throw openmpt::exception("invalid pitch factor"); } m_sndFile->m_nFreqFactor = mpt::saturate_round( 65536.0 * factor ); m_sndFile->RecalculateSamplesPerTick(); } else if ( ctl == "render.opl.volume_factor" ) { m_sndFile->m_OPLVolumeFactor = mpt::saturate_round( value * static_cast( OpenMPT::CSoundFile::m_OPLVolumeFactorScale ) ); } else { MPT_ASSERT_NOTREACHED(); } } void module_impl::ctl_set_text( std::string_view ctl, std::string_view value, bool throw_if_unknown ) { if ( !ctl.empty() ) { // cppcheck false-positive // cppcheck-suppress containerOutOfBounds char rightmost = ctl.back(); if ( rightmost == '!' || rightmost == '?' ) { if ( rightmost == '!' ) { throw_if_unknown = true; } else if ( rightmost == '?' ) { throw_if_unknown = false; } ctl = ctl.substr( 0, ctl.length() - 1 ); } } auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; }); if ( found_ctl == get_ctl_infos().second ) { if ( ctl == "" ) { throw openmpt::exception("empty ctl: := " + std::string( value ) ); } else if ( throw_if_unknown ) { throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + std::string(value)); } else { return; } } if ( ctl == "" ) { throw openmpt::exception("empty ctl: := " + std::string( value ) ); } else if ( ctl == "play.at_end" ) { if ( value == "fadeout" ) { m_ctl_play_at_end = song_end_action::fadeout_song; } else if(value == "continue") { m_ctl_play_at_end = song_end_action::continue_song; } else if(value == "stop") { m_ctl_play_at_end = song_end_action::stop_song; } else { throw openmpt::exception("unknown song end action:" + std::string(value)); } } else if ( ctl == "render.resampler.emulate_amiga_type" ) { if ( value == "a500" ) { m_ctl_render_resampler_emulate_amiga_type = amiga_filter_type::a500; } else if ( value == "a1200" ) { m_ctl_render_resampler_emulate_amiga_type = amiga_filter_type::a1200; } else if ( value == "unfiltered" ) { m_ctl_render_resampler_emulate_amiga_type = amiga_filter_type::unfiltered; } else if ( value == "auto" ) { m_ctl_render_resampler_emulate_amiga_type = amiga_filter_type::auto_filter; } else { throw openmpt::exception( "invalid amiga filter type" ); } if ( m_sndFile->m_Resampler.m_Settings.emulateAmiga != OpenMPT::Resampling::AmigaFilter::Off ) { OpenMPT::CResamplerSettings newsettings = m_sndFile->m_Resampler.m_Settings; newsettings.emulateAmiga = translate_amiga_filter_type( m_ctl_render_resampler_emulate_amiga_type ); if ( newsettings != m_sndFile->m_Resampler.m_Settings ) { m_sndFile->SetResamplerSettings( newsettings ); } } } else { MPT_ASSERT_NOTREACHED(); } } } // namespace openmpt libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_version.h0000644000175000017500000000622415023271504022521 00000000000000/* * libopenmpt_version.h * -------------------- * Purpose: libopenmpt public interface version * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_VERSION_H #define LIBOPENMPT_VERSION_H /* clang-format off */ /*! \addtogroup libopenmpt @{ */ /*! \brief libopenmpt major version number */ #define OPENMPT_API_VERSION_MAJOR 0 /*! \brief libopenmpt minor version number */ #define OPENMPT_API_VERSION_MINOR 8 /*! \brief libopenmpt patch version number */ #define OPENMPT_API_VERSION_PATCH 1 /*! \brief libopenmpt pre-release tag */ #define OPENMPT_API_VERSION_PREREL "" /*! \brief libopenmpt pre-release flag */ #define OPENMPT_API_VERSION_IS_PREREL 0 /*! \brief libopenmpt version number as a single integer value * \since 0.3 * \remarks Use the following shim if you need to support earlier libopenmpt versions: * \code * #include * #if !defined(OPENMPT_API_VERSION_MAKE) * #define OPENMPT_API_VERSION_MAKE(major, minor, patch) (((major)<<24)|((minor)<<16)|((patch)<<0)) * #endif * \endcode */ #define OPENMPT_API_VERSION_MAKE(major, minor, patch) (((major)<<24)|((minor)<<16)|((patch)<<0)) /*! \brief libopenmpt API version number */ #define OPENMPT_API_VERSION OPENMPT_API_VERSION_MAKE(OPENMPT_API_VERSION_MAJOR, OPENMPT_API_VERSION_MINOR, OPENMPT_API_VERSION_PATCH) /*! \brief Check whether the libopenmpt API is at least the provided version * \since 0.3 * \remarks Use the following shim if you need to support earlier libopenmpt versions: * \code * #include * #if !defined(OPENMPT_API_VERSION_AT_LEAST) * #define OPENMPT_API_VERSION_AT_LEAST(major, minor, patch) (OPENMPT_API_VERSION >= OPENMPT_API_VERSION_MAKE((major), (minor), (patch))) * #endif * \endcode */ #define OPENMPT_API_VERSION_AT_LEAST(major, minor, patch) (OPENMPT_API_VERSION >= OPENMPT_API_VERSION_MAKE((major), (minor), (patch))) /*! \brief Check whether the libopenmpt API is before the provided version * \since 0.3 * \remarks Use the following shim if you need to support earlier libopenmpt versions: * \code * #include * #if !defined(OPENMPT_API_VERSION_BEFORE) * #define OPENMPT_API_VERSION_BEFORE(major, minor, patch) (OPENMPT_API_VERSION < OPENMPT_API_VERSION_MAKE((major), (minor), (patch))) * #endif * \endcode */ #define OPENMPT_API_VERSION_BEFORE(major, minor, patch) (OPENMPT_API_VERSION < OPENMPT_API_VERSION_MAKE((major), (minor), (patch))) #define OPENMPT_API_VERSION_HELPER_STRINGIZE(x) #x #define OPENMPT_API_VERSION_STRINGIZE(x) OPENMPT_API_VERSION_HELPER_STRINGIZE(x) #define OPENMPT_API_VERSION_STRING OPENMPT_API_VERSION_STRINGIZE(OPENMPT_API_VERSION_MAJOR) "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_API_VERSION_MINOR) "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_API_VERSION_PATCH) OPENMPT_API_VERSION_PREREL /*! @} */ /* clang-format on */ #endif /* LIBOPENMPT_VERSION_H */ libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_stream_callbacks_file_posix.h0000644000175000017500000000505714172232041026547 00000000000000/* * libopenmpt_stream_callbacks_file_posix.h * ---------------------------------------- * Purpose: libopenmpt public c interface * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_H #define LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_H #include "libopenmpt.h" #include #include #include /*! \addtogroup libopenmpt_c * @{ */ #ifdef __cplusplus extern "C" { #endif static size_t openmpt_stream_file_posix_read_func( void * stream, void * dst, size_t bytes ) { FILE * f = 0; size_t retval = 0; f = (FILE*)stream; if ( !f ) { return 0; } retval = fread( dst, 1, bytes, f ); if ( retval <= 0 ) { return 0; } return retval; } static int openmpt_stream_file_posix_seek_func( void * stream, int64_t offset, int whence ) { FILE * f = 0; int fwhence = 0; f = (FILE*)stream; if ( !f ) { return -1; } switch ( whence ) { case OPENMPT_STREAM_SEEK_SET: fwhence = SEEK_SET; break; case OPENMPT_STREAM_SEEK_CUR: fwhence = SEEK_CUR; break; case OPENMPT_STREAM_SEEK_END: fwhence = SEEK_END; break; default: return -1; break; } if ( (off_t)offset != offset ) { return -1; } return fseeko( f, (off_t)offset, fwhence ) ? -1 : 0; } static int64_t openmpt_stream_file_posix_tell_func( void * stream ) { FILE * f = 0; off_t result = 0; int64_t retval = 0; f = (FILE*)stream; if ( !f ) { return -1; } result = ftello( f ); if ( (int64_t)result != result ) { return -1; } retval = (int64_t)result; if ( retval < 0 ) { return -1; } return retval; } /*! \brief Provide openmpt_stream_callbacks for standard C FILE objects * * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. * * \remarks The stream argument must be passed as `(void*)(FILE*)file`. * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \sa openmpt_could_open_probability2 * \sa openmpt_probe_file_header_from_stream * \sa openmpt_module_create2 */ static openmpt_stream_callbacks openmpt_stream_get_file_posix_callbacks(void) { openmpt_stream_callbacks retval; memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); retval.read = openmpt_stream_file_posix_read_func; retval.seek = openmpt_stream_file_posix_seek_func; retval.tell = openmpt_stream_file_posix_tell_func; return retval; } #ifdef __cplusplus } #endif /*! * @} */ #endif /* LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_H */ libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_version.mk0000644000175000017500000000027315023271504022677 00000000000000LIBOPENMPT_VERSION_MAJOR=0 LIBOPENMPT_VERSION_MINOR=8 LIBOPENMPT_VERSION_PATCH=1 LIBOPENMPT_VERSION_PREREL= LIBOPENMPT_LTVER_CURRENT=5 LIBOPENMPT_LTVER_REVISION=1 LIBOPENMPT_LTVER_AGE=5 libopenmpt-0.8.1+release.autotools/libopenmpt/bindings/0000755000175000017500000000000015023302361020277 500000000000000libopenmpt-0.8.1+release.autotools/libopenmpt/bindings/freebasic/0000755000175000017500000000000015023302363022224 500000000000000libopenmpt-0.8.1+release.autotools/libopenmpt/bindings/freebasic/libopenmpt_ext.bi0000644000175000017500000005752614201775654025546 00000000000000/' ' libopenmpt_ext.bi ' ----------------- ' Purpose: libopenmpt public FreeBASIC interface for libopenmpt extensions ' Notes : (currently none) ' Authors: Johannes Schultz ' OpenMPT Devs ' The OpenMPT source code is released under the BSD license. Read LICENSE for more details. '/ #Pragma Once #Include Once "libopenmpt.bi" Extern "C" '* \brief Opaque type representing a libopenmpt extension module Type openmpt_module_ext opaque As Any Ptr End Type /'* \brief Construct an openmpt_module_ext \param stream_callbacks Input stream callback operations. \param stream Input stream to load the module from. \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module_ext. May be NULL. \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. \param errorcode Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \param ctls A map of initial ctl values, see openmpt_module_get_ctls. \return A pointer to the constructed openmpt_module_ext, or NULL on failure. \remarks The input data can be discarded after an openmpt_module_ext has been constructed successfully. \sa openmpt_stream_callbacks \since 0.3.0 '/ Declare Function openmpt_module_ext_create(ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal Error As Long Ptr, ByVal error_message As Const ZString Ptr Ptr, ByVal ctls As Const openmpt_module_initial_ctl Ptr) As openmpt_module_ext Ptr /'* \brief Construct an openmpt_module_ext \param filedata Data to load the module from. \param filesize Amount of data available. \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module_ext. \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. \param errorcode Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \param ctls A map of initial ctl values, see openmpt_module_get_ctls. \return A pointer to the constructed openmpt_module_ext, or NULL on failure. \remarks The input data can be discarded after an openmpt_module_ext has been constructed successfully. \since 0.3.0 '/ Declare Function openmpt_module_ext_create_from_memory(ByVal filedata As Const Any Ptr, ByVal filesize As UInteger, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal Error As Long Ptr, ByVal error_message As Const ZString Ptr Ptr, ByVal ctls As Const openmpt_module_initial_ctl Ptr) As openmpt_module_ext Ptr /'* \brief Unload a previously created openmpt_module_ext from memory. \param mod_ext The module to unload. \since 0.3.0 '/ Declare Sub openmpt_module_ext_destroy(ByVal mod_ext As openmpt_module_ext Ptr) /'* \brief Retrieve the openmpt_module handle from an openmpt_module_ext handle. \param mod_ext The extension module handle to convert \return An equivalent openmpt_module handle to pass to standard libopenmpt functions \since 0.3.0 '/ Declare Function openmpt_module_ext_get_module(ByVal mod_ext As openmpt_module_ext Ptr) As openmpt_module Ptr /'* Retrieve a libopenmpt extension. \param mod_ext The module handle to work on. \param interface_id The name of the extension interface to retrieve (e.g. LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS). \param interface Appropriate structure of interface function pointers which is to be filled by this function (e.g. a pointer to a openmpt_module_ext_interface_pattern_vis structure). \param interface_size Size of the interface's structure of function pointers (e.g. sizeof(openmpt_module_ext_interface_pattern_vis)). \return 1 on success, 0 if the interface was not found. \since 0.3.0 '/ Declare Function openmpt_module_ext_get_interface(ByVal mod_ext As openmpt_module_ext Ptr, ByVal interface_id As Const ZString Ptr, ByVal interface As Any Ptr, ByVal interface_size As UInteger) As Long #define LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS "pattern_vis" '* Pattern command type Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_UNKNOWN = 0 Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_GENERAL = 1 Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_GLOBAL = 2 Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_VOLUME = 3 Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_PANNING = 4 Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_PITCH = 5 Type openmpt_module_ext_interface_pattern_vis /'* Get pattern command type for pattern highlighting \param mod_ext The module handle to work on. \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \return The command type in the effect column at the given pattern position (see OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_*) \sa get_pattern_row_channel_effect_type '/ get_pattern_row_channel_volume_effect_type As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long) As Long /'* Get pattern command type for pattern highlighting \param mod_ext The module handle to work on. \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \return The command type in the effect column at the given pattern position (see OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_*) \sa get_pattern_row_channel_volume_effect_type '/ get_pattern_row_channel_effect_type As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long) As Long End Type #define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE "interactive" Type openmpt_module_ext_interface_interactive /'* Set the current ticks per row (speed) \param mod_ext The module handle to work on. \param speed The new tick count in range [1, 65535]. \throws openmpt::exception Throws an exception derived from openmpt::exception if the speed is outside the specified range. \return 1 on success, 0 on failure. \sa openmpt_module_get_current_speed '/ set_current_speed As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal speed As Long) As Long /'* Set the current module tempo \param mod_ext The module handle to work on. \param tempo The new tempo in range [32, 512]. The exact meaning of the value depends on the tempo mode used by the module. \return 1 on success, 0 on failure. \remarks The tempo may be reset by pattern commands at any time. Use set_tempo_factor to apply a tempo factor that is independent of pattern commands. \sa openmpt_module_get_current_tempo \deprecated Please use openmpt_module_ext_interface_interactive3.set_current_tempo2(). '/ set_current_tempo As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal tempo As Long) As Long /'* Set the current module tempo factor without affecting playback pitch \param mod_ext The module handle to work on. \param factor The new tempo factor in range ]0.0, 4.0] - 1.0 means unmodified tempo. \return 1 on success, 0 on failure. \remarks Modifying the tempo without applying the same pitch factor using set_pitch_factor may cause rhythmic samples (e.g. drum loops) to go out of sync. \sa openmpt_module_ext_interface_interactive.get_tempo_factor '/ set_tempo_factor As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal factor As Double) As Long /'* Gets the current module tempo factor \param mod_ext The module handle to work on. \return The current tempo factor. \sa openmpt_module_ext_interface_interactive.set_tempo_factor '/ get_tempo_factor As Function(ByVal mod_ext As openmpt_module_ext Ptr) As Double /'* Set the current module pitch factor without affecting playback speed \param mod_ext The module handle to work on. \param factor The new pitch factor in range ]0.0, 4.0] - 1.0 means unmodified pitch. \return 1 on success, 0 on failure. \remarks Modifying the pitch without applying the the same tempo factor using set_tempo_factor may cause rhythmic samples (e.g. drum loops) to go out of sync. \remarks To shift the pich by `n` semitones, the parameter can be calculated as follows: `2.0 ^ ( n / 12.0 )` \sa openmpt_module_ext_interface_interactive.get_pitch_factor '/ set_pitch_factor As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal factor As Double) As Long /'* Gets the current module pitch factor \param mod_ext The module handle to work on. \return The current pitch factor. \sa openmpt_module_ext_interface_interactive.set_pitch_factor '/ get_pitch_factor As Function(ByVal mod_ext As openmpt_module_ext Ptr) As Double /'* Set the current global volume \param mod_ext The module handle to work on. \param volume The new global volume in range [0.0, 1.0] \return 1 on success, 0 on failure. \remarks The global volume may be reset by pattern commands at any time. Use openmpt_module_set_render_param to apply a global overall volume factor that is independent of pattern commands. \sa openmpt_module_ext_interface_interactive.get_global_volume '/ set_global_volume As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal volume As Double) As Long /'* Get the current global volume \param mod_ext The module handle to work on. \return The current global volume in range [0.0, 1.0] \sa openmpt_module_ext_interface_interactive.set_global_volume '/ get_global_volume As Function(ByVal mod_ext As openmpt_module_ext Ptr) As Double /'* Set the current channel volume for a channel \param mod_ext The module handle to work on. \param channel The channel whose volume should be set, in range [0, openmpt_module_get_num_channels()[ \param volume The new channel volume in range [0.0, 1.0] \return 1 on success, 0 on failure (channel out of range). \remarks The channel volume may be reset by pattern commands at any time. \sa openmpt_module_ext_interface_interactive.get_channel_volume '/ set_channel_volume As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long, ByVal volume As Double) As Long /'* Get the current channel volume for a channel \param mod_ext The module handle to work on. \param channel The channel whose volume should be retrieved, in range [0, openmpt_module_get_num_channels()[ \return The current channel volume in range [0.0, 1.0] \sa openmpt_module_ext_interface_interactive.set_channel_volume '/ get_channel_volume As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Double /'* Set the current mute status for a channel \param mod_ext The module handle to work on. \param channel The channel whose mute status should be set, in range [0, openmpt_module_get_num_channels()[ \param mute The new mute status. true is muted, false is unmuted. \return 1 on success, 0 on failure (channel out of range). \sa openmpt_module_ext_interface_interactive.get_channel_mute_status '/ set_channel_mute_status As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long, ByVal mute As Long) As Long /'* Get the current mute status for a channel \param mod_ext The module handle to work on. \param channel The channel whose mute status should be retrieved, in range [0, openmpt_module_get_num_channels()[ \return The current channel mute status. true is muted, false is unmuted. \sa openmpt_module_ext_interface_interactive.set_channel_mute_status '/ get_channel_mute_status As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Long /'* Set the current mute status for an instrument \param mod_ext The module handle to work on. \param instrument The instrument whose mute status should be set, in range [0, openmpt_module_get_num_instruments()[ if openmpt_module_get_num_instruments is not 0, otherwise in [0, openmpt_module_get_num_samples()[ \param mute The new mute status. true is muted, false is unmuted. \return 1 on success, 0 on failure (instrument out of range). \sa openmpt_module_ext_interface_interactive.get_instrument_mute_status '/ set_instrument_mute_status As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal instrument As Long, ByVal mute As Long) As Long /'* Get the current mute status for an instrument \param mod_ext The module handle to work on. \param instrument The instrument whose mute status should be retrieved, in range [0, openmpt_module_get_num_instruments()[ if openmpt_module_get_num_instruments is not 0, otherwise in [0, openmpt_module_get_num_samples()[ \return The current instrument mute status. 1 is muted, 0 is unmuted, -1 means the instrument was out of range. \sa openmpt_module_ext_interface_interactive.set_instrument_mute_status '/ get_instrument_mute_status As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal instrument As Long) As Long /'* Play a note using the specified instrument \param mod_ext The module handle to work on. \param instrument The instrument that should be played, in range [0, openmpt_module_get_num_instruments()[ if openmpt_module_get_num_instruments is not 0, otherwise in [0, openmpt_module_get_num_samples()[ \param note The note to play, in rage [0, 119]. 60 is the middle C. \param volume The volume at which the note should be triggered, in range [0.0, 1.0] \param panning The panning position at which the note should be triggered, in range [-1.0, 1.0], 0.0 is center. \return The channel on which the note is played. This can pe be passed to stop_note to stop the note. -1 means that no channel could be allocated and the note is not played. \sa openmpt_module_ext_interface_interactive.stop_note \sa openmpt_module_ext_interface_interactive2.note_off \sa openmpt_module_ext_interface_interactive2.note_fade '/ play_note As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal instrument As Long, ByVal note As Long, ByVal volume As Double, ByVal panning As Double) As Long /'* Stop the note playing on the specified channel \param mod_ext The module handle to work on. \param channel The channel on which the note should be stopped. This is the value returned by a previous play_note call. \return 1 on success, 0 on failure (channel out of range). \sa openmpt_module_ext_interface_interactive.play_note \sa openmpt_module_ext_interface_interactive.note_off \sa openmpt_module_ext_interface_interactive2.note_fade '/ stop_note As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Long End Type #define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE2 "interactive2" Type openmpt_module_ext_interface_interactive2 /'* Sends a key-off command for the note playing on the specified channel \param mod_ext The module handle to work on. \param channel The channel on which the key-off event should be triggered. This is the value returned by a previous play_note call. \return 1 on success, 0 on failure (channel out of range). \remarks This method releases envelopes and sample sustain loops. If the sample has no sustain loop, or if the module does not use instruments, it does nothing. \sa openmpt_module_ext_interface_interactive.play_note \sa openmpt_module_ext_interface_interactive.stop_note \sa note_fade '/ note_off As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Long /'* Sends a note fade command for the note playing on the specified channel \param mod_ext The module handle to work on. \param channel The channel on which the note should be faded. This is the value returned by a previous play_note call. \return 1 on success, 0 on failure (channel out of range). \remarks This method uses the instrument's fade-out value. If the module does not use instruments, or the instrument's fade-out value is 0, it does nothing. \sa openmpt_module_ext_interface_interactive.play_note \sa openmpt_module_ext_interface_interactive.stop_note \sa note_fade '/ note_fade As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Long /'* Set the current panning for a channel \param mod_ext The module handle to work on. \param channel The channel that should be panned. This is the value returned by a previous play_note call. \param panning The panning position to set on the channel, in range [-1.0, 1.0], 0.0 is center. \return 1 on success, 0 on failure (channel out of range). \remarks This command affects subsequent notes played on the same channel, and may itself be overridden by subsequent panning commands encountered in the module itself. \sa openmpt_module_ext_interface_interactive2.get_channel_panning '/ set_channel_panning As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long, ByVal panning As Double) As Long /'* Get the current panning position for a channel \param mod_ext The module handle to work on. \param channel The channel whose panning should be retrieved. This is the value returned by a previous play_note call. \return The current channel panning, in range [-1.0, 1.0], 0.0 is center. \sa openmpt_module_ext_interface_interactive2.set_channel_panning '/ get_channel_panning As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Double /'* Set the finetune for the currently playing note on a channel \param mod_ext The module handle to work on. \param channel The channel whose finetune will be changed, in range [0, openmpt::module::get_num_channels()[ \param finetune The finetune to set on the channel, in range [-1.0, 1.0], 0.0 is center. \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid. \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone. \remarks This command does not affect subsequent notes played on the same channel, but may itself be overridden by subsequent finetune commands encountered in the module itself. \sa openmpt_module_ext_interface_interactive2.get_note_finetune '/ set_note_finetune As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long, ByVal finetune As Double) As Long /'* Get the finetune for the currently playing note on a channel \param mod_ext The module handle to work on. \param channel The channel whose finetune should be retrieved, in range [0, openmpt::module::get_num_channels()[ \return The current channel finetune, in range [-1.0, 1.0], 0.0 is center. \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone. \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range. \sa openmpt_module_ext_interface_interactive2.set_note_finetune '/ get_note_finetune As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Double End Type #define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE3 "interactive3" Type openmpt_module_ext_interface_interactive3 /'* Set the current module tempo \param mod_ext The module handle to work on. \param tempo The new tempo in range [32, 512]. The exact meaning of the value depends on the tempo mode used by the module. \return 1 on success, 0 on failure. \remarks The tempo may be reset by pattern commands at any time. Use set_tempo_factor to apply a tempo factor that is independent of pattern commands. \sa openmpt_module_get_current_tempo2 \since 0.7.0 '/ set_current_tempo As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal tempo As Double) As Long End Type End Extern /'* \brief Construct an openmpt_module_ext \param file The FreeBASIC file handle to load from. \param logfunc Logging function where warning and errors are written. May be NULL. \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. Used to pass any user-defined data associated with this module to the error function. \param errorcode Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \param ctls A map of initial ctl values, see openmpt_module_get_ctls. \return A pointer to the constructed openmpt_module, or NULL on failure. \remarks The file handle can be closed after an openmpt_module has been constructed successfully. \sa openmpt_module_ext_create '/ Function openmpt_module_ext_create_from_fbhandle(_ ByVal file As Integer,_ ByVal logfunc As openmpt_log_func = 0,_ ByVal loguser As Any Ptr = 0,_ ByVal errfunc As openmpt_error_func = 0,_ ByVal erruser As Any Ptr = 0,_ ByVal errorcode As Long Ptr = 0,_ ByVal error_message As Const ZString Ptr Ptr = 0,_ ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module_ext Ptr Return openmpt_module_ext_create(openmpt_stream_get_file_callbacks(), Cast(FILE Ptr, FileAttr(file, fbFileAttrHandle)), logfunc, loguser, errfunc, erruser, errorcode, error_message, ctls) End Function /'* \brief Construct an openmpt_module_ext \param filename The file to load from. \param logfunc Logging function where warning and errors are written. May be NULL. \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. Used to pass any user-defined data associated with this module to the error function. \param errorcode Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \param ctls A map of initial ctl values, see openmpt_module_get_ctls. \return A pointer to the constructed openmpt_module, or NULL on failure. \sa openmpt_module_ext_create '/ Function openmpt_module_ext_create_from_filename(_ ByRef filename As String,_ ByVal logfunc As openmpt_log_func = 0,_ ByVal loguser As Any Ptr = 0,_ ByVal errfunc As openmpt_error_func = 0,_ ByVal erruser As Any Ptr = 0,_ ByVal errorcode As Long Ptr = 0,_ ByVal error_message As Const ZString Ptr Ptr = 0,_ ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module_ext Ptr Var file = fopen(filename, "rb") Var retval = CPtr(openmpt_module Ptr, 0) If(file <> 0) Then retval = openmpt_module_ext_create(openmpt_stream_get_file_callbacks(), file, logfunc, loguser, errfunc, erruser, errorcode, error_message, ctls) fclose(file) EndIf Return retval End Function libopenmpt-0.8.1+release.autotools/libopenmpt/bindings/freebasic/libopenmpt.bi0000644000175000017500000031131514705211733024643 00000000000000/' ' libopenmpt.bi ' ------------- ' Purpose: libopenmpt public interface for FreeBASIC ' Notes : (currently none) ' Authors: Johannes Schultz ' OpenMPT Devs ' The OpenMPT source code is released under the BSD license. Read LICENSE for more details. '/ #Include Once "crt/stdio.bi" #Include Once "file.bi" #Inclib "openmpt" /'* \page libopenmpt_freebasic_overview FreeBASIC API \section libopenmpt_freebasic_error Error Handling - Functions with no return value in the corresponding C++ API return 0 on failure and 1 on success. - Functions that return integer values signal error condition by returning an invalid value (-1 in most cases, 0 in some cases). - All functions that work on an openmpt_module object will call an openmpt_error_func and depending on the value returned by this function log the error code and/xor/or store it inside the openmpt_module object. Stored error codes can be accessed with the openmpt_module_error_get_last() and openmpt_module_error_get_last_message(). Stored errors will not get cleared automatically and should be reset with openmpt_module_error_clear(). - Some functions not directly related to an openmpt_module object take an explicit openmpt_error_func error function callback and a pointer to an int and behave analog to the functions working on an openmpt_module object. \section libopenmpt_freebasic_strings Strings - All strings returned from libopenmpt are encoded in UTF-8. - All strings passed to libopenmpt should also be encoded in UTF-8. Behaviour in case of invalid UTF-8 is unspecified. - libopenmpt does not enforce or expect any particular Unicode normalization form. - Some libopenmpt functions return strings and are provided in two flavours: The raw libopenmpt function (with a trailing underscore) and a FreeBASIC wrapper function that completely takes care of memory handling (recommended). All strings returned from raw libopenmpt functions are dynamically allocated and must be freed with openmpt_free_string(). When using the FreeBASIC wrappers (which is the recommended way), FreeBASIC automatically takes care of this. - All strings passed to libopenmpt are copied. No ownership is assumed or transferred. \section libopenmpt_freebasic_outputformat Output Format libopenmpt supports a wide range of PCM output formats: [8000..192000]/[mono|stereo|quad]/[f32|i16]. Unless you have some very specific requirements demanding a particular aspect of the output format, you should always prefer 48000/stereo/f32 as the libopenmpt PCM format. - Please prefer 48000Hz unless the user explicitly demands something else. Practically all audio equipment and file formats use 48000Hz nowadays. - Practically all module formats are made for stereo output. Mono will not give you any measurable speed improvements and can trivially be obtained from the stereo output anyway. Quad is not expected by almost all modules and even if they do use surround effects, they expect the effects to be mixed to stereo. - Floating point output provides headroom instead of hard clipping if the module is louder than 0dBFs, will give you a better signal-to-noise ratio than int16 output, and avoid the need to apply an additional dithering to the output by libopenmpt. Unless your platform has no floating point unit at all, floating point will thus also be slightly faster. \section libopenmpt_freebasic_threads libopenmpt in multi-threaded environments - libopenmpt is thread-aware. - Individual libopenmpt objects are not thread-safe. - libopenmpt itself does not spawn any user-visible threads but may spawn threads for internal use. - You must ensure to only ever access a particular libopenmpt object from a single thread at a time. - Consecutive accesses can happen from different threads. - Different objects can be accessed concurrently from different threads. \section libopenmpt_freebasic_detailed Detailed documentation \ref libopenmpt_freebasic '/ Extern "C" '* API version of this header file Const OPENMPT_API_VERSION_MAJOR = 0 Const OPENMPT_API_VERSION_MINOR = 3 Const OPENMPT_API_VERSION_PATCH = 0 Const OPENMPT_API_VERSION = (OPENMPT_API_VERSION_MAJOR Shl 24) Or (OPENMPT_API_VERSION_MINOR Shl 16) Or (OPENMPT_API_VERSION_PATCH Shl 0) #Define OPENMPT_API_VERSION_STRING (OPENMPT_API_VERSION_MAJOR & "." & OPENMPT_API_VERSION_MINOR & "." & OPENMPT_API_VERSION_PATCH) /'* \brief Get the libopenmpt version number Returns the libopenmpt version number. \return The value represents (major Shl 24 + minor Shl 16 + patch Shl 0). \remarks libopenmpt < 0.3.0-pre used the following scheme: (major Shl 24 + minor Shl 16 + revision). \remarks Check the HiWord of the return value against OPENMPT_API_VERSION to ensure that the correct library version is loaded. '/ Declare Function openmpt_get_library_version() As ULong /'* \brief Get the core version number Return the OpenMPT core version number. \return The value represents (majormajor << 24 + major << 16 + minor << 8 + minorminor). '/ Declare Function openmpt_get_core_version() As ULong '* Return a verbose library version string from openmpt_get_string(). \deprecated Please use \code "library_version" \endcode directly. #Define OPENMPT_STRING_LIBRARY_VERSION "library_version" '* Return a verbose library features string from openmpt_get_string(). \deprecated Please use \code "library_features" \endcode directly. #Define OPENMPT_STRING_LIBRARY_FEATURES "library_features" '* Return a verbose OpenMPT core version string from openmpt_get_string(). \deprecated Please use \code "core_version" \endcode directly. #Define OPENMPT_STRING_CORE_VERSION "core_version" '* Return information about the current build (e.g. the build date or compiler used) from openmpt_get_string(). \deprecated Please use \code "build" \endcode directly. #Define OPENMPT_STRING_BUILD "build" '* Return all contributors from openmpt_get_string(). \deprecated Please use \code "credits" \endcode directly. #Define OPENMPT_STRING_CREDITS "credits" '* Return contact information about libopenmpt from openmpt_get_string(). \deprecated Please use \code "contact" \endcode directly. #Define OPENMPT_STRING_CONTACT "contact" '* Return the libopenmpt license from openmpt_get_string(). \deprecated Please use \code "license" \endcode directly. #Define OPENMPT_STRING_LICENSE "license" /'* \brief Free a string returned by libopenmpt Frees any string that got returned by libopenmpt. '/ Declare Sub openmpt_free_string(ByVal Str As Const ZString Ptr) /'* \brief Get library related metadata. \param key Key to query. Possible keys are: - "library_version": verbose library version string - "library_version_is_release": "1" if the version is an officially released version - "library_features": verbose library features string - "core_version": verbose OpenMPT core version string - "source_url": original source code URL - "source_date": original source code date - "source_revision": original source code revision - "source_is_modified": "1" if the original source has been modified - "source_has_mixed_revisions": "1" if the original source has been compiled from different various revision - "source_is_package": "1" if the original source has been obtained from a source pacakge instead of source code version control - "build": information about the current build (e.g. the build date or compiler used) - "build_compiler": information about the compiler used to build libopenmpt - "credits": all contributors - "contact": contact information about libopenmpt - "license": the libopenmpt license - "url": libopenmpt website URL - "support_forum_url": libopenmpt support and discussions forum URL - "bugtracker_url": libopenmpt bug and issue tracker URL \return A (possibly multi-line) string containing the queried information. If no information is available, the string is empty. \remarks Use openmpt_get_string to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_get_string_ Alias "openmpt_get_string" (ByVal key As Const ZString Ptr) As Const ZString Ptr /'* \brief Get a list of supported file extensions \return The semicolon-separated list of extensions supported by this libopenmpt build. The extensions are returned lower-case without a leading dot. \remarks Use openmpt_get_supported_extensions to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_get_supported_extensions() As Const ZString Ptr /'* \brief Query whether a file extension is supported \param extension file extension to query without a leading dot. The case is ignored. \return 1 if the extension is supported by libopenmpt, 0 otherwise. '/ Declare Function openmpt_is_extension_supported(ByVal extension As Const ZString Ptr) As Long '* Seek to the given offset relative to the beginning of the file. Const OPENMPT_STREAM_SEEK_SET = 0 '* Seek to the given offset relative to the current position in the file. Const OPENMPT_STREAM_SEEK_CUR = 1 '* Seek to the given offset relative to the end of the file. Const OPENMPT_STREAM_SEEK_END = 2 /'* \brief Read bytes from stream Read bytes data from stream to dst. \param stream Stream to read data from \param dst Target where to copy data. \param bytes Number of bytes to read. \return Number of bytes actually read and written to dst. \retval 0 End of stream or error. \remarks Short reads are allowed as long as they return at least 1 byte if EOF is not reached. '/ Type openmpt_stream_read_func As Function(ByVal stream As Any Ptr, ByVal dst As Any Ptr, ByVal bytes As UInteger) As UInteger /'* \brief Seek stream position Seek to stream position offset at whence. \param stream Stream to operate on. \param offset Offset to seek to. \param whence OPENMPT_STREAM_SEEK_SET, OPENMPT_STREAM_SEEK_CUR, OPENMPT_STREAM_SEEK_END. See C89 documentation. \return Returns 0 on success. \retval 0 Success. \retval -1 Failure. Position does not get updated. \remarks libopenmpt will not try to seek beyond the file size, thus it is not important whether you allow for virtual positioning after the file end, or return an error in that case. The position equal to the file size needs to be seekable to. '/ Type openmpt_stream_seek_func As Function(ByVal stream As Any Ptr, ByVal offset As LongInt, ByVal whence As Long) As Long /'* \brief Tell stream position Tell position of stream. \param stream Stream to operate on. \return Current position in stream. \retval -1 Failure. '/ Type openmpt_stream_tell_func As Function(ByVal stream As Any Ptr) As LongInt /'* \brief Stream callbacks Stream callbacks used by libopenmpt for stream operations. '/ Type openmpt_stream_callbacks /'* \brief Read callback. \sa openmpt_stream_read_func '/ read_func As openmpt_stream_read_func /'* \brief Seek callback. Seek callback can be NULL if seeking is not supported. \sa openmpt_stream_seek_func '/ seek_func As openmpt_stream_seek_func /'* \brief Tell callback. Tell callback can be NULL if seeking is not supported. \sa openmpt_stream_tell_func '/ tell_func As openmpt_stream_tell_func End Type /'* \brief Logging function \param message UTF-8 encoded log message. \param user User context that was passed to openmpt_module_create2(), openmpt_module_create_from_memory2() or openmpt_could_open_probability2(). '/ Type openmpt_log_func As Sub(ByVal message As Const ZString Ptr, ByVal user As Any Ptr) /'* \brief Default logging function Default logging function that logs anything to stderr. '/ Declare Sub openmpt_log_func_default(ByVal message As Const ZString Ptr, ByVal user As Any Ptr) /'* \brief Silent logging function Silent logging function that throws any log message away. '/ Declare Sub openmpt_log_func_silent(ByVal message As Const ZString Ptr, ByVal user As Any Ptr) '* No error. \since 0.3.0 Const OPENMPT_ERROR_OK = 0 '* Lowest value libopenmpt will use for any of its own error codes. \since 0.3.0 Const OPENMPT_ERROR_BASE = 256 '* Unknown internal error. \since 0.3.0 Const OPENMPT_ERROR_UNKNOWN = OPENMPT_ERROR_BASE + 1 '* Unknown internal C++ exception. \since 0.3.0 Const OPENMPT_ERROR_EXCEPTION = OPENMPT_ERROR_BASE + 11 '* Out of memory. \since 0.3.0 Const OPENMPT_ERROR_OUT_OF_MEMORY = OPENMPT_ERROR_BASE + 21 '* Runtime error. \since 0.3.0 Const OPENMPT_ERROR_RUNTIME = OPENMPT_ERROR_BASE + 30 '* Range error. \since 0.3.0 Const OPENMPT_ERROR_RANGE = OPENMPT_ERROR_BASE + 31 '* Arithmetic overflow. \since 0.3.0 Const OPENMPT_ERROR_OVERFLOW = OPENMPT_ERROR_BASE + 32 '* Arithmetic underflow. \since 0.3.0 Const OPENMPT_ERROR_UNDERFLOW = OPENMPT_ERROR_BASE + 33 '* Logic error. \since 0.3.0 Const OPENMPT_ERROR_LOGIC = OPENMPT_ERROR_BASE + 40 '* Value domain error. \since 0.3.0 Const OPENMPT_ERROR_DOMAIN = OPENMPT_ERROR_BASE + 41 '* Maximum supported size exceeded. \since 0.3.0 Const OPENMPT_ERROR_LENGTH = OPENMPT_ERROR_BASE + 42 '* Argument out of range. \since 0.3.0 Const OPENMPT_ERROR_OUT_OF_RANGE = OPENMPT_ERROR_BASE + 43 '* Invalid argument. \since 0.3.0 Const OPENMPT_ERROR_INVALID_ARGUMENT = OPENMPT_ERROR_BASE + 44 '* General libopenmpt error. \since 0.3.0 Const OPENMPT_ERROR_GENERAL = OPENMPT_ERROR_BASE + 101 '* openmpt_module Ptr is invalid. \since 0.3.0 Const OPENMPT_ERROR_INVALID_MODULE_POINTER = OPENMPT_ERROR_BASE + 102 '* NULL pointer argument. \since 0.3.0 Const OPENMPT_ERROR_ARGUMENT_NULL_POINTER = OPENMPT_ERROR_BASE + 103 /'* \brief Check whether the error is transient Checks whether an error code represents a transient error which may not occur again in a later try if for example memory has been freed up after an out-of-memory error. \param errorcode Error code. \retval 0 Error is not transient. \retval 1 Error is transient. \sa OPENMPT_ERROR_OUT_OF_MEMORY \since 0.3.0 '/ Declare Function openmpt_error_is_transient(ByVal errorcode As Long) As Long /'* \brief Convert error code to text Converts an error code into a text string describing the error. \param errorcode Error code. \return Allocated string describing the error. \retval NULL Not enough memory to allocate the string. \since 0.3.0 \remarks Use openmpt_error_string to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_error_string_ Alias "openmpt_error_string" (ByVal errorcode As Long) As Const ZString Ptr '* Do not log or store the error. \since 0.3.0 Const OPENMPT_ERROR_FUNC_RESULT_NONE = 0 '* Log the error. \since 0.3.0 Const OPENMPT_ERROR_FUNC_RESULT_LOG = 1 '* Store the error. \since 0.3.0 Const OPENMPT_ERROR_FUNC_RESULT_STORE = 2 '* Log and store the error. \since 0.3.0 Const OPENMPT_ERROR_FUNC_RESULT_DEFAULT = OPENMPT_ERROR_FUNC_RESULT_LOG Or OPENMPT_ERROR_FUNC_RESULT_STORE /'* \brief Error function \param errorcode Error code. \param user User context that was passed to openmpt_module_create2(), openmpt_module_create_from_memory2() or openmpt_could_open_probability2(). \return Mask of OPENMPT_ERROR_FUNC_RESULT_LOG and OPENMPT_ERROR_FUNC_RESULT_STORE. \retval OPENMPT_ERROR_FUNC_RESULT_NONE Do not log or store the error. \retval OPENMPT_ERROR_FUNC_RESULT_LOG Log the error. \retval OPENMPT_ERROR_FUNC_RESULT_STORE Store the error. \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT Log and store the error. \sa OPENMPT_ERROR_FUNC_RESULT_NONE \sa OPENMPT_ERROR_FUNC_RESULT_LOG \sa OPENMPT_ERROR_FUNC_RESULT_STORE \sa OPENMPT_ERROR_FUNC_RESULT_DEFAULT \sa openmpt_error_func_default \sa openmpt_error_func_log \sa openmpt_error_func_store \sa openmpt_error_func_ignore \sa openmpt_error_func_errno \since 0.3.0 '/ Type openmpt_error_func As Function(ByVal errorcode As Long, ByVal user As Any Ptr) As Long /'* \brief Default error function Causes all errors to be logged and stored. \param errorcode Error code. \param user Ignored. \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT Always. \since 0.3.0 '/ Declare Function openmpt_error_func_default(ByVal errorcode As Long, ByVal User As Any Ptr) As Long /'* \brief Log error function Causes all errors to be logged. \param errorcode Error code. \param user Ignored. \retval OPENMPT_ERROR_FUNC_RESULT_LOG Always. \since 0.3.0 '/ Declare Function openmpt_error_func_log(ByVal errorcode As Long, ByVal user As Any Ptr) As Long /'* \brief Store error function Causes all errors to be stored. \param errorcode Error code. \param user Ignored. \retval OPENMPT_ERROR_FUNC_RESULT_STORE Always. \since 0.3.0 '/ Declare Function openmpt_error_func_store(ByVal errorcode As Long, ByVal user As Any Ptr) As Long /'* \brief Ignore error function Causes all errors to be neither logged nor stored. \param errorcode Error code. \param user Ignored. \retval OPENMPT_ERROR_FUNC_RESULT_NONE Always. \since 0.3.0 '/ Declare Function openmpt_error_func_ignore(ByVal errorcode As Long, ByVal user As Any Ptr) As Long /'* \brief Errno error function Causes all errors to be stored in the pointer passed in as user. \param errorcode Error code. \param user Pointer to an int as generated by openmpt_error_func_errno_userdata. \retval OPENMPT_ERROR_FUNC_RESULT_NONE user is not NULL. \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT user is NULL. \since 0.3.0 '/ Declare Function openmpt_error_func_errno(ByVal errorcode As Long, ByVal user As Any Ptr) As Long /'* \brief User pointer for openmpt_error_func_errno Provides a suitable user pointer argument for openmpt_error_func_errno. \param errorcode Pointer to an integer value to be used as output by openmpt_error_func_errno. \retval Cast(Any Ptr, errorcode). \since 0.3.0 '/ Declare Function openmpt_error_func_errno_userdata(ByVal errorcode As Long Ptr) As Any Ptr /'* \brief Roughly scan the input stream to find out whether libopenmpt might be able to open it \param stream_callbacks Input stream callback operations. \param stream Input stream to scan. \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file. \param logfunc Logging function where warning and errors are written. May be NULL. \param user Logging function user context. \return Probability between 0.0 and 1.0. \remarks openmpt_could_open_probability() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.). \remarks openmpt_could_open_probability() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_probability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_probability() returned 0.5. \sa openmpt_stream_callbacks \deprecated Please use openmpt_module_could_open_probability2(). \since 0.3.0 '/ Declare Function openmpt_could_open_probability(ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, ByVal effort As Double, ByVal logfunc As openmpt_log_func, ByVal user As Any Ptr) As Double /'* \brief Roughly scan the input stream to find out whether libopenmpt might be able to open it \param stream_callbacks Input stream callback operations. \param stream Input stream to scan. \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file. \param logfunc Logging function where warning and errors are written. May be NULL. \param loguser Logging function user context. \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. \param errorcode Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \return Probability between 0.0 and 1.0. \remarks openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize() provide a simpler and faster interface that fits almost all use cases better. It is recommended to use openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize() instead of openmpt_could_open_probability(). \remarks openmpt_could_open_probability2() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.). \remarks openmpt_could_open_probability2() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_probability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_probability() returned 0.5. \sa openmpt_stream_callbacks \sa openmpt_probe_file_header \sa openmpt_probe_file_header_without_filesize \since 0.3.0 '/ Declare Function openmpt_could_open_probability2(ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, ByVal effort As Double, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal errorcode As Long Ptr, ByVal error_message As Const ZString Ptr Ptr) As Double /'* \brief Get recommended header size for successfull format probing \sa openmpt_probe_file_header() \sa openmpt_probe_file_header_without_filesize() \since 0.3.0 '/ Declare Function openmpt_probe_file_header_get_recommended_size() As UInteger '* Probe for module formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES = 1 '* Probe for module-specific container formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS = 2 '* Probe for the default set of formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT = OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES or OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS '* Probe for no formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_FLAGS_NONE = 0 '* Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): The file will most likely be supported by libopenmpt. \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS = 1 '* Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): The file is not supported by libopenmpt. \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE = 0 '* Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): An answer could not be determined with the amount of data provided. \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA = -1 '* Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): An internal error occurred. \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR = -255 /'* \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it \param flags Bit mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT. \param data Beginning of the file data. \param size Size of the beginning of the file data. \param filesize Full size of the file data on disk. \param logfunc Logging function where warning and errors are written. May be NULL. \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function. \param error Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size and filesize to the file's size. \remarks openmpt_could_open_probability2() provides a more elaborate interface that might be required for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred. \sa openmpt_probe_file_header_get_recommended_size() \sa openmpt_probe_file_header_without_filesize() \sa openmpt_probe_file_header_from_stream() \sa openmpt_could_open_probability2() \since 0.3.0 '/ Declare Function openmpt_probe_file_header(ByVal flags As ULongInt, ByVal Data As Const Any Ptr, ByVal size As UInteger, ByVal filesize As ULongInt, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal Error As Long Ptr, ByVal error_message As Const ZString Ptr Ptr) As Long /'* \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it \param flags Bit mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT. \param data Beginning of the file data. \param size Size of the beginning of the file data. \param logfunc Logging function where warning and errors are written. May be NULL. \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function. \param error Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \remarks It is recommended to use openmpt_probe_file_header() and provide the acutal file's size as a parameter if at all possible. libopenmpt can provide more accurate answers if the filesize is known. \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size to the file's size. \remarks openmpt_could_open_probability2() provides a more elaborate interface that might be required for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred. \sa openmpt_probe_file_header_get_recommended_size() \sa openmpt_probe_file_header() \sa openmpt_probe_file_header_from_stream() \sa openmpt_could_open_probability2() \since 0.3.0 '/ Declare Function openmpt_probe_file_header_without_filesize(ByVal flags As ULongInt, ByVal Data As Const Any Ptr, ByVal size As UInteger, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal Error As Long Ptr, ByVal error_message As Const ZString Ptr Ptr) As Long /'* \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it \param flags Bit mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT. \param stream_callbacks Input stream callback operations. \param stream Input stream to scan. \param logfunc Logging function where warning and errors are written. May be NULL. \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function. \param error Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \remarks The stream is left in an unspecified state when this function returns. \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size and filesize to the file's size. \remarks openmpt_could_open_probability2() provides a more elaborate interface that might be required for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided. \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred. \sa openmpt_probe_file_header_get_recommended_size() \sa openmpt_probe_file_header() \sa openmpt_probe_file_header_without_filesize() \sa openmpt_could_open_probability2() \since 0.3.0 '/ Declare Function openmpt_probe_file_header_from_stream(ByVal flags As ULongInt, ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal Error As Long Ptr, ByVal error_message As Const ZString Ptr Ptr) As Long '* \brief Opaque type representing a libopenmpt module Type openmpt_module opaque As Any Ptr End Type Type openmpt_module_initial_ctl ctl As Const ZString Ptr value As Const ZString Ptr End Type /'* \brief Construct an openmpt_module \param stream_callbacks Input stream callback operations. \param stream Input stream to load the module from. \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. \param user User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set. \return A pointer to the constructed openmpt_module, or NULL on failure. \remarks The input data can be discarded after an openmpt_module has been constructed successfully. \sa openmpt_stream_callbacks '/ Declare Function openmpt_module_create(ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, ByVal logfunc As openmpt_log_func = 0, ByVal user As Any Ptr = 0, ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr /'* \brief Construct an openmpt_module \param stream_callbacks Input stream callback operations. \param stream Input stream to load the module from. \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. May be NULL. \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. \param errorcode Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set. \return A pointer to the constructed openmpt_module, or NULL on failure. \remarks The input data can be discarded after an openmpt_module has been constructed successfully. \sa openmpt_stream_callbacks \since 0.3.0 '/ Declare Function openmpt_module_create2(ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, ByVal logfunc As openmpt_log_func = 0, ByVal loguser As Any Ptr = 0, ByVal errfunc As openmpt_error_func = 0, ByVal erruser As Any Ptr = 0, ByVal errorcode As Long Ptr = 0, ByVal error_message As Const ZString Ptr Ptr = 0, ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr /'* \brief Construct an openmpt_module \param filedata Data to load the module from. \param filesize Amount of data available. \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. \param user User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set. \return A pointer to the constructed openmpt_module, or NULL on failure. \remarks The input data can be discarded after an openmpt_module has been constructed successfully. '/ Declare Function openmpt_module_create_from_memory(ByVal filedata As Const Any Ptr, ByVal filesize As UInteger, ByVal logfunc As openmpt_log_func = 0, ByVal user As Any Ptr = 0, ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr /'* \brief Construct an openmpt_module \param filedata Data to load the module from. \param filesize Amount of data available. \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. \param errorcode Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set. \return A pointer to the constructed openmpt_module, or NULL on failure. \remarks The input data can be discarded after an openmpt_module has been constructed successfully. \since 0.3.0 '/ Declare Function openmpt_module_create_from_memory2(ByVal filedata As Const Any Ptr, ByVal filesize As UInteger, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal errorcode As Long Ptr, ByVal error_message As Const ZString Ptr Ptr, ByVal ctls As Const openmpt_module_initial_ctl Ptr) As openmpt_module Ptr /'* \brief Unload a previously created openmpt_module from memory. \param module The module to unload. '/ Declare Sub openmpt_module_destroy(ByVal module As openmpt_module Ptr) /'* \brief Set logging function. Set the logging function of an already constructed openmpt_module. \param module The module handle to work on. \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) \since 0.3.0 '/ Declare Sub openmpt_module_set_log_func(ByVal module As openmpt_module Ptr, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr) /'* \brief Set error function. Set the error function of an already constructed openmpt_module. \param module The module handle to work on. \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. \since 0.3.0 '/ Declare Sub openmpt_module_set_error_func(ByVal module As openmpt_module Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr) /'* \brief Get last error. Return the error currently stored in an openmpt_module. The stored error is not cleared. \param module The module handle to work on. \return The error currently stored. \sa openmpt_module_error_get_last_message \sa openmpt_module_error_set_last \sa openmpt_module_error_clear \since 0.3.0 '/ Declare Function openmpt_module_error_get_last(ByVal module As openmpt_module Ptr) As Long /'* \brief Get last error message. Return the error message currently stored in an openmpt_module. The stored error is not cleared. \param module The module handle to work on. \return The error message currently stored. \sa openmpt_module_error_set_last \sa openmpt_module_error_clear \since 0.3.0 \remarks Use openmpt_module_error_get_last_message to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_error_get_last_message_ Alias "openmpt_module_error_get_last_message" (ByVal module As openmpt_module Ptr) As Const ZString Ptr /'* \brief Set last error. Set the error currently stored in an openmpt_module. \param module The module handle to work on. \param errorcode Error to be stored. \sa openmpt_module_error_get_last \sa openmpt_module_error_clear \since 0.3.0 '/ Declare Sub openmpt_module_error_set_last(ByVal module As openmpt_module Ptr, ByVal errorcode As Long) /'* \brief Clear last error. Set the error currently stored in an openmpt_module to OPPENMPT_ERROR_OK. \param module The module handle to work on. \sa openmpt_module_error_get_last \sa openmpt_module_error_set_last \since 0.3.0 '/ Declare Sub openmpt_module_error_clear(ByVal module As openmpt_module Ptr) /'* \defgroup openmpt_module_render_param Render param indices \brief Parameter index to use with openmpt_module_get_render_param() and openmpt_module_set_render_param() @{ '/ /'* \brief Master Gain The related value represents a relative gain in milliBel.\n The default value is 0.\n The supported value range is unlimited.\n '/ Const OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL = 1 /'* \brief Stereo Separation The related value represents the stereo separation generated by the libopenmpt mixer in percent.\n The default value is 100.\n The supported value range is [0,200].\n '/ Const OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT = 2 /'* \brief Interpolation Filter The related value represents the interpolation filter length used by the libopenmpt mixer.\n The default value is 0, which indicates a recommended default value.\n The supported value range is [0,inf). Values greater than the implementation limit are clamped to the maximum supported value.\n Currently supported values: - 0: internal default - 1: no interpolation (zero order hold) - 2: linear interpolation - 4: cubic interpolation - 8: windowed sinc with 8 taps '/ Const OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH = 3 /'* \brief Volume Ramping Strength The related value represents the amount of volume ramping done by the libopenmpt mixer.\n The default value is -1, which indicates a recommended default value.\n The meaningful value range is [-1..10].\n A value of 0 completely disables volume ramping. This might cause clicks in sound output.\n Higher values imply slower/softer volume ramps. '/ Const OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH = 4 '* @} /'* \defgroup openmpt_module_command_index Pattern cell indices \brief Parameter index to use with openmpt_module_get_pattern_row_channel_command(), openmpt_module_format_pattern_row_channel_command() and openmpt_module_highlight_pattern_row_channel_command() @{ '/ Const OPENMPT_MODULE_COMMAND_NOTE = 0 Const OPENMPT_MODULE_COMMAND_INSTRUMENT = 1 Const OPENMPT_MODULE_COMMAND_VOLUMEEFFECT = 2 Const OPENMPT_MODULE_COMMAND_EFFECT = 3 Const OPENMPT_MODULE_COMMAND_VOLUME = 4 Const OPENMPT_MODULE_COMMAND_PARAMETER = 5 '* @} /'* \brief Select a sub-song from a multi-song module \param module The module handle to work on. \param subsong Index of the sub-song. -1 plays all sub-songs consecutively. \return 1 on success, 0 on failure. \sa openmpt_module_get_num_subsongs, openmpt_module_get_selected_subsong, openmpt_module_get_subsong_name \remarks Whether subsong -1 (all subsongs consecutively), subsong 0 or some other subsong is selected by default, is an implementation detail and subject to change. If you do not want to care about subsongs, it is recommended to just not call openmpt_module_select_subsong() at all. '/ Declare Function openmpt_module_select_subsong(ByVal module As openmpt_module Ptr, ByVal subsong As Long) As Long /'* \brief Get currently selected sub-song from a multi-song module \param module The module handle to work on. \return Currently selected sub-song. -1 for all subsongs consecutively, 0 or greater for the current sub-song index. \sa openmpt_module_get_num_subsongs, openmpt_module_select_subsong, openmpt_module_get_subsong_name \since 0.3.0 '/ Declare Function openmpt_module_get_selected_subsong(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the restart order of the specified sub-song \param module The module handle to work on. \param subsong Index of the sub-song to retrieve the restart position from. \return The restart order of the specified sub-song. This is the order to which playback returns after the last pattern row of the song has been played. -1 is returned if if sub-song is not in range [0,openmpt_module_get_num_subsongs()[ \sa openmpt_module_get_restart_row \since 0.8.0 '/ Declare Function openmpt_module_get_restart_order(ByVal module As openmpt_module Ptr, ByVal subsong As Long) As Long /'* \brief Get the restart row of the specified sub-song \param module The module handle to work on. \param subsong Index of the sub-song to retrieve the restart position from. \return The restart row of the specified sub-song. This is the first played row of the order to which playback returns after the last pattern row of the song has been played. -1 is returned if if sub-song is not in range [0,openmpt_module_get_num_subsongs()[ \sa openmpt_module_get_restart_order \since 0.8.0 '/ Declare Function openmpt_module_get_restart_row(ByVal module As openmpt_module Ptr, ByVal subsong As Long) As Long /'* \brief Set Repeat Count \param module The module handle to work on. \param repeat_count Repeat Count - -1: repeat forever - 0: play once, repeat zero times (the default) - n>0: play once and repeat n times after that \return 1 on success, 0 on failure. \sa openmpt_module_get_repeat_count '/ Declare Function openmpt_module_set_repeat_count(ByVal module As openmpt_module Ptr, ByVal repeat_count As Long) As Long /'* \brief Get Repeat Count \param module The module handle to work on. \return Repeat Count - -1: repeat forever - 0: play once, repeat zero times (the default) - n>0: play once and repeat n times after that \sa openmpt_module_set_repeat_count '/ Declare Function openmpt_module_get_repeat_count(ByVal module As openmpt_module Ptr) As Long /'* \brief approximate song duration \param module The module handle to work on. \return Approximate duration of current sub-song in seconds. \remarks The function may return infinity if the pattern data is too complex to evaluate. '/ Declare Function openmpt_module_get_duration_seconds(ByVal module As openmpt_module Ptr) As Double /'* \brief Get approximate playback time in seconds at given position \param module The module handle to work on. \param order The order position at which the time should be retrieved. \param row The pattern row number at which the time should be retrieved. \return Approximate playback time in seconds of current sub-song at the start of the given order and row combination. Negative if the position does not exist, or the pattern data is too complex to evaluate. \remarks If an order / row combination is played multiple times (e.g. due the pattern loops), the first occurence of this position is returned. \since 0.8.0 '/ Declare Function openmpt_module_get_time_at_position(ByVal module As openmpt_module Ptr, ByVal order As Long, ByVal row As Long) As Double /'* \brief Set approximate current song position \param module The module handle to work on. \param seconds Seconds to seek to. If seconds is out of range, the position gets set to song start or end respectively. \return Approximate new song position in seconds. \sa openmpt_module_get_position_seconds '/ Declare Function openmpt_module_set_position_seconds(ByVal module As openmpt_module Ptr, ByVal seconds As Double) As Double /'* \brief Get current song position \param module The module handle to work on. \return Current song position in seconds. \sa openmpt_module_set_position_seconds '/ Declare Function openmpt_module_get_position_seconds(ByVal module As openmpt_module Ptr) As Double /'* \brief Set approximate current song position If order or row are out of range, to position is not modified and the current position is returned. \param module The module handle to work on. \param order Pattern order number to seek to. \param row Pattern row number to seek to. \return Approximate new song position in seconds. \sa openmpt_module_set_position_seconds \sa openmpt_module_get_position_seconds '/ Declare Function openmpt_module_set_position_order_row(ByVal module As openmpt_module Ptr, ByVal order As Long, ByVal row As Long) As Double /'* \brief Get render parameter \param module The module handle to work on. \param param Parameter to query. See \ref openmpt_module_render_param \param value Pointer to the variable that receives the current value of the parameter. \return 1 on success, 0 on failure (invalid param or value is NULL). \sa OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL \sa OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT \sa OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH \sa OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH \sa openmpt_module_set_render_param '/ Declare Function openmpt_module_get_render_param(ByVal module As openmpt_module Ptr, ByVal param As Long, ByVal value As Long Ptr) As Long /'* \brief Set render parameter \param module The module handle to work on. \param param Parameter to set. See \ref openmpt_module_render_param \param value The value to set param to. \return 1 on success, 0 on failure (invalid param). \sa OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL \sa OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT \sa OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH \sa OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH \sa openmpt_module_get_render_param '/ Declare Function openmpt_module_set_render_param(ByVal module As openmpt_module Ptr, ByVal param As Long, ByVal value As Long) As Long '*@{ /'* \brief Render audio data \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param mono Pointer to a buffer of at least count elements that receives the mono/center output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_freebasic_outputformat '/ Declare Function openmpt_module_read_mono(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal mono As Short Ptr) As UInteger /'* \brief Render audio data \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param left Pointer to a buffer of at least count elements that receives the left output. \param right Pointer to a buffer of at least count elements that receives the right output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_freebasic_outputformat '/ Declare Function openmpt_module_read_stereo(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal Left As Short Ptr, ByVal Right As Short Ptr) As UInteger /'* \brief Render audio data \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param left Pointer to a buffer of at least count elements that receives the left output. \param right Pointer to a buffer of at least count elements that receives the right output. \param rear_left Pointer to a buffer of at least count elements that receives the rear left output. \param rear_right Pointer to a buffer of at least count elements that receives the rear right output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_freebasic_outputformat '/ Declare Function openmpt_module_read_quad(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal Left As Short Ptr, ByVal Right As Short Ptr, ByVal rear_left As Short Ptr, ByVal rear_right As Short Ptr) As UInteger /'* \brief Render audio data \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param mono Pointer to a buffer of at least count elements that receives the mono/center output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_freebasic_outputformat '/ Declare Function openmpt_module_read_float_mono(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal mono As Single Ptr) As UInteger /'* \brief Render audio data \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param left Pointer to a buffer of at least count elements that receives the left output. \param right Pointer to a buffer of at least count elements that receives the right output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_freebasic_outputformat '/ Declare Function openmpt_module_read_float_stereo(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal Left As Single Ptr, ByVal Right As Single Ptr) As UInteger /'* \brief Render audio data \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param left Pointer to a buffer of at least count elements that receives the left output. \param right Pointer to a buffer of at least count elements that receives the right output. \param rear_left Pointer to a buffer of at least count elements that receives the rear left output. \param rear_right Pointer to a buffer of at least count elements that receives the rear right output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_freebasic_outputformat '/ Declare Function openmpt_module_read_float_quad(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal Left As Single Ptr, ByVal Right As Single Ptr, ByVal rear_left As Single Ptr, ByVal rear_right As Single Ptr) As UInteger /'* \brief Render audio data \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_freebasic_outputformat '/ Declare Function openmpt_module_read_interleaved_stereo(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal interleaved_stereo As Short Ptr) As UInteger /'* \brief Render audio data \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_freebasic_outputformat '/ Declare Function openmpt_module_read_interleaved_quad(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal interleaved_quad As Short Ptr) As UInteger /'* \brief Render audio data \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_freebasic_outputformat '/ Declare Function openmpt_module_read_interleaved_float_stereo(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal interleaved_stereo As Single Ptr) As UInteger /'* \brief Render audio data \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_freebasic_outputformat '/ Declare Function openmpt_module_read_interleaved_float_quad(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal interleaved_quad As Single Ptr) As UInteger '*@} /'* \brief Get the list of supported metadata item keys \param module The module handle to work on. \return Metadata item keys supported by openmpt_module_get_metadata, as a semicolon-separated list. \sa openmpt_module_get_metadata \remarks Use openmpt_module_get_metadata_keys to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_get_metadata_keys_ Alias "openmpt_module_get_metadata_keys" (ByVal module As openmpt_module Ptr) As Const ZString Ptr /'* \brief Get a metadata item value \param module The module handle to work on. \param key Metadata item key to query. Use openmpt_module_get_metadata_keys to check for available keys. Possible keys are: - type: Module format extension (e.g. it) or another similar identifier for modules formats that typically do not use a file extension - type_long: Format name associated with the module format (e.g. Impulse Tracker) - originaltype: Module format extension (e.g. it) of the original module in case the actual type is a converted format (e.g. mo3 or gdm) - originaltype_long: Format name associated with the module format (e.g. Impulse Tracker) of the original module in case the actual type is a converted format (e.g. mo3 or gdm) - container: Container format the module file is embedded in, if any (e.g. umx) - container_long: Full container name if the module is embedded in a container (e.g. Unreal Music) - tracker: Tracker that was (most likely) used to save the module file, if known - artist: Author of the module - title: Module title - date: Date the module was last saved, in ISO-8601 format. - message: Song message. If the song message is empty or the module format does not support song messages, a list of instrument and sample names is returned instead. - message_raw: Song message. If the song message is empty or the module format does not support song messages, an empty string is returned. - warnings: A list of warnings that were generated while loading the module. \return The associated value for key. \sa openmpt_module_get_metadata_keys \remarks Use openmpt_module_get_metadata to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_get_metadata_ Alias "openmpt_module_get_metadata" (ByVal module As openmpt_module Ptr, ByVal key As Const ZString Ptr) As Const ZString Ptr /'* \brief Get the current estimated beats per minute (BPM). \param module The module handle to work on. \remarks Many module formats lack time signature metadata. It is common that this estimate is off by a factor of two, but other multipliers are also possible. \remarks Due to the nature of how module tempo works, the estimate may change slightly after switching libopenmpt's output to a different sample rate. \return The current estimated BPM. '/ Declare Function openmpt_module_get_current_estimated_bpm(ByVal module As openmpt_module Ptr) As Double /'* \brief Get the current speed \param module The module handle to work on. \return The current speed in ticks per row. '/ Declare Function openmpt_module_get_current_speed(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the current tempo \param module The module handle to work on. \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. \deprecated Please use openmpt_module_get_current_tempo2(). '/ Declare Function openmpt_module_get_current_tempo(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the current tempo \param module The module handle to work on. \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. \since 0.7.0 '/ Declare Function openmpt_module_get_current_tempo2(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the current order \param module The module handle to work on. \return The current order at which the module is being played back. '/ Declare Function openmpt_module_get_current_order(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the current pattern \param module The module handle to work on. \return The current pattern that is being played. '/ Declare Function openmpt_module_get_current_pattern(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the current row \param module The module handle to work on. \return The current row at which the current pattern is being played. '/ Declare Function openmpt_module_get_current_row(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the current amount of playing channels. \param module The module handle to work on. \return The amount of sample channels that are currently being rendered. '/ Declare Function openmpt_module_get_current_playing_channels(ByVal module As openmpt_module Ptr) As Long /'* \brief Get an approximate indication of the channel volume. \param module The module handle to work on. \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. '/ Declare Function openmpt_module_get_current_channel_vu_mono(ByVal module As openmpt_module Ptr, ByVal channel As Long) As Single /'* \brief Get an approximate indication of the channel volume on the front-left speaker. \param module The module handle to work on. \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. '/ Declare Function openmpt_module_get_current_channel_vu_left(ByVal module As openmpt_module Ptr, ByVal channel As Long) As Single /'* \brief Get an approximate indication of the channel volume on the front-right speaker. \param module The module handle to work on. \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. '/ Declare Function openmpt_module_get_current_channel_vu_right(ByVal module As openmpt_module Ptr, ByVal channel As Long) As Single /'* \brief Get an approximate indication of the channel volume on the rear-left speaker. \param module The module handle to work on. \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. '/ Declare Function openmpt_module_get_current_channel_vu_rear_left(ByVal module As openmpt_module Ptr, ByVal channel As Long) As Single /'* \brief Get an approximate indication of the channel volume on the rear-right speaker. \param module The module handle to work on. \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. '/ Declare Function openmpt_module_get_current_channel_vu_rear_right(ByVal module As openmpt_module Ptr, ByVal channel As Long) As Single /'* \brief Get the number of sub-songs \param module The module handle to work on. \return The number of sub-songs in the module. This includes any "hidden" songs (songs that share the same sequence, but start at different order indices) and "normal" sub-songs or "sequences" (if the format supports them). \sa openmpt_module_get_subsong_name, openmpt_module_select_subsong, openmpt_module_get_selected_subsong '/ Declare Function openmpt_module_get_num_subsongs(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the number of pattern channels \param module The module handle to work on. \return The number of pattern channels in the module. Not all channels do necessarily contain data. \remarks The number of pattern channels is completely independent of the number of output channels. libopenmpt can render modules in mono, stereo or quad surround, but the choice of which of the three modes to use must not be made based on the return value of this function, which may be any positive integer amount. Only use this function for informational purposes. '/ Declare Function openmpt_module_get_num_channels(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the number of orders \param module The module handle to work on. \return The number of orders in the current sequence of the module. '/ Declare Function openmpt_module_get_num_orders(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the number of patterns \param module The module handle to work on. \return The number of distinct patterns in the module. '/ Declare Function openmpt_module_get_num_patterns(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the number of instruments \param module The module handle to work on. \return The number of instrument slots in the module. Instruments are a layer on top of samples, and are not supported by all module formats. '/ Declare Function openmpt_module_get_num_instruments(ByVal module As openmpt_module Ptr) As Long /'* \brief Get the number of samples \param module The module handle to work on. \return The number of sample slots in the module. '/ Declare Function openmpt_module_get_num_samples(ByVal module As openmpt_module Ptr) As Long /'* \brief Get a sub-song name \param module The module handle to work on. \param index The sub-song whose name should be retrieved \return The sub-song name. \sa openmpt_module_get_num_subsongs, openmpt_module_select_subsong, openmpt_module_get_selected_subsong \remarks Use openmpt_module_get_subsong_name to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_get_subsong_name_ Alias "openmpt_module_get_subsong_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr /'* \brief Get a channel name \param module The module handle to work on. \param index The channel whose name should be retrieved \return The channel name. \sa openmpt_module_get_num_channels \remarks Use openmpt_module_get_channel_name to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_get_channel_name_ Alias "openmpt_module_get_channel_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr /'* \brief Get an order name \param module The module handle to work on. \param index The order whose name should be retrieved \return The order name. \sa openmpt_module_get_num_orders \remarks Use openmpt_module_get_order_name to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_get_order_name_ Alias "openmpt_module_get_order_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr /'* \brief Get a pattern name \param module The module handle to work on. \param index The pattern whose name should be retrieved \return The pattern name. \sa openmpt_module_get_num_patterns \remarks Use openmpt_module_get_pattern_name to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_get_pattern_name_ Alias "openmpt_module_get_pattern_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr /'* \brief Get an instrument name \param module The module handle to work on. \param index The instrument whose name should be retrieved \return The instrument name. \sa openmpt_module_get_num_instruments \remarks Use openmpt_module_get_instrument_name to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_get_instrument_name_ Alias "openmpt_module_get_instrument_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr /'* \brief Get a sample name \param module The module handle to work on. \param index The sample whose name should be retrieved \return The sample name. \sa openmpt_module_get_num_samples \remarks Use openmpt_module_get_sample_name to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_get_sample_name_ Alias "openmpt_module_get_sample_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr /'* \brief Get pattern at order position \param module The module handle to work on. \param order The order item whose pattern index should be retrieved. \return The pattern index found at the given order position of the current sequence. '/ Declare Function openmpt_module_get_order_pattern(ByVal module As openmpt_module Ptr, ByVal order As Long) As Long /'* \brief Check if specified order is a skip ("+++") item \param order The order index to check. \return Returns non-zero value if the pattern index at the given order position represents a skip item. During playback, this item is ignored and playback resumes at the next order list item. \sa openmpt_module_is_order_stop_entry, openmpt_module_is_pattern_skip_item \since 0.8.0 '/ Declare Function openmpt_module_is_order_skip_entry(ByVal module As openmpt_module Ptr, ByVal order As Long) As Long /'* \brief Check if specified pattern index is a skip ("+++") item \param pattern The pattern index to check. \return Returns non-zero value if the pattern index represents a skip item. During playback, this item is ignored and playback resumes at the next order list item. \sa openmpt_module_is_pattern_stop_item, openmpt_module_is_order_skip_entry, openmpt_module_get_order_pattern \since 0.8.0 '/ Declare Function openmpt_module_is_pattern_skip_item(ByVal module As openmpt_module Ptr, ByVal pattern As Long) As Long /'* \brief Check if specified order is a stop ("---") item \param order The order index to check. \return Returns non-zero value if the pattern index at the given order position represents a stop item. When this item is reached, playback continues at the restart position of the current sub-song. \sa openmpt_module_is_order_skip_entry, openmpt_module_is_pattern_stop_item \since 0.8.0 '/ Declare Function openmpt_module_is_order_stop_entry(ByVal module As openmpt_module Ptr, ByVal order As Long) As Long /'* \brief Check if specified pattern index is a stop ("---") item \param pattern The pattern index to check. \return Returns non-zero value if the pattern index represents a stop item. When this item is reached, playback continues at the restart position of the current sub-song. \sa openmpt_module_is_pattern_skip_item, openmpt_module_is_order_stop_entry, openmpt_module_get_order_pattern \since 0.8.0 '/ Declare Function openmpt_module_is_pattern_stop_item(ByVal module As openmpt_module Ptr, ByVal pattern As Long) As Long /'* \brief Get the number of rows in a pattern \param module The module handle to work on. \param pattern The pattern whose row count should be retrieved. \return The number of rows in the given pattern. If the pattern does not exist, 0 is returned. '/ Declare Function openmpt_module_get_pattern_num_rows(ByVal module As openmpt_module Ptr, ByVal pattern As Long) As Long /'* \brief Get the rows per beat of a pattern \param mod The module handle to work on. \param pattern The pattern whose time signature should be retrieved. \return The rows per beat of the given pattern. If the pattern does not exist or the time signature is not defined, 0 is returned. \remarks Many module formats lack time signature metadata. In this case, the returned value may be an incorrect estimation. \since 0.8.0 '/ Declare Function openmpt_module_get_pattern_rows_per_beat(ByVal module As openmpt_module Ptr, ByVal pattern As Long) As Long /'* \brief Get the rows per measure of a pattern \param mod The module handle to work on. \param pattern The pattern whose time signature should be retrieved. \return The rows per measure of the given pattern. If the pattern does not exist or the time signature is not defined, 0 is returned. \remarks Many module formats lack time signature metadata. In this case, the returned value may be an incorrect estimation. \since 0.8.0 '/ Declare Function openmpt_module_get_pattern_rows_per_measure(ByVal module As openmpt_module Ptr, ByVal pattern As Long) As Long /'* \brief Get raw pattern content \param module The module handle to work on. \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \param command The cell index at which the data should be retrieved. See \ref openmpt_module_command_index \return The internal, raw pattern data at the given pattern position. '/ Declare Function openmpt_module_get_pattern_row_channel_command_(ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal command_ As Long) As UByte /'* \brief Get formatted (human-readable) pattern content \param module The module handle to work on. \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \param command The cell index at which the data should be retrieved. \return The formatted pattern data at the given pattern position. See \ref openmpt_module_command_index \sa openmpt_module_highlight_pattern_row_channel_command \remarks Use openmpt_module_format_pattern_row_channel_command to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_format_pattern_row_channel_command_ Alias "openmpt_module_format_pattern_row_channel_command" (ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal command_ As Long) As Const ZString Ptr /'* \brief Get highlighting information for formatted pattern content \param module The module handle to work on. \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \param command The cell index at which the data should be retrieved. See \ref openmpt_module_command_index \return The highlighting string for the formatted pattern data as retrieved by openmpt_module_get_pattern_row_channel_command at the given pattern position. \remarks The returned string will map each character position of the string returned by openmpt_module_get_pattern_row_channel_command to a highlighting instruction. Possible highlighting characters are: - " " : empty/space - "." : empty/dot - "n" : generic note - "m" : special note - "i" : generic instrument - "u" : generic volume column effect - "v" : generic volume column parameter - "e" : generic effect column effect - "f" : generic effect column parameter \sa openmpt_module_get_pattern_row_channel_command \remarks Use openmpt_module_highlight_pattern_row_channel_command to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_highlight_pattern_row_channel_command_ Alias "openmpt_module_highlight_pattern_row_channel_command" (ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal command_ As Long) As Const ZString Ptr /'* \brief Get formatted (human-readable) pattern content \param module The module handle to work on. \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \param width The maximum number of characters the string should contain. 0 means no limit. \param pad If true, the string will be resized to the exact length provided in the width parameter. \return The formatted pattern data at the given pattern position. \sa openmpt_module_highlight_pattern_row_channel \remarks Use openmpt_module_format_pattern_row_channel to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_format_pattern_row_channel_ Alias "openmpt_module_format_pattern_row_channel" (ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal width_ As UInteger, ByVal pad As Long) As Const ZString Ptr /'* \brief Get highlighting information for formatted pattern content \param module The module handle to work on. \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \param width The maximum number of characters the string should contain. 0 means no limit. \param pad If true, the string will be resized to the exact length provided in the width parameter. \return The highlighting string for the formatted pattern data as retrieved by openmpt_module_format_pattern_row_channel at the given pattern position. \sa openmpt_module_format_pattern_row_channel \remarks Use openmpt_module_highlight_pattern_row_channel to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_highlight_pattern_row_channel_ Alias "openmpt_module_highlight_pattern_row_channel" (ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal width_ As UInteger, ByVal pad As Long) As Const ZString Ptr /'* \brief Retrieve supported ctl keys \param module The module handle to work on. \return A semicolon-separated list containing all supported ctl keys. \remarks Currently supported ctl values are: - load.skip_samples: Set to "1" to avoid loading samples into memory - load.skip_patterns: Set to "1" to avoid loading patterns into memory - load.skip_plugins: Set to "1" to avoid loading plugins - load.skip_subsongs_init: Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking. - seek.sync_samples: Set to "0" to not sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row. - subsong: The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong. - play.at_end (text): Chooses the behaviour when the end of song is reached. The song end is considered to be reached after the number of reptitions set by openmpt_module_set_repeat_count was played, so if the song is set to repeat infinitely, its end is never considered to be reached. - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames. - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the loop start (if the song is not programmed to loop, playback resumed from the song start). - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames. - play.tempo_factor: Set a floating point tempo factor. "1.0" is the default tempo. - play.pitch_factor: Set a floating point pitch factor. "1.0" is the default pitch. - render.resampler.emulate_amiga: Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. - render.resampler.emulate_amiga_type: Configures the filter type to use for the Amiga resampler. Supported values are: - "auto": Filter type is chosen by the library and might change. This is the default. - "a500": Amiga A500 filter. - "a1200": Amiga A1200 filter. - "unfiltered": BLEP synthesis without model-specific filters. The LED filter is ignored by this setting. This filter mode is considered to be experimental and might change in the future. - render.opl.volume_factor: Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume. - dither: Set the dither algorithm that is used for the 16 bit versions of openmpt_module_read. Supported values are: - 0: No dithering. - 1: Default mode. Chosen by OpenMPT code, might change. - 2: Rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker). - 3: Rectangular, 1 bit depth, simple 1st order noise shaping \remarks Use openmpt_module_get_ctls to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_get_ctls_ Alias "openmpt_module_get_ctls" (ByVal module As openmpt_module Ptr) As Const ZString Ptr /'* \brief Get current ctl value \param module The module handle to work on. \param ctl The ctl key whose value should be retrieved. \return The associated ctl value, or NULL on failure. \sa openmpt_module_get_ctls \remarks Use openmpt_module_ctl_get to automatically handle the lifetime of the returned pointer. '/ Declare Function openmpt_module_ctl_get_ Alias "openmpt_module_ctl_get" (ByVal module As openmpt_module Ptr, ByVal ctl As Const ZString Ptr) As Const ZString Ptr /'* \brief Set ctl value \param module The module handle to work on. \param ctl The ctl key whose value should be set. \param value The value that should be set. \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized. \sa openmpt_module_get_ctls '/ Declare Function openmpt_module_ctl_set(ByVal module As openmpt_module Ptr, ByVal ctl As Const ZString Ptr, ByVal value As Const ZString Ptr) As Long '* Callbacks for CRT FILE* handling Function openmpt_stream_read_func(ByVal stream As Any Ptr, ByVal dst As Any Ptr, ByVal bytes As UInteger) As UInteger Dim retval As UInteger = 0 Var f = Cast( FILE Ptr, stream ) If ( f = 0 ) Then Return 0 retval = fread( dst, 1, bytes, f ) If ( retval <= 0 ) Then Return 0 Return retval End Function '* Callbacks for CRT FILE* handling Function openmpt_stream_seek_func(ByVal stream As Any Ptr, ByVal offset As LongInt, ByVal whence As Long) As Long Var f = Cast( FILE Ptr, stream ) If ( f = 0 ) Then Return -1 Dim fwhence As Long Select Case whence Case OPENMPT_STREAM_SEEK_SET fwhence = SEEK_SET Case OPENMPT_STREAM_SEEK_CUR fwhence = SEEK_CUR Case OPENMPT_STREAM_SEEK_END fwhence = SEEK_END Case Else Return -1 End Select Return IIf(fseek( f, offset, fwhence ) <> 0, -1, 0) End Function '* Callbacks for CRT FILE* handling Function openmpt_stream_tell_func(ByVal stream As Any Ptr) As LongInt Dim retval As LongInt = 0 Var f = Cast( FILE Ptr, stream ) If ( f = 0 ) Then Return -1 EndIf retval = ftell( f ) If ( retval < 0 ) Then Return -1 Return retval End Function End Extern '* Retrieve the set of stream callbacks for CRT FILE* Function openmpt_stream_get_file_callbacks() As openmpt_stream_callbacks Static callbacks As openmpt_stream_callbacks = (@openmpt_stream_read_func, @openmpt_stream_seek_func, @openmpt_stream_tell_func) Return callbacks End Function /'* \brief Construct an openmpt_module \param file The FreeBASIC file handle to load from. \param logfunc Logging function where warning and errors are written. May be NULL. \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. Used to pass any user-defined data associated with this module to the error function. \param errorcode Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \param ctls A map of initial ctl values. See openmpt_module_get_ctls(). \return A pointer to the constructed openmpt_module, or NULL on failure. \remarks The file handle can be closed after an openmpt_module has been constructed successfully. \sa openmpt_module_create2 '/ Function openmpt_module_create_from_fbhandle2(_ ByVal file As Integer,_ ByVal logfunc As openmpt_log_func = 0,_ ByVal loguser As Any Ptr = 0,_ ByVal errfunc As openmpt_error_func = 0,_ ByVal erruser As Any Ptr = 0,_ ByVal errorcode As Long Ptr = 0,_ ByVal error_message As Const ZString Ptr Ptr = 0,_ ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr Return openmpt_module_create2(openmpt_stream_get_file_callbacks(), Cast(FILE Ptr, FileAttr(file, fbFileAttrHandle)), logfunc, loguser, errfunc, erruser, errorcode, error_message, ctls) End Function /'* \brief Construct an openmpt_module \param file The FreeBASIC file handle to load from. \param logfunc Logging function where warning and errors are written. May be NULL. \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. \param ctls A map of initial ctl values. See openmpt_module_get_ctls(). \return A pointer to the constructed openmpt_module, or NULL on failure. \remarks The file handle can be closed after an openmpt_module has been constructed successfully. \deprecated Please use openmpt_module_create_from_fbhandle2(). \sa openmpt_module_create2 '/ Function openmpt_module_create_from_fbhandle(_ ByVal file As Integer,_ ByVal logfunc As openmpt_log_func = 0,_ ByVal loguser As Any Ptr = 0,_ ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr Return openmpt_module_create_from_fbhandle2(file, logfunc, loguser, 0, 0, 0, 0, ctls) End Function /'* \brief Construct an openmpt_module \param filename The file to load from. \param logfunc Logging function where warning and errors are written. May be NULL. \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. \param errfunc Error function to define error behaviour. May be NULL. \param erruser Error function user context. Used to pass any user-defined data associated with this module to the error function. \param errorcode Pointer to an integer where an error may get stored. May be NULL. \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. \param ctls A map of initial ctl values. See openmpt_module_get_ctls(). \return A pointer to the constructed openmpt_module, or NULL on failure. \sa openmpt_module_create2 '/ Function openmpt_module_create_from_filename2(_ ByRef filename As String,_ ByVal logfunc As openmpt_log_func = 0,_ ByVal loguser As Any Ptr = 0,_ ByVal errfunc As openmpt_error_func = 0,_ ByVal erruser As Any Ptr = 0,_ ByVal errorcode As Long Ptr = 0,_ ByVal error_message As Const ZString Ptr Ptr = 0,_ ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr Var file = fopen(filename, "rb") Var retval = CPtr(openmpt_module Ptr, 0) If(file <> 0) Then retval = openmpt_module_create2(openmpt_stream_get_file_callbacks(), file, logfunc, loguser, errfunc, erruser, errorcode, error_message, ctls) fclose(file) EndIf Return retval End Function /'* \brief Construct an openmpt_module \param filename The file to load from. \param logfunc Logging function where warning and errors are written. May be NULL. \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function. \param ctls A map of initial ctl values. See openmpt_module_get_ctls(). \return A pointer to the constructed openmpt_module, or NULL on failure. \deprecated Please use openmpt_module_create_from_filename2(). \sa openmpt_module_create2 '/ Function openmpt_module_create_from_filename(_ ByRef filename As String,_ ByVal logfunc As openmpt_log_func = 0,_ ByVal loguser As Any Ptr = 0,_ ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr Return openmpt_module_create_from_filename2(filename, logfunc, loguser, 0, 0, 0, 0, ctls) End Function '* String handling for wrapping and freeing ZStrings returned by libopenmpt Function openmpt_get_zstring(sz As Const ZString Ptr) As String If(sz = 0) Then Return "" Dim As String s = *sz openmpt_free_string(sz) Return s End Function '* \sa openmpt_get_string_ Function openmpt_get_string(ByVal key As Const ZString Ptr) As String Return openmpt_get_zstring(openmpt_get_string_(key)) End Function '* \sa openmpt_error_string_ Function openmpt_error_string (ByVal errorcode As Long) As String Return openmpt_get_zstring(openmpt_error_string_(errorcode)) End Function '* \sa openmpt_module_error_get_last_message_ Function openmpt_module_error_get_last_message (ByVal module As openmpt_module Ptr) As String Return openmpt_get_zstring(openmpt_module_error_get_last_message_(module)) End Function '* \sa openmpt_module_get_metadata_keys_ Function openmpt_module_get_metadata_keys(ByVal module As openmpt_module Ptr) As String Return openmpt_get_zstring(openmpt_module_get_metadata_keys_(module)) End Function '* \sa openmpt_module_get_metadata_ Function openmpt_module_get_metadata(ByVal module As openmpt_module Ptr, ByVal key As Const ZString Ptr) As String Return openmpt_get_zstring(openmpt_module_get_metadata_(module, key)) End Function '* \sa openmpt_module_get_subsong_name_ Function openmpt_module_get_subsong_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String Return openmpt_get_zstring(openmpt_module_get_subsong_name_(module, index)) End Function '* \sa openmpt_module_get_channel_name_ Function openmpt_module_get_channel_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String Return openmpt_get_zstring(openmpt_module_get_channel_name_(module, index)) End Function '* \sa openmpt_module_get_order_name_ Function openmpt_module_get_order_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String Return openmpt_get_zstring(openmpt_module_get_order_name_(module, index)) End Function '* \sa openmpt_module_get_pattern_name_ Function openmpt_module_get_pattern_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String Return openmpt_get_zstring(openmpt_module_get_pattern_name_(module, index)) End Function '* \sa openmpt_module_get_instrument_name_ Function openmpt_module_get_instrument_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String Return openmpt_get_zstring(openmpt_module_get_instrument_name_(module, index)) End Function '* \sa openmpt_module_get_sample_name_ Function openmpt_module_get_sample_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String Return openmpt_get_zstring(openmpt_module_get_sample_name_(module, index)) End Function '* \sa openmpt_module_format_pattern_row_channel_command_ Function openmpt_module_format_pattern_row_channel_command(ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal command_ As Long) As String Return openmpt_get_zstring(openmpt_module_format_pattern_row_channel_command_(module, pattern, row, channel, command_)) End Function '* \sa openmpt_module_highlight_pattern_row_channel_command_ Function openmpt_module_highlight_pattern_row_channel_command(ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal command_ As Long) As String Return openmpt_get_zstring(openmpt_module_highlight_pattern_row_channel_command_(module, pattern, row, channel, command_)) End Function '* \sa openmpt_module_format_pattern_row_channel_ Function openmpt_module_format_pattern_row_channel(ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal width_ As UInteger, ByVal pad As Long) As String Return openmpt_get_zstring(openmpt_module_format_pattern_row_channel_(module, pattern, row, channel, width_, pad)) End Function '* \sa openmpt_module_highlight_pattern_row_channel_ Function openmpt_module_highlight_pattern_row_channel(ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal width_ As UInteger, ByVal pad As Long) As String Return openmpt_get_zstring(openmpt_module_highlight_pattern_row_channel_(module, pattern, row, channel, width_, pad)) End Function '* \sa openmpt_module_get_ctls_ Function openmpt_module_get_ctls(ByVal module As openmpt_module Ptr) As String Return openmpt_get_zstring(openmpt_module_get_ctls_(module)) End Function '* \sa openmpt_module_ctl_get_ Function openmpt_module_ctl_get(ByVal module As openmpt_module Ptr, ByVal ctl As Const ZString Ptr) As String Return openmpt_get_zstring(openmpt_module_ctl_get_(module, ctl)) End Function libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_ext.h0000644000175000017500000005236214202013343021631 00000000000000/* * libopenmpt_ext.h * ---------------- * Purpose: libopenmpt public c interface for libopenmpt extensions * Notes : * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_EXT_H #define LIBOPENMPT_EXT_H #include "libopenmpt_config.h" #include "libopenmpt.h" #ifdef __cplusplus extern "C" { #endif /*! * \page libopenmpt_ext_c_overview libopenmpt_ext C API * * libopenmpt_ext is included in all builds by default. * * \section libopenmpt-ext-c-detailed Detailed documentation * * \ref libopenmpt_ext_c * */ /*! \defgroup libopenmpt_ext_c libopenmpt_ext C */ /*! \addtogroup libopenmpt_ext_c * @{ */ /*! \brief Opaque type representing a libopenmpt extension module */ typedef struct openmpt_module_ext openmpt_module_ext; /*! \brief Construct an openmpt_module_ext * * \param stream_callbacks Input stream callback operations. * \param stream Input stream to load the module from. * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module_ext. May be NULL. * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) * \param errfunc Error function to define error behaviour. May be NULL. * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function. * \param error Pointer to an integer where an error may get stored. May be NULL. * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. * \param ctls A map of initial ctl values, see openmpt_module_get_ctls. * \return A pointer to the constructed openmpt_module_ext, or NULL on failure. * \remarks The input data can be discarded after an openmpt_module_ext has been constructed successfully. * \sa openmpt_stream_callbacks * \sa \ref libopenmpt_c_fileio * \since 0.3.0 */ LIBOPENMPT_API openmpt_module_ext * openmpt_module_ext_create( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ); /*! \brief Construct an openmpt_module_ext * * \param filedata Data to load the module from. * \param filesize Amount of data available. * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module_ext. * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc) * \param errfunc Error function to define error behaviour. May be NULL. * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function. * \param error Pointer to an integer where an error may get stored. May be NULL. * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL. * \param ctls A map of initial ctl values, see openmpt_module_get_ctls. * \return A pointer to the constructed openmpt_module_ext, or NULL on failure. * \remarks The input data can be discarded after an openmpt_module_ext has been constructed successfully. * \sa \ref libopenmpt_c_fileio * \since 0.3.0 */ LIBOPENMPT_API openmpt_module_ext * openmpt_module_ext_create_from_memory( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ); /*! \brief Unload a previously created openmpt_module_ext from memory. * * \param mod_ext The module to unload. */ LIBOPENMPT_API void openmpt_module_ext_destroy( openmpt_module_ext * mod_ext ); /*! \brief Retrieve the openmpt_module handle from an openmpt_module_ext handle. * * \param mod_ext The extension module handle to convert * \return An equivalent openmpt_module handle to pass to standard libopenmpt functions * \since 0.3.0 */ LIBOPENMPT_API openmpt_module * openmpt_module_ext_get_module( openmpt_module_ext * mod_ext ); /*! Retrieve a libopenmpt extension. * * \param mod_ext The module handle to work on. * \param interface_id The name of the extension interface to retrieve (e.g. LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS). * \param interface Appropriate structure of interface function pointers which is to be filled by this function (e.g. a pointer to a openmpt_module_ext_interface_pattern_vis structure). * \param interface_size Size of the interface's structure of function pointers (e.g. sizeof(openmpt_module_ext_interface_pattern_vis)). * \return 1 on success, 0 if the interface was not found. * \since 0.3.0 */ LIBOPENMPT_API int openmpt_module_ext_get_interface( openmpt_module_ext * mod_ext, const char * interface_id, void * interface, size_t interface_size ); #ifndef LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS #define LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS "pattern_vis" #endif /*! Pattern command type */ #define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_UNKNOWN 0 #define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_GENERAL 1 #define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_GLOBAL 2 #define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_VOLUME 3 #define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_PANNING 4 #define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_PITCH 5 typedef struct openmpt_module_ext_interface_pattern_vis { /*! Get pattern command type for pattern highlighting * * \param mod_ext The module handle to work on. * \param pattern The pattern whose data should be retrieved. * \param row The row from which the data should be retrieved. * \param channel The channel from which the data should be retrieved. * \return The command type in the effect column at the given pattern position (see OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_*) * \sa openmpt_module_ext_interface_pattern_vis::get_pattern_row_channel_volume_effect_type */ int ( * get_pattern_row_channel_volume_effect_type ) ( openmpt_module_ext * mod_ext, int32_t pattern, int32_t row, int32_t channel ); /*! Get pattern command type for pattern highlighting * * \param mod_ext The module handle to work on. * \param pattern The pattern whose data should be retrieved. * \param row The row from which the data should be retrieved. * \param channel The channel from which the data should be retrieved. * \return The command type in the effect column at the given pattern position (see OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_*) * \sa openmpt_module_ext_interface_pattern_vis::get_pattern_row_channel_volume_effect_type */ int ( * get_pattern_row_channel_effect_type ) ( openmpt_module_ext * mod_ext, int32_t pattern, int32_t row, int32_t channel ); } openmpt_module_ext_interface_pattern_vis; #ifndef LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE #define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE "interactive" #endif typedef struct openmpt_module_ext_interface_interactive { /*! Set the current ticks per row (speed) * * \param mod_ext The module handle to work on. * \param speed The new tick count in range [1, 65535]. * \return 1 on success, 0 on failure. * \remarks The tick count may be reset by pattern commands at any time. * \sa openmpt_module_get_current_speed */ int ( * set_current_speed ) ( openmpt_module_ext * mod_ext, int32_t speed ); /*! Set the current module tempo * * \param mod_ext The module handle to work on. * \param tempo The new tempo in range [32, 512]. The exact meaning of the value depends on the tempo mode used by the module. * \return 1 on success, 0 on failure. * \remarks The tempo may be reset by pattern commands at any time. Use openmpt_module_ext_interface_interactive::set_tempo_factor to apply a tempo factor that is independent of pattern commands. * \sa openmpt_module_get_current_tempo * \deprecated Please use openmpt_module_ext_interface_interactive3::set_current_tempo2(). */ LIBOPENMPT_DEPRECATED int ( * set_current_tempo ) ( openmpt_module_ext * mod_ext, int32_t tempo ); /*! Set the current module tempo factor without affecting playback pitch * * \param mod_ext The module handle to work on. * \param factor The new tempo factor in range ]0.0, 4.0] - 1.0 means unmodified tempo. * \return 1 on success, 0 on failure. * \remarks Modifying the tempo without applying the same pitch factor using openmpt_module_ext_interface_interactive::set_pitch_factor may cause rhythmic samples (e.g. drum loops) to go out of sync. * \sa openmpt_module_ext_interface_interactive::get_tempo_factor */ int ( * set_tempo_factor ) ( openmpt_module_ext * mod_ext, double factor ); /*! Gets the current module tempo factor * * \param mod_ext The module handle to work on. * \return The current tempo factor. * \sa openmpt_module_ext_interface_interactive::set_tempo_factor */ double ( * get_tempo_factor ) ( openmpt_module_ext * mod_ext ); /*! Set the current module pitch factor without affecting playback speed * * \param mod_ext The module handle to work on. * \param factor The new pitch factor in range ]0.0, 4.0] - 1.0 means unmodified pitch. * \return 1 on success, 0 on failure. * \remarks Modifying the pitch without applying the the same tempo factor using openmpt_module_ext_interface_interactive::set_tempo_factor may cause rhythmic samples (e.g. drum loops) to go out of sync. * \remarks To shift the pich by `n` semitones, the parameter can be calculated as follows: `pow( 2.0, n / 12.0 )` * \sa openmpt_module_ext_interface_interactive::get_pitch_factor */ int ( * set_pitch_factor ) ( openmpt_module_ext * mod_ext, double factor ); /*! Gets the current module pitch factor * * \param mod_ext The module handle to work on. * \return The current pitch factor. * \sa openmpt_module_ext_interface_interactive::set_pitch_factor */ double ( * get_pitch_factor ) ( openmpt_module_ext * mod_ext ); /*! Set the current global volume * * \param mod_ext The module handle to work on. * \param volume The new global volume in range [0.0, 1.0] * \return 1 on success, 0 on failure. * \remarks The global volume may be reset by pattern commands at any time. Use openmpt_module_set_render_param to apply a global overall volume factor that is independent of pattern commands. * \sa openmpt_module_ext_interface_interactive::get_global_volume */ int ( * set_global_volume ) ( openmpt_module_ext * mod_ext, double volume ); /*! Get the current global volume * * \param mod_ext The module handle to work on. * \return The current global volume in range [0.0, 1.0] * \sa openmpt_module_ext_interface_interactive::set_global_volume */ double ( * get_global_volume ) ( openmpt_module_ext * mod_ext ); /*! Set the current channel volume for a channel * * \param mod_ext The module handle to work on. * \param channel The channel whose volume should be set, in range [0, openmpt_module_get_num_channels()[ * \param volume The new channel volume in range [0.0, 1.0] * \return 1 on success, 0 on failure (channel out of range). * \remarks The channel volume may be reset by pattern commands at any time. * \sa openmpt_module_ext_interface_interactive::get_channel_volume */ int ( * set_channel_volume ) ( openmpt_module_ext * mod_ext, int32_t channel, double volume ); /*! Get the current channel volume for a channel * * \param mod_ext The module handle to work on. * \param channel The channel whose volume should be retrieved, in range [0, openmpt_module_get_num_channels()[ * \return The current channel volume in range [0.0, 1.0] * \sa openmpt_module_ext_interface_interactive::set_channel_volume */ double ( * get_channel_volume ) ( openmpt_module_ext * mod_ext, int32_t channel ); /*! Set the current mute status for a channel * * \param mod_ext The module handle to work on. * \param channel The channel whose mute status should be set, in range [0, openmpt_module_get_num_channels()[ * \param mute The new mute status. true is muted, false is unmuted. * \return 1 on success, 0 on failure (channel out of range). * \sa openmpt_module_ext_interface_interactive::get_channel_mute_status */ int ( * set_channel_mute_status ) ( openmpt_module_ext * mod_ext, int32_t channel, int mute ); /*! Get the current mute status for a channel * * \param mod_ext The module handle to work on. * \param channel The channel whose mute status should be retrieved, in range [0, openmpt_module_get_num_channels()[ * \return The current channel mute status. 1 is muted, 0 is unmuted, -1 means the instrument was out of range * \sa openmpt_module_ext_interface_interactive::set_channel_mute_status */ int ( * get_channel_mute_status ) ( openmpt_module_ext * mod_ext, int32_t channel ); /*! Set the current mute status for an instrument * * \param mod_ext The module handle to work on. * \param instrument The instrument whose mute status should be set, in range [0, openmpt_module_get_num_instruments()[ if openmpt_module_get_num_instruments is not 0, otherwise in [0, openmpt_module_get_num_samples()[ * \param mute The new mute status. true is muted, false is unmuted. * \return 1 on success, 0 on failure (instrument out of range). * \sa openmpt_module_ext_interface_interactive::get_instrument_mute_status */ int ( * set_instrument_mute_status ) ( openmpt_module_ext * mod_ext, int32_t instrument, int mute ); /*! Get the current mute status for an instrument * * \param mod_ext The module handle to work on. * \param instrument The instrument whose mute status should be retrieved, in range [0, openmpt_module_get_num_instruments()[ if openmpt_module_get_num_instruments is not 0, otherwise in [0, openmpt_module_get_num_samples()[ * \return The current instrument mute status. 1 is muted, 0 is unmuted, -1 means the instrument was out of range * \sa openmpt_module_ext_interface_interactive::set_instrument_mute_status */ int ( * get_instrument_mute_status ) ( openmpt_module_ext * mod_ext, int32_t instrument ); /*! Play a note using the specified instrument * * \param mod_ext The module handle to work on. * \param instrument The instrument that should be played, in range [0, openmpt_module_get_num_instruments()[ if openmpt_module_get_num_instruments is not 0, otherwise in [0, openmpt_module_get_num_samples()[ * \param note The note to play, in rage [0, 119]. 60 is the middle C. * \param volume The volume at which the note should be triggered, in range [0.0, 1.0] * \param panning The panning position at which the note should be triggered, in range [-1.0, 1.0], 0.0 is center. * \return The channel on which the note is played. This can pe be passed to openmpt_module_ext_interface_interactive::stop_note to stop the note. -1 means that no channel could be allocated and the note is not played. * \sa openmpt_module_ext_interface_interactive::stop_note * \sa openmpt_module_ext_interface_interactive2::note_off * \sa openmpt_module_ext_interface_interactive2::note_fade */ int32_t ( * play_note ) ( openmpt_module_ext * mod_ext, int32_t instrument, int32_t note, double volume, double panning ); /*! Stop the note playing on the specified channel * * \param mod_ext The module handle to work on. * \param channel The channel on which the note should be stopped. This is the value returned by a previous play_note call. * \return 1 on success, 0 on failure (channel out of range). * \sa openmpt_module_ext_interface_interactive::play_note * \sa openmpt_module_ext_interface_interactive2::note_off * \sa openmpt_module_ext_interface_interactive2::note_fade */ int ( * stop_note ) ( openmpt_module_ext * mod_ext, int32_t channel ); } openmpt_module_ext_interface_interactive; #ifndef LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE2 #define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE2 "interactive2" #endif typedef struct openmpt_module_ext_interface_interactive2 { //! Sends a key-off command for the note playing on the specified channel /*! * \param mod_ext The module handle to work on. * \param channel The channel on which the key-off event should be triggered. This is the value returned by a previous play_note call. * \return 1 on success, 0 on failure (channel out of range). * \remarks This method releases envelopes and sample sustain loops. If the sample has no sustain loop, or if the module does not use instruments, it does nothing. * \sa openmpt_module_ext_interface_interactive::play_note * \sa openmpt_module_ext_interface_interactive::stop_note * \sa openmpt_module_ext_interface_interactive2::note_fade * \since 0.6.0 */ int ( *note_off ) ( openmpt_module_ext * mod_ext, int32_t channel ); //! Sends a note fade command for the note playing on the specified channel /*! * \param mod_ext The module handle to work on. * \param channel The channel on which the note should be faded. This is the value returned by a previous play_note call. * \return 1 on success, 0 on failure (channel out of range). * \remarks This method uses the instrument's fade-out value. If the module does not use instruments, or the instrument's fade-out value is 0, it does nothing. * \sa openmpt_module_ext_interface_interactive::play_note * \sa openmpt_module_ext_interface_interactive::stop_note * \sa openmpt_module_ext_interface_interactive2::note_fade * \since 0.6.0 */ int ( *note_fade ) ( openmpt_module_ext * mod_ext, int32_t channel ); //! Set the current panning for a channel /*! * \param mod_ext The module handle to work on. * \param channel The channel that should be panned. This is the value returned by a previous play_note call. * \param panning The panning position to set on the channel, in range [-1.0, 1.0], 0.0 is center. * \return 1 on success, 0 on failure (channel out of range). * \remarks This command affects subsequent notes played on the same channel, and may itself be overridden by subsequent panning commands encountered in the module itself. * \sa openmpt_module_ext_interface_interactive2::get_channel_panning * \since 0.6.0 */ int ( *set_channel_panning) ( openmpt_module_ext * mod_ext, int32_t channel, double panning ); //! Get the current panning position for a channel /*! * \param mod_ext The module handle to work on. * \param channel The channel whose panning should be retrieved. This is the value returned by a previous play_note call. * \return The current channel panning, in range [-1.0, 1.0], 0.0 is center. * \sa openmpt_module_ext_interface_interactive2::set_channel_panning * \since 0.6.0 */ double (*get_channel_panning) ( openmpt_module_ext * mod_ext, int32_t channel ); //! Set the finetune for the currently playing note on a channel /*! * \param mod_ext The module handle to work on. * \param channel The channel whose finetune will be changed, in range [0, openmpt::module::get_num_channels()[ * \param finetune The finetune to set on the channel, in range [-1.0, 1.0], 0.0 is center. * \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid. * \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone. * \remarks This command does not affect subsequent notes played on the same channel, but may itself be overridden by subsequent finetune commands encountered in the module itself. * \sa openmpt_module_ext_interface_interactive2::get_note_finetune * \since 0.6.0 */ int ( *set_note_finetune) ( openmpt_module_ext * mod_ext, int32_t channel, double finetune ); //! Get the finetune for the currently playing note on a channel /*! * \param mod_ext The module handle to work on. * \param channel The channel whose finetune should be retrieved, in range [0, openmpt::module::get_num_channels()[ * \return The current channel finetune, in range [-1.0, 1.0], 0.0 is center. * \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone. * \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range. * \sa openmpt_module_ext_interface_interactive2::set_note_finetune * \since 0.6.0 */ double (*get_note_finetune) ( openmpt_module_ext * mod_ext, int32_t channel ); } openmpt_module_ext_interface_interactive2; #ifndef LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE3 #define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE3 "interactive3" #endif typedef struct openmpt_module_ext_interface_interactive3 { /*! Set the current module tempo * * \param mod_ext The module handle to work on. * \param tempo The new tempo in range [32, 512]. The exact meaning of the value depends on the tempo mode used by the module. * \return 1 on success, 0 on failure. * \remarks The tempo may be reset by pattern commands at any time. Use openmpt_module_ext_interface_interactive::set_tempo_factor to apply a tempo factor that is independent of pattern commands. * \sa openmpt_module_get_current_tempo2 */ int ( * set_current_tempo2 ) ( openmpt_module_ext * mod_ext, double tempo ); } openmpt_module_ext_interface_interactive3; /* add stuff here */ #ifdef __cplusplus } #endif /*! * @} */ #endif /* LIBOPENMPT_EXT_H */ libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_cxx.cpp0000644000175000017500000004635114705170364022206 00000000000000/* * libopenmpt_cxx.cpp * ------------------ * Purpose: libopenmpt C++ interface implementation * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "openmpt/all/BuildSettings.hpp" #if defined(__MINGW32__) && !defined(__MINGW64__) #include #endif #include "libopenmpt_internal.h" #include "libopenmpt.hpp" #include "libopenmpt_ext.hpp" #include "libopenmpt_impl.hpp" #include "libopenmpt_ext_impl.hpp" #include #include #include #include namespace openmpt { exception::exception( const std::string & text_ ) noexcept : std::exception() , text(0) { text = static_cast( std::malloc( text_.length() + 1 ) ); if ( text ) { std::memcpy( text, text_.c_str(), text_.length() + 1 ); } } exception::exception( const exception & other ) noexcept : std::exception() , text(0) { const char * const text_ = ( other.what() ? other.what() : "" ); text = static_cast( std::malloc( std::strlen( text_ ) + 1 ) ); if ( text ) { std::memcpy( text, text_, std::strlen( text_ ) + 1 ); } } exception::exception( exception && other ) noexcept : std::exception() , text(0) { text = std::move( other.text ); other.text = 0; } exception & exception::operator = ( const exception & other ) noexcept { if ( this == &other ) { return *this; } if ( text ) { std::free( text ); text = 0; } const char * const text_ = ( other.what() ? other.what() : "" ); text = static_cast( std::malloc( std::strlen( text_ ) + 1 ) ); if ( text ) { std::memcpy( text, text_, std::strlen( text_ ) + 1 ); } return *this; } exception & exception::operator = ( exception && other ) noexcept { if ( this == &other ) { return *this; } if ( text ) { std::free( text ); text = 0; } text = std::move( other.text ); other.text = 0; return *this; } exception::~exception() noexcept { if ( text ) { std::free( text ); text = 0; } } const char * exception::what() const noexcept { if ( text ) { return text; } else { return "out of memory"; } } std::uint32_t get_library_version() { return openmpt::version::get_library_version(); } std::uint32_t get_core_version() { return openmpt::version::get_core_version(); } namespace string { std::string get( const std::string & key ) { return openmpt::version::get_string( key ); } } // namespace string } // namespace openmpt namespace openmpt { std::vector get_supported_extensions() { return openmpt::module_impl::get_supported_extensions(); } bool is_extension_supported( const std::string & extension ) { return openmpt::module_impl::is_extension_supported( extension ); } bool is_extension_supported2( std::string_view extension ) { return openmpt::module_impl::is_extension_supported( extension ); } double could_open_probability( std::istream & stream, double effort, std::ostream & log ) { return openmpt::module_impl::could_open_probability( stream, effort, openmpt::helper::make_unique( log ) ); } double could_open_propability( std::istream & stream, double effort, std::ostream & log ) { return openmpt::module_impl::could_open_probability( stream, effort, openmpt::helper::make_unique( log ) ); } std::size_t probe_file_header_get_recommended_size() { return openmpt::module_impl::probe_file_header_get_recommended_size(); } int probe_file_header( std::uint64_t flags, const std::byte * data, std::size_t size, std::uint64_t filesize ) { return openmpt::module_impl::probe_file_header( flags, data, size, filesize ); } int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size, std::uint64_t filesize ) { return openmpt::module_impl::probe_file_header( flags, data, size, filesize ); } int probe_file_header( std::uint64_t flags, const std::byte * data, std::size_t size ) { return openmpt::module_impl::probe_file_header( flags, data, size ); } int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size ) { return openmpt::module_impl::probe_file_header( flags, data, size ); } int probe_file_header( std::uint64_t flags, std::istream & stream ) { return openmpt::module_impl::probe_file_header( flags, stream ); } #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4702) // unreachable code #endif // _MSC_VER module::module( const module & ) : impl(nullptr) { throw exception("openmpt::module is non-copyable"); } // cppcheck-suppress operatorEqVarError void module::operator = ( const module & ) { throw exception("openmpt::module is non-copyable"); } #if defined(_MSC_VER) #pragma warning(pop) #endif // _MSC_VER module::module() : impl(0) { return; } void module::set_impl( module_impl * i ) { impl = i; } module::module( std::istream & stream, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) { impl = new module_impl( stream, openmpt::helper::make_unique( log ), ctls ); } module::module( const std::vector & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) { impl = new module_impl( data, openmpt::helper::make_unique( log ), ctls ); } module::module( const std::byte * beg, const std::byte * end, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) { impl = new module_impl( beg, end - beg, openmpt::helper::make_unique( log ), ctls ); } module::module( const std::byte * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) { impl = new module_impl( data, size, openmpt::helper::make_unique( log ), ctls ); } module::module( const std::vector & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) { impl = new module_impl( data, openmpt::helper::make_unique( log ), ctls ); } module::module( const std::uint8_t * beg, const std::uint8_t * end, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) { impl = new module_impl( beg, end - beg, openmpt::helper::make_unique( log ), ctls ); } module::module( const std::uint8_t * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) { impl = new module_impl( data, size, openmpt::helper::make_unique( log ), ctls ); } module::module( const std::vector & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) { impl = new module_impl( data, openmpt::helper::make_unique( log ), ctls ); } module::module( const char * beg, const char * end, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) { impl = new module_impl( beg, end - beg, openmpt::helper::make_unique( log ), ctls ); } module::module( const char * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) { impl = new module_impl( data, size, openmpt::helper::make_unique( log ), ctls ); } module::module( const void * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) { impl = new module_impl( data, size, openmpt::helper::make_unique( log ), ctls ); } module::~module() { delete impl; impl = 0; } void module::select_subsong( std::int32_t subsong ) { impl->select_subsong( subsong ); } std::int32_t module::get_selected_subsong() const { return impl->get_selected_subsong(); } std::int32_t module::get_restart_order( std::int32_t subsong ) const { return impl->get_restart_order( subsong ); } std::int32_t module::get_restart_row( std::int32_t subsong ) const { return impl->get_restart_row( subsong ); } void module::set_repeat_count( std::int32_t repeat_count ) { impl->set_repeat_count( repeat_count ); } std::int32_t module::get_repeat_count() const { return impl->get_repeat_count(); } double module::get_duration_seconds() const { return impl->get_duration_seconds(); } double module::get_time_at_position( std::int32_t order, std::int32_t row ) const { return impl->get_time_at_position( order, row ); } double module::set_position_seconds( double seconds ) { return impl->set_position_seconds( seconds ); } double module::get_position_seconds() const { return impl->get_position_seconds(); } double module::set_position_order_row( std::int32_t order, std::int32_t row ) { return impl->set_position_order_row( order, row ); } std::int32_t module::get_render_param( int param ) const { return impl->get_render_param( param ); } void module::set_render_param( int param, std::int32_t value ) { impl->set_render_param( param, value ); } std::size_t module::read( std::int32_t samplerate, std::size_t count, std::int16_t * mono ) { return impl->read( samplerate, count, mono ); } std::size_t module::read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right ) { return impl->read( samplerate, count, left, right ); } std::size_t module::read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right ) { return impl->read( samplerate, count, left, right, rear_left, rear_right ); } std::size_t module::read( std::int32_t samplerate, std::size_t count, float * mono ) { return impl->read( samplerate, count, mono ); } std::size_t module::read( std::int32_t samplerate, std::size_t count, float * left, float * right ) { return impl->read( samplerate, count, left, right ); } std::size_t module::read( std::int32_t samplerate, std::size_t count, float * left, float * right, float * rear_left, float * rear_right ) { return impl->read( samplerate, count, left, right, rear_left, rear_right ); } std::size_t module::read_interleaved_stereo( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_stereo ) { return impl->read_interleaved_stereo( samplerate, count, interleaved_stereo ); } std::size_t module::read_interleaved_quad( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_quad ) { return impl->read_interleaved_quad( samplerate, count, interleaved_quad ); } std::size_t module::read_interleaved_stereo( std::int32_t samplerate, std::size_t count, float * interleaved_stereo ) { return impl->read_interleaved_stereo( samplerate, count, interleaved_stereo ); } std::size_t module::read_interleaved_quad( std::int32_t samplerate, std::size_t count, float * interleaved_quad ) { return impl->read_interleaved_quad( samplerate, count, interleaved_quad ); } std::vector module::get_metadata_keys() const { return impl->get_metadata_keys(); } std::string module::get_metadata( const std::string & key ) const { return impl->get_metadata( key ); } double module::get_current_estimated_bpm() const { return impl->get_current_estimated_bpm(); } std::int32_t module::get_current_speed() const { return impl->get_current_speed(); } std::int32_t module::get_current_tempo() const { return impl->get_current_tempo(); } double module::get_current_tempo2() const { return impl->get_current_tempo2(); } std::int32_t module::get_current_order() const { return impl->get_current_order(); } std::int32_t module::get_current_pattern() const { return impl->get_current_pattern(); } std::int32_t module::get_current_row() const { return impl->get_current_row(); } std::int32_t module::get_current_playing_channels() const { return impl->get_current_playing_channels(); } float module::get_current_channel_vu_mono( std::int32_t channel ) const { return impl->get_current_channel_vu_mono( channel ); } float module::get_current_channel_vu_left( std::int32_t channel ) const { return impl->get_current_channel_vu_left( channel ); } float module::get_current_channel_vu_right( std::int32_t channel ) const { return impl->get_current_channel_vu_right( channel ); } float module::get_current_channel_vu_rear_left( std::int32_t channel ) const { return impl->get_current_channel_vu_rear_left( channel ); } float module::get_current_channel_vu_rear_right( std::int32_t channel ) const { return impl->get_current_channel_vu_rear_right( channel ); } std::int32_t module::get_num_subsongs() const { return impl->get_num_subsongs(); } std::int32_t module::get_num_channels() const { return impl->get_num_channels(); } std::int32_t module::get_num_orders() const { return impl->get_num_orders(); } std::int32_t module::get_num_patterns() const { return impl->get_num_patterns(); } std::int32_t module::get_num_instruments() const { return impl->get_num_instruments(); } std::int32_t module::get_num_samples() const { return impl->get_num_samples(); } std::vector module::get_subsong_names() const { return impl->get_subsong_names(); } std::vector module::get_channel_names() const { return impl->get_channel_names(); } std::vector module::get_order_names() const { return impl->get_order_names(); } std::vector module::get_pattern_names() const { return impl->get_pattern_names(); } std::vector module::get_instrument_names() const { return impl->get_instrument_names(); } std::vector module::get_sample_names() const { return impl->get_sample_names(); } std::int32_t module::get_order_pattern( std::int32_t order ) const { return impl->get_order_pattern( order ); } bool module::is_order_skip_entry(std::int32_t order) const { return impl->is_order_skip_entry( order ); } bool module::is_pattern_skip_item( std::int32_t pattern ) const { return module_impl::is_pattern_skip_item( pattern ); } bool module::is_order_stop_entry( std::int32_t order ) const { return impl->is_order_stop_entry( order ); } bool module::is_pattern_stop_item( std::int32_t pattern ) const { return module_impl::is_pattern_stop_item( pattern ); } std::int32_t module::get_pattern_num_rows( std::int32_t pattern ) const { return impl->get_pattern_num_rows( pattern ); } std::int32_t module::get_pattern_rows_per_beat( std::int32_t pattern ) const { return impl->get_pattern_rows_per_beat( pattern ); } std::int32_t module::get_pattern_rows_per_measure( std::int32_t pattern ) const { return impl->get_pattern_rows_per_measure( pattern ); } std::uint8_t module::get_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const { return impl->get_pattern_row_channel_command( pattern, row, channel, command ); } std::string module::format_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const { return impl->format_pattern_row_channel_command( pattern, row, channel, command ); } std::string module::highlight_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const { return impl->highlight_pattern_row_channel_command( pattern, row, channel, command ); } std::string module::format_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width, bool pad ) const { return impl->format_pattern_row_channel( pattern, row, channel, width, pad ); } std::string module::highlight_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width, bool pad ) const { return impl->highlight_pattern_row_channel( pattern, row, channel, width, pad ); } std::vector module::get_ctls() const { return impl->get_ctls(); } std::string module::ctl_get( const std::string & ctl ) const { return impl->ctl_get( ctl ); } bool module::ctl_get_boolean( std::string_view ctl ) const { return impl->ctl_get_boolean( ctl ); } std::int64_t module::ctl_get_integer( std::string_view ctl ) const { return impl->ctl_get_integer( ctl ); } double module::ctl_get_floatingpoint( std::string_view ctl ) const { return impl->ctl_get_floatingpoint( ctl ); } std::string module::ctl_get_text( std::string_view ctl ) const { return impl->ctl_get_text( ctl ); } void module::ctl_set( const std::string & ctl, const std::string & value ) { impl->ctl_set( ctl, value ); } void module::ctl_set_boolean( std::string_view ctl, bool value ) { impl->ctl_set_boolean( ctl, value ); } void module::ctl_set_integer( std::string_view ctl, std::int64_t value ) { impl->ctl_set_integer( ctl, value ); } void module::ctl_set_floatingpoint( std::string_view ctl, double value ) { impl->ctl_set_floatingpoint( ctl, value ); } void module::ctl_set_text( std::string_view ctl, std::string_view value ) { impl->ctl_set_text( ctl, value ); } module_ext::module_ext( std::istream & stream, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) { ext_impl = new module_ext_impl( stream, openmpt::helper::make_unique( log ), ctls ); set_impl( ext_impl ); } module_ext::module_ext( const std::vector & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) { ext_impl = new module_ext_impl( data, openmpt::helper::make_unique( log ), ctls ); set_impl( ext_impl ); } module_ext::module_ext( const std::vector & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) { ext_impl = new module_ext_impl( data, openmpt::helper::make_unique( log ), ctls ); set_impl( ext_impl ); } module_ext::module_ext( const std::vector & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) { ext_impl = new module_ext_impl( data, openmpt::helper::make_unique( log ), ctls ); set_impl( ext_impl ); } module_ext::module_ext( const std::uint8_t * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) { ext_impl = new module_ext_impl( data, size, openmpt::helper::make_unique( log ), ctls ); set_impl( ext_impl ); } module_ext::module_ext( const char * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) { ext_impl = new module_ext_impl( data, size, openmpt::helper::make_unique( log ), ctls ); set_impl( ext_impl ); } module_ext::module_ext( const std::byte * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) { ext_impl = new module_ext_impl( data, size, openmpt::helper::make_unique( log ), ctls ); set_impl( ext_impl ); } module_ext::module_ext( const void * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) { ext_impl = new module_ext_impl( data, size, openmpt::helper::make_unique( log ), ctls ); set_impl( ext_impl ); } module_ext::~module_ext() { set_impl( 0 ); delete ext_impl; ext_impl = 0; } #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4702) // unreachable code #endif // _MSC_VER module_ext::module_ext( const module_ext & other ) : module(other), ext_impl(nullptr) { throw std::runtime_error("openmpt::module_ext is non-copyable"); } // cppcheck-suppress operatorEqVarError void module_ext::operator = ( const module_ext & ) { throw std::runtime_error("openmpt::module_ext is non-copyable"); } #if defined(_MSC_VER) #pragma warning(pop) #endif // _MSC_VER void * module_ext::get_interface( const std::string & interface_id ) { return ext_impl->get_interface( interface_id ); } } // namespace openmpt libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_stream_callbacks_file.h0000644000175000017500000001031214172233672025326 00000000000000/* * libopenmpt_stream_callbacks_file.h * ---------------------------------- * Purpose: libopenmpt public c interface * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_STREAM_CALLBACKS_FILE_H #define LIBOPENMPT_STREAM_CALLBACKS_FILE_H #include "libopenmpt.h" #include #include #include /*! \addtogroup libopenmpt_c * @{ */ #ifdef __cplusplus extern "C" { #endif /* This stuff has to be in a header file because of possibly different MSVC CRTs which cause problems for FILE * crossing CRT boundaries. */ static size_t openmpt_stream_file_read_func( void * stream, void * dst, size_t bytes ) { FILE * f = 0; size_t retval = 0; f = (FILE*)stream; if ( !f ) { return 0; } retval = fread( dst, 1, bytes, f ); if ( retval <= 0 ) { return 0; } return retval; } static int openmpt_stream_file_seek_func( void * stream, int64_t offset, int whence ) { FILE * f = 0; int fwhence = 0; f = (FILE*)stream; if ( !f ) { return -1; } switch ( whence ) { case OPENMPT_STREAM_SEEK_SET: fwhence = SEEK_SET; break; case OPENMPT_STREAM_SEEK_CUR: fwhence = SEEK_CUR; break; case OPENMPT_STREAM_SEEK_END: fwhence = SEEK_END; break; default: return -1; break; } if ( (long)offset != offset ) { return -1; } return fseek( f, (long)offset, fwhence ) ? -1 : 0; } static int64_t openmpt_stream_file_tell_func( void * stream ) { FILE * f = 0; long result = 0; int64_t retval = 0; f = (FILE*)stream; if ( !f ) { return -1; } result = ftell( f ); if ( (int64_t)result != result ) { return -1; } retval = (int64_t)result; if ( retval < 0 ) { return -1; } return retval; } /*! \brief Provide openmpt_stream_callbacks for standard C FILE objects * * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. * Since 0.7.0, it does not try to use platform-specific file seeking any more, * but sticks to standard C fseek/ftell only, which means on platforms where * long is 32bit, there is no 64bit file access possible any more. * * \remarks The stream argument must be passed as `(void*)(FILE*)file`. * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \sa openmpt_could_open_probability2 * \sa openmpt_probe_file_header_from_stream * \sa openmpt_module_create2 * \sa openmpt_stream_get_file_callbacks2() * \sa openmpt_stream_get_file_mingw_callbacks() * \sa openmpt_stream_get_file_msvcrt_callbacks() * \sa openmpt_stream_get_file_posix_callbacks() * \sa openmpt_stream_get_file_posix_lfs64_callbacks() * \deprecated Please use openmpt_stream_get_file_callbacks2(). */ LIBOPENMPT_DEPRECATED static LIBOPENMPT_C_INLINE openmpt_stream_callbacks openmpt_stream_get_file_callbacks(void) { openmpt_stream_callbacks retval; memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); retval.read = openmpt_stream_file_read_func; retval.seek = openmpt_stream_file_seek_func; retval.tell = openmpt_stream_file_tell_func; return retval; } /*! \brief Provide openmpt_stream_callbacks for standard C FILE objects * * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. * This function uses the standard C fseek and ftell, thus platform-specific file size limits apply accordingly. * * \remarks The stream argument must be passed as `(void*)(FILE*)file`. * \remarks The provided callbacks are limited to handling files up to the size representable in the platform's long type. * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \sa openmpt_could_open_probability2 * \sa openmpt_probe_file_header_from_stream * \sa openmpt_module_create2 * \since 0.7.0 */ static openmpt_stream_callbacks openmpt_stream_get_file_callbacks2(void) { openmpt_stream_callbacks retval; memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); retval.read = openmpt_stream_file_read_func; retval.seek = openmpt_stream_file_seek_func; retval.tell = openmpt_stream_file_tell_func; return retval; } #ifdef __cplusplus } #endif /*! * @} */ #endif /* LIBOPENMPT_STREAM_CALLBACKS_FILE_H */ libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_ext.hpp0000644000175000017500000004633114320233106022172 00000000000000/* * libopenmpt_ext.hpp * ------------------ * Purpose: libopenmpt public c++ interface for libopenmpt extensions * Notes : * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_EXT_HPP #define LIBOPENMPT_EXT_HPP #include "libopenmpt_config.h" #include "libopenmpt.hpp" /*! * \page libopenmpt_ext_cpp_overview libopenmpt_ext C++ API * * libopenmpt_ext is now included in all builds by default. * * \section libopenmpt-ext-cpp-detailed Detailed documentation * * \ref libopenmpt_ext_cpp * */ /*! \defgroup libopenmpt_ext_cpp libopenmpt_ext C++ */ namespace openmpt { /*! \addtogroup libopenmpt_ext_cpp @{ */ class module_ext_impl; class LIBOPENMPT_CXX_API_CLASS module_ext : public module { private: module_ext_impl * ext_impl; private: // non-copyable LIBOPENMPT_CXX_API_MEMBER module_ext( const module_ext & ); LIBOPENMPT_CXX_API_MEMBER void operator = ( const module_ext & ); public: LIBOPENMPT_CXX_API_MEMBER module_ext( std::istream & stream, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); LIBOPENMPT_CXX_API_MEMBER module_ext( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); LIBOPENMPT_CXX_API_MEMBER module_ext( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); LIBOPENMPT_CXX_API_MEMBER module_ext( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); LIBOPENMPT_CXX_API_MEMBER module_ext( const std::byte * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); LIBOPENMPT_CXX_API_MEMBER module_ext( const std::uint8_t * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); LIBOPENMPT_CXX_API_MEMBER module_ext( const char * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); LIBOPENMPT_CXX_API_MEMBER module_ext( const void * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); LIBOPENMPT_CXX_API_MEMBER virtual ~module_ext(); public: //! Retrieve a libopenmpt extension. /*! Example: Retrieving the interactive extension to change the tempo of a module: \code{.cpp} openmpt::module_ext *mod = new openmpt::module_ext( stream ); #ifdef LIBOPENMPT_EXT_INTERFACE_INTERACTIVE openmpt::ext::interactive *interactive = static_cast( self->mod->get_interface( openmpt::ext::interactive_id ) ); if ( interactive ) { interactive->set_tempo_factor( 2.0 ); // play module at double speed } else { // interface not available } #else // interfae not available #endif \endcode \param interface_id The name of the extension interface to retrieve. \return The interface object. This may be a nullptr if the extension was not found. */ LIBOPENMPT_CXX_API_MEMBER void * get_interface( const std::string & interface_id ); }; // class module_ext /*! @} */ namespace ext { /*! \addtogroup libopenmpt_ext_cpp @{ */ #define LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(name) \ static const char name ## _id [] = # name ; \ class name; \ /**/ #define LIBOPENMPT_EXT_CXX_INTERFACE(name) \ protected: \ name () {} \ virtual ~ name () {} \ public: \ /**/ #ifndef LIBOPENMPT_EXT_INTERFACE_PATTERN_VIS #define LIBOPENMPT_EXT_INTERFACE_PATTERN_VIS #endif LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(pattern_vis) class pattern_vis { LIBOPENMPT_EXT_CXX_INTERFACE(pattern_vis) //! Pattern command type enum effect_type { effect_unknown = 0, effect_general = 1, effect_global = 2, effect_volume = 3, effect_panning = 4, effect_pitch = 5 }; // enum effect_type //! Get pattern command type for pattern highlighting /*! \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \return The command type in the effect column at the given pattern position (see openmpt::ext::pattern_vis::effect_type) \sa openmpt::ext::pattern_vis::get_pattern_row_channel_effect_type */ virtual effect_type get_pattern_row_channel_volume_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const = 0; //! Get pattern command type for pattern highlighting /*! \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \return The command type in the volume column at the given pattern position (see openmpt::ext::pattern_vis::effect_type) \sa openmpt::ext::pattern_vis::get_pattern_row_channel_volume_effect_type */ virtual effect_type get_pattern_row_channel_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const = 0; }; // class pattern_vis #ifndef LIBOPENMPT_EXT_INTERFACE_INTERACTIVE #define LIBOPENMPT_EXT_INTERFACE_INTERACTIVE #endif LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(interactive) class interactive { LIBOPENMPT_EXT_CXX_INTERFACE(interactive) //! Set the current ticks per row (speed) /*! \param speed The new tick count in range [1, 65535]. \throws openmpt::exception Throws an exception derived from openmpt::exception if the speed is outside the specified range. \remarks The tick count may be reset by pattern commands at any time. \sa openmpt::module::get_current_speed */ virtual void set_current_speed( std::int32_t speed ) = 0; //! Set the current module tempo /*! \param tempo The new tempo in range [32, 512]. The exact meaning of the value depends on the tempo mode used by the module. \throws openmpt::exception Throws an exception derived from openmpt::exception if the tempo is outside the specified range. \remarks The tempo may be reset by pattern commands at any time. Use openmpt::ext:interactive::set_tempo_factor to apply a tempo factor that is independent of pattern commands. \sa openmpt::module::get_current_tempo \deprecated Please use openmpt::ext::interactive3::set_current_tempo2(). */ LIBOPENMPT_ATTR_DEPRECATED virtual void set_current_tempo( std::int32_t tempo ) = 0; //! Set the current module tempo factor without affecting playback pitch /*! \param factor The new tempo factor in range ]0.0, 4.0] - 1.0 means unmodified tempo. \throws openmpt::exception Throws an exception derived from openmpt::exception if the factor is outside the specified range. \remarks Modifying the tempo without applying the same pitch factor using openmpt::ext::interactive::set_pitch_factor may cause rhythmic samples (e.g. drum loops) to go out of sync. \sa openmpt::ext::interactive::get_tempo_factor */ virtual void set_tempo_factor( double factor ) = 0; //! Gets the current module tempo factor /*! \return The current tempo factor. \sa openmpt::ext::interactive::set_tempo_factor */ virtual double get_tempo_factor( ) const = 0; //! Set the current module pitch factor without affecting playback speed /*! \param factor The new pitch factor in range ]0.0, 4.0] - 1.0 means unmodified pitch. \throws openmpt::exception Throws an exception derived from openmpt::exception if the factor is outside the specified range. \remarks Modifying the pitch without applying the the same tempo factor using openmpt::ext::interactive::set_tempo_factor may cause rhythmic samples (e.g. drum loops) to go out of sync. \remarks To shift the pich by `n` semitones, the parameter can be calculated as follows: `pow( 2.0, n / 12.0 )` \sa openmpt::ext::interactive::get_pitch_factor */ virtual void set_pitch_factor( double factor ) = 0; //! Gets the current module pitch factor /*! \return The current pitch factor. \throws openmpt::exception Throws an exception derived from openmpt::exception if the pitch is outside the specified range. \sa openmpt::ext::interactive::set_pitch_factor */ virtual double get_pitch_factor( ) const = 0; //! Set the current global volume /*! \param volume The new global volume in range [0.0, 1.0] \throws openmpt::exception Throws an exception derived from openmpt::exception if the volume is outside the specified range. \remarks The global volume may be reset by pattern commands at any time. Use openmpt::module::set_render_param to apply a global overall volume factor that is independent of pattern commands. \sa openmpt::ext::interactive::get_global_volume */ virtual void set_global_volume( double volume ) = 0; //! Get the current global volume /*! \return The current global volume in range [0.0, 1.0] \sa openmpt::ext::interactive::set_global_volume */ virtual double get_global_volume( ) const = 0; //! Set the current channel volume for a channel /*! \param channel The channel whose volume should be set, in range [0, openmpt::module::get_num_channels()[ \param volume The new channel volume in range [0.0, 1.0] \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel or volume is outside the specified range. \remarks The channel volume may be reset by pattern commands at any time. \sa openmpt::ext::interactive::get_channel_volume */ virtual void set_channel_volume( std::int32_t channel, double volume ) = 0; //! Get the current channel volume for a channel /*! \param channel The channel whose volume should be retrieved, in range [0, openmpt::module::get_num_channels()[ \return The current channel volume in range [0.0, 1.0] \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range. \sa openmpt::ext::interactive::set_channel_volume */ virtual double get_channel_volume( std::int32_t channel ) const = 0; //! Set the current mute status for a channel /*! \param channel The channel whose mute status should be set, in range [0, openmpt::module::get_num_channels()[ \param mute The new mute status. true is muted, false is unmuted. \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range. \sa openmpt::ext::interactive::get_channel_mute_status */ virtual void set_channel_mute_status( std::int32_t channel, bool mute ) = 0; //! Get the current mute status for a channel /*! \param channel The channel whose mute status should be retrieved, in range [0, openmpt::module::get_num_channels()[ \return The current channel mute status. true is muted, false is unmuted. \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range. \sa openmpt::ext::interactive::set_channel_mute_status */ virtual bool get_channel_mute_status( std::int32_t channel ) const = 0; //! Set the current mute status for an instrument /*! \param instrument The instrument whose mute status should be set, in range [0, openmpt::module::get_num_instruments()[ if openmpt::module::get_num_instruments is not 0, otherwise in [0, openmpt::module::get_num_samples()[ \param mute The new mute status. true is muted, false is unmuted. \throws openmpt::exception Throws an exception derived from openmpt::exception if the instrument is outside the specified range. \sa openmpt::ext::interactive::get_instrument_mute_status */ virtual void set_instrument_mute_status( std::int32_t instrument, bool mute ) = 0; //! Get the current mute status for an instrument /*! \param instrument The instrument whose mute status should be retrieved, in range [0, openmpt::module::get_num_instruments()[ if openmpt::module::get_num_instruments is not 0, otherwise in [0, openmpt::module::get_num_samples()[ \return The current instrument mute status. true is muted, false is unmuted. \throws openmpt::exception Throws an exception derived from openmpt::exception if the instrument is outside the specified range. \sa openmpt::ext::interactive::set_instrument_mute_status */ virtual bool get_instrument_mute_status( std::int32_t instrument ) const = 0; //! Play a note using the specified instrument /*! \param instrument The instrument that should be played, in range [0, openmpt::module::get_num_instruments()[ if openmpt::module::get_num_instruments is not 0, otherwise in [0, openmpt::module::get_num_samples()[ \param note The note to play, in rage [0, 119]. 60 is the middle C. \param volume The volume at which the note should be triggered, in range [0.0, 1.0] \param panning The panning position at which the note should be triggered, in range [-1.0, 1.0], 0.0 is center. \return The channel on which the note is played. This can pe be passed to openmpt::ext::interactive::stop_note to stop the note. \throws openmpt::exception Throws an exception derived from openmpt::exception if the instrument or note is outside the specified range. \sa openmpt::ext::interactive::stop_note \sa openmpt::ext::interactive2::note_off \sa openmpt::ext::interactive2::note_fade */ virtual std::int32_t play_note( std::int32_t instrument, std::int32_t note, double volume, double panning ) = 0; //! Stop the note playing on the specified channel /*! \param channel The channel on which the note should be stopped. This is the value returned by a previous play_note call. \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid. \sa openmpt::ext::interactive::play_note \sa openmpt::ext::interactive2::note_off \sa openmpt::ext::interactive2::note_fade */ virtual void stop_note( std::int32_t channel ) = 0; }; // class interactive #ifndef LIBOPENMPT_EXT_INTERFACE_INTERACTIVE2 #define LIBOPENMPT_EXT_INTERFACE_INTERACTIVE2 #endif LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(interactive2) class interactive2 { LIBOPENMPT_EXT_CXX_INTERFACE(interactive2) //! Sends a key-off command for the note playing on the specified channel /*! \param channel The channel on which the key-off event should be triggered. This is the value returned by a previous play_note call. \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid. \remarks This method releases envelopes and sample sustain loops. If the sample has no sustain loop, or if the module does not use instruments, it does nothing. \sa openmpt::ext::interactive::play_note \sa openmpt::ext::interactive::stop_note \sa openmpt::ext::interactive2::note_fade \since 0.6.0 */ virtual void note_off(int32_t channel ) = 0; //! Sends a note fade command for the note playing on the specified channel /*! \param channel The channel on which the note should be faded. This is the value returned by a previous play_note call. \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid. \remarks This method uses the instrument's fade-out value. If the module does not use instruments, or the instrument's fade-out value is 0, it does nothing. \sa openmpt::ext::interactive::play_note \sa openmpt::ext::interactive::stop_note \sa openmpt::ext::interactive2::note_off \since 0.6.0 */ virtual void note_fade(int32_t channel) = 0; //! Set the current panning position for a channel /*! \param channel The channel whose panning will be changed, in range [0, openmpt::module::get_num_channels()[ \param panning The panning position to set on the channel, in range [-1.0, 1.0], 0.0 is center. \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid. \remarks This command affects subsequent notes played on the same channel, and may itself be overridden by subsequent panning commands encountered in the module itself. \sa openmpt::ext::interactive2::get_channel_panning \since 0.6.0 */ virtual void set_channel_panning(int32_t channel, double panning ) = 0; //! Get the current panning position for a channel /*! \param channel The channel whose panning should be retrieved, in range [0, openmpt::module::get_num_channels()[ \return The current channel panning, in range [-1.0, 1.0], 0.0 is center. \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range. \sa openmpt::ext::interactive2::set_channel_panning \since 0.6.0 */ virtual double get_channel_panning( int32_t channel ) = 0; //! Set the finetune for the currently playing note on a channel /*! \param channel The channel whose finetune will be changed, in range [0, openmpt::module::get_num_channels()[ \param finetune The finetune to set on the channel, in range [-1.0, 1.0], 0.0 is center. \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid. \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone. \remarks This command does not affect subsequent notes played on the same channel, but may itself be overridden by subsequent finetune commands encountered in the module itself. \sa openmpt::ext::interactive2::get_note_finetune \since 0.6.0 */ virtual void set_note_finetune(int32_t channel, double finetune ) = 0; //! Get the finetune for the currently playing note on a channel /*! \param channel The channel whose finetune should be retrieved, in range [0, openmpt::module::get_num_channels()[ \return The current channel finetune, in range [-1.0, 1.0], 0.0 is center. \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range. \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone. \sa openmpt::ext::interactive2::set_note_finetune \since 0.6.0 */ virtual double get_note_finetune( int32_t channel ) = 0; }; // class interactive2 #ifndef LIBOPENMPT_EXT_INTERFACE_INTERACTIVE3 #define LIBOPENMPT_EXT_INTERFACE_INTERACTIVE3 #endif LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(interactive3) class interactive3 { LIBOPENMPT_EXT_CXX_INTERFACE(interactive3) //! Set the current module tempo /*! \param tempo The new tempo in range [32, 512]. The exact meaning of the value depends on the tempo mode used by the module. \throws openmpt::exception Throws an exception derived from openmpt::exception if the tempo is outside the specified range. \remarks The tempo may be reset by pattern commands at any time. Use openmpt::ext:interactive::set_tempo_factor to apply a tempo factor that is independent of pattern commands. \sa openmpt::module::get_current_tempo2 \since 0.7.0 */ virtual void set_current_tempo2( double tempo ) = 0; }; // class interactive3 /* add stuff here */ #undef LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE #undef LIBOPENMPT_EXT_CXX_INTERFACE /*! @} */ } // namespace ext } // namespace openmpt #endif // LIBOPENMPT_EXT_HPP libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_stream_callbacks_fd.h0000644000175000017500000000450714376420353025011 00000000000000/* * libopenmpt_stream_callbacks_fd.h * -------------------------------- * Purpose: libopenmpt public c interface * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_STREAM_CALLBACKS_FD_H #define LIBOPENMPT_STREAM_CALLBACKS_FD_H #include "libopenmpt.h" #ifndef _MSC_VER #include #endif #ifdef _MSC_VER #include #endif #include #include #include #include #ifndef _MSC_VER #include #endif /*! \addtogroup libopenmpt_c * @{ */ #ifdef __cplusplus extern "C" { #endif /* This stuff has to be in a header file because of possibly different MSVC CRTs which cause problems for fd crossing CRT boundaries. */ static size_t openmpt_stream_fd_read_func( void * stream, void * dst, size_t bytes ) { int fd = 0; #if defined(_MSC_VER) size_t retval = 0; int to_read = 0; int ret_read = 0; #else ssize_t retval = 0; #endif fd = (int)(uintptr_t)stream; if ( fd < 0 ) { return 0; } #if defined(_MSC_VER) retval = 0; while ( bytes > 0 ) { to_read = 0; if ( bytes < (size_t)INT_MAX ) { to_read = (int)bytes; } else { to_read = INT_MAX; } ret_read = _read( fd, dst, to_read ); if ( ret_read <= 0 ) { return retval; } bytes -= ret_read; retval += ret_read; } #else do { retval = read( fd, dst, bytes ); } while ( ( retval == -1 ) && ( errno == EINTR ) ); #endif if ( retval <= 0 ) { return 0; } return retval; } /*! \brief Provide openmpt_stream_callbacks for standard POSIX file descriptors * * Fills openmpt_stream_callbacks suitable for passing a POSIX filer descriptor as a stream parameter to functions doing file input/output. * * \remarks The stream argument must be passed as `(void*)(uintptr_t)(int)fd`. * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \sa openmpt_could_open_probability2 * \sa openmpt_probe_file_header_from_stream * \sa openmpt_module_create2 */ static openmpt_stream_callbacks openmpt_stream_get_fd_callbacks(void) { openmpt_stream_callbacks retval; memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); retval.read = openmpt_stream_fd_read_func; return retval; } #ifdef __cplusplus } #endif /*! * @} */ #endif /* LIBOPENMPT_STREAM_CALLBACKS_FD_H */ libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt.hpp0000644000175000017500000022743514733472461021341 00000000000000/* * libopenmpt.hpp * -------------- * Purpose: libopenmpt public c++ interface * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_HPP #define LIBOPENMPT_HPP #include "libopenmpt_config.h" #include #include #include #include #include #include #include #include #include /*! * \page libopenmpt_cpp_overview C++ API * * \section libopenmpt_cpp_error Error Handling * * libopenmpt C++ uses C++ exception handling for errror reporting. * * Unless otherwise noted, any libopenmpt function may throw exceptions and * all exceptions thrown by libopenmpt itself are derived from * openmpt::exception. * In addition, any libopenmpt function may also throw any exception specified * by the C++ language and C++ standard library. These are all derived from * std::exception. * * \section libopenmpt_cpp_strings Strings * * - All strings returned from libopenmpt are encoded in UTF-8. * - All strings passed to libopenmpt should also be encoded in UTF-8. * Behaviour in case of invalid UTF-8 is unspecified. * - libopenmpt does not enforce or expect any particular Unicode * normalization form. * * \section libopenmpt_cpp_fileio File I/O * * libopenmpt can use 3 different strategies for file I/O. * * - openmpt::module::module() with a seekable std::istream as parameter will * load the module via the stream interface. This is the recommended strategy. * - openmpt::module::module() with an unseekable std::istream as parameter * will load the module via the stream interface. libopempt will make an * internal copy as it goes along, and sometimes have to pre-cache the whole * file in case it needs to know the complete file size. This strategy is * intended to be used if the file is located on a high latency network. * - openmpt::module::module() with any kind of memory buffer as parameter will * load the module from the provided memory buffer, which will require loading * all data upfront by the library caller. This strategy has the disadvantage of * requiring all data to be loaded even when the module loading happens to fail * after that. It should only be used when the data has already been loaded into * memory for other reasons. * * | constructor | speed | memory consumption | * | ----------------: | :---: | :----------------: | * | seekable stream |

medium

|

low

| * | unseekable stream |

medium

|

high

| * | memory buffer |

fast

|

medium

| * * In all cases, the data or stream passed to the constructor is no longer * needed after the openmpt::module has been constructed and can be destroyed * by the caller. * * \section libopenmpt_cpp_outputformat Output Format * * libopenmpt supports a wide range of PCM output formats: * [8000..192000]/[mono|stereo|quad]/[f32|i16]. * * Unless you have some very specific requirements demanding a particular aspect * of the output format, you should always prefer 48000/stereo/f32 as the * libopenmpt PCM format. * * - Please prefer 48000Hz unless the user explicitly demands something else. * Practically all audio equipment and file formats use 48000Hz nowadays. * - Practically all module formats are made for stereo output. Mono will not * give you any measurable speed improvements and can trivially be obtained from * the stereo output anyway. Quad is not expected by almost all modules and even * if they do use surround effects, they expect the effects to be mixed to * stereo. * - Floating point output provides headroom instead of hard clipping if the * module is louder than 0dBFs, will give you a better signal-to-noise ratio * than int16 output, and avoid the need to apply an additional dithering to the * output by libopenmpt. Unless your platform has no floating point unit at all, * floating point will thus also be slightly faster. * * \section libopenmpt_cpp_threads libopenmpt in multi-threaded environments * * - libopenmpt is thread-aware. * - Individual libopenmpt objects are not thread-safe. * - libopenmpt itself does not spawn any user-visible threads but may spawn * threads for internal use. * - You must ensure to only ever access a particular libopenmpt object via * non-const member functions from a single thread at a time. * - You may access a particular libopenmpt object concurrently from different * threads when using only const member functions from all threads. * - Consecutive accesses can happen from different threads. * - Different objects can be accessed concurrently from different threads. * * \section libopenmpt-cpp-windows Windows support * * Using the libopenmpt C++ API when libopenmpt is compiled as a DLL on Windows * requires `#define LIBOPENMPT_USE_DLL` (or some equivalent build system * configuration) before `#include ` in order to * correctly import the symbols from the DLL. * * \section libopenmpt-cpp-detailed Detailed documentation * * \ref libopenmpt_cpp * * \section libopenmpt_cpp_examples Example * * \include libopenmpt_example_cxx.cpp * */ /*! \defgroup libopenmpt_cpp libopenmpt C++ */ namespace openmpt { /*! \addtogroup libopenmpt_cpp @{ */ #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4275) #endif //! libopenmpt exception base class /*! Base class used for all exceptions that are thrown by libopenmpt itself. Libopenmpt may additionally throw any exception thrown by the standard library which are all derived from std::exception. \sa \ref libopenmpt_cpp_error */ class LIBOPENMPT_CXX_API_CLASS exception : public std::exception { private: char * text; public: LIBOPENMPT_CXX_API_MEMBER exception( const std::string & text ) noexcept; LIBOPENMPT_CXX_API_MEMBER exception( const exception & other ) noexcept; LIBOPENMPT_CXX_API_MEMBER exception( exception && other ) noexcept; LIBOPENMPT_CXX_API_MEMBER exception & operator = ( const exception & other ) noexcept; LIBOPENMPT_CXX_API_MEMBER exception & operator = ( exception && other ) noexcept; LIBOPENMPT_CXX_API_MEMBER virtual ~exception() noexcept; LIBOPENMPT_CXX_API_MEMBER const char * what() const noexcept override; }; // class exception #if defined(_MSC_VER) #pragma warning(pop) #endif //! Get the libopenmpt version number /*! Returns the libopenmpt version number. \return The value represents (major << 24 + minor << 16 + patch << 0). \remarks libopenmpt < 0.3.0-pre used the following scheme: (major << 24 + minor << 16 + revision). */ LIBOPENMPT_CXX_API std::uint32_t get_library_version(); //! Get the core version number /*! Return the OpenMPT core version number. \return The value represents (majormajor << 24 + major << 16 + minor << 8 + minorminor). */ LIBOPENMPT_CXX_API std::uint32_t get_core_version(); namespace string { //! Return a verbose library version string from openmpt::string::get(). \deprecated Please use `"library_version"` directly. static const char library_version LIBOPENMPT_ATTR_DEPRECATED [] = "library_version"; //! Return a verbose library features string from openmpt::string::get(). \deprecated Please use `"library_features"` directly. static const char library_features LIBOPENMPT_ATTR_DEPRECATED [] = "library_features"; //! Return a verbose OpenMPT core version string from openmpt::string::get(). \deprecated Please use `"core_version"` directly. static const char core_version LIBOPENMPT_ATTR_DEPRECATED [] = "core_version"; //! Return information about the current build (e.g. the build date or compiler used) from openmpt::string::get(). \deprecated Please use `"build"` directly. static const char build LIBOPENMPT_ATTR_DEPRECATED [] = "build"; //! Return all contributors from openmpt::string::get(). \deprecated Please use `"credits"` directly. static const char credits LIBOPENMPT_ATTR_DEPRECATED [] = "credits"; //! Return contact information about libopenmpt from openmpt::string::get(). \deprecated Please use `"contact"` directly. static const char contact LIBOPENMPT_ATTR_DEPRECATED [] = "contact"; //! Return the libopenmpt license from openmpt::string::get(). \deprecated Please use `"license"` directly. static const char license LIBOPENMPT_ATTR_DEPRECATED [] = "license"; //! Get library related metadata. /*! \param key Key to query. Possible keys are: - "library_version": verbose library version string - "library_version_major": libopenmpt major version number - "library_version_minor": libopenmpt minor version number - "library_version_patch": libopenmpt patch version number - "library_version_prerel": libopenmpt pre-release version string - "library_version_is_release": "1" if the version is an officially released version - "library_features": verbose library features string - "core_version": verbose OpenMPT core version string - "source_url": original source code URL - "source_date": original source code date - "source_revision": original source code revision - "source_is_modified": "1" if the original source has been modified - "source_has_mixed_revisions": "1" if the original source has been compiled from different various revision - "source_is_package": "1" if the original source has been obtained from a source pacakge instead of source code version control - "build": information about the current build (e.g. the build date or compiler used) - "build_compiler": information about the compiler used to build libopenmpt - "credits": all contributors - "contact": contact information about libopenmpt - "license": the libopenmpt license - "url": libopenmpt website URL - "support_forum_url": libopenmpt support and discussions forum URL - "bugtracker_url": libopenmpt bug and issue tracker URL \return A (possibly multi-line) string containing the queried information. If no information is available, the string is empty. */ LIBOPENMPT_CXX_API std::string get( const std::string & key ); } // namespace string //! Get a list of supported file extensions /*! \return The list of extensions supported by this libopenmpt build. The extensions are returned lower-case without a leading dot. */ LIBOPENMPT_CXX_API std::vector get_supported_extensions(); //! Query whether a file extension is supported /*! \param extension file extension to query without a leading dot. The case is ignored. \return true if the extension is supported by libopenmpt, false otherwise. \deprecated Please use openmpt::is_extension_supported2(). */ LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API bool is_extension_supported( const std::string & extension ); //! Query whether a file extension is supported /*! \param extension file extension to query without a leading dot. The case is ignored. \return true if the extension is supported by libopenmpt, false otherwise. \since 0.5.0 */ LIBOPENMPT_CXX_API bool is_extension_supported2( std::string_view extension ); //! Roughly scan the input stream to find out whether libopenmpt might be able to open it /*! \param stream Input stream to scan. \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file. \param log Log where warning and errors are written. \return Probability between 0.0 and 1.0. \remarks openmpt::probe_file_header() provides a simpler and faster interface that fits almost all use cases better. It is recommended to use openmpt::probe_file_header() instead of openmpt::could_open_probability(). \remarks openmpt::could_open_probability() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.). \remarks openmpt::could_open_probability() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your std::istream implementation whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt::could_open_probability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt::could_open_probability() returned 0.5. \sa \ref libopenmpt_c_fileio \sa openmpt::probe_file_header() \since 0.3.0 */ LIBOPENMPT_CXX_API double could_open_probability( std::istream & stream, double effort = 1.0, std::ostream & log = std::clog ); //! Roughly scan the input stream to find out whether libopenmpt might be able to open it /*! \deprecated Please use openmpt::could_open_probability(). */ LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API double could_open_propability( std::istream & stream, double effort = 1.0, std::ostream & log = std::clog ); //! Get recommended header size for successfull format probing /*! \sa openmpt::probe_file_header() \since 0.3.0 */ LIBOPENMPT_CXX_API std::size_t probe_file_header_get_recommended_size(); //! Probe for module formats in openmpt::probe_file_header(). \since 0.3.0 \deprecated Please use openmpt::probe_file_header_flags_modules2. static const std::uint64_t probe_file_header_flags_modules LIBOPENMPT_ATTR_DEPRECATED = 0x1ull; //! Probe for module-specific container formats in openmpt::probe_file_header(). \since 0.3.0 \deprecated Please use openmpt::probe_file_header_flags_containers2. static const std::uint64_t probe_file_header_flags_containers LIBOPENMPT_ATTR_DEPRECATED = 0x2ull; //! Probe for the default set of formats in openmpt::probe_file_header(). \since 0.3.0 \deprecated Please use openmpt::probe_file_header_flags_default2. static const std::uint64_t probe_file_header_flags_default LIBOPENMPT_ATTR_DEPRECATED = 0x1ull | 0x2ull; //! Probe for no formats in openmpt::probe_file_header(). \since 0.3.0 \deprecated Please use openmpt::probe_file_header_flags_none2. static const std::uint64_t probe_file_header_flags_none LIBOPENMPT_ATTR_DEPRECATED = 0x0ull; //! Possible values for openmpt::probe_file_header() flags parameter. \since 0.6.0 enum probe_file_header_flags : std::uint64_t { //! Probe for module formats in openmpt::probe_file_header(). \since 0.6.0 probe_file_header_flags_modules2 = 0x1ull, //! Probe for module-specific container formats in openmpt::probe_file_header(). \since 0.6.0 probe_file_header_flags_containers2 = 0x2ull, //! Probe for the default set of formats in openmpt::probe_file_header(). \since 0.6.0 probe_file_header_flags_default2 = probe_file_header_flags_modules2 | probe_file_header_flags_containers2, //! Probe for no formats in openmpt::probe_file_header(). \since 0.6.0 probe_file_header_flags_none2 = 0x0ull }; //! Possible return values for openmpt::probe_file_header(). \since 0.3.0 enum probe_file_header_result { //! The file will most likely be supported by libopenmpt. \since 0.3.0 probe_file_header_result_success = 1, //! The file is not supported by libopenmpt. \since 0.3.0 probe_file_header_result_failure = 0, //! An answer could not be determined with the amount of data provided. \since 0.3.0 probe_file_header_result_wantmoredata = -1 }; //! Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it /*! \param flags Bit mask of openmpt::probe_file_header_flags_modules2 and openmpt::probe_file_header_flags_containers2, or openmpt::probe_file_header_flags_default2. \param data Beginning of the file data. \param size Size of the beginning of the file data. \param filesize Full size of the file data on disk. \remarks It is recommended to provide openmpt::probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size and filesize to the file's size. \remarks openmpt::could_open_probability() provides a more elaborate interface that might be required for special use cases. It is recommended to use openmpt::probe_file_header() though, if possible. \retval probe_file_header_result_success The file will most likely be supported by libopenmpt. \retval probe_file_header_result_failure The file is not supported by libopenmpt. \retval probe_file_header_result_wantmoredata An answer could not be determined with the amount of data provided. \sa openmpt::probe_file_header_get_recommended_size() \sa openmpt::could_open_probability() \since 0.5.0 */ LIBOPENMPT_CXX_API int probe_file_header( std::uint64_t flags, const std::byte * data, std::size_t size, std::uint64_t filesize ); //! Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it /*! \param flags Bit mask of openmpt::probe_file_header_flags_modules2 and openmpt::probe_file_header_flags_containers2, or openmpt::probe_file_header_flags_default2. \param data Beginning of the file data. \param size Size of the beginning of the file data. \param filesize Full size of the file data on disk. \remarks It is recommended to provide openmpt::probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size and filesize to the file's size. \remarks openmpt::could_open_probability() provides a more elaborate interface that might be required for special use cases. It is recommended to use openmpt::probe_file_header() though, if possible. \retval probe_file_header_result_success The file will most likely be supported by libopenmpt. \retval probe_file_header_result_failure The file is not supported by libopenmpt. \retval probe_file_header_result_wantmoredata An answer could not be determined with the amount of data provided. \sa openmpt::probe_file_header_get_recommended_size() \sa openmpt::could_open_probability() \since 0.3.0 */ LIBOPENMPT_CXX_API int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size, std::uint64_t filesize ); //! Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it /*! \param flags Bit mask of openmpt::probe_file_header_flags_modules2 and openmpt::probe_file_header_flags_containers2, or openmpt::probe_file_header_flags_default2. \param data Beginning of the file data. \param size Size of the beginning of the file data. \remarks It is recommended to use the overload of this function that also takes the filesize as parameter if at all possile. libopenmpt can provide more accurate answers if the filesize is known. \remarks It is recommended to provide openmpt::probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size to the file's size. \remarks openmpt::could_open_probability() provides a more elaborate interface that might be required for special use cases. It is recommended to use openmpt::probe_file_header() though, if possible. \retval probe_file_header_result_success The file will most likely be supported by libopenmpt. \retval probe_file_header_result_failure The file is not supported by libopenmpt. \retval probe_file_header_result_wantmoredata An answer could not be determined with the amount of data provided. \sa openmpt::probe_file_header_get_recommended_size() \sa openmpt::could_open_probability() \since 0.5.0 */ LIBOPENMPT_CXX_API int probe_file_header( std::uint64_t flags, const std::byte * data, std::size_t size ); //! Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it /*! \param flags Bit mask of openmpt::probe_file_header_flags_modules2 and openmpt::probe_file_header_flags_containers2, or openmpt::probe_file_header_flags_default2. \param data Beginning of the file data. \param size Size of the beginning of the file data. \remarks It is recommended to use the overload of this function that also takes the filesize as parameter if at all possile. libopenmpt can provide more accurate answers if the filesize is known. \remarks It is recommended to provide openmpt::probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size to the file's size. \remarks openmpt::could_open_probability() provides a more elaborate interface that might be required for special use cases. It is recommended to use openmpt::probe_file_header() though, if possible. \retval probe_file_header_result_success The file will most likely be supported by libopenmpt. \retval probe_file_header_result_failure The file is not supported by libopenmpt. \retval probe_file_header_result_wantmoredata An answer could not be determined with the amount of data provided. \sa openmpt::probe_file_header_get_recommended_size() \sa openmpt::could_open_probability() \since 0.3.0 */ LIBOPENMPT_CXX_API int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size ); //! Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it /*! \param flags Bit mask of openmpt::probe_file_header_flags_modules2 and openmpt::probe_file_header_flags_containers2, or openmpt::probe_file_header_flags_default2. \param stream Input stream to scan. \remarks stream is left in an unspecified state when this function returns. \remarks openmpt::could_open_probability() provides a more elaborate interface that might be required for special use cases. It is recommended to use openmpt::probe_file_header() though, if possible. \retval probe_file_header_result_success The file will most likely be supported by libopenmpt. \retval probe_file_header_result_failure The file is not supported by libopenmpt. \retval probe_file_header_result_wantmoredata An answer could not be determined with the amount of data provided. \sa openmpt::probe_file_header_get_recommended_size() \sa openmpt::could_open_probability() \since 0.3.0 */ LIBOPENMPT_CXX_API int probe_file_header( std::uint64_t flags, std::istream & stream ); class module_impl; class module_ext; namespace detail { typedef std::map< std::string, std::string > initial_ctls_map; } // namespace detail class LIBOPENMPT_CXX_API_CLASS module { friend class module_ext; public: //! Parameter index to use with openmpt::module::get_render_param and openmpt::module::set_render_param enum render_param { //! Master Gain /*! The related value represents a relative gain in milliBel.\n The default value is 0.\n The supported value range is unlimited.\n */ RENDER_MASTERGAIN_MILLIBEL = 1, //! Stereo Separation /*! The related value represents the stereo separation generated by the libopenmpt mixer in percent.\n The default value is 100.\n The supported value range is [0,200].\n */ RENDER_STEREOSEPARATION_PERCENT = 2, //! Interpolation Filter /*! The related value represents the interpolation filter length used by the libopenmpt mixer.\n The default value is 0, which indicates a recommended default value.\n The supported value range is [0,inf). Values greater than the implementation limit are clamped to the maximum supported value.\n Currently supported values: - 0: internal default - 1: no interpolation (zero order hold) - 2: linear interpolation - 4: cubic interpolation - 8: windowed sinc with 8 taps */ RENDER_INTERPOLATIONFILTER_LENGTH = 3, //! Volume Ramping Strength /*! The related value represents the amount of volume ramping done by the libopenmpt mixer.\n The default value is -1, which indicates a recommended default value.\n The meaningful value range is [-1..10].\n A value of 0 completely disables volume ramping. This might cause clicks in sound output.\n Higher values imply slower/softer volume ramps. */ RENDER_VOLUMERAMPING_STRENGTH = 4 }; //! Parameter index to use with openmpt::module::get_pattern_row_channel_command, openmpt::module::format_pattern_row_channel_command and openmpt::module::highlight_pattern_row_channel_command enum command_index { command_note = 0, command_instrument = 1, command_volumeffect = 2, command_effect = 3, command_volume = 4, command_parameter = 5 }; private: module_impl * impl; private: // non-copyable module( const module & ); void operator = ( const module & ); private: // for module_ext module(); void set_impl( module_impl * i ); public: //! Construct an openmpt::module /*! \param stream Input stream from which the module is loaded. After the constructor has finished successfully, the input position of stream is set to the byte after the last byte that has been read. If the constructor fails, the state of the input position of stream is undefined. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. \param ctls A map of initial ctl values, see \ref openmpt::module::get_ctls and openmpt::module::ctl_set. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ LIBOPENMPT_CXX_API_MEMBER module( std::istream & stream, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. \param ctls A map of initial ctl values, see \ref openmpt::module::get_ctls and openmpt::module::ctl_set. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio \since 0.5.0 */ LIBOPENMPT_CXX_API_MEMBER module( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param beg Begin of data to load the module from. \param end End of data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. \param ctls A map of initial ctl values, see \ref openmpt::module::get_ctls and openmpt::module::ctl_set. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio \since 0.5.0 */ LIBOPENMPT_CXX_API_MEMBER module( const std::byte * beg, const std::byte * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param size Amount of data available. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio \since 0.5.0 */ LIBOPENMPT_CXX_API_MEMBER module( const std::byte * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. \param ctls A map of initial ctl values, see \ref openmpt::module::get_ctls and openmpt::module::ctl_set. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ LIBOPENMPT_CXX_API_MEMBER module( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param beg Begin of data to load the module from. \param end End of data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ LIBOPENMPT_CXX_API_MEMBER module( const std::uint8_t * beg, const std::uint8_t * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param size Amount of data available. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ LIBOPENMPT_CXX_API_MEMBER module( const std::uint8_t * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ LIBOPENMPT_CXX_API_MEMBER module( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param beg Begin of data to load the module from. \param end End of data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ LIBOPENMPT_CXX_API_MEMBER module( const char * beg, const char * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param size Amount of data available. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ LIBOPENMPT_CXX_API_MEMBER module( const char * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param size Amount of data available. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ LIBOPENMPT_CXX_API_MEMBER module( const void * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); LIBOPENMPT_CXX_API_MEMBER virtual ~module(); public: //! Select a sub-song from a multi-song module /*! \param subsong Index of the sub-song. -1 plays all sub-songs consecutively. \throws openmpt::exception Throws an exception derived from openmpt::exception if sub-song is not in range [-1,openmpt::module::get_num_subsongs()[ \sa openmpt::module::get_num_subsongs, openmpt::module::get_selected_subsong, openmpt::module::get_subsong_names \remarks Whether subsong -1 (all subsongs consecutively), subsong 0 or some other subsong is selected by default, is an implementation detail and subject to change. If you do not want to care about subsongs, it is recommended to just not call openmpt::module::select_subsong() at all. */ LIBOPENMPT_CXX_API_MEMBER void select_subsong( std::int32_t subsong ); //! Get currently selected sub-song from a multi-song module /*! \return Currently selected sub-song. -1 for all subsongs consecutively, 0 or greater for the current sub-song index. \sa openmpt::module::get_num_subsongs, openmpt::module::select_subsong, openmpt::module::get_subsong_names \since 0.3.0 */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_selected_subsong() const; //! Get the restart order of the specified sub-song /*! \param subsong Index of the sub-song to retrieve the restart position from. \return The restart order of the specified sub-song. This is the order to which playback returns after the last pattern row of the song has been played. \throws openmpt::exception Throws an exception derived from openmpt::exception if sub-song is not in range [0,openmpt::module::get_num_subsongs()[ \sa openmpt::module::get_restart_row \since 0.8.0 */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_restart_order( std::int32_t subsong ) const; //! Get the restart row of the specified sub-song /*! \param subsong Index of the sub-song to retrieve the restart position from. \return The restart row of the specified sub-song. This is the first played row of the order to which playback returns after the last pattern row of the song has been played. \throws openmpt::exception Throws an exception derived from openmpt::exception if sub-song is not in range [0,openmpt::module::get_num_subsongs()[ \sa openmpt::module::get_restart_order \since 0.8.0 */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_restart_row( std::int32_t subsong ) const; //! Set Repeat Count /*! \param repeat_count Repeat Count - -1: repeat forever - 0: play once, repeat zero times (the default) - n>0: play once and repeat n times after that \sa openmpt::module::get_repeat_count */ LIBOPENMPT_CXX_API_MEMBER void set_repeat_count( std::int32_t repeat_count ); //! Get Repeat Count /*! \return Repeat Count - -1: repeat forever - 0: play once, repeat zero times (the default) - n>0: play once and repeat n times after that \sa openmpt::module::set_repeat_count */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_repeat_count() const; //! Get approximate song duration /*! \return Approximate duration of current sub-song in seconds. \remarks The function may return infinity if the pattern data is too complex to evaluate. */ LIBOPENMPT_CXX_API_MEMBER double get_duration_seconds() const; //! Get approximate playback time in seconds at given position /*! \param order The order position at which the time should be retrieved. \param row The pattern row number at which the time should be retrieved. \return Approximate playback time in seconds of current sub-song at the start of the given order and row combination. Negative if the position does not exist, or the pattern data is too complex to evaluate. \remarks If an order / row combination is played multiple times (e.g. due the pattern loops), the first occurence of this position is returned. \since 0.8.0 */ LIBOPENMPT_CXX_API_MEMBER double get_time_at_position( std::int32_t order, std::int32_t row ) const; //! Set approximate current song position /*! \param seconds Seconds to seek to. If seconds is out of range, the position gets set to song start or end respectively. \return Approximate new song position in seconds. \sa openmpt::module::get_position_seconds */ LIBOPENMPT_CXX_API_MEMBER double set_position_seconds( double seconds ); //! Get current song position /*! \return Current song position in seconds. \sa openmpt::module::set_position_seconds */ LIBOPENMPT_CXX_API_MEMBER double get_position_seconds() const; //! Set approximate current song position /*! If order or row are out of range, to position is not modified and the current position is returned. \param order Pattern order number to seek to. \param row Pattern row number to seek to. \return Approximate new song position in seconds. \sa openmpt::module::set_position_seconds \sa openmpt::module::get_position_seconds */ LIBOPENMPT_CXX_API_MEMBER double set_position_order_row( std::int32_t order, std::int32_t row ); //! Get render parameter /*! \param param Parameter to query. See openmpt::module::render_param. \return The current value of the parameter. \throws openmpt::exception Throws an exception derived from openmpt::exception if param is invalid. \sa openmpt::module::render_param \sa openmpt::module::set_render_param */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_render_param( int param ) const; //! Set render parameter /*! \param param Parameter to set. See openmpt::module::render_param. \param value The value to set param to. \throws openmpt::exception Throws an exception derived from openmpt::exception if param is invalid or value is out of range. \sa openmpt::module::render_param \sa openmpt::module::get_render_param */ LIBOPENMPT_CXX_API_MEMBER void set_render_param( int param, std::int32_t value ); /*@{*/ //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param mono Pointer to a buffer of at least count elements that receives the mono/center output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_cpp_outputformat */ LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * mono ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param left Pointer to a buffer of at least count elements that receives the left output. \param right Pointer to a buffer of at least count elements that receives the right output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_cpp_outputformat */ LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param left Pointer to a buffer of at least count elements that receives the left output. \param right Pointer to a buffer of at least count elements that receives the right output. \param rear_left Pointer to a buffer of at least count elements that receives the rear left output. \param rear_right Pointer to a buffer of at least count elements that receives the rear right output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_cpp_outputformat */ LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param mono Pointer to a buffer of at least count elements that receives the mono/center output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_cpp_outputformat */ LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, float * mono ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param left Pointer to a buffer of at least count elements that receives the left output. \param right Pointer to a buffer of at least count elements that receives the right output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_cpp_outputformat */ LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param left Pointer to a buffer of at least count elements that receives the left output. \param right Pointer to a buffer of at least count elements that receives the right output. \param rear_left Pointer to a buffer of at least count elements that receives the rear left output. \param rear_right Pointer to a buffer of at least count elements that receives the rear right output. \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_cpp_outputformat */ LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right, float * rear_left, float * rear_right ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_cpp_outputformat */ LIBOPENMPT_CXX_API_MEMBER std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_stereo ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_cpp_outputformat */ LIBOPENMPT_CXX_API_MEMBER std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_quad ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_cpp_outputformat */ LIBOPENMPT_CXX_API_MEMBER std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, float * interleaved_stereo ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module. \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_cpp_outputformat */ LIBOPENMPT_CXX_API_MEMBER std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, float * interleaved_quad ); /*@}*/ //! Get the list of supported metadata item keys /*! \return Metadata item keys supported by openmpt::module::get_metadata \sa openmpt::module::get_metadata */ LIBOPENMPT_CXX_API_MEMBER std::vector get_metadata_keys() const; //! Get a metadata item value /*! \param key Metadata item key to query. Use openmpt::module::get_metadata_keys to check for available keys. Possible keys are: - type: Module format extension (e.g. it) or another similar identifier for modules formats that typically do not use a file extension - type_long: Format name associated with the module format (e.g. Impulse Tracker) - originaltype: Module format extension (e.g. it) of the original module in case the actual type is a converted format (e.g. mo3 or gdm) - originaltype_long: Format name associated with the module format (e.g. Impulse Tracker) of the original module in case the actual type is a converted format (e.g. mo3 or gdm) - container: Container format the module file is embedded in, if any (e.g. umx) - container_long: Full container name if the module is embedded in a container (e.g. Unreal Music) - tracker: Tracker that was (most likely) used to save the module file, if known - artist: Author of the module - title: Module title - date: Date the module was last saved, in ISO-8601 format. - message: Song message. If the song message is empty or the module format does not support song messages, a list of instrument and sample names is returned instead. - message_raw: Song message. If the song message is empty or the module format does not support song messages, an empty string is returned. - warnings: A list of warnings that were generated while loading the module. \return The associated value for key. \sa openmpt::module::get_metadata_keys */ LIBOPENMPT_CXX_API_MEMBER std::string get_metadata( const std::string & key ) const; //! Get the current estimated beats per minute (BPM). /*! \remarks Many module formats lack time signature metadata. It is common that this estimate is off by a factor of two, but other multipliers are also possible. \remarks Due to the nature of how module tempo works, the estimate may change slightly after switching libopenmpt's output to a different sample rate. \return The current estimated BPM. */ LIBOPENMPT_CXX_API_MEMBER double get_current_estimated_bpm() const; //! Get the current speed /*! \return The current speed in ticks per row. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_speed() const; //! Get the current tempo /*! \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. \deprecated Please use openmpt::module::get_current_tempo2(). */ LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_tempo() const; //! Get the current tempo /*! \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. \since 0.7.0 */ LIBOPENMPT_CXX_API_MEMBER double get_current_tempo2() const; //! Get the current order /*! \return The current order at which the module is being played back. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_order() const; //! Get the current pattern /*! \return The current pattern that is being played. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_pattern() const; //! Get the current row /*! \return The current row at which the current pattern is being played. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_row() const; //! Get the current amount of playing channels. /*! \return The amount of sample channels that are currently being rendered. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_playing_channels() const; //! Get an approximate indication of the channel volume. /*! \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ LIBOPENMPT_CXX_API_MEMBER float get_current_channel_vu_mono( std::int32_t channel ) const; //! Get an approximate indication of the channel volume on the front-left speaker. /*! \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ LIBOPENMPT_CXX_API_MEMBER float get_current_channel_vu_left( std::int32_t channel ) const; //! Get an approximate indication of the channel volume on the front-right speaker. /*! \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ LIBOPENMPT_CXX_API_MEMBER float get_current_channel_vu_right( std::int32_t channel ) const; //! Get an approximate indication of the channel volume on the rear-left speaker. /*! \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ LIBOPENMPT_CXX_API_MEMBER float get_current_channel_vu_rear_left( std::int32_t channel ) const; //! Get an approximate indication of the channel volume on the rear-right speaker. /*! \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ LIBOPENMPT_CXX_API_MEMBER float get_current_channel_vu_rear_right( std::int32_t channel ) const; //! Get the number of sub-songs /*! \return The number of sub-songs in the module. This includes any "hidden" songs (songs that share the same sequence, but start at different order indices) and "normal" sub-songs or "sequences" (if the format supports them). \sa openmpt::module::get_subsong_names, openmpt::module::select_subsong, openmpt::module::get_selected_subsong */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_subsongs() const; //! Get the number of pattern channels /*! \return The number of pattern channels in the module. Not all channels do necessarily contain data. \remarks The number of pattern channels is completely independent of the number of output channels. libopenmpt can render modules in mono, stereo or quad surround, but the choice of which of the three modes to use must not be made based on the return value of this function, which may be any positive integer amount. Only use this function for informational purposes. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_channels() const; //! Get the number of orders /*! \return The number of orders in the current sequence of the module. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_orders() const; //! Get the number of patterns /*! \return The number of distinct patterns in the module. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_patterns() const; //! Get the number of instruments /*! \return The number of instrument slots in the module. Instruments are a layer on top of samples, and are not supported by all module formats. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_instruments() const; //! Get the number of samples /*! \return The number of sample slots in the module. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_samples() const; //! Get a list of sub-song names /*! \return All sub-song names. \sa openmpt::module::get_num_subsongs, openmpt::module::select_subsong, openmpt::module::get_selected_subsong */ LIBOPENMPT_CXX_API_MEMBER std::vector get_subsong_names() const; //! Get a list of channel names /*! \return All channel names. \sa openmpt::module::get_num_channels */ LIBOPENMPT_CXX_API_MEMBER std::vector get_channel_names() const; //! Get a list of order names /*! \return All order names. \sa openmpt::module::get_num_orders */ LIBOPENMPT_CXX_API_MEMBER std::vector get_order_names() const; //! Get a list of pattern names /*! \return All pattern names. \sa openmpt::module::get_num_patterns */ LIBOPENMPT_CXX_API_MEMBER std::vector get_pattern_names() const; //! Get a list of instrument names /*! \return All instrument names. \sa openmpt::module::get_num_instruments */ LIBOPENMPT_CXX_API_MEMBER std::vector get_instrument_names() const; //! Get a list of sample names /*! \return All sample names. \sa openmpt::module::get_num_samples */ LIBOPENMPT_CXX_API_MEMBER std::vector get_sample_names() const; //! Get pattern at order position /*! \param order The order item whose pattern index should be retrieved. \return The pattern index found at the given order position of the current sequence. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_order_pattern( std::int32_t order ) const; //! Check if specified order is a skip ("+++") item /*! \param order The order index to check. \return Returns true if the pattern index at the given order position represents a skip item. During playback, this item is ignored and playback resumes at the next order list item. \sa openmpt::module::is_order_stop_entry, openmpt::module::is_pattern_skip_item \since 0.8.0 */ LIBOPENMPT_CXX_API_MEMBER bool is_order_skip_entry( std::int32_t order ) const ; //! Check if specified pattern index is a skip ("+++") item /*! \param pattern The pattern index to check. \return Returns true if the pattern index represents a skip item. During playback, this item is ignored and playback resumes at the next order list item. \sa openmpt::module::is_pattern_stop_item, openmpt::module::is_order_skip_entry, openmpt::module::get_order_pattern \since 0.8.0 */ LIBOPENMPT_CXX_API_MEMBER bool is_pattern_skip_item( std::int32_t pattern ) const; //! Check if specified order is a stop ("---") item /*! \param order The order index to check. \return Returns true if the pattern index at the given order position represents a stop item. When this item is reached, playback continues at the restart position of the current sub-song. \sa openmpt::module::is_order_skip_entry, openmpt::module::is_pattern_stop_item \since 0.8.0 */ LIBOPENMPT_CXX_API_MEMBER bool is_order_stop_entry( std::int32_t order ) const; //! Check if specified pattern index is a stop ("---") item /*! \param pattern The pattern index to check. \return Returns true if the pattern index represents a stop item. When this item is reached, playback continues at the restart position of the current sub-song. \sa openmpt::module::is_pattern_skip_item, openmpt::module::is_order_stop_entry, openmpt::module::get_order_pattern \since 0.8.0 */ LIBOPENMPT_CXX_API_MEMBER bool is_pattern_stop_item( std::int32_t pattern ) const; //! Get the number of rows in a pattern /*! \param pattern The pattern whose row count should be retrieved. \return The number of rows in the given pattern. If the pattern does not exist, 0 is returned. */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_pattern_num_rows( std::int32_t pattern ) const; //! Get the rows per beat of a pattern /*! \param pattern The pattern whose time signature should be retrieved. \return The rows per beat of the given pattern. If the pattern does not exist or the time signature is not defined, 0 is returned. \remarks Many module formats lack time signature metadata. In this case, the returned value may be an incorrect estimation. \since 0.8.0 */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_pattern_rows_per_beat( std::int32_t pattern ) const; //! Get the rows per measure of a pattern /*! \param pattern The pattern whose time signature should be retrieved. \return The rows per measure of the given pattern. If the pattern does not exist or the time signature is not defined, 0 is returned. \remarks Many module formats lack time signature metadata. In this case, the returned value may be an incorrect estimation. \since 0.8.0 */ LIBOPENMPT_CXX_API_MEMBER std::int32_t get_pattern_rows_per_measure( std::int32_t pattern ) const; //! Get raw pattern content /*! \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \param command The cell index at which the data should be retrieved. See openmpt::module::command_index \return The internal, raw pattern data at the given pattern position. */ LIBOPENMPT_CXX_API_MEMBER std::uint8_t get_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; //! Get formatted (human-readable) pattern content /*! \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \param command The cell index at which the data should be retrieved. \return The formatted pattern data at the given pattern position. See openmpt::module::command_index \sa openmpt::module::highlight_pattern_row_channel_command */ LIBOPENMPT_CXX_API_MEMBER std::string format_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; //! Get highlighting information for formatted pattern content /*! \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \param command The cell index at which the data should be retrieved. See openmpt::module::command_index \return The highlighting string for the formatted pattern data as retrieved by openmpt::module::get_pattern_row_channel_command at the given pattern position. \remarks The returned string will map each character position of the string returned by openmpt::module::get_pattern_row_channel_command to a highlighting instruction. Possible highlighting characters are: - " " : empty/space - "." : empty/dot - "n" : generic note - "m" : special note - "i" : generic instrument - "u" : generic volume column effect - "v" : generic volume column parameter - "e" : generic effect column effect - "f" : generic effect column parameter \sa openmpt::module::get_pattern_row_channel_command */ LIBOPENMPT_CXX_API_MEMBER std::string highlight_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; //! Get formatted (human-readable) pattern content /*! \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \param width The maximum number of characters the string should contain. 0 means no limit. \param pad If true, the string will be resized to the exact length provided in the width parameter. \return The formatted pattern data at the given pattern position. \sa openmpt::module::highlight_pattern_row_channel */ LIBOPENMPT_CXX_API_MEMBER std::string format_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width = 0, bool pad = true ) const; //! Get highlighting information for formatted pattern content /*! \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \param width The maximum number of characters the string should contain. 0 means no limit. \param pad If true, the string will be resized to the exact length provided in the width parameter. \return The highlighting string for the formatted pattern data as retrieved by openmpt::module::format_pattern_row_channel at the given pattern position. \sa openmpt::module::format_pattern_row_channel */ LIBOPENMPT_CXX_API_MEMBER std::string highlight_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width = 0, bool pad = true ) const; //! Retrieve supported ctl keys /*! \return A vector containing all supported ctl keys. \remarks Currently supported ctl values are: - load.skip_samples (boolean): Set to "1" to avoid loading samples into memory - load.skip_patterns (boolean): Set to "1" to avoid loading patterns into memory - load.skip_plugins (boolean): Set to "1" to avoid loading plugins - load.skip_subsongs_init (boolean): Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking. - seek.sync_samples (boolean): Set to "0" to not sync sample playback when using openmpt::module::set_position_seconds or openmpt::module::set_position_order_row. - subsong (integer): The current subsong. Setting it has identical semantics as openmpt::module::select_subsong(), getting it returns the currently selected subsong. - play.at_end (text): Chooses the behaviour when the end of song is reached. The song end is considered to be reached after the number of reptitions set by openmpt::module::set_repeat_count was played, so if the song is set to repeat infinitely, its end is never considered to be reached. - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames. - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the loop start (if the song is not programmed to loop, playback resumed from the song start). - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames. - play.tempo_factor (floatingpoint): Set a floating point tempo factor. "1.0" is the default tempo. - play.pitch_factor (floatingpoint): Set a floating point pitch factor. "1.0" is the default pitch. - render.resampler.emulate_amiga (boolean): Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. - render.resampler.emulate_amiga_type (string): Configures the filter type to use for the Amiga resampler. Supported values are: - "auto": Filter type is chosen by the library and might change. This is the default. - "a500": Amiga A500 filter. - "a1200": Amiga A1200 filter. - "unfiltered": BLEP synthesis without model-specific filters. The LED filter is ignored by this setting. This filter mode is considered to be experimental and might change in the future. - render.opl.volume_factor (floatingpoint): Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume. - dither (integer): Set the dither algorithm that is used for the 16 bit versions of openmpt::module::read. Supported values are: - 0: No dithering. - 1: Default mode. Chosen by OpenMPT code, might change. - 2: Rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker). - 3: Rectangular, 1 bit depth, simple 1st order noise shaping An exclamation mark ("!") or a question mark ("?") can be appended to any ctl key in order to influence the behaviour in case of an unknown ctl key. "!" causes an exception to be thrown; "?" causes the ctl to be silently ignored. In case neither is appended to the key name, unknown init_ctls are ignored by default and other ctls throw an exception by default. */ LIBOPENMPT_CXX_API_MEMBER std::vector get_ctls() const; //! Get current ctl value /*! \param ctl The ctl key whose value should be retrieved. \return The associated ctl value. \sa openmpt::module::get_ctls \deprecated Please use openmpt::module::ctl_get_boolean(), openmpt::module::ctl_get_integer(), openmpt::module::ctl_get_floatingpoint(), or openmpt::module::ctl_get_text(). */ LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API_MEMBER std::string ctl_get( const std::string & ctl ) const; //! Get current ctl boolean value /*! \param ctl The ctl key whose value should be retrieved. \return The associated ctl value. \sa openmpt::module::get_ctls \since 0.5.0 */ LIBOPENMPT_CXX_API_MEMBER bool ctl_get_boolean( std::string_view ctl ) const; //! Get current ctl integer value /*! \param ctl The ctl key whose value should be retrieved. \return The associated ctl value. \sa openmpt::module::get_ctls \since 0.5.0 */ LIBOPENMPT_CXX_API_MEMBER std::int64_t ctl_get_integer( std::string_view ctl ) const; //! Get current ctl floatingpoint value /*! \param ctl The ctl key whose value should be retrieved. \return The associated ctl value. \sa openmpt::module::get_ctls \since 0.5.0 */ LIBOPENMPT_CXX_API_MEMBER double ctl_get_floatingpoint( std::string_view ctl ) const; //! Get current ctl text value /*! \param ctl The ctl key whose value should be retrieved. \return The associated ctl value. \sa openmpt::module::get_ctls \since 0.5.0 */ LIBOPENMPT_CXX_API_MEMBER std::string ctl_get_text( std::string_view ctl ) const; //! Set ctl value /*! \param ctl The ctl key whose value should be set. \param value The value that should be set. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls. \sa openmpt::module::get_ctls \deprecated Please use openmpt::module::ctl_set_boolean(), openmpt::module::ctl_set_integer(), openmpt::module::ctl_set_floatingpoint(), or openmpt::module::ctl_set_text(). */ LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API_MEMBER void ctl_set( const std::string & ctl, const std::string & value ); //! Set ctl boolean value /*! \param ctl The ctl key whose value should be set. \param value The value that should be set. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls. \sa openmpt::module::get_ctls \since 0.5.0 */ LIBOPENMPT_CXX_API_MEMBER void ctl_set_boolean( std::string_view ctl, bool value ); //! Set ctl integer value /*! \param ctl The ctl key whose value should be set. \param value The value that should be set. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls. \sa openmpt::module::get_ctls \since 0.5.0 */ LIBOPENMPT_CXX_API_MEMBER void ctl_set_integer( std::string_view ctl, std::int64_t value ); //! Set ctl floatingpoint value /*! \param ctl The ctl key whose value should be set. \param value The value that should be set. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls. \sa openmpt::module::get_ctls \since 0.5.0 */ LIBOPENMPT_CXX_API_MEMBER void ctl_set_floatingpoint( std::string_view ctl, double value ); //! Set ctl text value /*! \param ctl The ctl key whose value should be set. \param value The value that should be set. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls. \sa openmpt::module::get_ctls \since 0.5.0 */ LIBOPENMPT_CXX_API_MEMBER void ctl_set_text( std::string_view ctl, std::string_view value ); // remember to add new functions to both C and C++ interfaces and to increase OPENMPT_API_VERSION_MINOR }; // class module /*! @} */ } // namespace openmpt #endif // LIBOPENMPT_HPP libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h0000644000175000017500000000520114172232041027554 00000000000000/* * libopenmpt_stream_callbacks_file_posix_lfs64.h * ---------------------------------------------- * Purpose: libopenmpt public c interface * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_LFS64_H #define LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_LFS64_H #include "libopenmpt.h" #include #include #include /*! \addtogroup libopenmpt_c * @{ */ #ifdef __cplusplus extern "C" { #endif static size_t openmpt_stream_file_posix_lfs64_read_func( void * stream, void * dst, size_t bytes ) { FILE * f = 0; size_t retval = 0; f = (FILE*)stream; if ( !f ) { return 0; } retval = fread( dst, 1, bytes, f ); if ( retval <= 0 ) { return 0; } return retval; } static int openmpt_stream_file_posix_lfs64_seek_func( void * stream, int64_t offset, int whence ) { FILE * f = 0; int fwhence = 0; f = (FILE*)stream; if ( !f ) { return -1; } switch ( whence ) { case OPENMPT_STREAM_SEEK_SET: fwhence = SEEK_SET; break; case OPENMPT_STREAM_SEEK_CUR: fwhence = SEEK_CUR; break; case OPENMPT_STREAM_SEEK_END: fwhence = SEEK_END; break; default: return -1; break; } if ( (off64_t)offset != offset ) { return -1; } return fseeko64( f, (off64_t)offset, fwhence ) ? -1 : 0; } static int64_t openmpt_stream_file_posix_lfs64_tell_func( void * stream ) { FILE * f = 0; off64_t result = 0; int64_t retval = 0; f = (FILE*)stream; if ( !f ) { return -1; } result = ftello64( f ); if ( (int64_t)result != result ) { return -1; } retval = (int64_t)result; if ( retval < 0 ) { return -1; } return retval; } /*! \brief Provide openmpt_stream_callbacks for standard C FILE objects * * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. * * \remarks The stream argument must be passed as `(void*)(FILE*)file`. * \sa \ref libopenmpt_c_fileio * \sa openmpt_stream_callbacks * \sa openmpt_could_open_probability2 * \sa openmpt_probe_file_header_from_stream * \sa openmpt_module_create2 */ static openmpt_stream_callbacks openmpt_stream_get_file_posix_lfs64_callbacks(void) { openmpt_stream_callbacks retval; memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); retval.read = openmpt_stream_file_posix_lfs64_read_func; retval.seek = openmpt_stream_file_posix_lfs64_seek_func; retval.tell = openmpt_stream_file_posix_lfs64_tell_func; return retval; } #ifdef __cplusplus } #endif /*! * @} */ #endif /* LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_LFS64_H */ libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_impl.hpp0000644000175000017500000003304614705170364022347 00000000000000/* * libopenmpt_impl.hpp * ------------------- * Purpose: libopenmpt private interface * Notes : This is not a public header. Do NOT ship in distributions dev packages. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_IMPL_HPP #define LIBOPENMPT_IMPL_HPP #include "libopenmpt_internal.h" #include "libopenmpt.hpp" #include #include #include #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4512) // assignment operator could not be generated #endif // forward declarations namespace mpt { inline namespace mpt_libopenmpt { template class BasicPathString; struct NativePathTraits; struct Utf8PathTraits; using native_path = BasicPathString; namespace IO { class FileCursorTraitsFileData; template class FileCursorFilenameTraits; template class FileCursor; } // namespace IO } // namespace mpt_libopenmpt } // namespace mpt namespace OpenMPT { namespace detail { template using FileCursor = mpt::IO::FileCursor; } // namespace detail namespace mpt { #if defined(MPT_ENABLE_CHARSET_LOCALE) using PathString = mpt::native_path; #else using PathString = mpt::BasicPathString; #endif } // namespace mpt using FileCursor = detail::FileCursor>; class CSoundFile; struct DithersWrapperOpenMPT; } // namespace OpenMPT namespace openmpt { namespace version { std::uint32_t get_library_version(); std::uint32_t get_core_version(); std::string get_string( const std::string & key ); } // namespace version class log_interface { protected: log_interface(); public: virtual ~log_interface(); virtual void log( const std::string & message ) const = 0; }; // class log_interface class std_ostream_log : public log_interface { private: std::ostream & destination; public: std_ostream_log( std::ostream & dst ); virtual ~std_ostream_log(); void log( const std::string & message ) const override; }; // class CSoundFileLog_std_ostream class log_forwarder; struct callback_stream_wrapper { void * stream; std::size_t (*read)( void * stream, void * dst, std::size_t bytes ); int (*seek)( void * stream, std::int64_t offset, int whence ); std::int64_t (*tell)( void * stream ); }; // struct callback_stream_wrapper class module_impl { public: enum class amiga_filter_type { a500, a1200, unfiltered, auto_filter, }; protected: struct subsong_data { double duration; std::int32_t start_row; std::int32_t start_order; std::int32_t sequence; std::int32_t restart_row; std::int32_t restart_order; subsong_data( double duration, std::int32_t start_row, std::int32_t start_order, std::int32_t sequence, std::int32_t restart_row, std::int32_t restart_order ); }; // struct subsong_data typedef std::vector subsongs_type; enum class song_end_action { fadeout_song, continue_song, stop_song, }; static constexpr std::int32_t all_subsongs = -1; enum class ctl_type { boolean, integer, floatingpoint, text, }; struct ctl_info { const char * name; ctl_type type; }; std::unique_ptr m_Log; std::unique_ptr m_LogForwarder; std::int32_t m_current_subsong; double m_currentPositionSeconds; std::unique_ptr m_sndFile; bool m_loaded; bool m_mixer_initialized; std::unique_ptr m_Dithers; subsongs_type m_subsongs; float m_Gain; song_end_action m_ctl_play_at_end; amiga_filter_type m_ctl_render_resampler_emulate_amiga_type = amiga_filter_type::auto_filter; bool m_ctl_load_skip_samples; bool m_ctl_load_skip_patterns; bool m_ctl_load_skip_plugins; bool m_ctl_load_skip_subsongs_init; bool m_ctl_seek_sync_samples; std::vector m_loaderMessages; public: void PushToCSoundFileLog( const std::string & text ) const; void PushToCSoundFileLog( int loglevel, const std::string & text ) const; protected: std::string mod_string_to_utf8( const std::string & encoded ) const; void apply_mixer_settings( std::int32_t samplerate, int channels ); void apply_libopenmpt_defaults(); subsongs_type get_subsongs() const; void init_subsongs( subsongs_type & subsongs ) const; bool has_subsongs_inited() const; void ctor( const std::map< std::string, std::string > & ctls ); void load( const OpenMPT::FileCursor & file, const std::map< std::string, std::string > & ctls ); bool is_loaded() const; std::size_t read_wrapper( std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right ); std::size_t read_wrapper( std::size_t count, float * left, float * right, float * rear_left, float * rear_right ); std::size_t read_interleaved_wrapper( std::size_t count, std::size_t channels, std::int16_t * interleaved ); std::size_t read_interleaved_wrapper( std::size_t count, std::size_t channels, float * interleaved ); std::string get_message_instruments() const; std::string get_message_samples() const; std::pair< std::string, std::string > format_and_highlight_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int command ) const; std::pair< std::string, std::string > format_and_highlight_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const; static double could_open_probability( const OpenMPT::FileCursor & file, double effort, std::unique_ptr log ); public: static std::vector get_supported_extensions(); static bool is_extension_supported( std::string_view extension ); static double could_open_probability( callback_stream_wrapper stream, double effort, std::unique_ptr log ); static double could_open_probability( std::istream & stream, double effort, std::unique_ptr log ); static std::size_t probe_file_header_get_recommended_size(); static int probe_file_header( std::uint64_t flags, const std::byte * data, std::size_t size, std::uint64_t filesize ); static int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size, std::uint64_t filesize ); static int probe_file_header( std::uint64_t flags, const void * data, std::size_t size, std::uint64_t filesize ); static int probe_file_header( std::uint64_t flags, const std::byte * data, std::size_t size ); static int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size ); static int probe_file_header( std::uint64_t flags, const void * data, std::size_t size ); static int probe_file_header( std::uint64_t flags, std::istream & stream ); static int probe_file_header( std::uint64_t flags, callback_stream_wrapper stream ); module_impl( callback_stream_wrapper stream, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_impl( std::istream & stream, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_impl( const std::vector & data, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_impl( const std::byte * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_impl( const std::uint8_t * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_impl( const char * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); module_impl( const void * data, std::size_t size, std::unique_ptr log, const std::map< std::string, std::string > & ctls ); ~module_impl(); public: void select_subsong( std::int32_t subsong ); std::int32_t get_selected_subsong() const; std::int32_t get_restart_order( std::int32_t subsong ) const; std::int32_t get_restart_row( std::int32_t subsong ) const; void set_repeat_count( std::int32_t repeat_count ); std::int32_t get_repeat_count() const; double get_duration_seconds() const; double get_time_at_position( std::int32_t order, std::int32_t row ) const; double set_position_seconds( double seconds ); double get_position_seconds() const; double set_position_order_row( std::int32_t order, std::int32_t row ); std::int32_t get_render_param( int param ) const; void set_render_param( int param, std::int32_t value ); std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * mono ); std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right ); std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right ); std::size_t read( std::int32_t samplerate, std::size_t count, float * mono ); std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right ); std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right, float * rear_left, float * rear_right ); std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_stereo ); std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_quad ); std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, float * interleaved_stereo ); std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, float * interleaved_quad ); std::vector get_metadata_keys() const; std::string get_metadata( const std::string & key ) const; double get_current_estimated_bpm() const; std::int32_t get_current_speed() const; std::int32_t get_current_tempo() const; double get_current_tempo2() const; std::int32_t get_current_order() const; std::int32_t get_current_pattern() const; std::int32_t get_current_row() const; std::int32_t get_current_playing_channels() const; float get_current_channel_vu_mono( std::int32_t channel ) const; float get_current_channel_vu_left( std::int32_t channel ) const; float get_current_channel_vu_right( std::int32_t channel ) const; float get_current_channel_vu_rear_left( std::int32_t channel ) const; float get_current_channel_vu_rear_right( std::int32_t channel ) const; std::int32_t get_num_subsongs() const; std::int32_t get_num_channels() const; std::int32_t get_num_orders() const; std::int32_t get_num_patterns() const; std::int32_t get_num_instruments() const; std::int32_t get_num_samples() const; std::vector get_subsong_names() const; std::vector get_channel_names() const; std::vector get_order_names() const; std::vector get_pattern_names() const; std::vector get_instrument_names() const; std::vector get_sample_names() const; std::int32_t get_order_pattern( std::int32_t o ) const; bool is_order_skip_entry( std::int32_t order ) const; static bool is_pattern_skip_item( std::int32_t pattern ); bool is_order_stop_entry( std::int32_t order ) const; static bool is_pattern_stop_item( std::int32_t pattern ); std::int32_t get_pattern_num_rows( std::int32_t p ) const; std::int32_t get_pattern_rows_per_beat( std::int32_t pattern ) const; std::int32_t get_pattern_rows_per_measure( std::int32_t pattern ) const; std::uint8_t get_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const; std::string format_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const; std::string highlight_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const; std::string format_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const; std::string highlight_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const; std::pair get_ctl_infos() const; std::vector get_ctls() const; std::string ctl_get( std::string ctl, bool throw_if_unknown = true ) const; bool ctl_get_boolean( std::string_view ctl, bool throw_if_unknown = true ) const; std::int64_t ctl_get_integer( std::string_view ctl, bool throw_if_unknown = true ) const; double ctl_get_floatingpoint( std::string_view ctl, bool throw_if_unknown = true ) const; std::string ctl_get_text( std::string_view ctl, bool throw_if_unknown = true ) const; void ctl_set( std::string ctl, const std::string & value, bool throw_if_unknown = true ); void ctl_set_boolean( std::string_view ctl, bool value, bool throw_if_unknown = true ); void ctl_set_integer( std::string_view ctl, std::int64_t value, bool throw_if_unknown = true ); void ctl_set_floatingpoint( std::string_view ctl, double value, bool throw_if_unknown = true ); void ctl_set_text( std::string_view ctl, std::string_view value, bool throw_if_unknown = true ); }; // class module_impl namespace helper { template std::unique_ptr make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } } // namespace helper } // namespace openmpt #if defined(_MSC_VER) #pragma warning(pop) #endif #endif // LIBOPENMPT_IMPL_HPP libopenmpt-0.8.1+release.autotools/libopenmpt/libopenmpt_internal.h0000644000175000017500000000162014057134205022645 00000000000000/* * libopenmpt_internal.h * --------------------- * Purpose: libopenmpt internal interface configuration, overruling the public interface configuration (only used and needed when building libopenmpt) * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef LIBOPENMPT_INTERNAL_H #define LIBOPENMPT_INTERNAL_H #include "libopenmpt_config.h" #ifdef __cplusplus #if defined(LIBOPENMPT_BUILD_DLL) || defined(LIBOPENMPT_USE_DLL) #if defined(_MSC_VER) && !defined(_DLL) /* #pragma message( "libopenmpt C++ interface is disabled if libopenmpt is built as a DLL and the runtime is statically linked. This is not supported by microsoft and cannot possibly work. Ever." ) */ #undef LIBOPENMPT_CXX_API #define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_LOCAL #endif #endif #endif #endif /* LIBOPENMPT_INTERNAL_H */ libopenmpt-0.8.1+release.autotools/configure0000755000175000017500000314510215023302323016164 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for libopenmpt 0.8.1+release.autotools. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and $0: https://bugs.openmpt.org/ about your system, including $0: any error possibly output before this message. Then $0: install a modern shell, or manually run the script $0: under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='libopenmpt' PACKAGE_TARNAME='libopenmpt' PACKAGE_VERSION='0.8.1+release.autotools' PACKAGE_STRING='libopenmpt 0.8.1+release.autotools' PACKAGE_BUGREPORT='https://bugs.openmpt.org/' PACKAGE_URL='https://lib.openmpt.org/' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS DX_RULES PAPER_SIZE DOXYGEN_PAPER_SIZE GENERATE_LATEX DX_PDFLATEX DX_FLAG_pdf DX_EGREP DX_DVIPS DX_MAKEINDEX DX_LATEX DX_FLAG_ps DX_FLAG_html GENERATE_CHI DX_FLAG_chi GENERATE_HTMLHELP GENERATE_HTML HHC_PATH DX_HHC DX_FLAG_chm GENERATE_XML DX_FLAG_xml GENERATE_RTF DX_FLAG_rtf GENERATE_MAN DX_FLAG_man DOT_PATH HAVE_DOT DX_DOT DX_FLAG_dot PERL_PATH DX_PERL DX_DOXYGEN DX_FLAG_doc PROJECT SRCDIR DX_ENV DX_DOCDIR DX_CONFIG DX_PROJECT FLAC_LIBS FLAC_CFLAGS SNDFILE_LIBS SNDFILE_CFLAGS SDL2_LIBS SDL2_CFLAGS HAVE_PORTAUDIOCPP_FALSE HAVE_PORTAUDIOCPP_TRUE PORTAUDIOCPP_LIBS PORTAUDIOCPP_CFLAGS HAVE_PORTAUDIO_FALSE HAVE_PORTAUDIO_TRUE PORTAUDIO_LIBS PORTAUDIO_CFLAGS PULSEAUDIO_LIBS PULSEAUDIO_CFLAGS ENABLE_TESTS_FALSE ENABLE_TESTS_TRUE ENABLE_EXAMPLES_FALSE ENABLE_EXAMPLES_TRUE ENABLE_OPENMPT123_FALSE ENABLE_OPENMPT123_TRUE LIBOPENMPT_LIBS_PRIVATE LIBOPENMPT_REQUIRES_PRIVATE VORBISFILE_LIBS VORBISFILE_CFLAGS VORBIS_LIBS VORBIS_CFLAGS OGG_LIBS OGG_CFLAGS MPG123_LIBS MPG123_CFLAGS ZLIB_LIBS ZLIB_CFLAGS WIN32_CONSOLE_CFLAGS WIN32_CONSOLE_CXXFLAGS WIN32_CFLAGS WIN32_CXXFLAGS WIN32_CPPFLAGS OPENMPT123_WIN32_LIBS LIBOPENMPTTEST_WIN32_LIBS LIBOPENMPT_WIN32_LIBS CXXSTDLIB_PCLIBSPRIVATE LIBOPENMPT_LTVER_AGE LIBOPENMPT_LTVER_REVISION LIBOPENMPT_LTVER_CURRENT GLOBAL_CXXFLAGS GLOBAL_CFLAGS GLOBAL_CPPFLAGS PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CXX PTHREAD_CC ax_pthread_config CPP HAVE_CXX17 HAVE_CXX20 HAVE_CXX23 CXXCPP am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE ac_ct_CXX CXXFLAGS CXX PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG LT_SYS_LIBRARY_PATH OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB DLLTOOL OBJDUMP FILECMD LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL ac_ct_AR AR am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V CSCOPE ETAGS CTAGS am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking enable_shared enable_static with_pic enable_fast_install with_aix_soname with_gnu_ld with_sysroot enable_libtool_lock enable_largefile with_zlib with_mpg123 with_ogg with_vorbis with_vorbisfile enable_openmpt123 enable_examples enable_tests with_pulseaudio with_portaudio with_portaudiocpp with_sdl2 with_sndfile with_flac enable_doxygen_doc enable_doxygen_dot enable_doxygen_man enable_doxygen_rtf enable_doxygen_xml enable_doxygen_chm enable_doxygen_chi enable_doxygen_html enable_doxygen_ps enable_doxygen_pdf ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS LT_SYS_LIBRARY_PATH PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR CXX CXXFLAGS CCC CXXCPP CPP CXXSTDLIB_PCLIBSPRIVATE ZLIB_CFLAGS ZLIB_LIBS MPG123_CFLAGS MPG123_LIBS OGG_CFLAGS OGG_LIBS VORBIS_CFLAGS VORBIS_LIBS VORBISFILE_CFLAGS VORBISFILE_LIBS PULSEAUDIO_CFLAGS PULSEAUDIO_LIBS PORTAUDIO_CFLAGS PORTAUDIO_LIBS PORTAUDIOCPP_CFLAGS PORTAUDIOCPP_LIBS SDL2_CFLAGS SDL2_LIBS SNDFILE_CFLAGS SNDFILE_LIBS FLAC_CFLAGS FLAC_LIBS DOXYGEN_PAPER_SIZE' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures libopenmpt 0.8.1+release.autotools to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/libopenmpt] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of libopenmpt 0.8.1+release.autotools:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --disable-largefile omit support for large files --disable-openmpt123 Disable the openmpt123 command line player. --disable-examples Disable the example programs. --disable-tests Disable the test suite. --disable-doxygen-doc don't generate any doxygen documentation --enable-doxygen-dot generate graphics for doxygen documentation --enable-doxygen-man generate doxygen manual pages --enable-doxygen-rtf generate doxygen RTF documentation --enable-doxygen-xml generate doxygen XML documentation --enable-doxygen-chm generate doxygen compressed HTML help documentation --enable-doxygen-chi generate doxygen separate compressed HTML help index file --disable-doxygen-html don't generate doxygen plain HTML documentation --enable-doxygen-ps generate doxygen PostScript documentation --enable-doxygen-pdf generate doxygen PDF documentation Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-aix-soname=aix|svr4|both shared library versioning (aka "SONAME") variant to provide on AIX, [default=aix]. --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --without-zlib Disable use of zlib. --without-mpg123 Disable use of libmpg123. --without-ogg Disable use of libogg. --without-vorbis Disable use of libvorbis. --without-vorbisfile Disable use of libvorbisfile. --with-pulseaudio Enable use of libpulse and libpulse-simple (enabled by default on Linux). --without-portaudio Disable use of libportaudio. --without-portaudiocpp Disable use of libportaudiocpp. --with-sdl2 Enable use of libsdl2. --without-sndfile Disable use of libsndfile. --without-flac Disable use of libflac. Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory LT_SYS_LIBRARY_PATH User-defined run-time library search path. PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path CXX C++ compiler command CXXFLAGS C++ compiler flags CXXCPP C++ preprocessor CPP C preprocessor CXXSTDLIB_PCLIBSPRIVATE C++ standard library (or libraries) required for static linking. This will be put in the pkg-config file libopenmpt.pc Libs.private field and used for nothing else. ZLIB_CFLAGS C compiler flags for ZLIB, overriding pkg-config ZLIB_LIBS linker flags for ZLIB, overriding pkg-config MPG123_CFLAGS C compiler flags for MPG123, overriding pkg-config MPG123_LIBS linker flags for MPG123, overriding pkg-config OGG_CFLAGS C compiler flags for OGG, overriding pkg-config OGG_LIBS linker flags for OGG, overriding pkg-config VORBIS_CFLAGS C compiler flags for VORBIS, overriding pkg-config VORBIS_LIBS linker flags for VORBIS, overriding pkg-config VORBISFILE_CFLAGS C compiler flags for VORBISFILE, overriding pkg-config VORBISFILE_LIBS linker flags for VORBISFILE, overriding pkg-config PULSEAUDIO_CFLAGS C compiler flags for PULSEAUDIO, overriding pkg-config PULSEAUDIO_LIBS linker flags for PULSEAUDIO, overriding pkg-config PORTAUDIO_CFLAGS C compiler flags for PORTAUDIO, overriding pkg-config PORTAUDIO_LIBS linker flags for PORTAUDIO, overriding pkg-config PORTAUDIOCPP_CFLAGS C compiler flags for PORTAUDIOCPP, overriding pkg-config PORTAUDIOCPP_LIBS linker flags for PORTAUDIOCPP, overriding pkg-config SDL2_CFLAGS C compiler flags for SDL2, overriding pkg-config SDL2_LIBS linker flags for SDL2, overriding pkg-config SNDFILE_CFLAGS C compiler flags for SNDFILE, overriding pkg-config SNDFILE_LIBS linker flags for SNDFILE, overriding pkg-config FLAC_CFLAGS C compiler flags for FLAC, overriding pkg-config FLAC_LIBS linker flags for FLAC, overriding pkg-config DOXYGEN_PAPER_SIZE a4wide (default), a4, letter, legal or executive Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . libopenmpt home page: . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF libopenmpt configure 0.8.1+release.autotools generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by libopenmpt $as_me 0.8.1+release.autotools, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" # Test code for whether the C++ compiler supports C++98 (global declarations) ac_cxx_conftest_cxx98_globals=' // Does the compiler advertise C++98 conformance? #if !defined __cplusplus || __cplusplus < 199711L # error "Compiler does not advertise C++98 conformance" #endif // These inclusions are to reject old compilers that // lack the unsuffixed header files. #include #include // and are *not* freestanding headers in C++98. extern void assert (int); namespace std { extern int strcmp (const char *, const char *); } // Namespaces, exceptions, and templates were all added after "C++ 2.0". using std::exception; using std::strcmp; namespace { void test_exception_syntax() { try { throw "test"; } catch (const char *s) { // Extra parentheses suppress a warning when building autoconf itself, // due to lint rules shared with more typical C programs. assert (!(strcmp) (s, "test")); } } template struct test_template { T const val; explicit test_template(T t) : val(t) {} template T add(U u) { return static_cast(u) + val; } }; } // anonymous namespace ' # Test code for whether the C++ compiler supports C++98 (body of main) ac_cxx_conftest_cxx98_main=' assert (argc); assert (! argv[0]); { test_exception_syntax (); test_template tt (2.0); assert (tt.add (4) == 6.0); assert (true && !false); } ' # Test code for whether the C++ compiler supports C++11 (global declarations) ac_cxx_conftest_cxx11_globals=' // Does the compiler advertise C++ 2011 conformance? #if !defined __cplusplus || __cplusplus < 201103L # error "Compiler does not advertise C++11 conformance" #endif namespace cxx11test { constexpr int get_val() { return 20; } struct testinit { int i; double d; }; class delegate { public: delegate(int n) : n(n) {} delegate(): delegate(2354) {} virtual int getval() { return this->n; }; protected: int n; }; class overridden : public delegate { public: overridden(int n): delegate(n) {} virtual int getval() override final { return this->n * 2; } }; class nocopy { public: nocopy(int i): i(i) {} nocopy() = default; nocopy(const nocopy&) = delete; nocopy & operator=(const nocopy&) = delete; private: int i; }; // for testing lambda expressions template Ret eval(Fn f, Ret v) { return f(v); } // for testing variadic templates and trailing return types template auto sum(V first) -> V { return first; } template auto sum(V first, Args... rest) -> V { return first + sum(rest...); } } ' # Test code for whether the C++ compiler supports C++11 (body of main) ac_cxx_conftest_cxx11_main=' { // Test auto and decltype auto a1 = 6538; auto a2 = 48573953.4; auto a3 = "String literal"; int total = 0; for (auto i = a3; *i; ++i) { total += *i; } decltype(a2) a4 = 34895.034; } { // Test constexpr short sa[cxx11test::get_val()] = { 0 }; } { // Test initializer lists cxx11test::testinit il = { 4323, 435234.23544 }; } { // Test range-based for int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; for (auto &x : array) { x += 23; } } { // Test lambda expressions using cxx11test::eval; assert (eval ([](int x) { return x*2; }, 21) == 42); double d = 2.0; assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); assert (d == 5.0); assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); assert (d == 5.0); } { // Test use of variadic templates using cxx11test::sum; auto a = sum(1); auto b = sum(1, 2); auto c = sum(1.0, 2.0, 3.0); } { // Test constructor delegation cxx11test::delegate d1; cxx11test::delegate d2(); cxx11test::delegate d3(45); } { // Test override and final cxx11test::overridden o1(55464); } { // Test nullptr char *c = nullptr; } { // Test template brackets test_template<::test_template> v(test_template(12)); } { // Unicode literals char const *utf8 = u8"UTF-8 string \u2500"; char16_t const *utf16 = u"UTF-8 string \u2500"; char32_t const *utf32 = U"UTF-32 string \u2500"; } ' # Test code for whether the C compiler supports C++11 (complete). ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} ${ac_cxx_conftest_cxx11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_cxx_conftest_cxx98_main} ${ac_cxx_conftest_cxx11_main} return ok; } " # Test code for whether the C compiler supports C++98 (complete). ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} int main (int argc, char **argv) { int ok = 0; ${ac_cxx_conftest_cxx98_main} return ok; } " # Auxiliary files required by this configure script. ac_aux_files="config.guess config.sub ltmain.sh ar-lib compile missing install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}/build-aux" # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # we do want 2.70, but distributions are not ready yet #AC_PREREQ([2.70]) ac_config_files="$ac_config_files Makefile libopenmpt/libopenmpt.pc Doxyfile" am__api_version='1.16' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. case $as_dir in #(( ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir ('*'coreutils) '* | \ 'BusyBox '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test ${enable_silent_rules+y} then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 else $as_nop if printf "%s\n" 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='libopenmpt' VERSION='0.8.1+release.autotools' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi if test -z "$ETAGS"; then ETAGS=etags fi if test -z "$CSCOPE"; then CSCOPE=cscope fi # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in #( '0:this is the am__doit target') : case $s in #( BSD) : am__include='.include' am__quote='"' ;; #( *) : am__include='include' am__quote='' ;; esac ;; #( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 printf "%s\n" "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } if test ${ac_cv_safe_to_define___extensions__+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 $ac_includes_default int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_safe_to_define___extensions__=yes else $as_nop ac_cv_safe_to_define___extensions__=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } if test ${ac_cv_should_define__xopen_source+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_should_define__xopen_source=no if test $ac_cv_header_wchar_h = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 500 #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_should_define__xopen_source=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } printf "%s\n" "#define _ALL_SOURCE 1" >>confdefs.h printf "%s\n" "#define _DARWIN_C_SOURCE 1" >>confdefs.h printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h printf "%s\n" "#define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h printf "%s\n" "#define _NETBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _OPENBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h printf "%s\n" "#define _TANDEM_SOURCE 1" >>confdefs.h if test $ac_cv_header_minix_config_h = yes then : MINIX=yes printf "%s\n" "#define _MINIX 1" >>confdefs.h printf "%s\n" "#define _POSIX_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h else $as_nop MINIX= fi if test $ac_cv_safe_to_define___extensions__ = yes then : printf "%s\n" "#define __EXTENSIONS__ 1" >>confdefs.h fi if test $ac_cv_should_define__xopen_source = yes then : printf "%s\n" "#define _XOPEN_SOURCE 500" >>confdefs.h fi if test -n "$ac_tool_prefix"; then for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 printf %s "checking the archiver ($AR) interface... " >&6; } if test ${am_cv_ar_interface+y} then : printf %s "(cached) " >&6 else $as_nop ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am_cv_ar_interface=ar cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int some_variable = 0; _ACEOF if ac_fn_c_try_compile "$LINENO" then : am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 printf "%s\n" "$am_cv_ar_interface" >&6; } case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) as_fn_error $? "could not determine $AR interface" "$LINENO" 5 ;; esac case `pwd` in *\ * | *\ *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 printf "%s\n" "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.7' macro_revision='2.4.7' ltmain=$ac_aux_dir/ltmain.sh # Make sure we can run config.sub. $SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 printf %s "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case $ECHO in printf*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: printf" >&5 printf "%s\n" "printf" >&6; } ;; print*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 printf "%s\n" "print -r" >&6; } ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cat" >&5 printf "%s\n" "cat" >&6; } ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 printf %s "checking for a sed that does not truncate output... " >&6; } if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 else $as_nop ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in sed gsed do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 printf "%s\n" "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in grep ggrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in egrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 printf %s "checking for fgrep... " >&6; } if test ${ac_cv_path_FGREP+y} then : printf %s "(cached) " >&6 else $as_nop if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in fgrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 printf "%s\n" "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test ${with_gnu_ld+y} then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes else $as_nop with_gnu_ld=no fi ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 printf %s "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 printf %s "checking for GNU ld... " >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 printf %s "checking for non-GNU ld... " >&6; } fi if test ${lt_cv_path_LD+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 printf "%s\n" "$LD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 printf %s "checking if the linker ($LD) is GNU ld... " >&6; } if test ${lt_cv_prog_gnu_ld+y} then : printf %s "(cached) " >&6 else $as_nop # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if test ${lt_cv_path_NM+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_nm if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 printf "%s\n" "$lt_cv_path_NM" >&6; } if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 printf "%s\n" "$DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 printf "%s\n" "$ac_ct_DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 printf %s "checking the name lister ($NM) interface... " >&6; } if test ${lt_cv_nm_interface+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 printf "%s\n" "$lt_cv_nm_interface" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 printf "%s\n" "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 printf %s "checking the maximum length of command line arguments... " >&6; } if test ${lt_cv_sys_max_cmd_len+y} then : printf %s "(cached) " >&6 else $as_nop i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n "$lt_cv_sys_max_cmd_len"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 printf "%s\n" "$lt_cv_sys_max_cmd_len" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 printf "%s\n" "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 printf %s "checking how to convert $build file names to $host format... " >&6; } if test ${lt_cv_to_host_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 printf "%s\n" "$lt_cv_to_host_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 printf %s "checking how to convert $build file names to toolchain format... " >&6; } if test ${lt_cv_to_tool_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 printf "%s\n" "$lt_cv_to_tool_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 printf %s "checking for $LD option to reload object files... " >&6; } if test ${lt_cv_ld_reload_flag+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ld_reload_flag='-r' fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 printf "%s\n" "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test yes != "$GCC"; then reload_cmds=false fi ;; darwin*) if test yes = "$GCC"; then reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}file", so it can be a program name with args. set dummy ${ac_tool_prefix}file; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_FILECMD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$FILECMD"; then ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_FILECMD="${ac_tool_prefix}file" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi FILECMD=$ac_cv_prog_FILECMD if test -n "$FILECMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 printf "%s\n" "$FILECMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_FILECMD"; then ac_ct_FILECMD=$FILECMD # Extract the first word of "file", so it can be a program name with args. set dummy file; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_FILECMD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_FILECMD"; then ac_cv_prog_ac_ct_FILECMD="$ac_ct_FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_FILECMD="file" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_FILECMD=$ac_cv_prog_ac_ct_FILECMD if test -n "$ac_ct_FILECMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_FILECMD" >&5 printf "%s\n" "$ac_ct_FILECMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_FILECMD" = x; then FILECMD=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac FILECMD=$ac_ct_FILECMD fi else FILECMD="$ac_cv_prog_FILECMD" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 printf "%s\n" "$OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 printf "%s\n" "$ac_ct_OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 printf %s "checking how to recognize dependent libraries... " >&6; } if test ${lt_cv_deplibs_check_method+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure # whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='$FILECMD -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly* | midnightbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=$FILECMD lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=$FILECMD case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=$FILECMD lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 printf "%s\n" "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 printf "%s\n" "$DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 printf "%s\n" "$ac_ct_DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 printf %s "checking how to associate runtime and link libraries... " >&6; } if test ${lt_cv_sharedlib_from_linklib_cmd+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 printf "%s\n" "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} # Use ARFLAGS variable as AR's operation code to sync the variable naming with # Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have # higher priority because thats what people were doing historically (setting # ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS # variable obsoleted/removed. test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} lt_ar_flags=$AR_FLAGS # Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override # by AR_FLAGS because that was never working and AR_FLAGS is about to die. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 printf %s "checking for archiver @FILE support... " >&6; } if test ${lt_cv_ar_at_file+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 printf "%s\n" "$lt_cv_ar_at_file" >&6; } if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 printf %s "checking command to parse $NM output from $compiler object... " >&6; } if test ${lt_cv_sys_global_symbol_pipe+y} then : printf %s "(cached) " >&6 else $as_nop # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++ or ICC, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 printf "%s\n" "failed" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5 printf "%s\n" "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 printf %s "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test ${with_sysroot+y} then : withval=$with_sysroot; else $as_nop with_sysroot=no fi lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 printf "%s\n" "$with_sysroot" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 printf "%s\n" "${lt_sysroot:-no}" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 printf %s "checking for a working dd... " >&6; } if test ${ac_cv_path_lt_DD+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} if test -z "$lt_DD"; then ac_path_lt_DD_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in dd do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_lt_DD" || continue if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi $ac_path_lt_DD_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_lt_DD"; then : fi else ac_cv_path_lt_DD=$lt_DD fi rm -f conftest.i conftest2.i conftest.out fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 printf "%s\n" "$ac_cv_path_lt_DD" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 printf %s "checking how to truncate binary pipes... " >&6; } if test ${lt_cv_truncate_bin+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 printf "%s\n" "$lt_cv_truncate_bin" >&6; } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # Check whether --enable-libtool-lock was given. if test ${enable_libtool_lock+y} then : enableval=$enable_libtool_lock; fi test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test yes = "$lt_cv_prog_gnu_ld"; then case `$FILECMD conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `$FILECMD conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then emul=elf case `$FILECMD conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `$FILECMD conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `$FILECMD conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `$FILECMD conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 printf %s "checking whether the C compiler needs -belf... " >&6; } if test ${lt_cv_cc_needs_belf+y} then : printf %s "(cached) " >&6 else $as_nop ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_cc_needs_belf=yes else $as_nop lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 printf "%s\n" "$lt_cv_cc_needs_belf" >&6; } if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 printf "%s\n" "$MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 printf "%s\n" "$ac_ct_MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if test ${lt_cv_path_mainfest_tool+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; } if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 printf "%s\n" "$DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 printf "%s\n" "$ac_ct_DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 printf "%s\n" "$NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 printf "%s\n" "$ac_ct_NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 printf "%s\n" "$LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 printf "%s\n" "$ac_ct_LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 printf "%s\n" "$OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 printf "%s\n" "$ac_ct_OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 printf "%s\n" "$OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 printf "%s\n" "$ac_ct_OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 printf %s "checking for -single_module linker flag... " >&6; } if test ${lt_cv_apple_cc_single_mod+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 printf %s "checking for -exported_symbols_list linker flag... " >&6; } if test ${lt_cv_ld_exported_symbols_list+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_ld_exported_symbols_list=yes else $as_nop lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 printf %s "checking for -force_load linker flag... " >&6; } if test ${lt_cv_ld_force_load+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR $AR_FLAGS libconftest.a conftest.o" >&5 $AR $AR_FLAGS libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 printf "%s\n" "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) case $MACOSX_DEPLOYMENT_TARGET,$host in 10.[012],*|,*powerpc*-darwin[5-8]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; *) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes then : printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h fi # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test ${enable_shared+y} then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac else $as_nop enable_shared=yes fi # Check whether --enable-static was given. if test ${enable_static+y} then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac else $as_nop enable_static=yes fi # Check whether --with-pic was given. if test ${with_pic+y} then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac else $as_nop pic_mode=default fi # Check whether --enable-fast-install was given. if test ${enable_fast_install+y} then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac else $as_nop enable_fast_install=yes fi shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[5-9]*,yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 printf %s "checking which variant of shared library versioning to provide... " >&6; } # Check whether --with-aix-soname was given. if test ${with_aix_soname+y} then : withval=$with_aix_soname; case $withval in aix|svr4|both) ;; *) as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 ;; esac lt_cv_with_aix_soname=$with_aix_soname else $as_nop if test ${lt_cv_with_aix_soname+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_with_aix_soname=aix fi with_aix_soname=$lt_cv_with_aix_soname fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 printf "%s\n" "$with_aix_soname" >&6; } if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 printf %s "checking for objdir... " >&6; } if test ${lt_cv_objdir+y} then : printf %s "(cached) " >&6 else $as_nop rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 printf "%s\n" "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir printf "%s\n" "#define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC and # ICC, which need '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o func_cc_basename $compiler cc_basename=$func_cc_basename_result # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 printf %s "checking for ${ac_tool_prefix}file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/${ac_tool_prefix}file"; then lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for file" >&5 printf %s "checking for file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/file"; then lt_cv_path_MAGIC_CMD=$ac_dir/"file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC=$CC ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test yes = "$GCC"; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if test ${lt_cv_prog_compiler_rtti_exceptions+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test yes = "$GCC"; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi lt_prog_compiler_pic='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | $SED 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 printf %s "checking for $compiler option to produce PIC... " >&6; } if test ${lt_cv_prog_compiler_pic+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if test ${lt_cv_prog_compiler_pic_works+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; } if test yes = "$lt_cv_prog_compiler_pic_works"; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if test ${lt_cv_prog_compiler_static_works+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_static_works=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; } if test yes = "$lt_cv_prog_compiler_static_works"; then : else lt_prog_compiler_static= fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } hard_links=nottested if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 printf %s "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 printf "%s\n" "$hard_links" >&6; } if test no = "$hard_links"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 printf "%s\n" "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ' (' and ')$', so one must not match beginning or # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', # as well as any symbol that contains 'd'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' export_dynamic_flag_spec='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='$wl--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' link_all_deplibs=yes ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='$wl-rpath,$libdir' export_dynamic_flag_spec='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | $SED 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' export_dynamic_flag_spec='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test no = "$ld_shlibs"; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. hardcode_direct=no hardcode_direct_absolute=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi export_dynamic_flag_spec='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' $wl-bernotok' allow_undefined_flag=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl* | icl*) # Native MSVC or ICC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC and ICC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test yes = "$lt_cv_ld_force_load"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" archive_expsym_cmds="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" module_expsym_cmds="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly* | midnightbsd*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test yes = "$GCC"; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 printf %s "checking if $CC understands -b... " >&6; } if test ${lt_cv_prog_compiler__b+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler__b=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 printf "%s\n" "$lt_cv_prog_compiler__b" >&6; } if test yes = "$lt_cv_prog_compiler__b"; then archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test no = "$with_gnu_ld"; then hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if test ${lt_cv_irix_exported_symbol+y} then : printf %s "(cached) " >&6 else $as_nop save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_irix_exported_symbol=yes else $as_nop lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } if test yes = "$lt_cv_irix_exported_symbol"; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi link_all_deplibs=no else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler ld_shlibs=yes archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' ;; esac ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='$wl-rpath,$libdir' export_dynamic_flag_spec='$wl-E' else archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath,$libdir' fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; osf3*) if test yes = "$GCC"; then allow_undefined_flag=' $wl-expect_unresolved $wl\*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then allow_undefined_flag=' $wl-expect_unresolved $wl\*' archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test yes = "$GCC"; then wlarc='$wl' archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='$wl' archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='$wl-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='$wl-z,text' allow_undefined_flag='$wl-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='$wl-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='$wl-Blargedynsym' ;; esac fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 printf "%s\n" "$ld_shlibs" >&6; } test no = "$ld_shlibs" && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test yes,yes = "$GCC,$enable_shared"; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 printf %s "checking whether -lc should be explicitly linked in... " >&6; } if test ${lt_cv_archive_cmds_need_lc+y} then : printf %s "(cached) " >&6 else $as_nop $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 printf %s "checking dynamic linker characteristics... " >&6; } if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([A-Za-z]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a(lib.so.V)' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl* | *,icl*) # Native MSVC or ICC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC and ICC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly* | midnightbsd*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. hardcode_libdir_flag_spec='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if test ${lt_cv_shlibpath_overrides_runpath+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 printf "%s\n" "$dynamic_linker" >&6; } test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 printf %s "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test yes = "$hardcode_automatic"; then # We can hardcode non-existent directories. if test no != "$hardcode_direct" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && test no != "$hardcode_minus_L"; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 printf "%s\n" "$hardcode_action" >&6; } if test relink = "$hardcode_action" || test yes = "$inherit_rpath"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else $as_nop lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes then : lt_cv_dlopen=shl_load else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 printf %s "checking for shl_load in -ldld... " >&6; } if test ${ac_cv_lib_dld_shl_load+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char shl_load (); int main (void) { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_shl_load=yes else $as_nop ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes then : lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld else $as_nop ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes then : lt_cv_dlopen=dlopen else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 printf %s "checking for dlopen in -lsvld... " >&6; } if test ${ac_cv_lib_svld_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_svld_dlopen=yes else $as_nop ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 printf "%s\n" "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 printf %s "checking for dld_link in -ldld... " >&6; } if test ${ac_cv_lib_dld_dld_link+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char dld_link (); int main (void) { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_dld_link=yes else $as_nop ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 printf "%s\n" "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes then : lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld fi fi fi fi fi fi ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 printf %s "checking whether a program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 printf "%s\n" "$lt_cv_dlopen_self" >&6; } if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 printf %s "checking whether a statically linked program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self_static+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 printf "%s\n" "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 printf %s "checking whether stripping libraries is possible... " >&6; } if test -z "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case $host_os in darwin*) # FIXME - insert some real tests, host_os isn't really good enough striplib="$STRIP -x" old_striplib="$STRIP -S" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } ;; freebsd*) if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi fi # Report what library types will actually be built { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 printf %s "checking if libtool supports shared libraries... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 printf "%s\n" "$can_build_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 printf %s "checking whether to build shared libraries... " >&6; } test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 printf "%s\n" "$enable_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 printf %s "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 printf "%s\n" "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC=$lt_save_CC ac_config_commands="$ac_config_commands libtool" # Only expand once: # Check whether --enable-largefile was given. if test ${enable_largefile+y} then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 printf %s "checking for special C compiler options needed for large files... " >&6; } if test ${ac_cv_sys_largefile_CC+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : break fi rm -f core conftest.err conftest.$ac_objext conftest.beam CC="$CC -n32" if ac_fn_c_try_compile "$LINENO" then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if test ${ac_cv_sys_file_offset_bits+y} then : printf %s "(cached) " >&6 else $as_nop while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 printf %s "checking for _LARGE_FILES value needed for large files... " >&6; } if test ${ac_cv_sys_large_files+y} then : printf %s "(cached) " >&6 else $as_nop while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 printf "%s\n" "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h ;; esac rm -rf conftest* fi fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else $as_nop case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 printf "%s\n" "$PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.24 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } PKG_CONFIG="" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CXX+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 printf "%s\n" "$CXX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CXX+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 printf "%s\n" "$ac_ct_CXX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 printf %s "checking whether the compiler supports GNU C++... " >&6; } if test ${ac_cv_cxx_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+y} ac_save_CXXFLAGS=$CXXFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 printf %s "checking whether $CXX accepts -g... " >&6; } if test ${ac_cv_prog_cxx_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes else $as_nop CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : else $as_nop ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } if test $ac_test_CXXFLAGS; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_prog_cxx_stdcxx=no if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 printf %s "checking for $CXX option to enable C++11 features... " >&6; } if test ${ac_cv_prog_cxx_cxx11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cxx_cxx11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_cxx_conftest_cxx11_program _ACEOF for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_cxx11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx11" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi if test "x$ac_cv_prog_cxx_cxx11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cxx_cxx11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } CXX="$CXX $ac_cv_prog_cxx_cxx11" fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 ac_prog_cxx_stdcxx=cxx11 fi fi if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 printf %s "checking for $CXX option to enable C++98 features... " >&6; } if test ${ac_cv_prog_cxx_cxx98+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cxx_cxx98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_cxx_conftest_cxx98_program _ACEOF for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_cxx98=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx98" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi if test "x$ac_cv_prog_cxx_cxx98" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cxx_cxx98" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } CXX="$CXX $ac_cv_prog_cxx_cxx98" fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 ac_prog_cxx_stdcxx=cxx98 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CXX_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi func_stripname_cnf () { case $2 in .*) func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%\\\\$2\$%%"`;; *) func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%$2\$%%"`;; esac } # func_stripname_cnf if test -n "$CXX" && ( test no != "$CXX" && ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || (test g++ != "$CXX"))); then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 printf %s "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if test ${ac_cv_prog_CXXCPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CXX needs to be expanded for CXXCPP in "$CXX -E" cpp /lib/cpp do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 printf "%s\n" "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu else _lt_caught_CXX_error=yes fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu archive_cmds_need_lc_CXX=no allow_undefined_flag_CXX= always_export_symbols_CXX=no archive_expsym_cmds_CXX= compiler_needs_object_CXX=no export_dynamic_flag_spec_CXX= hardcode_direct_CXX=no hardcode_direct_absolute_CXX=no hardcode_libdir_flag_spec_CXX= hardcode_libdir_separator_CXX= hardcode_minus_L_CXX=no hardcode_shlibpath_var_CXX=unsupported hardcode_automatic_CXX=no inherit_rpath_CXX=no module_cmds_CXX= module_expsym_cmds_CXX= link_all_deplibs_CXX=unknown old_archive_cmds_CXX=$old_archive_cmds reload_flag_CXX=$reload_flag reload_cmds_CXX=$reload_cmds no_undefined_flag_CXX= whole_archive_flag_spec_CXX= enable_shared_with_static_runtimes_CXX=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o objext_CXX=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_caught_CXX_error"; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC compiler_CXX=$CC func_cc_basename $compiler cc_basename=$func_cc_basename_result if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test yes = "$GXX"; then lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' else lt_prog_compiler_no_builtin_flag_CXX= fi if test yes = "$GXX"; then # Set up default GNU C++ configuration # Check whether --with-gnu-ld was given. if test ${with_gnu_ld+y} then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes else $as_nop with_gnu_ld=no fi ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 printf %s "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 printf %s "checking for GNU ld... " >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 printf %s "checking for non-GNU ld... " >&6; } fi if test ${lt_cv_path_LD+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 printf "%s\n" "$LD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 printf %s "checking if the linker ($LD) is GNU ld... " >&6; } if test ${lt_cv_prog_gnu_ld+y} then : printf %s "(cached) " >&6 else $as_nop # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test yes = "$with_gnu_ld"; then archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' export_dynamic_flag_spec_CXX='$wl--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='$wl' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else whole_archive_flag_spec_CXX= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } ld_shlibs_CXX=yes case $host_os in aix3*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aix[4-9]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_CXX='' hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes file_list_spec_CXX='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. hardcode_direct_CXX=no hardcode_direct_absolute_CXX=no ;; esac if test yes = "$GXX"; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct_CXX=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_CXX=yes hardcode_libdir_flag_spec_CXX='-L$libdir' hardcode_libdir_separator_CXX= fi esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag=$shared_flag' $wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi export_dynamic_flag_spec_CXX='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. always_export_symbols_CXX=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. # The "-G" linker flag allows undefined symbols. no_undefined_flag_CXX='-bernotok' # Determine the default libpath from the value encoded in an empty # executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath__CXX+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO" then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath__CXX fi hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then hardcode_libdir_flag_spec_CXX='$wl-R $libdir:/usr/lib:/lib' allow_undefined_flag_CXX="-z nodefs" archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath__CXX+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO" then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath__CXX fi hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_CXX=' $wl-bernotok' allow_undefined_flag_CXX=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_CXX='$convenience' fi archive_cmds_need_lc_CXX=yes archive_expsym_cmds_CXX='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$RM -r $output_objdir/$realname.d' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_CXX=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else ld_shlibs_CXX=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl* | ,icl* | no,icl*) # Native MSVC or ICC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec_CXX=' ' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=yes file_list_spec_CXX='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' archive_expsym_cmds_CXX='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' enable_shared_with_static_runtimes_CXX=yes # Don't use ranlib old_postinstall_cmds_CXX='chmod 644 $oldlib' postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ func_to_tool_file "$lt_outputfile"~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_CXX='-L$libdir' export_dynamic_flag_spec_CXX='$wl--export-all-symbols' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=no enable_shared_with_static_runtimes_CXX=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... archive_expsym_cmds_CXX='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs_CXX=no fi ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc_CXX=no hardcode_direct_CXX=no hardcode_automatic_CXX=yes hardcode_shlibpath_var_CXX=unsupported if test yes = "$lt_cv_ld_force_load"; then whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec_CXX='' fi link_all_deplibs_CXX=yes allow_undefined_flag_CXX=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" archive_expsym_cmds_CXX="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" module_expsym_cmds_CXX="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" if test yes != "$lt_cv_apple_cc_single_mod"; then archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" archive_expsym_cmds_CXX="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" fi else ld_shlibs_CXX=no fi ;; os2*) hardcode_libdir_flag_spec_CXX='-L$libdir' hardcode_minus_L_CXX=yes allow_undefined_flag_CXX=unsupported shrext_cmds=.dll archive_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds_CXX='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes_CXX=yes file_list_spec_CXX='@' ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF ld_shlibs_CXX=no ;; freebsd-elf*) archive_cmds_need_lc_CXX=no ;; freebsd* | dragonfly* | midnightbsd*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions ld_shlibs_CXX=yes ;; haiku*) archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' link_all_deplibs_CXX=yes ;; hpux9*) hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir' hardcode_libdir_separator_CXX=: export_dynamic_flag_spec_CXX='$wl-E' hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; hpux10*|hpux11*) if test no = "$with_gnu_ld"; then hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir' hardcode_libdir_separator_CXX=: case $host_cpu in hppa*64*|ia64*) ;; *) export_dynamic_flag_spec_CXX='$wl-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no ;; *) hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; interix[3-9]*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' export_dynamic_flag_spec_CXX='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds_CXX='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' fi fi link_all_deplibs_CXX=yes ;; esac hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' hardcode_libdir_separator_CXX=: inherit_rpath_CXX=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' export_dynamic_flag_spec_CXX='$wl--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac archive_cmds_need_lc_CXX=no hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' export_dynamic_flag_spec_CXX='$wl--export-dynamic' whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [1-5].* | *pgcpp\ [1-5].*) prelink_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' old_archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='$wl--rpath $wl$libdir' export_dynamic_flag_spec_CXX='$wl--export-dynamic' whole_archive_flag_spec_CXX='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' ;; cxx*) # Compaq C++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' export_dynamic_flag_spec_CXX='$wl--export-dynamic' archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | $SED 5q` in *Sun\ C*) # Sun C++ 5.9 no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' hardcode_libdir_flag_spec_CXX='-R$libdir' whole_archive_flag_spec_CXX='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object_CXX=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; m88k*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) ld_shlibs_CXX=yes ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no hardcode_direct_absolute_CXX=yes archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' export_dynamic_flag_spec_CXX='$wl-E' whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else ld_shlibs_CXX=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx*) case $host in osf3*) allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*' archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' ;; *) allow_undefined_flag_CXX=' -expect_unresolved \*' archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ $RM $lib.exp' hardcode_libdir_flag_spec_CXX='-rpath $libdir' ;; esac hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes,no = "$GXX,$with_gnu_ld"; then allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*' case $host in osf3*) archive_cmds_CXX='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; *) archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ archive_cmds_need_lc_CXX=yes no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_shlibpath_var_CXX=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs_CXX=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test yes,no = "$GXX,$with_gnu_ld"; then no_undefined_flag_CXX=' $wl-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. archive_cmds_CXX='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' fi hardcode_libdir_flag_spec_CXX='$wl-R $wl$libdir' case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) whole_archive_flag_spec_CXX='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag_CXX='$wl-z,text' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag_CXX='$wl-z,text' allow_undefined_flag_CXX='$wl-z,nodefs' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='$wl-R,$libdir' hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes export_dynamic_flag_spec_CXX='$wl-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ '"$old_archive_cmds_CXX" reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ '"$reload_cmds_CXX" ;; *) archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 printf "%s\n" "$ld_shlibs_CXX" >&6; } test no = "$ld_shlibs_CXX" && can_build_shared=no GCC_CXX=$GXX LD_CXX=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... # Dependencies to place before and after the object being linked: predep_objects_CXX= postdep_objects_CXX= predeps_CXX= postdeps_CXX= compiler_lib_search_path_CXX= cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $prev$p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test x-L = "$p" || test x-R = "$p"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test no = "$pre_test_object_deps_done"; then case $prev in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$compiler_lib_search_path_CXX"; then compiler_lib_search_path_CXX=$prev$p else compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} $prev$p" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$postdeps_CXX"; then postdeps_CXX=$prev$p else postdeps_CXX="${postdeps_CXX} $prev$p" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test no = "$pre_test_object_deps_done"; then if test -z "$predep_objects_CXX"; then predep_objects_CXX=$p else predep_objects_CXX="$predep_objects_CXX $p" fi else if test -z "$postdep_objects_CXX"; then postdep_objects_CXX=$p else postdep_objects_CXX="$postdep_objects_CXX $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling CXX test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken case $host_os in interix[3-9]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. predep_objects_CXX= postdep_objects_CXX= postdeps_CXX= ;; esac case " $postdeps_CXX " in *" -lc "*) archive_cmds_need_lc_CXX=no ;; esac compiler_lib_search_dirs_CXX= if test -n "${compiler_lib_search_path_CXX}"; then compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | $SED -e 's! -L! !g' -e 's!^ !!'` fi lt_prog_compiler_wl_CXX= lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX= # C++ specific cases for pic, static, wl, etc. if test yes = "$GXX"; then lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' fi lt_prog_compiler_pic_CXX='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic_CXX='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic_CXX='-DDLL_EXPORT' case $host_os in os2*) lt_prog_compiler_static_CXX='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_CXX='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all lt_prog_compiler_pic_CXX= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static_CXX= ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_CXX=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac else case $host_os in aix[4-9]*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' else lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; dgux*) case $cc_basename in ec++*) lt_prog_compiler_pic_CXX='-KPIC' ;; ghcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; freebsd* | dragonfly* | midnightbsd*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='$wl-a ${wl}archive' if test ia64 != "$host_cpu"; then lt_prog_compiler_pic_CXX='+Z' fi ;; aCC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='$wl-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_CXX='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler lt_prog_compiler_wl_CXX='--backend -Wl,' lt_prog_compiler_pic_CXX='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64, which still supported -KPIC. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fPIC' lt_prog_compiler_static_CXX='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fpic' lt_prog_compiler_static_CXX='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) # IBM XL 8.0, 9.0 on PPC and BlueGene lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-qpic' lt_prog_compiler_static_CXX='-qstaticlink' ;; *) case `$CC -V 2>&1 | $SED 5q` in *Sun\ C*) # Sun C++ 5.9 lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) lt_prog_compiler_pic_CXX='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) lt_prog_compiler_wl_CXX='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 lt_prog_compiler_pic_CXX='-pic' ;; cxx*) # Digital/Compaq C++ lt_prog_compiler_wl_CXX='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x lt_prog_compiler_pic_CXX='-pic' lt_prog_compiler_static_CXX='-Bstatic' ;; lcc*) # Lucid lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 lt_prog_compiler_pic_CXX='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) lt_prog_compiler_can_build_shared_CXX=no ;; esac fi case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_CXX= ;; *) lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 printf %s "checking for $compiler option to produce PIC... " >&6; } if test ${lt_cv_prog_compiler_pic_CXX+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_CXX" >&6; } lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } if test ${lt_cv_prog_compiler_pic_works_CXX+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_pic_works_CXX=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works_CXX=yes fi fi $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_works_CXX" >&6; } if test yes = "$lt_cv_prog_compiler_pic_works_CXX"; then case $lt_prog_compiler_pic_CXX in "" | " "*) ;; *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; esac else lt_prog_compiler_pic_CXX= lt_prog_compiler_can_build_shared_CXX=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if test ${lt_cv_prog_compiler_static_works_CXX+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_static_works_CXX=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works_CXX=yes fi else lt_cv_prog_compiler_static_works_CXX=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 printf "%s\n" "$lt_cv_prog_compiler_static_works_CXX" >&6; } if test yes = "$lt_cv_prog_compiler_static_works_CXX"; then : else lt_prog_compiler_static_CXX= fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o_CXX+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o_CXX" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o_CXX+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o_CXX" >&6; } hard_links=nottested if test no = "$lt_cv_prog_compiler_c_o_CXX" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 printf %s "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 printf "%s\n" "$hard_links" >&6; } if test no = "$hard_links"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 printf "%s\n" "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' case $host_os in aix[4-9]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_CXX='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi ;; pw32*) export_symbols_cmds_CXX=$ltdll_cmds ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl* | icl*) exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' ;; esac ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs_CXX=no ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 printf "%s\n" "$ld_shlibs_CXX" >&6; } test no = "$ld_shlibs_CXX" && can_build_shared=no with_gnu_ld_CXX=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_CXX" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_CXX=yes if test yes,yes = "$GCC,$enable_shared"; then case $archive_cmds_CXX in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 printf %s "checking whether -lc should be explicitly linked in... " >&6; } if test ${lt_cv_archive_cmds_need_lc_CXX+y} then : printf %s "(cached) " >&6 else $as_nop $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_CXX pic_flag=$lt_prog_compiler_pic_CXX compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_CXX allow_undefined_flag_CXX= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc_CXX=no else lt_cv_archive_cmds_need_lc_CXX=yes fi allow_undefined_flag_CXX=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 printf "%s\n" "$lt_cv_archive_cmds_need_lc_CXX" >&6; } archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX ;; esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 printf %s "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a(lib.so.V)' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl* | *,icl*) # Native MSVC or ICC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC and ICC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly* | midnightbsd*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. hardcode_libdir_flag_spec_CXX='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if test ${lt_cv_shlibpath_overrides_runpath+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO" then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 printf "%s\n" "$dynamic_linker" >&6; } test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 printf %s "checking how to hardcode library paths into programs... " >&6; } hardcode_action_CXX= if test -n "$hardcode_libdir_flag_spec_CXX" || test -n "$runpath_var_CXX" || test yes = "$hardcode_automatic_CXX"; then # We can hardcode non-existent directories. if test no != "$hardcode_direct_CXX" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" && test no != "$hardcode_minus_L_CXX"; then # Linking always hardcodes the temporary library directory. hardcode_action_CXX=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_CXX=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_CXX=unsupported fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 printf "%s\n" "$hardcode_action_CXX" >&6; } if test relink = "$hardcode_action_CXX" || test yes = "$inherit_rpath_CXX"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test yes != "$_lt_caught_CXX_error" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # We need C++17 support. ax_cxx_compile_alternatives="23" ax_cxx_compile_cxx23_required=false ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_success=no if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do if test x"$switch" = xMSVC; then switch=-std:c++${alternative} cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx23_${switch}_MSVC" | $as_tr_sh` else cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx23_$switch" | $as_tr_sh` fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++23 features with $switch" >&5 printf %s "checking whether $CXX supports C++23 features with $switch... " >&6; } if eval test \${$cachevar+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_CXX="$CXX" CXX="$CXX $switch" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ // If the compiler admits that it is not ready for C++11, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" // MSVC always sets __cplusplus to 199711L in older versions; newer versions // only set it correctly if /Zc:__cplusplus is specified as well as a // /std:c++NN switch: // // https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ // // The value __cplusplus ought to have is available in _MSVC_LANG since // Visual Studio 2015 Update 3: // // https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros // // This was also the first MSVC version to support C++14 so we can't use the // value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having // C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later. #elif __cplusplus < 201103L && !defined _MSC_VER #error "This is not a C++11 compiler" #else namespace cxx11 { namespace test_static_assert { template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; } namespace test_final_override { struct Base { virtual ~Base() {} virtual void f() {} }; struct Derived : public Base { virtual ~Derived() override {} virtual void f() override {} }; } namespace test_double_right_angle_brackets { template < typename T > struct check {}; typedef check single_type; typedef check> double_type; typedef check>> triple_type; typedef check>>> quadruple_type; } namespace test_decltype { int f() { int a = 1; decltype(a) b = 2; return a + b; } } namespace test_type_deduction { template < typename T1, typename T2 > struct is_same { static const bool value = false; }; template < typename T > struct is_same { static const bool value = true; }; template < typename T1, typename T2 > auto add(T1 a1, T2 a2) -> decltype(a1 + a2) { return a1 + a2; } int test(const int c, volatile int v) { static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == false, ""); auto ac = c; auto av = v; auto sumi = ac + av + 'x'; auto sumf = ac + av + 1.0; static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == true, ""); return (sumf > 0.0) ? sumi : add(c, v); } } namespace test_noexcept { int f() { return 0; } int g() noexcept { return 0; } static_assert(noexcept(f()) == false, ""); static_assert(noexcept(g()) == true, ""); } namespace test_constexpr { template < typename CharT > unsigned long constexpr strlen_c_r(const CharT *const s, const unsigned long acc) noexcept { return *s ? strlen_c_r(s + 1, acc + 1) : acc; } template < typename CharT > unsigned long constexpr strlen_c(const CharT *const s) noexcept { return strlen_c_r(s, 0UL); } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("1") == 1UL, ""); static_assert(strlen_c("example") == 7UL, ""); static_assert(strlen_c("another\0example") == 7UL, ""); } namespace test_rvalue_references { template < int N > struct answer { static constexpr int value = N; }; answer<1> f(int&) { return answer<1>(); } answer<2> f(const int&) { return answer<2>(); } answer<3> f(int&&) { return answer<3>(); } void test() { int i = 0; const int c = 0; static_assert(decltype(f(i))::value == 1, ""); static_assert(decltype(f(c))::value == 2, ""); static_assert(decltype(f(0))::value == 3, ""); } } namespace test_uniform_initialization { struct test { static const int zero {}; static const int one {1}; }; static_assert(test::zero == 0, ""); static_assert(test::one == 1, ""); } namespace test_lambdas { void test1() { auto lambda1 = [](){}; auto lambda2 = lambda1; lambda1(); lambda2(); } int test2() { auto a = [](int i, int j){ return i + j; }(1, 2); auto b = []() -> int { return '0'; }(); auto c = [=](){ return a + b; }(); auto d = [&](){ return c; }(); auto e = [a, &b](int x) mutable { const auto identity = [](int y){ return y; }; for (auto i = 0; i < a; ++i) a += b--; return x + identity(a + b); }(0); return a + b + c + d + e; } int test3() { const auto nullary = [](){ return 0; }; const auto unary = [](int x){ return x; }; using nullary_t = decltype(nullary); using unary_t = decltype(unary); const auto higher1st = [](nullary_t f){ return f(); }; const auto higher2nd = [unary](nullary_t f1){ return [unary, f1](unary_t f2){ return f2(unary(f1())); }; }; return higher1st(nullary) + higher2nd(nullary)(unary); } } namespace test_variadic_templates { template struct sum; template struct sum { static constexpr auto value = N0 + sum::value; }; template <> struct sum<> { static constexpr auto value = 0; }; static_assert(sum<>::value == 0, ""); static_assert(sum<1>::value == 1, ""); static_assert(sum<23>::value == 23, ""); static_assert(sum<1, 2>::value == 3, ""); static_assert(sum<5, 5, 11>::value == 21, ""); static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); } // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function // because of this. namespace test_template_alias_sfinae { struct foo {}; template using member = typename T::member_type; template void func(...) {} template void func(member*) {} void test(); void test() { func(0); } } } // namespace cxx11 #endif // __cplusplus >= 201103L // If the compiler admits that it is not ready for C++14, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201402L && !defined _MSC_VER #error "This is not a C++14 compiler" #else namespace cxx14 { namespace test_polymorphic_lambdas { int test() { const auto lambda = [](auto&&... args){ const auto istiny = [](auto x){ return (sizeof(x) == 1UL) ? 1 : 0; }; const int aretiny[] = { istiny(args)... }; return aretiny[0]; }; return lambda(1, 1L, 1.0f, '1'); } } namespace test_binary_literals { constexpr auto ivii = 0b0000000000101010; static_assert(ivii == 42, "wrong value"); } namespace test_generalized_constexpr { template < typename CharT > constexpr unsigned long strlen_c(const CharT *const s) noexcept { auto length = 0UL; for (auto p = s; *p; ++p) ++length; return length; } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("x") == 1UL, ""); static_assert(strlen_c("test") == 4UL, ""); static_assert(strlen_c("another\0test") == 7UL, ""); } namespace test_lambda_init_capture { int test() { auto x = 0; const auto lambda1 = [a = x](int b){ return a + b; }; const auto lambda2 = [a = lambda1(x)](){ return a; }; return lambda2(); } } namespace test_digit_separators { constexpr auto ten_million = 100'000'000; static_assert(ten_million == 100000000, ""); } namespace test_return_type_deduction { auto f(int& x) { return x; } decltype(auto) g(int& x) { return x; } template < typename T1, typename T2 > struct is_same { static constexpr auto value = false; }; template < typename T > struct is_same { static constexpr auto value = true; }; int test() { auto x = 0; static_assert(is_same::value, ""); static_assert(is_same::value, ""); return x; } } } // namespace cxx14 #endif // __cplusplus >= 201402L // If the compiler admits that it is not ready for C++17, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L #error "This is not a C++17 compiler" #else #include #include #include namespace cxx17 { namespace test_constexpr_lambdas { constexpr int foo = [](){return 42;}(); } namespace test::nested_namespace::definitions { } namespace test_fold_expression { template int multiply(Args... args) { return (args * ... * 1); } template bool all(Args... args) { return (args && ...); } } namespace test_extended_static_assert { static_assert (true); } namespace test_auto_brace_init_list { auto foo = {5}; auto bar {5}; static_assert(std::is_same, decltype(foo)>::value); static_assert(std::is_same::value); } namespace test_typename_in_template_template_parameter { template typename X> struct D; } namespace test_fallthrough_nodiscard_maybe_unused_attributes { int f1() { return 42; } [[nodiscard]] int f2() { [[maybe_unused]] auto unused = f1(); switch (f1()) { case 17: f1(); [[fallthrough]]; case 42: f1(); } return f1(); } } namespace test_extended_aggregate_initialization { struct base1 { int b1, b2 = 42; }; struct base2 { base2() { b3 = 42; } int b3; }; struct derived : base1, base2 { int d; }; derived d1 {{1, 2}, {}, 4}; // full initialization derived d2 {{}, {}, 4}; // value-initialized bases } namespace test_general_range_based_for_loop { struct iter { int i; int& operator* () { return i; } const int& operator* () const { return i; } iter& operator++() { ++i; return *this; } }; struct sentinel { int i; }; bool operator== (const iter& i, const sentinel& s) { return i.i == s.i; } bool operator!= (const iter& i, const sentinel& s) { return !(i == s); } struct range { iter begin() const { return {0}; } sentinel end() const { return {5}; } }; void f() { range r {}; for (auto i : r) { [[maybe_unused]] auto v = i; } } } namespace test_lambda_capture_asterisk_this_by_value { struct t { int i; int foo() { return [*this]() { return i; }(); } }; } namespace test_enum_class_construction { enum class byte : unsigned char {}; byte foo {42}; } namespace test_constexpr_if { template int f () { if constexpr(cond) { return 13; } else { return 42; } } } namespace test_selection_statement_with_initializer { int f() { return 13; } int f2() { if (auto i = f(); i > 0) { return 3; } switch (auto i = f(); i + 4) { case 17: return 2; default: return 1; } } } namespace test_template_argument_deduction_for_class_templates { template struct pair { pair (T1 p1, T2 p2) : m1 {p1}, m2 {p2} {} T1 m1; T2 m2; }; void f() { [[maybe_unused]] auto p = pair{13, 42u}; } } namespace test_non_type_auto_template_parameters { template struct B {}; B<5> b1; B<'a'> b2; } namespace test_structured_bindings { int arr[2] = { 1, 2 }; std::pair pr = { 1, 2 }; auto f1() -> int(&)[2] { return arr; } auto f2() -> std::pair& { return pr; } struct S { int x1 : 2; volatile double y1; }; S f3() { return {}; } auto [ x1, y1 ] = f1(); auto& [ xr1, yr1 ] = f1(); auto [ x2, y2 ] = f2(); auto& [ xr2, yr2 ] = f2(); const auto [ x3, y3 ] = f3(); } namespace test_exception_spec_type_system { struct Good {}; struct Bad {}; void g1() noexcept; void g2(); template Bad f(T*, T*); template Good f(T1*, T2*); static_assert (std::is_same_v); } namespace test_inline_variables { template void f(T) {} template inline T g(T) { return T{}; } template<> inline void f<>(int) {} template<> int g<>(int) { return 5; } } } // namespace cxx17 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L #error "This is not a C++20 compiler" #else #include namespace cxx20 { // As C++20 supports feature test macros in the standard, there is no // immediate need to actually test for feature availability on the // Autoconf side. } // namespace cxx20 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L #error "This is not a C++23 compiler" #else #include namespace cxx23 { // As C++23 supports feature test macros in the standard, there is no // immediate need to actually test for feature availability on the // Autoconf side. } // namespace cxx23 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : eval $cachevar=yes else $as_nop eval $cachevar=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CXX="$ac_save_CXX" fi eval ac_res=\$$cachevar { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done if test x$ac_success = xyes; then break fi done fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test x$ax_cxx_compile_cxx23_required = xtrue; then if test x$ac_success = xno; then as_fn_error $? "*** A compiler with support for C++23 language features is required." "$LINENO" 5 fi fi if test x$ac_success = xno; then HAVE_CXX23=0 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: No compiler with C++23 support was found" >&5 printf "%s\n" "$as_me: No compiler with C++23 support was found" >&6;} else HAVE_CXX23=1 printf "%s\n" "#define HAVE_CXX23 1" >>confdefs.h fi if test "x$HAVE_CXX23" != "x1" then : ax_cxx_compile_alternatives="20" ax_cxx_compile_cxx20_required=false ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_success=no if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do if test x"$switch" = xMSVC; then switch=-std:c++${alternative} cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx20_${switch}_MSVC" | $as_tr_sh` else cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx20_$switch" | $as_tr_sh` fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++20 features with $switch" >&5 printf %s "checking whether $CXX supports C++20 features with $switch... " >&6; } if eval test \${$cachevar+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_CXX="$CXX" CXX="$CXX $switch" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ // If the compiler admits that it is not ready for C++11, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" // MSVC always sets __cplusplus to 199711L in older versions; newer versions // only set it correctly if /Zc:__cplusplus is specified as well as a // /std:c++NN switch: // // https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ // // The value __cplusplus ought to have is available in _MSVC_LANG since // Visual Studio 2015 Update 3: // // https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros // // This was also the first MSVC version to support C++14 so we can't use the // value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having // C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later. #elif __cplusplus < 201103L && !defined _MSC_VER #error "This is not a C++11 compiler" #else namespace cxx11 { namespace test_static_assert { template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; } namespace test_final_override { struct Base { virtual ~Base() {} virtual void f() {} }; struct Derived : public Base { virtual ~Derived() override {} virtual void f() override {} }; } namespace test_double_right_angle_brackets { template < typename T > struct check {}; typedef check single_type; typedef check> double_type; typedef check>> triple_type; typedef check>>> quadruple_type; } namespace test_decltype { int f() { int a = 1; decltype(a) b = 2; return a + b; } } namespace test_type_deduction { template < typename T1, typename T2 > struct is_same { static const bool value = false; }; template < typename T > struct is_same { static const bool value = true; }; template < typename T1, typename T2 > auto add(T1 a1, T2 a2) -> decltype(a1 + a2) { return a1 + a2; } int test(const int c, volatile int v) { static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == false, ""); auto ac = c; auto av = v; auto sumi = ac + av + 'x'; auto sumf = ac + av + 1.0; static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == true, ""); return (sumf > 0.0) ? sumi : add(c, v); } } namespace test_noexcept { int f() { return 0; } int g() noexcept { return 0; } static_assert(noexcept(f()) == false, ""); static_assert(noexcept(g()) == true, ""); } namespace test_constexpr { template < typename CharT > unsigned long constexpr strlen_c_r(const CharT *const s, const unsigned long acc) noexcept { return *s ? strlen_c_r(s + 1, acc + 1) : acc; } template < typename CharT > unsigned long constexpr strlen_c(const CharT *const s) noexcept { return strlen_c_r(s, 0UL); } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("1") == 1UL, ""); static_assert(strlen_c("example") == 7UL, ""); static_assert(strlen_c("another\0example") == 7UL, ""); } namespace test_rvalue_references { template < int N > struct answer { static constexpr int value = N; }; answer<1> f(int&) { return answer<1>(); } answer<2> f(const int&) { return answer<2>(); } answer<3> f(int&&) { return answer<3>(); } void test() { int i = 0; const int c = 0; static_assert(decltype(f(i))::value == 1, ""); static_assert(decltype(f(c))::value == 2, ""); static_assert(decltype(f(0))::value == 3, ""); } } namespace test_uniform_initialization { struct test { static const int zero {}; static const int one {1}; }; static_assert(test::zero == 0, ""); static_assert(test::one == 1, ""); } namespace test_lambdas { void test1() { auto lambda1 = [](){}; auto lambda2 = lambda1; lambda1(); lambda2(); } int test2() { auto a = [](int i, int j){ return i + j; }(1, 2); auto b = []() -> int { return '0'; }(); auto c = [=](){ return a + b; }(); auto d = [&](){ return c; }(); auto e = [a, &b](int x) mutable { const auto identity = [](int y){ return y; }; for (auto i = 0; i < a; ++i) a += b--; return x + identity(a + b); }(0); return a + b + c + d + e; } int test3() { const auto nullary = [](){ return 0; }; const auto unary = [](int x){ return x; }; using nullary_t = decltype(nullary); using unary_t = decltype(unary); const auto higher1st = [](nullary_t f){ return f(); }; const auto higher2nd = [unary](nullary_t f1){ return [unary, f1](unary_t f2){ return f2(unary(f1())); }; }; return higher1st(nullary) + higher2nd(nullary)(unary); } } namespace test_variadic_templates { template struct sum; template struct sum { static constexpr auto value = N0 + sum::value; }; template <> struct sum<> { static constexpr auto value = 0; }; static_assert(sum<>::value == 0, ""); static_assert(sum<1>::value == 1, ""); static_assert(sum<23>::value == 23, ""); static_assert(sum<1, 2>::value == 3, ""); static_assert(sum<5, 5, 11>::value == 21, ""); static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); } // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function // because of this. namespace test_template_alias_sfinae { struct foo {}; template using member = typename T::member_type; template void func(...) {} template void func(member*) {} void test(); void test() { func(0); } } } // namespace cxx11 #endif // __cplusplus >= 201103L // If the compiler admits that it is not ready for C++14, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201402L && !defined _MSC_VER #error "This is not a C++14 compiler" #else namespace cxx14 { namespace test_polymorphic_lambdas { int test() { const auto lambda = [](auto&&... args){ const auto istiny = [](auto x){ return (sizeof(x) == 1UL) ? 1 : 0; }; const int aretiny[] = { istiny(args)... }; return aretiny[0]; }; return lambda(1, 1L, 1.0f, '1'); } } namespace test_binary_literals { constexpr auto ivii = 0b0000000000101010; static_assert(ivii == 42, "wrong value"); } namespace test_generalized_constexpr { template < typename CharT > constexpr unsigned long strlen_c(const CharT *const s) noexcept { auto length = 0UL; for (auto p = s; *p; ++p) ++length; return length; } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("x") == 1UL, ""); static_assert(strlen_c("test") == 4UL, ""); static_assert(strlen_c("another\0test") == 7UL, ""); } namespace test_lambda_init_capture { int test() { auto x = 0; const auto lambda1 = [a = x](int b){ return a + b; }; const auto lambda2 = [a = lambda1(x)](){ return a; }; return lambda2(); } } namespace test_digit_separators { constexpr auto ten_million = 100'000'000; static_assert(ten_million == 100000000, ""); } namespace test_return_type_deduction { auto f(int& x) { return x; } decltype(auto) g(int& x) { return x; } template < typename T1, typename T2 > struct is_same { static constexpr auto value = false; }; template < typename T > struct is_same { static constexpr auto value = true; }; int test() { auto x = 0; static_assert(is_same::value, ""); static_assert(is_same::value, ""); return x; } } } // namespace cxx14 #endif // __cplusplus >= 201402L // If the compiler admits that it is not ready for C++17, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L #error "This is not a C++17 compiler" #else #include #include #include namespace cxx17 { namespace test_constexpr_lambdas { constexpr int foo = [](){return 42;}(); } namespace test::nested_namespace::definitions { } namespace test_fold_expression { template int multiply(Args... args) { return (args * ... * 1); } template bool all(Args... args) { return (args && ...); } } namespace test_extended_static_assert { static_assert (true); } namespace test_auto_brace_init_list { auto foo = {5}; auto bar {5}; static_assert(std::is_same, decltype(foo)>::value); static_assert(std::is_same::value); } namespace test_typename_in_template_template_parameter { template typename X> struct D; } namespace test_fallthrough_nodiscard_maybe_unused_attributes { int f1() { return 42; } [[nodiscard]] int f2() { [[maybe_unused]] auto unused = f1(); switch (f1()) { case 17: f1(); [[fallthrough]]; case 42: f1(); } return f1(); } } namespace test_extended_aggregate_initialization { struct base1 { int b1, b2 = 42; }; struct base2 { base2() { b3 = 42; } int b3; }; struct derived : base1, base2 { int d; }; derived d1 {{1, 2}, {}, 4}; // full initialization derived d2 {{}, {}, 4}; // value-initialized bases } namespace test_general_range_based_for_loop { struct iter { int i; int& operator* () { return i; } const int& operator* () const { return i; } iter& operator++() { ++i; return *this; } }; struct sentinel { int i; }; bool operator== (const iter& i, const sentinel& s) { return i.i == s.i; } bool operator!= (const iter& i, const sentinel& s) { return !(i == s); } struct range { iter begin() const { return {0}; } sentinel end() const { return {5}; } }; void f() { range r {}; for (auto i : r) { [[maybe_unused]] auto v = i; } } } namespace test_lambda_capture_asterisk_this_by_value { struct t { int i; int foo() { return [*this]() { return i; }(); } }; } namespace test_enum_class_construction { enum class byte : unsigned char {}; byte foo {42}; } namespace test_constexpr_if { template int f () { if constexpr(cond) { return 13; } else { return 42; } } } namespace test_selection_statement_with_initializer { int f() { return 13; } int f2() { if (auto i = f(); i > 0) { return 3; } switch (auto i = f(); i + 4) { case 17: return 2; default: return 1; } } } namespace test_template_argument_deduction_for_class_templates { template struct pair { pair (T1 p1, T2 p2) : m1 {p1}, m2 {p2} {} T1 m1; T2 m2; }; void f() { [[maybe_unused]] auto p = pair{13, 42u}; } } namespace test_non_type_auto_template_parameters { template struct B {}; B<5> b1; B<'a'> b2; } namespace test_structured_bindings { int arr[2] = { 1, 2 }; std::pair pr = { 1, 2 }; auto f1() -> int(&)[2] { return arr; } auto f2() -> std::pair& { return pr; } struct S { int x1 : 2; volatile double y1; }; S f3() { return {}; } auto [ x1, y1 ] = f1(); auto& [ xr1, yr1 ] = f1(); auto [ x2, y2 ] = f2(); auto& [ xr2, yr2 ] = f2(); const auto [ x3, y3 ] = f3(); } namespace test_exception_spec_type_system { struct Good {}; struct Bad {}; void g1() noexcept; void g2(); template Bad f(T*, T*); template Good f(T1*, T2*); static_assert (std::is_same_v); } namespace test_inline_variables { template void f(T) {} template inline T g(T) { return T{}; } template<> inline void f<>(int) {} template<> int g<>(int) { return 5; } } } // namespace cxx17 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L #error "This is not a C++20 compiler" #else #include namespace cxx20 { // As C++20 supports feature test macros in the standard, there is no // immediate need to actually test for feature availability on the // Autoconf side. } // namespace cxx20 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : eval $cachevar=yes else $as_nop eval $cachevar=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CXX="$ac_save_CXX" fi eval ac_res=\$$cachevar { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done if test x$ac_success = xyes; then break fi done fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test x$ax_cxx_compile_cxx20_required = xtrue; then if test x$ac_success = xno; then as_fn_error $? "*** A compiler with support for C++20 language features is required." "$LINENO" 5 fi fi if test x$ac_success = xno; then HAVE_CXX20=0 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: No compiler with C++20 support was found" >&5 printf "%s\n" "$as_me: No compiler with C++20 support was found" >&6;} else HAVE_CXX20=1 printf "%s\n" "#define HAVE_CXX20 1" >>confdefs.h fi if test "x$HAVE_CXX20" != "x1" then : ax_cxx_compile_alternatives="17 1z" ax_cxx_compile_cxx17_required=true ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_success=no if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do if test x"$switch" = xMSVC; then switch=-std:c++${alternative} cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx17_${switch}_MSVC" | $as_tr_sh` else cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx17_$switch" | $as_tr_sh` fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++17 features with $switch" >&5 printf %s "checking whether $CXX supports C++17 features with $switch... " >&6; } if eval test \${$cachevar+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_CXX="$CXX" CXX="$CXX $switch" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ // If the compiler admits that it is not ready for C++11, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" // MSVC always sets __cplusplus to 199711L in older versions; newer versions // only set it correctly if /Zc:__cplusplus is specified as well as a // /std:c++NN switch: // // https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ // // The value __cplusplus ought to have is available in _MSVC_LANG since // Visual Studio 2015 Update 3: // // https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros // // This was also the first MSVC version to support C++14 so we can't use the // value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having // C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later. #elif __cplusplus < 201103L && !defined _MSC_VER #error "This is not a C++11 compiler" #else namespace cxx11 { namespace test_static_assert { template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; } namespace test_final_override { struct Base { virtual ~Base() {} virtual void f() {} }; struct Derived : public Base { virtual ~Derived() override {} virtual void f() override {} }; } namespace test_double_right_angle_brackets { template < typename T > struct check {}; typedef check single_type; typedef check> double_type; typedef check>> triple_type; typedef check>>> quadruple_type; } namespace test_decltype { int f() { int a = 1; decltype(a) b = 2; return a + b; } } namespace test_type_deduction { template < typename T1, typename T2 > struct is_same { static const bool value = false; }; template < typename T > struct is_same { static const bool value = true; }; template < typename T1, typename T2 > auto add(T1 a1, T2 a2) -> decltype(a1 + a2) { return a1 + a2; } int test(const int c, volatile int v) { static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == false, ""); auto ac = c; auto av = v; auto sumi = ac + av + 'x'; auto sumf = ac + av + 1.0; static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == true, ""); return (sumf > 0.0) ? sumi : add(c, v); } } namespace test_noexcept { int f() { return 0; } int g() noexcept { return 0; } static_assert(noexcept(f()) == false, ""); static_assert(noexcept(g()) == true, ""); } namespace test_constexpr { template < typename CharT > unsigned long constexpr strlen_c_r(const CharT *const s, const unsigned long acc) noexcept { return *s ? strlen_c_r(s + 1, acc + 1) : acc; } template < typename CharT > unsigned long constexpr strlen_c(const CharT *const s) noexcept { return strlen_c_r(s, 0UL); } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("1") == 1UL, ""); static_assert(strlen_c("example") == 7UL, ""); static_assert(strlen_c("another\0example") == 7UL, ""); } namespace test_rvalue_references { template < int N > struct answer { static constexpr int value = N; }; answer<1> f(int&) { return answer<1>(); } answer<2> f(const int&) { return answer<2>(); } answer<3> f(int&&) { return answer<3>(); } void test() { int i = 0; const int c = 0; static_assert(decltype(f(i))::value == 1, ""); static_assert(decltype(f(c))::value == 2, ""); static_assert(decltype(f(0))::value == 3, ""); } } namespace test_uniform_initialization { struct test { static const int zero {}; static const int one {1}; }; static_assert(test::zero == 0, ""); static_assert(test::one == 1, ""); } namespace test_lambdas { void test1() { auto lambda1 = [](){}; auto lambda2 = lambda1; lambda1(); lambda2(); } int test2() { auto a = [](int i, int j){ return i + j; }(1, 2); auto b = []() -> int { return '0'; }(); auto c = [=](){ return a + b; }(); auto d = [&](){ return c; }(); auto e = [a, &b](int x) mutable { const auto identity = [](int y){ return y; }; for (auto i = 0; i < a; ++i) a += b--; return x + identity(a + b); }(0); return a + b + c + d + e; } int test3() { const auto nullary = [](){ return 0; }; const auto unary = [](int x){ return x; }; using nullary_t = decltype(nullary); using unary_t = decltype(unary); const auto higher1st = [](nullary_t f){ return f(); }; const auto higher2nd = [unary](nullary_t f1){ return [unary, f1](unary_t f2){ return f2(unary(f1())); }; }; return higher1st(nullary) + higher2nd(nullary)(unary); } } namespace test_variadic_templates { template struct sum; template struct sum { static constexpr auto value = N0 + sum::value; }; template <> struct sum<> { static constexpr auto value = 0; }; static_assert(sum<>::value == 0, ""); static_assert(sum<1>::value == 1, ""); static_assert(sum<23>::value == 23, ""); static_assert(sum<1, 2>::value == 3, ""); static_assert(sum<5, 5, 11>::value == 21, ""); static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); } // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function // because of this. namespace test_template_alias_sfinae { struct foo {}; template using member = typename T::member_type; template void func(...) {} template void func(member*) {} void test(); void test() { func(0); } } } // namespace cxx11 #endif // __cplusplus >= 201103L // If the compiler admits that it is not ready for C++14, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201402L && !defined _MSC_VER #error "This is not a C++14 compiler" #else namespace cxx14 { namespace test_polymorphic_lambdas { int test() { const auto lambda = [](auto&&... args){ const auto istiny = [](auto x){ return (sizeof(x) == 1UL) ? 1 : 0; }; const int aretiny[] = { istiny(args)... }; return aretiny[0]; }; return lambda(1, 1L, 1.0f, '1'); } } namespace test_binary_literals { constexpr auto ivii = 0b0000000000101010; static_assert(ivii == 42, "wrong value"); } namespace test_generalized_constexpr { template < typename CharT > constexpr unsigned long strlen_c(const CharT *const s) noexcept { auto length = 0UL; for (auto p = s; *p; ++p) ++length; return length; } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("x") == 1UL, ""); static_assert(strlen_c("test") == 4UL, ""); static_assert(strlen_c("another\0test") == 7UL, ""); } namespace test_lambda_init_capture { int test() { auto x = 0; const auto lambda1 = [a = x](int b){ return a + b; }; const auto lambda2 = [a = lambda1(x)](){ return a; }; return lambda2(); } } namespace test_digit_separators { constexpr auto ten_million = 100'000'000; static_assert(ten_million == 100000000, ""); } namespace test_return_type_deduction { auto f(int& x) { return x; } decltype(auto) g(int& x) { return x; } template < typename T1, typename T2 > struct is_same { static constexpr auto value = false; }; template < typename T > struct is_same { static constexpr auto value = true; }; int test() { auto x = 0; static_assert(is_same::value, ""); static_assert(is_same::value, ""); return x; } } } // namespace cxx14 #endif // __cplusplus >= 201402L // If the compiler admits that it is not ready for C++17, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L #error "This is not a C++17 compiler" #else #include #include #include namespace cxx17 { namespace test_constexpr_lambdas { constexpr int foo = [](){return 42;}(); } namespace test::nested_namespace::definitions { } namespace test_fold_expression { template int multiply(Args... args) { return (args * ... * 1); } template bool all(Args... args) { return (args && ...); } } namespace test_extended_static_assert { static_assert (true); } namespace test_auto_brace_init_list { auto foo = {5}; auto bar {5}; static_assert(std::is_same, decltype(foo)>::value); static_assert(std::is_same::value); } namespace test_typename_in_template_template_parameter { template typename X> struct D; } namespace test_fallthrough_nodiscard_maybe_unused_attributes { int f1() { return 42; } [[nodiscard]] int f2() { [[maybe_unused]] auto unused = f1(); switch (f1()) { case 17: f1(); [[fallthrough]]; case 42: f1(); } return f1(); } } namespace test_extended_aggregate_initialization { struct base1 { int b1, b2 = 42; }; struct base2 { base2() { b3 = 42; } int b3; }; struct derived : base1, base2 { int d; }; derived d1 {{1, 2}, {}, 4}; // full initialization derived d2 {{}, {}, 4}; // value-initialized bases } namespace test_general_range_based_for_loop { struct iter { int i; int& operator* () { return i; } const int& operator* () const { return i; } iter& operator++() { ++i; return *this; } }; struct sentinel { int i; }; bool operator== (const iter& i, const sentinel& s) { return i.i == s.i; } bool operator!= (const iter& i, const sentinel& s) { return !(i == s); } struct range { iter begin() const { return {0}; } sentinel end() const { return {5}; } }; void f() { range r {}; for (auto i : r) { [[maybe_unused]] auto v = i; } } } namespace test_lambda_capture_asterisk_this_by_value { struct t { int i; int foo() { return [*this]() { return i; }(); } }; } namespace test_enum_class_construction { enum class byte : unsigned char {}; byte foo {42}; } namespace test_constexpr_if { template int f () { if constexpr(cond) { return 13; } else { return 42; } } } namespace test_selection_statement_with_initializer { int f() { return 13; } int f2() { if (auto i = f(); i > 0) { return 3; } switch (auto i = f(); i + 4) { case 17: return 2; default: return 1; } } } namespace test_template_argument_deduction_for_class_templates { template struct pair { pair (T1 p1, T2 p2) : m1 {p1}, m2 {p2} {} T1 m1; T2 m2; }; void f() { [[maybe_unused]] auto p = pair{13, 42u}; } } namespace test_non_type_auto_template_parameters { template struct B {}; B<5> b1; B<'a'> b2; } namespace test_structured_bindings { int arr[2] = { 1, 2 }; std::pair pr = { 1, 2 }; auto f1() -> int(&)[2] { return arr; } auto f2() -> std::pair& { return pr; } struct S { int x1 : 2; volatile double y1; }; S f3() { return {}; } auto [ x1, y1 ] = f1(); auto& [ xr1, yr1 ] = f1(); auto [ x2, y2 ] = f2(); auto& [ xr2, yr2 ] = f2(); const auto [ x3, y3 ] = f3(); } namespace test_exception_spec_type_system { struct Good {}; struct Bad {}; void g1() noexcept; void g2(); template Bad f(T*, T*); template Good f(T1*, T2*); static_assert (std::is_same_v); } namespace test_inline_variables { template void f(T) {} template inline T g(T) { return T{}; } template<> inline void f<>(int) {} template<> int g<>(int) { return 5; } } } // namespace cxx17 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : eval $cachevar=yes else $as_nop eval $cachevar=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CXX="$ac_save_CXX" fi eval ac_res=\$$cachevar { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done if test x$ac_success = xyes; then break fi done fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test x$ax_cxx_compile_cxx17_required = xtrue; then if test x$ac_success = xno; then as_fn_error $? "*** A compiler with support for C++17 language features is required." "$LINENO" 5 fi fi if test x$ac_success = xno; then HAVE_CXX17=0 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: No compiler with C++17 support was found" >&5 printf "%s\n" "$as_me: No compiler with C++17 support was found" >&6;} else HAVE_CXX17=1 printf "%s\n" "#define HAVE_CXX17 1" >>confdefs.h fi fi fi GLOBAL_CPPFLAGS= GLOBAL_CFLAGS= GLOBAL_CXXFLAGS= ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fvisibility=hidden" >&5 printf %s "checking whether C compiler accepts -fvisibility=hidden... " >&6; } if test ${ax_cv_check_cflags___fvisibility_hidden+y} then : printf %s "(cached) " >&6 else $as_nop ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -fvisibility=hidden" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ax_cv_check_cflags___fvisibility_hidden=yes else $as_nop ax_cv_check_cflags___fvisibility_hidden=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fvisibility_hidden" >&5 printf "%s\n" "$ax_cv_check_cflags___fvisibility_hidden" >&6; } if test "x$ax_cv_check_cflags___fvisibility_hidden" = xyes then : GLOBAL_CFLAGS="$GLOBAL_CFLAGS -fvisibility=hidden" else $as_nop : fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler vendor" >&5 printf %s "checking for C compiler vendor... " >&6; } if test ${ax_cv_c_compiler_vendor+y} then : printf %s "(cached) " >&6 else $as_nop vendors=" intel: __ICC,__ECC,__INTEL_COMPILER ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__,__ibmxl__ pathscale: __PATHCC__,__PATHSCALE__ clang: __clang__ cray: _CRAYC fujitsu: __FUJITSU sdcc: SDCC,__SDCC sx: _SX nvhpc: __NVCOMPILER portland: __PGI gnu: __GNUC__ sun: __SUNPRO_C,__SUNPRO_CC,__SUNPRO_F90,__SUNPRO_F95 hp: __HP_cc,__HP_aCC dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland: __BORLANDC__,__CODEGEARC__,__TURBOC__ comeau: __COMO__ kai: __KCC lcc: __LCC__ sgi: __sgi,sgi microsoft: _MSC_VER metrowerks: __MWERKS__ watcom: __WATCOMC__ tcc: __TINYC__ unknown: UNKNOWN " for ventest in $vendors; do case $ventest in *:) vendor=$ventest continue ;; *) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;; esac cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #if !($vencpp) thisisanerror; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done ax_cv_c_compiler_vendor=`echo $vendor | cut -d: -f1` fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_c_compiler_vendor" >&5 printf "%s\n" "$ax_cv_c_compiler_vendor" >&6; } ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking CFLAGS for most reasonable warnings" >&5 printf %s "checking CFLAGS for most reasonable warnings... " >&6; } if test ${ac_cv_cflags_warn_all+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_cflags_warn_all="" ac_save_cflags_warn_all_found="yes" case "$ax_cv_c_compiler_vendor" in #( intel) : ac_cv_cflags_warn_all="-w2" ;; #( ibm) : ac_cv_cflags_warn_all="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" ;; #( pathscale) : ;; #( clang) : ac_cv_cflags_warn_all="-Wall" ;; #( cray) : ac_cv_cflags_warn_all="-h msglevel 2" ;; #( fujitsu) : ;; #( sdcc) : ;; #( sx) : ac_cv_cflags_warn_all="-pvctl,fullmsg" ;; #( portland) : ;; #( gnu) : ac_cv_cflags_warn_all="-Wall" ;; #( sun) : ac_cv_cflags_warn_all="-v" ;; #( hp) : ac_cv_cflags_warn_all="+w1" ;; #( dec) : ac_cv_cflags_warn_all="-verbose -w0 -warnprotos" ;; #( borland) : ;; #( comeau) : ;; #( kai) : ;; #( lcc) : ;; #( sgi) : ac_cv_cflags_warn_all="-fullwarn" ;; #( microsoft) : ;; #( metrowerks) : ;; #( watcom) : ;; #( tcc) : ;; #( unknown) : ac_cv_cflags_warn_all="" ac_save_cflags_warn_all_found="no" ;; #( *) : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Unknown compiler vendor returned by AX_COMPILER_VENDOR" >&5 printf "%s\n" "$as_me: WARNING: Unknown compiler vendor returned by AX_COMPILER_VENDOR" >&2;} ac_cv_cflags_warn_all="" ac_save_cflags_warn_all_found="no" ;; esac if test "x$ac_save_cflags_warn_all_found" = "xyes" then : if test "x$ac_cv_cflags_warn_all" != "x" then : if test ${CFLAGS+y} then : case " $CFLAGS " in #( *" $ac_cv_cflags_warn_all "*) : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CFLAGS already contains \$ac_cv_cflags_warn_all"; } >&5 (: CFLAGS already contains $ac_cv_cflags_warn_all) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } ;; #( *) : CFLAGS="$ac_cv_cflags_warn_all $CFLAGS" { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CFLAGS=\"\$CFLAGS\""; } >&5 (: CFLAGS="$CFLAGS") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } ;; esac else $as_nop CFLAGS=$ac_cv_cflags_warn_all { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CFLAGS=\"\$CFLAGS\""; } >&5 (: CFLAGS="$CFLAGS") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } fi fi else $as_nop true fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags_warn_all" >&5 printf "%s\n" "$ac_cv_cflags_warn_all" >&6; } ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts -fvisibility=hidden" >&5 printf %s "checking whether C++ compiler accepts -fvisibility=hidden... " >&6; } if test ${ax_cv_check_cxxflags___fvisibility_hidden+y} then : printf %s "(cached) " >&6 else $as_nop ax_check_save_flags=$CXXFLAGS CXXFLAGS="$CXXFLAGS -fvisibility=hidden" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ax_cv_check_cxxflags___fvisibility_hidden=yes else $as_nop ax_cv_check_cxxflags___fvisibility_hidden=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CXXFLAGS=$ax_check_save_flags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cxxflags___fvisibility_hidden" >&5 printf "%s\n" "$ax_cv_check_cxxflags___fvisibility_hidden" >&6; } if test "x$ax_cv_check_cxxflags___fvisibility_hidden" = xyes then : GLOBAL_CXXFLAGS="$GLOBAL_CXXFLAGS -fvisibility=hidden" else $as_nop : fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking CXXFLAGS for most reasonable warnings" >&5 printf %s "checking CXXFLAGS for most reasonable warnings... " >&6; } if test ${ac_cv_cxxflags_warn_all+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_cxxflags_warn_all="" ac_save_cxxflags_warn_all_found="yes" case "$ax_cv_cxx_compiler_vendor" in #( intel) : ac_cv_cxxflags_warn_all="-w2" ;; #( ibm) : ac_cv_cxxflags_warn_all="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" ;; #( pathscale) : ;; #( clang) : ac_cv_cxxflags_warn_all="-Wall" ;; #( cray) : ac_cv_cxxflags_warn_all="-h msglevel 2" ;; #( fujitsu) : ;; #( sdcc) : ;; #( sx) : ac_cv_cxxflags_warn_all="-pvctl,fullmsg" ;; #( portland) : ;; #( gnu) : ac_cv_cxxflags_warn_all="-Wall" ;; #( sun) : ac_cv_cxxflags_warn_all="-v" ;; #( hp) : ac_cv_cxxflags_warn_all="+w1" ;; #( dec) : ac_cv_cxxflags_warn_all="-verbose -w0 -warnprotos" ;; #( borland) : ;; #( comeau) : ;; #( kai) : ;; #( lcc) : ;; #( sgi) : ac_cv_cxxflags_warn_all="-fullwarn" ;; #( microsoft) : ;; #( metrowerks) : ;; #( watcom) : ;; #( tcc) : ;; #( unknown) : ac_cv_cxxflags_warn_all="" ac_save_cxxflags_warn_all_found="no" ;; #( *) : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Unknown compiler vendor returned by AX_COMPILER_VENDOR" >&5 printf "%s\n" "$as_me: WARNING: Unknown compiler vendor returned by AX_COMPILER_VENDOR" >&2;} ac_cv_cxxflags_warn_all="" ac_save_cxxflags_warn_all_found="no" ;; esac if test "x$ac_save_cxxflags_warn_all_found" = "xyes" then : if test "x$ac_cv_cxxflags_warn_all" != "x" then : if test ${CXXFLAGS+y} then : case " $CXXFLAGS " in #( *" $ac_cv_cxxflags_warn_all "*) : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CXXFLAGS already contains \$ac_cv_cxxflags_warn_all"; } >&5 (: CXXFLAGS already contains $ac_cv_cxxflags_warn_all) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } ;; #( *) : CXXFLAGS="$ac_cv_cxxflags_warn_all $CXXFLAGS" { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CXXFLAGS=\"\$CXXFLAGS\""; } >&5 (: CXXFLAGS="$CXXFLAGS") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } ;; esac else $as_nop CXXFLAGS=$ac_cv_cxxflags_warn_all { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CXXFLAGS=\"\$CXXFLAGS\""; } >&5 (: CXXFLAGS="$CXXFLAGS") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } fi fi else $as_nop true fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxxflags_warn_all" >&5 printf "%s\n" "$ac_cv_cxxflags_warn_all" >&6; } ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports exceptions" >&5 printf %s "checking whether the compiler supports exceptions... " >&6; } if test ${ax_cv_cxx_exceptions+y} then : printf %s "(cached) " >&6 else $as_nop ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { try { throw 1; } catch (int i) { return i; } ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ax_cv_cxx_exceptions=yes else $as_nop ax_cv_cxx_exceptions=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_exceptions" >&5 printf "%s\n" "$ax_cv_cxx_exceptions" >&6; } if test "$ax_cv_cxx_exceptions" = yes; then printf "%s\n" "#define HAVE_EXCEPTIONS /**/" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports Run-Time Type Identification" >&5 printf %s "checking whether the compiler supports Run-Time Type Identification... " >&6; } if test ${ax_cv_cxx_rtti+y} then : printf %s "(cached) " >&6 else $as_nop ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include class Base { public : Base () {} virtual int f () { return 0; } }; class Derived : public Base { public : Derived () {} virtual int f () { return 1; } }; int main (void) { Derived d; Base *ptr = &d; return typeid (*ptr) == typeid (Derived); ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ax_cv_cxx_rtti=yes else $as_nop ax_cv_cxx_rtti=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_rtti" >&5 printf "%s\n" "$ax_cv_cxx_rtti" >&6; } if test "$ax_cv_cxx_rtti" = yes; then printf "%s\n" "#define HAVE_RTTI /**/" >>confdefs.h fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then ax_pthread_save_CC="$CC" ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" if test "x$PTHREAD_CC" != "x" then : CC="$PTHREAD_CC" fi if test "x$PTHREAD_CXX" != "x" then : CXX="$PTHREAD_CXX" fi CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS" >&5 printf %s "checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char pthread_join (); int main (void) { return pthread_join (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ax_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 printf "%s\n" "$ax_pthread_ok" >&6; } if test "x$ax_pthread_ok" = "xno"; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi CC="$ax_pthread_save_CC" CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items with a "," contain both # C compiler flags (before ",") and linker flags (after ","). Other items # starting with a "-" are C compiler flags, and remaining items are # library names, except for "none" which indicates that we try without # any flags at all, and "pthread-config" which is a program returning # the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 # (Note: HP C rejects this with "bad form for `-t' option") # -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads and # -D_REENTRANT too), HP C (must be checked before -lpthread, which # is present but should not be used directly; and before -mthreads, # because the compiler interprets this as "-mt" + "-hreads") # -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case $host_os in freebsd*) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) ax_pthread_flags="-kthread lthread $ax_pthread_flags" ;; hpux*) # From the cc(1) man page: "[-mt] Sets various -D flags to enable # multi-threading and also sets -lpthread." ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" ;; openedition*) # IBM z/OS requires a feature-test macro to be defined in order to # enable POSIX threads at all, so give the user a hint if this is # not set. (We don't define these ourselves, as they can affect # other portions of the system API in unpredictable ways.) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) AX_PTHREAD_ZOS_MISSING # endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1 then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5 printf "%s\n" "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;} fi rm -rf conftest* ;; solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (N.B.: The stubs are missing # pthread_cleanup_push, or rather a function called by this macro, # so we could check for that, but who knows whether they'll stub # that too in a future libc.) So we'll check first for the # standard Solaris way of linking pthreads (-mt -lpthread). ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags" ;; esac # Are we compiling with Clang? { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC is Clang" >&5 printf %s "checking whether $CC is Clang... " >&6; } if test ${ax_cv_PTHREAD_CLANG+y} then : printf %s "(cached) " >&6 else $as_nop ax_cv_PTHREAD_CLANG=no # Note that Autoconf sets GCC=yes for Clang as well as GCC if test "x$GCC" = "xyes"; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Note: Clang 2.7 lacks __clang_[a-z]+__ */ # if defined(__clang__) && defined(__llvm__) AX_PTHREAD_CC_IS_CLANG # endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1 then : ax_cv_PTHREAD_CLANG=yes fi rm -rf conftest* fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5 printf "%s\n" "$ax_cv_PTHREAD_CLANG" >&6; } ax_pthread_clang="$ax_cv_PTHREAD_CLANG" # GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) # Note that for GCC and Clang -pthread generally implies -lpthread, # except when -nostdlib is passed. # This is problematic using libtool to build C++ shared libraries with pthread: # [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460 # [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333 # [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555 # To solve this, first try -pthread together with -lpthread for GCC if test "x$GCC" = "xyes" then : ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags" fi # Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first if test "x$ax_pthread_clang" = "xyes" then : ax_pthread_flags="-pthread,-lpthread -pthread" fi # The presence of a feature test macro requesting re-entrant function # definitions is, on some systems, a strong hint that pthreads support is # correctly enabled case $host_os in darwin* | hpux* | linux* | osf* | solaris*) ax_pthread_check_macro="_REENTRANT" ;; aix*) ax_pthread_check_macro="_THREAD_SAFE" ;; *) ax_pthread_check_macro="--" ;; esac if test "x$ax_pthread_check_macro" = "x--" then : ax_pthread_check_cond=0 else $as_nop ax_pthread_check_cond="!defined($ax_pthread_check_macro)" fi if test "x$ax_pthread_ok" = "xno"; then for ax_pthread_try_flag in $ax_pthread_flags; do case $ax_pthread_try_flag in none) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 printf %s "checking whether pthreads work without any flags... " >&6; } ;; *,*) PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"` PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with \"$PTHREAD_CFLAGS\" and \"$PTHREAD_LIBS\"" >&5 printf %s "checking whether pthreads work with \"$PTHREAD_CFLAGS\" and \"$PTHREAD_LIBS\"... " >&6; } ;; -*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $ax_pthread_try_flag" >&5 printf %s "checking whether pthreads work with $ax_pthread_try_flag... " >&6; } PTHREAD_CFLAGS="$ax_pthread_try_flag" ;; pthread-config) # Extract the first word of "pthread-config", so it can be a program name with args. set dummy pthread-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ax_pthread_config+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ax_pthread_config"; then ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ax_pthread_config="yes" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no" fi fi ax_pthread_config=$ac_cv_prog_ax_pthread_config if test -n "$ax_pthread_config"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5 printf "%s\n" "$ax_pthread_config" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ax_pthread_config" = "xno" then : continue fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$ax_pthread_try_flag" >&5 printf %s "checking for the pthreads library -l$ax_pthread_try_flag... " >&6; } PTHREAD_LIBS="-l$ax_pthread_try_flag" ;; esac ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include # if $ax_pthread_check_cond # error "$ax_pthread_check_macro must be defined" # endif static void *some_global = NULL; static void routine(void *a) { /* To avoid any unused-parameter or unused-but-set-parameter warning. */ some_global = a; } static void *start_routine(void *a) { return a; } int main (void) { pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */ ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ax_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 printf "%s\n" "$ax_pthread_ok" >&6; } if test "x$ax_pthread_ok" = "xyes" then : break fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Clang needs special handling, because older versions handle the -pthread # option in a rather... idiosyncratic way if test "x$ax_pthread_clang" = "xyes"; then # Clang takes -pthread; it has never supported any other flag # (Note 1: This will need to be revisited if a system that Clang # supports has POSIX threads in a separate library. This tends not # to be the way of modern systems, but it's conceivable.) # (Note 2: On some systems, notably Darwin, -pthread is not needed # to get POSIX threads support; the API is always present and # active. We could reasonably leave PTHREAD_CFLAGS empty. But # -pthread does define _REENTRANT, and while the Darwin headers # ignore this macro, third-party headers might not.) # However, older versions of Clang make a point of warning the user # that, in an invocation where only linking and no compilation is # taking place, the -pthread option has no effect ("argument unused # during compilation"). They expect -pthread to be passed in only # when source code is being compiled. # # Problem is, this is at odds with the way Automake and most other # C build frameworks function, which is that the same flags used in # compilation (CFLAGS) are also used in linking. Many systems # supported by AX_PTHREAD require exactly this for POSIX threads # support, and in fact it is often not straightforward to specify a # flag that is used only in the compilation phase and not in # linking. Such a scenario is extremely rare in practice. # # Even though use of the -pthread flag in linking would only print # a warning, this can be a nuisance for well-run software projects # that build with -Werror. So if the active version of Clang has # this misfeature, we search for an option to squash it. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread" >&5 printf %s "checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread... " >&6; } if test ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+y} then : printf %s "(cached) " >&6 else $as_nop ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown # Create an alternate version of $ac_link that compiles and # links in two steps (.c -> .o, .o -> exe) instead of one # (.c -> exe), because the warning occurs only in the second # step ax_pthread_save_ac_link="$ac_link" ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' ax_pthread_link_step=`printf "%s\n" "$ac_link" | sed "$ax_pthread_sed"` ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" ax_pthread_save_CFLAGS="$CFLAGS" for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do if test "x$ax_pthread_try" = "xunknown" then : break fi CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" ac_link="$ax_pthread_save_ac_link" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void){return 0;} _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_link="$ax_pthread_2step_ac_link" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void){return 0;} _ACEOF if ac_fn_c_try_link "$LINENO" then : break fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext done ac_link="$ax_pthread_save_ac_link" CFLAGS="$ax_pthread_save_CFLAGS" if test "x$ax_pthread_try" = "x" then : ax_pthread_try=no fi ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5 printf "%s\n" "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; } case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in no | unknown) ;; *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; esac fi # $ax_pthread_clang = yes # Various other checks: if test "x$ax_pthread_ok" = "xyes"; then ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 printf %s "checking for joinable pthread attribute... " >&6; } if test ${ax_cv_PTHREAD_JOINABLE_ATTR+y} then : printf %s "(cached) " >&6 else $as_nop ax_cv_PTHREAD_JOINABLE_ATTR=unknown for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { int attr = $ax_pthread_attr; return attr /* ; */ ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5 printf "%s\n" "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; } if test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ test "x$ax_pthread_joinable_attr_defined" != "xyes" then : printf "%s\n" "#define PTHREAD_CREATE_JOINABLE $ax_cv_PTHREAD_JOINABLE_ATTR" >>confdefs.h ax_pthread_joinable_attr_defined=yes fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether more special flags are required for pthreads" >&5 printf %s "checking whether more special flags are required for pthreads... " >&6; } if test ${ax_cv_PTHREAD_SPECIAL_FLAGS+y} then : printf %s "(cached) " >&6 else $as_nop ax_cv_PTHREAD_SPECIAL_FLAGS=no case $host_os in solaris*) ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5 printf "%s\n" "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; } if test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ test "x$ax_pthread_special_flags_added" != "xyes" then : PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" ax_pthread_special_flags_added=yes fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5 printf %s "checking for PTHREAD_PRIO_INHERIT... " >&6; } if test ${ax_cv_PTHREAD_PRIO_INHERIT+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { int i = PTHREAD_PRIO_INHERIT; return i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ax_cv_PTHREAD_PRIO_INHERIT=yes else $as_nop ax_cv_PTHREAD_PRIO_INHERIT=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5 printf "%s\n" "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; } if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ test "x$ax_pthread_prio_inherit_defined" != "xyes" then : printf "%s\n" "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h ax_pthread_prio_inherit_defined=yes fi CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" # More AIX lossage: compile with *_r variant if test "x$GCC" != "xyes"; then case $host_os in aix*) case "x/$CC" in #( x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) : #handle absolute path differently from PATH based program lookup case "x$CC" in #( x/*) : if as_fn_executable_p ${CC}_r then : PTHREAD_CC="${CC}_r" fi if test "x${CXX}" != "x" then : if as_fn_executable_p ${CXX}_r then : PTHREAD_CXX="${CXX}_r" fi fi ;; #( *) : for ac_prog in ${CC}_r do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_PTHREAD_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$PTHREAD_CC"; then ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_PTHREAD_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi PTHREAD_CC=$ac_cv_prog_PTHREAD_CC if test -n "$PTHREAD_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 printf "%s\n" "$PTHREAD_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$PTHREAD_CC" && break done test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" if test "x${CXX}" != "x" then : for ac_prog in ${CXX}_r do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_PTHREAD_CXX+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$PTHREAD_CXX"; then ac_cv_prog_PTHREAD_CXX="$PTHREAD_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_PTHREAD_CXX="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi PTHREAD_CXX=$ac_cv_prog_PTHREAD_CXX if test -n "$PTHREAD_CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CXX" >&5 printf "%s\n" "$PTHREAD_CXX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$PTHREAD_CXX" && break done test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" fi ;; esac ;; #( *) : ;; esac ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test "x$ax_pthread_ok" = "xyes"; then LIBS="$PTHREAD_LIBS $LIBS" GLOBAL_CFLAGS="$GLOBAL_CFLAGS $PTHREAD_CFLAGS" GLOBAL_CXXFLAGS="$GLOBAL_CXXFLAGS $PTHREAD_CFLAGS" #CC="$PTHREAD_CC" #CXX="$PTHREAD_CXX" : else ax_pthread_ok=no fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # work-around # This is somewhat pessimistic, but necessary for GCC 8 or earlier, # which we still support and where we cannot use #pragma GCC optimize. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fno-ipa-ra" >&5 printf %s "checking whether C compiler accepts -fno-ipa-ra... " >&6; } if test ${ax_cv_check_cflags___fno_ipa_ra+y} then : printf %s "(cached) " >&6 else $as_nop ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -fno-ipa-ra" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ax_cv_check_cflags___fno_ipa_ra=yes else $as_nop ax_cv_check_cflags___fno_ipa_ra=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fno_ipa_ra" >&5 printf "%s\n" "$ax_cv_check_cflags___fno_ipa_ra" >&6; } if test "x$ax_cv_check_cflags___fno_ipa_ra" = xyes then : GLOBAL_CFLAGS="$GLOBAL_CFLAGS -fno-ipa-ra" else $as_nop : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking CFLAGS for most reasonable warnings" >&5 printf %s "checking CFLAGS for most reasonable warnings... " >&6; } if test ${ac_cv_cflags_warn_all+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_cflags_warn_all="" ac_save_cflags_warn_all_found="yes" case "$ax_cv_c_compiler_vendor" in #( intel) : ac_cv_cflags_warn_all="-w2" ;; #( ibm) : ac_cv_cflags_warn_all="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" ;; #( pathscale) : ;; #( clang) : ac_cv_cflags_warn_all="-Wall" ;; #( cray) : ac_cv_cflags_warn_all="-h msglevel 2" ;; #( fujitsu) : ;; #( sdcc) : ;; #( sx) : ac_cv_cflags_warn_all="-pvctl,fullmsg" ;; #( portland) : ;; #( gnu) : ac_cv_cflags_warn_all="-Wall" ;; #( sun) : ac_cv_cflags_warn_all="-v" ;; #( hp) : ac_cv_cflags_warn_all="+w1" ;; #( dec) : ac_cv_cflags_warn_all="-verbose -w0 -warnprotos" ;; #( borland) : ;; #( comeau) : ;; #( kai) : ;; #( lcc) : ;; #( sgi) : ac_cv_cflags_warn_all="-fullwarn" ;; #( microsoft) : ;; #( metrowerks) : ;; #( watcom) : ;; #( tcc) : ;; #( unknown) : ac_cv_cflags_warn_all="" ac_save_cflags_warn_all_found="no" ;; #( *) : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Unknown compiler vendor returned by AX_COMPILER_VENDOR" >&5 printf "%s\n" "$as_me: WARNING: Unknown compiler vendor returned by AX_COMPILER_VENDOR" >&2;} ac_cv_cflags_warn_all="" ac_save_cflags_warn_all_found="no" ;; esac if test "x$ac_save_cflags_warn_all_found" = "xyes" then : if test "x$ac_cv_cflags_warn_all" != "x" then : if test ${CFLAGS+y} then : case " $CFLAGS " in #( *" $ac_cv_cflags_warn_all "*) : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CFLAGS already contains \$ac_cv_cflags_warn_all"; } >&5 (: CFLAGS already contains $ac_cv_cflags_warn_all) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } ;; #( *) : CFLAGS="$ac_cv_cflags_warn_all $CFLAGS" { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CFLAGS=\"\$CFLAGS\""; } >&5 (: CFLAGS="$CFLAGS") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } ;; esac else $as_nop CFLAGS=$ac_cv_cflags_warn_all { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CFLAGS=\"\$CFLAGS\""; } >&5 (: CFLAGS="$CFLAGS") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } fi fi else $as_nop true fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags_warn_all" >&5 printf "%s\n" "$ac_cv_cflags_warn_all" >&6; } ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts -fno-ipa-ra" >&5 printf %s "checking whether C++ compiler accepts -fno-ipa-ra... " >&6; } if test ${ax_cv_check_cxxflags___fno_ipa_ra+y} then : printf %s "(cached) " >&6 else $as_nop ax_check_save_flags=$CXXFLAGS CXXFLAGS="$CXXFLAGS -fno-ipa-ra" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ax_cv_check_cxxflags___fno_ipa_ra=yes else $as_nop ax_cv_check_cxxflags___fno_ipa_ra=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CXXFLAGS=$ax_check_save_flags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cxxflags___fno_ipa_ra" >&5 printf "%s\n" "$ax_cv_check_cxxflags___fno_ipa_ra" >&6; } if test "x$ax_cv_check_cxxflags___fno_ipa_ra" = xyes then : GLOBAL_CXXFLAGS="$GLOBAL_CXXFLAGS -fno-ipa-ra" else $as_nop : fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking CXXFLAGS for most reasonable warnings" >&5 printf %s "checking CXXFLAGS for most reasonable warnings... " >&6; } if test ${ac_cv_cxxflags_warn_all+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_cxxflags_warn_all="" ac_save_cxxflags_warn_all_found="yes" case "$ax_cv_cxx_compiler_vendor" in #( intel) : ac_cv_cxxflags_warn_all="-w2" ;; #( ibm) : ac_cv_cxxflags_warn_all="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" ;; #( pathscale) : ;; #( clang) : ac_cv_cxxflags_warn_all="-Wall" ;; #( cray) : ac_cv_cxxflags_warn_all="-h msglevel 2" ;; #( fujitsu) : ;; #( sdcc) : ;; #( sx) : ac_cv_cxxflags_warn_all="-pvctl,fullmsg" ;; #( portland) : ;; #( gnu) : ac_cv_cxxflags_warn_all="-Wall" ;; #( sun) : ac_cv_cxxflags_warn_all="-v" ;; #( hp) : ac_cv_cxxflags_warn_all="+w1" ;; #( dec) : ac_cv_cxxflags_warn_all="-verbose -w0 -warnprotos" ;; #( borland) : ;; #( comeau) : ;; #( kai) : ;; #( lcc) : ;; #( sgi) : ac_cv_cxxflags_warn_all="-fullwarn" ;; #( microsoft) : ;; #( metrowerks) : ;; #( watcom) : ;; #( tcc) : ;; #( unknown) : ac_cv_cxxflags_warn_all="" ac_save_cxxflags_warn_all_found="no" ;; #( *) : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Unknown compiler vendor returned by AX_COMPILER_VENDOR" >&5 printf "%s\n" "$as_me: WARNING: Unknown compiler vendor returned by AX_COMPILER_VENDOR" >&2;} ac_cv_cxxflags_warn_all="" ac_save_cxxflags_warn_all_found="no" ;; esac if test "x$ac_save_cxxflags_warn_all_found" = "xyes" then : if test "x$ac_cv_cxxflags_warn_all" != "x" then : if test ${CXXFLAGS+y} then : case " $CXXFLAGS " in #( *" $ac_cv_cxxflags_warn_all "*) : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CXXFLAGS already contains \$ac_cv_cxxflags_warn_all"; } >&5 (: CXXFLAGS already contains $ac_cv_cxxflags_warn_all) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } ;; #( *) : CXXFLAGS="$ac_cv_cxxflags_warn_all $CXXFLAGS" { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CXXFLAGS=\"\$CXXFLAGS\""; } >&5 (: CXXFLAGS="$CXXFLAGS") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } ;; esac else $as_nop CXXFLAGS=$ac_cv_cxxflags_warn_all { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : CXXFLAGS=\"\$CXXFLAGS\""; } >&5 (: CXXFLAGS="$CXXFLAGS") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } fi fi else $as_nop true fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxxflags_warn_all" >&5 printf "%s\n" "$ac_cv_cxxflags_warn_all" >&6; } ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu LIBOPENMPT_LTVER_CURRENT=5 LIBOPENMPT_LTVER_REVISION=5 LIBOPENMPT_LTVER_AGE=5 printf "%s\n" "#define MPT_SVNURL \"https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.8.1\"" >>confdefs.h printf "%s\n" "#define MPT_SVNVERSION \"23497\"" >>confdefs.h printf "%s\n" "#define MPT_SVNDATE \"2025-06-14T13:04:39.042416Z\"" >>confdefs.h printf "%s\n" "#define MPT_PACKAGE true" >>confdefs.h # work-around NetBSD toolchain not understanding transitive shared object dependencies at all case $host_os in #( netbsd*) : LIBS="$LIBS -lstdc++" ;; #( *) : ;; esac case $host_os in #( mingw32*) : LIBOPENMPT_WIN32_LIBS= LIBOPENMPT_LIBS_PRIVATE_WIN32= LIBOPENMPTTEST_WIN32_LIBS="-lole32 -lrpcrt4" OPENMPT123_WIN32_LIBS=-lwinmm WIN32_CPPFLAGS="-D_UNICODE -DNOMINMAX" WIN32_CXXFLAGS="-municode -mthreads" WIN32_CFLAGS="-municode -mthreads" WIN32_CONSOLE_CXXFLAGS=-mconsole WIN32_CONSOLE_CFLAGS=-mconsole ;; #( *) : LIBOPENMPT_WIN32_LIBS= LIBOPENMPT_LIBS_PRIVATE_WIN32= LIBOPENMPTTEST_WIN32_LIBS= OPENMPT123_WIN32_LIBS= WIN32_CPPFLAGS= WIN32_CXXFLAGS= WIN32_CFLAGS= WIN32_CONSOLE_CXXFLAGS= WIN32_CONSOLE_CFLAGS= ;; esac LIBOPENMPT_REQUIRES_PRIVATE= LIBOPENMPT_LIBS_PRIVATE= # Required libopenmpt dependency: zlib ZLIB_PKG= # Check whether --with-zlib was given. if test ${with_zlib+y} then : withval=$with_zlib; fi if test "x$with_zlib" != "xno" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib" >&5 printf %s "checking for zlib... " >&6; } if test -n "$ZLIB_CFLAGS"; then pkg_cv_ZLIB_CFLAGS="$ZLIB_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5 ($PKG_CONFIG --exists --print-errors "zlib") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ZLIB_CFLAGS=`$PKG_CONFIG --cflags "zlib" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$ZLIB_LIBS"; then pkg_cv_ZLIB_LIBS="$ZLIB_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5 ($PKG_CONFIG --exists --print-errors "zlib") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ZLIB_LIBS=`$PKG_CONFIG --libs "zlib" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then ZLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "zlib" 2>&1` else ZLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "zlib" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$ZLIB_PKG_ERRORS" >&5 as_fn_error $? "Unable to find zlib." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "Unable to find zlib." "$LINENO" 5 else ZLIB_CFLAGS=$pkg_cv_ZLIB_CFLAGS ZLIB_LIBS=$pkg_cv_ZLIB_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } ZLIB_PKG=zlib ZLIB_CFLAGS="-DMPT_WITH_ZLIB $ZLIB_CFLAGS" fi fi # Required libopenmpt dependency: mpg123 MPG123_PKG= # Check whether --with-mpg123 was given. if test ${with_mpg123+y} then : withval=$with_mpg123; fi if test "x$with_mpg123" != "xno" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libmpg123 >= 1.14.0" >&5 printf %s "checking for libmpg123 >= 1.14.0... " >&6; } if test -n "$MPG123_CFLAGS"; then pkg_cv_MPG123_CFLAGS="$MPG123_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmpg123 >= 1.14.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libmpg123 >= 1.14.0") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_MPG123_CFLAGS=`$PKG_CONFIG --cflags "libmpg123 >= 1.14.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$MPG123_LIBS"; then pkg_cv_MPG123_LIBS="$MPG123_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmpg123 >= 1.14.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "libmpg123 >= 1.14.0") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_MPG123_LIBS=`$PKG_CONFIG --libs "libmpg123 >= 1.14.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then MPG123_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libmpg123 >= 1.14.0" 2>&1` else MPG123_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libmpg123 >= 1.14.0" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$MPG123_PKG_ERRORS" >&5 as_fn_error $? "Unable to find libmpg123." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "Unable to find libmpg123." "$LINENO" 5 else MPG123_CFLAGS=$pkg_cv_MPG123_CFLAGS MPG123_LIBS=$pkg_cv_MPG123_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } MPG123_PKG=libmpg123 MPG123_CFLAGS="-DMPT_WITH_MPG123 $MPG123_CFLAGS" fi fi # Required libopenmpt dependency: ogg OGG_PKG= # Check whether --with-ogg was given. if test ${with_ogg+y} then : withval=$with_ogg; fi if test "x$with_ogg" != "xno" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ogg" >&5 printf %s "checking for ogg... " >&6; } if test -n "$OGG_CFLAGS"; then pkg_cv_OGG_CFLAGS="$OGG_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ogg\""; } >&5 ($PKG_CONFIG --exists --print-errors "ogg") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_OGG_CFLAGS=`$PKG_CONFIG --cflags "ogg" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$OGG_LIBS"; then pkg_cv_OGG_LIBS="$OGG_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ogg\""; } >&5 ($PKG_CONFIG --exists --print-errors "ogg") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_OGG_LIBS=`$PKG_CONFIG --libs "ogg" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then OGG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ogg" 2>&1` else OGG_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ogg" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$OGG_PKG_ERRORS" >&5 as_fn_error $? "Unable to find libogg." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "Unable to find libogg." "$LINENO" 5 else OGG_CFLAGS=$pkg_cv_OGG_CFLAGS OGG_LIBS=$pkg_cv_OGG_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } OGG_PKG=ogg OGG_CFLAGS="-DMPT_WITH_OGG $OGG_CFLAGS" fi fi # Required libopenmpt dependency: vorbis VORBIS_PKG= # Check whether --with-vorbis was given. if test ${with_vorbis+y} then : withval=$with_vorbis; fi if test "x$with_vorbis" != "xno" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for vorbis" >&5 printf %s "checking for vorbis... " >&6; } if test -n "$VORBIS_CFLAGS"; then pkg_cv_VORBIS_CFLAGS="$VORBIS_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"vorbis\""; } >&5 ($PKG_CONFIG --exists --print-errors "vorbis") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_VORBIS_CFLAGS=`$PKG_CONFIG --cflags "vorbis" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$VORBIS_LIBS"; then pkg_cv_VORBIS_LIBS="$VORBIS_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"vorbis\""; } >&5 ($PKG_CONFIG --exists --print-errors "vorbis") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_VORBIS_LIBS=`$PKG_CONFIG --libs "vorbis" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then VORBIS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "vorbis" 2>&1` else VORBIS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "vorbis" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$VORBIS_PKG_ERRORS" >&5 as_fn_error $? "Unable to find libvorbis." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "Unable to find libvorbis." "$LINENO" 5 else VORBIS_CFLAGS=$pkg_cv_VORBIS_CFLAGS VORBIS_LIBS=$pkg_cv_VORBIS_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } VORBIS_PKG=vorbis VORBIS_CFLAGS="-DMPT_WITH_VORBIS $VORBIS_CFLAGS" fi fi # Required libopenmpt dependency: vorbisfile VORBISFILE_PKG= # Check whether --with-vorbisfile was given. if test ${with_vorbisfile+y} then : withval=$with_vorbisfile; fi if test "x$with_vorbisfile" != "xno" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for vorbisfile" >&5 printf %s "checking for vorbisfile... " >&6; } if test -n "$VORBISFILE_CFLAGS"; then pkg_cv_VORBISFILE_CFLAGS="$VORBISFILE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"vorbisfile\""; } >&5 ($PKG_CONFIG --exists --print-errors "vorbisfile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_VORBISFILE_CFLAGS=`$PKG_CONFIG --cflags "vorbisfile" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$VORBISFILE_LIBS"; then pkg_cv_VORBISFILE_LIBS="$VORBISFILE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"vorbisfile\""; } >&5 ($PKG_CONFIG --exists --print-errors "vorbisfile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_VORBISFILE_LIBS=`$PKG_CONFIG --libs "vorbisfile" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then VORBISFILE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "vorbisfile" 2>&1` else VORBISFILE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "vorbisfile" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$VORBISFILE_PKG_ERRORS" >&5 as_fn_error $? "Unable to find libvorbisfile." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "Unable to find libvorbisfile." "$LINENO" 5 else VORBISFILE_CFLAGS=$pkg_cv_VORBISFILE_CFLAGS VORBISFILE_LIBS=$pkg_cv_VORBISFILE_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } VORBISFILE_PKG=vorbisfile VORBISFILE_CFLAGS="-DMPT_WITH_VORBISFILE $VORBISFILE_CFLAGS" fi fi LIBOPENMPT_REQUIRES_PRIVATE="$ZLIB_PKG $MPG123_PKG $OGG_PKG $VORBIS_PKG $VORBISFILE_PKG" LIBOPENMPT_LIBS_PRIVATE="$CXXSTDLIB_PCLIBSPRIVATE $LIBOPENMPT_LIBS_PRIVATE_WIN32" # openmpt123 # Check whether --enable-openmpt123 was given. if test ${enable_openmpt123+y} then : enableval=$enable_openmpt123; fi if test "x$enable_openmpt123" != "xno"; then ENABLE_OPENMPT123_TRUE= ENABLE_OPENMPT123_FALSE='#' else ENABLE_OPENMPT123_TRUE='#' ENABLE_OPENMPT123_FALSE= fi # examples # Check whether --enable-examples was given. if test ${enable_examples+y} then : enableval=$enable_examples; fi if test "x$enable_examples" != "xno"; then ENABLE_EXAMPLES_TRUE= ENABLE_EXAMPLES_FALSE='#' else ENABLE_EXAMPLES_TRUE='#' ENABLE_EXAMPLES_FALSE= fi # tests # Check whether --enable-tests was given. if test ${enable_tests+y} then : enableval=$enable_tests; fi if test "x$enable_tests" != "xno"; then ENABLE_TESTS_TRUE= ENABLE_TESTS_FALSE='#' else ENABLE_TESTS_TRUE='#' ENABLE_TESTS_FALSE= fi # Optional openmpt123 dependency # Check whether --with-pulseaudio was given. if test ${with_pulseaudio+y} then : withval=$with_pulseaudio; fi if test "x$enable_openmpt123" != "xno" then : case $host_os in #( linux*) : if test "x$with_pulseaudio" != "xno" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libpulse libpulse-simple" >&5 printf %s "checking for libpulse libpulse-simple... " >&6; } if test -n "$PULSEAUDIO_CFLAGS"; then pkg_cv_PULSEAUDIO_CFLAGS="$PULSEAUDIO_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse libpulse-simple\""; } >&5 ($PKG_CONFIG --exists --print-errors "libpulse libpulse-simple") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PULSEAUDIO_CFLAGS=`$PKG_CONFIG --cflags "libpulse libpulse-simple" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$PULSEAUDIO_LIBS"; then pkg_cv_PULSEAUDIO_LIBS="$PULSEAUDIO_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse libpulse-simple\""; } >&5 ($PKG_CONFIG --exists --print-errors "libpulse libpulse-simple") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PULSEAUDIO_LIBS=`$PKG_CONFIG --libs "libpulse libpulse-simple" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then PULSEAUDIO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpulse libpulse-simple" 2>&1` else PULSEAUDIO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpulse libpulse-simple" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$PULSEAUDIO_PKG_ERRORS" >&5 have_pulseaudio=0 as_fn_error $? "Unable to find libpulse and/or libpulse-simple." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } have_pulseaudio=0 as_fn_error $? "Unable to find libpulse and/or libpulse-simple." "$LINENO" 5 else PULSEAUDIO_CFLAGS=$pkg_cv_PULSEAUDIO_CFLAGS PULSEAUDIO_LIBS=$pkg_cv_PULSEAUDIO_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } have_pulseaudio=1 PULSEAUDIO_CFLAGS="-DMPT_WITH_PULSEAUDIO $PULSEAUDIO_CFLAGS" fi else $as_nop have_pulseaudio=0 fi ;; *) if test "x$with_pulseaudio" = "xyes" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libpulse libpulse-simple" >&5 printf %s "checking for libpulse libpulse-simple... " >&6; } if test -n "$PULSEAUDIO_CFLAGS"; then pkg_cv_PULSEAUDIO_CFLAGS="$PULSEAUDIO_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse libpulse-simple\""; } >&5 ($PKG_CONFIG --exists --print-errors "libpulse libpulse-simple") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PULSEAUDIO_CFLAGS=`$PKG_CONFIG --cflags "libpulse libpulse-simple" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$PULSEAUDIO_LIBS"; then pkg_cv_PULSEAUDIO_LIBS="$PULSEAUDIO_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse libpulse-simple\""; } >&5 ($PKG_CONFIG --exists --print-errors "libpulse libpulse-simple") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PULSEAUDIO_LIBS=`$PKG_CONFIG --libs "libpulse libpulse-simple" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then PULSEAUDIO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpulse libpulse-simple" 2>&1` else PULSEAUDIO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpulse libpulse-simple" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$PULSEAUDIO_PKG_ERRORS" >&5 have_pulseaudio=0 as_fn_error $? "Unable to find libpulse and/or libpulse-simple." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } have_pulseaudio=0 as_fn_error $? "Unable to find libpulse and/or libpulse-simple." "$LINENO" 5 else PULSEAUDIO_CFLAGS=$pkg_cv_PULSEAUDIO_CFLAGS PULSEAUDIO_LIBS=$pkg_cv_PULSEAUDIO_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } have_pulseaudio=1 PULSEAUDIO_CFLAGS="-DMPT_WITH_PULSEAUDIO $PULSEAUDIO_CFLAGS" fi else $as_nop have_pulseaudio=0 fi ;; #( *) : ;; esac else $as_nop have_pulseaudio=0 fi # Optional openmpt123 and examples dependency # Check whether --with-portaudio was given. if test ${with_portaudio+y} then : withval=$with_portaudio; fi if test "x$enable_openmpt123$enable_examples" != "xnono" then : if test "x$with_portaudio" != "xno" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for portaudio-2.0" >&5 printf %s "checking for portaudio-2.0... " >&6; } if test -n "$PORTAUDIO_CFLAGS"; then pkg_cv_PORTAUDIO_CFLAGS="$PORTAUDIO_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"portaudio-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "portaudio-2.0") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PORTAUDIO_CFLAGS=`$PKG_CONFIG --cflags "portaudio-2.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$PORTAUDIO_LIBS"; then pkg_cv_PORTAUDIO_LIBS="$PORTAUDIO_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"portaudio-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "portaudio-2.0") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PORTAUDIO_LIBS=`$PKG_CONFIG --libs "portaudio-2.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then PORTAUDIO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "portaudio-2.0" 2>&1` else PORTAUDIO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "portaudio-2.0" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$PORTAUDIO_PKG_ERRORS" >&5 have_portaudio=0 as_fn_error $? "Unable to find libportaudio." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } have_portaudio=0 as_fn_error $? "Unable to find libportaudio." "$LINENO" 5 else PORTAUDIO_CFLAGS=$pkg_cv_PORTAUDIO_CFLAGS PORTAUDIO_LIBS=$pkg_cv_PORTAUDIO_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } have_portaudio=1 PORTAUDIO_CFLAGS="-DMPT_WITH_PORTAUDIO $PORTAUDIO_CFLAGS" fi else $as_nop have_portaudio=0 fi else $as_nop have_portaudio=0 fi if test x$have_portaudio = x1; then HAVE_PORTAUDIO_TRUE= HAVE_PORTAUDIO_FALSE='#' else HAVE_PORTAUDIO_TRUE='#' HAVE_PORTAUDIO_FALSE= fi # Optional examples dependency: PortAudio C++ # Check whether --with-portaudiocpp was given. if test ${with_portaudiocpp+y} then : withval=$with_portaudiocpp; fi if test "x$enable_examples" != "xno" then : if test "x$with_portaudiocpp" != "xno" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for portaudiocpp" >&5 printf %s "checking for portaudiocpp... " >&6; } if test -n "$PORTAUDIOCPP_CFLAGS"; then pkg_cv_PORTAUDIOCPP_CFLAGS="$PORTAUDIOCPP_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"portaudiocpp\""; } >&5 ($PKG_CONFIG --exists --print-errors "portaudiocpp") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PORTAUDIOCPP_CFLAGS=`$PKG_CONFIG --cflags "portaudiocpp" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$PORTAUDIOCPP_LIBS"; then pkg_cv_PORTAUDIOCPP_LIBS="$PORTAUDIOCPP_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"portaudiocpp\""; } >&5 ($PKG_CONFIG --exists --print-errors "portaudiocpp") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PORTAUDIOCPP_LIBS=`$PKG_CONFIG --libs "portaudiocpp" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then PORTAUDIOCPP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "portaudiocpp" 2>&1` else PORTAUDIOCPP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "portaudiocpp" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$PORTAUDIOCPP_PKG_ERRORS" >&5 have_portaudiocpp=0 as_fn_error $? "Unable to find libportaudiocpp." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } have_portaudiocpp=0 as_fn_error $? "Unable to find libportaudiocpp." "$LINENO" 5 else PORTAUDIOCPP_CFLAGS=$pkg_cv_PORTAUDIOCPP_CFLAGS PORTAUDIOCPP_LIBS=$pkg_cv_PORTAUDIOCPP_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } have_portaudiocpp=1 PORTAUDIOCPP_CFLAGS="-DMPT_WITH_PORTAUDIOCPP $PORTAUDIOCPP_CFLAGS" fi else $as_nop have_portaudiocpp=0 fi else $as_nop have_portaudiocpp=0 fi if test x$have_portaudiocpp = x1; then HAVE_PORTAUDIOCPP_TRUE= HAVE_PORTAUDIOCPP_FALSE='#' else HAVE_PORTAUDIOCPP_TRUE='#' HAVE_PORTAUDIOCPP_FALSE= fi # Optional disabled openmpt123 dependency: libsdl2 # Check whether --with-sdl2 was given. if test ${with_sdl2+y} then : withval=$with_sdl2; fi if test "x$enable_openmpt123" != "xno" then : if test "x$with_sdl2" = "xyes" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sdl2 >= 2.0.4" >&5 printf %s "checking for sdl2 >= 2.0.4... " >&6; } if test -n "$SDL2_CFLAGS"; then pkg_cv_SDL2_CFLAGS="$SDL2_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sdl2 >= 2.0.4\""; } >&5 ($PKG_CONFIG --exists --print-errors "sdl2 >= 2.0.4") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SDL2_CFLAGS=`$PKG_CONFIG --cflags "sdl2 >= 2.0.4" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$SDL2_LIBS"; then pkg_cv_SDL2_LIBS="$SDL2_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sdl2 >= 2.0.4\""; } >&5 ($PKG_CONFIG --exists --print-errors "sdl2 >= 2.0.4") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SDL2_LIBS=`$PKG_CONFIG --libs "sdl2 >= 2.0.4" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then SDL2_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sdl2 >= 2.0.4" 2>&1` else SDL2_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sdl2 >= 2.0.4" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$SDL2_PKG_ERRORS" >&5 as_fn_error $? "Unable to find libsdl2." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "Unable to find libsdl2." "$LINENO" 5 else SDL2_CFLAGS=$pkg_cv_SDL2_CFLAGS SDL2_LIBS=$pkg_cv_SDL2_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SDL2_CFLAGS="-DMPT_WITH_SDL2 $SDL2_CFLAGS" fi fi fi # Optional openmpt123 dependency: libsndfile # Check whether --with-sndfile was given. if test ${with_sndfile+y} then : withval=$with_sndfile; fi if test "x$enable_openmpt123" != "xno" then : if test "x$with_sndfile" != "xno" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sndfile" >&5 printf %s "checking for sndfile... " >&6; } if test -n "$SNDFILE_CFLAGS"; then pkg_cv_SNDFILE_CFLAGS="$SNDFILE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sndfile\""; } >&5 ($PKG_CONFIG --exists --print-errors "sndfile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SNDFILE_CFLAGS=`$PKG_CONFIG --cflags "sndfile" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$SNDFILE_LIBS"; then pkg_cv_SNDFILE_LIBS="$SNDFILE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sndfile\""; } >&5 ($PKG_CONFIG --exists --print-errors "sndfile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SNDFILE_LIBS=`$PKG_CONFIG --libs "sndfile" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then SNDFILE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sndfile" 2>&1` else SNDFILE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sndfile" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$SNDFILE_PKG_ERRORS" >&5 as_fn_error $? "Unable to find libsndfile." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "Unable to find libsndfile." "$LINENO" 5 else SNDFILE_CFLAGS=$pkg_cv_SNDFILE_CFLAGS SNDFILE_LIBS=$pkg_cv_SNDFILE_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SNDFILE_CFLAGS="-DMPT_WITH_SNDFILE $SNDFILE_CFLAGS" fi fi fi # Optional openmpt123 dependency: libFLAC # Check whether --with-flac was given. if test ${with_flac+y} then : withval=$with_flac; fi if test "x$enable_openmpt123" != "xno" then : if test "x$with_flac" != "xno" then : pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for flac >= 1.3.0" >&5 printf %s "checking for flac >= 1.3.0... " >&6; } if test -n "$FLAC_CFLAGS"; then pkg_cv_FLAC_CFLAGS="$FLAC_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"flac >= 1.3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "flac >= 1.3.0") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_FLAC_CFLAGS=`$PKG_CONFIG --cflags "flac >= 1.3.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$FLAC_LIBS"; then pkg_cv_FLAC_LIBS="$FLAC_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"flac >= 1.3.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "flac >= 1.3.0") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_FLAC_LIBS=`$PKG_CONFIG --libs "flac >= 1.3.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then FLAC_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "flac >= 1.3.0" 2>&1` else FLAC_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "flac >= 1.3.0" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$FLAC_PKG_ERRORS" >&5 as_fn_error $? "Unable to find libflac >= 1.3.0." "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "Unable to find libflac >= 1.3.0." "$LINENO" 5 else FLAC_CFLAGS=$pkg_cv_FLAC_CFLAGS FLAC_LIBS=$pkg_cv_FLAC_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } FLAC_CFLAGS="-DMPT_WITH_FLAC $FLAC_CFLAGS" fi fi fi # Files: DX_PROJECT=libopenmpt DX_CONFIG='Doxyfile' DX_DOCDIR='doxygen-doc' # Environment variables used inside doxygen.cfg: DX_ENV="$DX_ENV SRCDIR='$srcdir'" SRCDIR=$srcdir DX_ENV="$DX_ENV PROJECT='$DX_PROJECT'" PROJECT=$DX_PROJECT DX_ENV="$DX_ENV VERSION='$PACKAGE_VERSION'" # Doxygen itself: # Check whether --enable-doxygen-doc was given. if test ${enable_doxygen_doc+y} then : enableval=$enable_doxygen_doc; case "$enableval" in #( y|Y|yes|Yes|YES) DX_FLAG_doc=1 ;; #( n|N|no|No|NO) DX_FLAG_doc=0 ;; #( *) as_fn_error $? "invalid value '$enableval' given to doxygen-doc" "$LINENO" 5 ;; esac else $as_nop DX_FLAG_doc=1 fi if test "$DX_FLAG_doc" = 1; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}doxygen", so it can be a program name with args. set dummy ${ac_tool_prefix}doxygen; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DX_DOXYGEN+y} then : printf %s "(cached) " >&6 else $as_nop case $DX_DOXYGEN in [\\/]* | ?:[\\/]*) ac_cv_path_DX_DOXYGEN="$DX_DOXYGEN" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_DX_DOXYGEN="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DX_DOXYGEN=$ac_cv_path_DX_DOXYGEN if test -n "$DX_DOXYGEN"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DX_DOXYGEN" >&5 printf "%s\n" "$DX_DOXYGEN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_DX_DOXYGEN"; then ac_pt_DX_DOXYGEN=$DX_DOXYGEN # Extract the first word of "doxygen", so it can be a program name with args. set dummy doxygen; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_DX_DOXYGEN+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_DX_DOXYGEN in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_DX_DOXYGEN="$ac_pt_DX_DOXYGEN" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_DX_DOXYGEN="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_DX_DOXYGEN=$ac_cv_path_ac_pt_DX_DOXYGEN if test -n "$ac_pt_DX_DOXYGEN"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_DX_DOXYGEN" >&5 printf "%s\n" "$ac_pt_DX_DOXYGEN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_DX_DOXYGEN" = x; then DX_DOXYGEN="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DX_DOXYGEN=$ac_pt_DX_DOXYGEN fi else DX_DOXYGEN="$ac_cv_path_DX_DOXYGEN" fi if test "$DX_FLAG_doc$DX_DOXYGEN" = 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: doxygen not found - will not generate any doxygen documentation" >&5 printf "%s\n" "$as_me: WARNING: doxygen not found - will not generate any doxygen documentation" >&2;} DX_FLAG_doc=0 fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}perl", so it can be a program name with args. set dummy ${ac_tool_prefix}perl; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DX_PERL+y} then : printf %s "(cached) " >&6 else $as_nop case $DX_PERL in [\\/]* | ?:[\\/]*) ac_cv_path_DX_PERL="$DX_PERL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_DX_PERL="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DX_PERL=$ac_cv_path_DX_PERL if test -n "$DX_PERL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DX_PERL" >&5 printf "%s\n" "$DX_PERL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_DX_PERL"; then ac_pt_DX_PERL=$DX_PERL # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_DX_PERL+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_DX_PERL in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_DX_PERL="$ac_pt_DX_PERL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_DX_PERL="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_DX_PERL=$ac_cv_path_ac_pt_DX_PERL if test -n "$ac_pt_DX_PERL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_DX_PERL" >&5 printf "%s\n" "$ac_pt_DX_PERL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_DX_PERL" = x; then DX_PERL="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DX_PERL=$ac_pt_DX_PERL fi else DX_PERL="$ac_cv_path_DX_PERL" fi if test "$DX_FLAG_doc$DX_PERL" = 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: perl not found - will not generate any doxygen documentation" >&5 printf "%s\n" "$as_me: WARNING: perl not found - will not generate any doxygen documentation" >&2;} DX_FLAG_doc=0 fi : fi if test "$DX_FLAG_doc" = 1; then DX_ENV="$DX_ENV PERL_PATH='$DX_PERL'" PERL_PATH=$DX_PERL : else : fi # Dot for graphics: # Check whether --enable-doxygen-dot was given. if test ${enable_doxygen_dot+y} then : enableval=$enable_doxygen_dot; case "$enableval" in #( y|Y|yes|Yes|YES) DX_FLAG_dot=1 test "$DX_FLAG_doc" = "1" \ || as_fn_error $? "doxygen-dot requires doxygen-doc" "$LINENO" 5 ;; #( n|N|no|No|NO) DX_FLAG_dot=0 ;; #( *) as_fn_error $? "invalid value '$enableval' given to doxygen-dot" "$LINENO" 5 ;; esac else $as_nop DX_FLAG_dot=0 test "$DX_FLAG_doc" = "1" || DX_FLAG_dot=0 fi if test "$DX_FLAG_dot" = 1; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dot", so it can be a program name with args. set dummy ${ac_tool_prefix}dot; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DX_DOT+y} then : printf %s "(cached) " >&6 else $as_nop case $DX_DOT in [\\/]* | ?:[\\/]*) ac_cv_path_DX_DOT="$DX_DOT" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_DX_DOT="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DX_DOT=$ac_cv_path_DX_DOT if test -n "$DX_DOT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DX_DOT" >&5 printf "%s\n" "$DX_DOT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_DX_DOT"; then ac_pt_DX_DOT=$DX_DOT # Extract the first word of "dot", so it can be a program name with args. set dummy dot; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_DX_DOT+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_DX_DOT in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_DX_DOT="$ac_pt_DX_DOT" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_DX_DOT="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_DX_DOT=$ac_cv_path_ac_pt_DX_DOT if test -n "$ac_pt_DX_DOT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_DX_DOT" >&5 printf "%s\n" "$ac_pt_DX_DOT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_DX_DOT" = x; then DX_DOT="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DX_DOT=$ac_pt_DX_DOT fi else DX_DOT="$ac_cv_path_DX_DOT" fi if test "$DX_FLAG_dot$DX_DOT" = 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: dot not found - will not generate graphics for doxygen documentation" >&5 printf "%s\n" "$as_me: WARNING: dot not found - will not generate graphics for doxygen documentation" >&2;} DX_FLAG_dot=0 fi : fi if test "$DX_FLAG_dot" = 1; then DX_ENV="$DX_ENV HAVE_DOT='YES'" HAVE_DOT=YES DX_ENV="$DX_ENV DOT_PATH='`expr ".$DX_DOT" : '\(\.\)[^/]*$' \| "x$DX_DOT" : 'x\(.*\)/[^/]*$'`'" DOT_PATH=`expr ".$DX_DOT" : '\(\.\)[^/]*$' \| "x$DX_DOT" : 'x\(.*\)/[^/]*$'` : else DX_ENV="$DX_ENV HAVE_DOT='NO'" HAVE_DOT=NO : fi # Man pages generation: # Check whether --enable-doxygen-man was given. if test ${enable_doxygen_man+y} then : enableval=$enable_doxygen_man; case "$enableval" in #( y|Y|yes|Yes|YES) DX_FLAG_man=1 test "$DX_FLAG_doc" = "1" \ || as_fn_error $? "doxygen-man requires doxygen-doc" "$LINENO" 5 ;; #( n|N|no|No|NO) DX_FLAG_man=0 ;; #( *) as_fn_error $? "invalid value '$enableval' given to doxygen-man" "$LINENO" 5 ;; esac else $as_nop DX_FLAG_man=0 test "$DX_FLAG_doc" = "1" || DX_FLAG_man=0 fi if test "$DX_FLAG_man" = 1; then : fi if test "$DX_FLAG_man" = 1; then DX_ENV="$DX_ENV GENERATE_MAN='YES'" GENERATE_MAN=YES : else DX_ENV="$DX_ENV GENERATE_MAN='NO'" GENERATE_MAN=NO : fi # RTF file generation: # Check whether --enable-doxygen-rtf was given. if test ${enable_doxygen_rtf+y} then : enableval=$enable_doxygen_rtf; case "$enableval" in #( y|Y|yes|Yes|YES) DX_FLAG_rtf=1 test "$DX_FLAG_doc" = "1" \ || as_fn_error $? "doxygen-rtf requires doxygen-doc" "$LINENO" 5 ;; #( n|N|no|No|NO) DX_FLAG_rtf=0 ;; #( *) as_fn_error $? "invalid value '$enableval' given to doxygen-rtf" "$LINENO" 5 ;; esac else $as_nop DX_FLAG_rtf=0 test "$DX_FLAG_doc" = "1" || DX_FLAG_rtf=0 fi if test "$DX_FLAG_rtf" = 1; then : fi if test "$DX_FLAG_rtf" = 1; then DX_ENV="$DX_ENV GENERATE_RTF='YES'" GENERATE_RTF=YES : else DX_ENV="$DX_ENV GENERATE_RTF='NO'" GENERATE_RTF=NO : fi # XML file generation: # Check whether --enable-doxygen-xml was given. if test ${enable_doxygen_xml+y} then : enableval=$enable_doxygen_xml; case "$enableval" in #( y|Y|yes|Yes|YES) DX_FLAG_xml=1 test "$DX_FLAG_doc" = "1" \ || as_fn_error $? "doxygen-xml requires doxygen-doc" "$LINENO" 5 ;; #( n|N|no|No|NO) DX_FLAG_xml=0 ;; #( *) as_fn_error $? "invalid value '$enableval' given to doxygen-xml" "$LINENO" 5 ;; esac else $as_nop DX_FLAG_xml=0 test "$DX_FLAG_doc" = "1" || DX_FLAG_xml=0 fi if test "$DX_FLAG_xml" = 1; then : fi if test "$DX_FLAG_xml" = 1; then DX_ENV="$DX_ENV GENERATE_XML='YES'" GENERATE_XML=YES : else DX_ENV="$DX_ENV GENERATE_XML='NO'" GENERATE_XML=NO : fi # (Compressed) HTML help generation: # Check whether --enable-doxygen-chm was given. if test ${enable_doxygen_chm+y} then : enableval=$enable_doxygen_chm; case "$enableval" in #( y|Y|yes|Yes|YES) DX_FLAG_chm=1 test "$DX_FLAG_doc" = "1" \ || as_fn_error $? "doxygen-chm requires doxygen-doc" "$LINENO" 5 ;; #( n|N|no|No|NO) DX_FLAG_chm=0 ;; #( *) as_fn_error $? "invalid value '$enableval' given to doxygen-chm" "$LINENO" 5 ;; esac else $as_nop DX_FLAG_chm=0 test "$DX_FLAG_doc" = "1" || DX_FLAG_chm=0 fi if test "$DX_FLAG_chm" = 1; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}hhc", so it can be a program name with args. set dummy ${ac_tool_prefix}hhc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DX_HHC+y} then : printf %s "(cached) " >&6 else $as_nop case $DX_HHC in [\\/]* | ?:[\\/]*) ac_cv_path_DX_HHC="$DX_HHC" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_DX_HHC="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DX_HHC=$ac_cv_path_DX_HHC if test -n "$DX_HHC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DX_HHC" >&5 printf "%s\n" "$DX_HHC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_DX_HHC"; then ac_pt_DX_HHC=$DX_HHC # Extract the first word of "hhc", so it can be a program name with args. set dummy hhc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_DX_HHC+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_DX_HHC in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_DX_HHC="$ac_pt_DX_HHC" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_DX_HHC="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_DX_HHC=$ac_cv_path_ac_pt_DX_HHC if test -n "$ac_pt_DX_HHC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_DX_HHC" >&5 printf "%s\n" "$ac_pt_DX_HHC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_DX_HHC" = x; then DX_HHC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DX_HHC=$ac_pt_DX_HHC fi else DX_HHC="$ac_cv_path_DX_HHC" fi if test "$DX_FLAG_chm$DX_HHC" = 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: hhc not found - will not generate doxygen compressed HTML help documentation" >&5 printf "%s\n" "$as_me: WARNING: hhc not found - will not generate doxygen compressed HTML help documentation" >&2;} DX_FLAG_chm=0 fi : fi if test "$DX_FLAG_chm" = 1; then DX_ENV="$DX_ENV HHC_PATH='$DX_HHC'" HHC_PATH=$DX_HHC DX_ENV="$DX_ENV GENERATE_HTML='YES'" GENERATE_HTML=YES DX_ENV="$DX_ENV GENERATE_HTMLHELP='YES'" GENERATE_HTMLHELP=YES : else DX_ENV="$DX_ENV GENERATE_HTMLHELP='NO'" GENERATE_HTMLHELP=NO : fi # Separate CHI file generation. # Check whether --enable-doxygen-chi was given. if test ${enable_doxygen_chi+y} then : enableval=$enable_doxygen_chi; case "$enableval" in #( y|Y|yes|Yes|YES) DX_FLAG_chi=1 test "$DX_FLAG_chm" = "1" \ || as_fn_error $? "doxygen-chi requires doxygen-chm" "$LINENO" 5 ;; #( n|N|no|No|NO) DX_FLAG_chi=0 ;; #( *) as_fn_error $? "invalid value '$enableval' given to doxygen-chi" "$LINENO" 5 ;; esac else $as_nop DX_FLAG_chi=0 test "$DX_FLAG_chm" = "1" || DX_FLAG_chi=0 fi if test "$DX_FLAG_chi" = 1; then : fi if test "$DX_FLAG_chi" = 1; then DX_ENV="$DX_ENV GENERATE_CHI='YES'" GENERATE_CHI=YES : else DX_ENV="$DX_ENV GENERATE_CHI='NO'" GENERATE_CHI=NO : fi # Plain HTML pages generation: # Check whether --enable-doxygen-html was given. if test ${enable_doxygen_html+y} then : enableval=$enable_doxygen_html; case "$enableval" in #( y|Y|yes|Yes|YES) DX_FLAG_html=1 test "$DX_FLAG_doc" = "1" \ || as_fn_error $? "doxygen-html requires doxygen-doc" "$LINENO" 5 test "$DX_FLAG_chm" = "0" \ || as_fn_error $? "doxygen-html contradicts doxygen-chm" "$LINENO" 5 ;; #( n|N|no|No|NO) DX_FLAG_html=0 ;; #( *) as_fn_error $? "invalid value '$enableval' given to doxygen-html" "$LINENO" 5 ;; esac else $as_nop DX_FLAG_html=1 test "$DX_FLAG_doc" = "1" || DX_FLAG_html=0 test "$DX_FLAG_chm" = "0" || DX_FLAG_html=0 fi if test "$DX_FLAG_html" = 1; then : fi if test "$DX_FLAG_html" = 1; then DX_ENV="$DX_ENV GENERATE_HTML='YES'" GENERATE_HTML=YES : else test "$DX_FLAG_chm" = 1 || DX_ENV="$DX_ENV GENERATE_HTML='NO'" GENERATE_HTML=NO : fi # PostScript file generation: # Check whether --enable-doxygen-ps was given. if test ${enable_doxygen_ps+y} then : enableval=$enable_doxygen_ps; case "$enableval" in #( y|Y|yes|Yes|YES) DX_FLAG_ps=1 test "$DX_FLAG_doc" = "1" \ || as_fn_error $? "doxygen-ps requires doxygen-doc" "$LINENO" 5 ;; #( n|N|no|No|NO) DX_FLAG_ps=0 ;; #( *) as_fn_error $? "invalid value '$enableval' given to doxygen-ps" "$LINENO" 5 ;; esac else $as_nop DX_FLAG_ps=0 test "$DX_FLAG_doc" = "1" || DX_FLAG_ps=0 fi if test "$DX_FLAG_ps" = 1; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}latex", so it can be a program name with args. set dummy ${ac_tool_prefix}latex; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DX_LATEX+y} then : printf %s "(cached) " >&6 else $as_nop case $DX_LATEX in [\\/]* | ?:[\\/]*) ac_cv_path_DX_LATEX="$DX_LATEX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_DX_LATEX="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DX_LATEX=$ac_cv_path_DX_LATEX if test -n "$DX_LATEX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DX_LATEX" >&5 printf "%s\n" "$DX_LATEX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_DX_LATEX"; then ac_pt_DX_LATEX=$DX_LATEX # Extract the first word of "latex", so it can be a program name with args. set dummy latex; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_DX_LATEX+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_DX_LATEX in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_DX_LATEX="$ac_pt_DX_LATEX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_DX_LATEX="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_DX_LATEX=$ac_cv_path_ac_pt_DX_LATEX if test -n "$ac_pt_DX_LATEX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_DX_LATEX" >&5 printf "%s\n" "$ac_pt_DX_LATEX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_DX_LATEX" = x; then DX_LATEX="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DX_LATEX=$ac_pt_DX_LATEX fi else DX_LATEX="$ac_cv_path_DX_LATEX" fi if test "$DX_FLAG_ps$DX_LATEX" = 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: latex not found - will not generate doxygen PostScript documentation" >&5 printf "%s\n" "$as_me: WARNING: latex not found - will not generate doxygen PostScript documentation" >&2;} DX_FLAG_ps=0 fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}makeindex", so it can be a program name with args. set dummy ${ac_tool_prefix}makeindex; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DX_MAKEINDEX+y} then : printf %s "(cached) " >&6 else $as_nop case $DX_MAKEINDEX in [\\/]* | ?:[\\/]*) ac_cv_path_DX_MAKEINDEX="$DX_MAKEINDEX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_DX_MAKEINDEX="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DX_MAKEINDEX=$ac_cv_path_DX_MAKEINDEX if test -n "$DX_MAKEINDEX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DX_MAKEINDEX" >&5 printf "%s\n" "$DX_MAKEINDEX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_DX_MAKEINDEX"; then ac_pt_DX_MAKEINDEX=$DX_MAKEINDEX # Extract the first word of "makeindex", so it can be a program name with args. set dummy makeindex; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_DX_MAKEINDEX+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_DX_MAKEINDEX in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_DX_MAKEINDEX="$ac_pt_DX_MAKEINDEX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_DX_MAKEINDEX="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_DX_MAKEINDEX=$ac_cv_path_ac_pt_DX_MAKEINDEX if test -n "$ac_pt_DX_MAKEINDEX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_DX_MAKEINDEX" >&5 printf "%s\n" "$ac_pt_DX_MAKEINDEX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_DX_MAKEINDEX" = x; then DX_MAKEINDEX="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DX_MAKEINDEX=$ac_pt_DX_MAKEINDEX fi else DX_MAKEINDEX="$ac_cv_path_DX_MAKEINDEX" fi if test "$DX_FLAG_ps$DX_MAKEINDEX" = 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: makeindex not found - will not generate doxygen PostScript documentation" >&5 printf "%s\n" "$as_me: WARNING: makeindex not found - will not generate doxygen PostScript documentation" >&2;} DX_FLAG_ps=0 fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dvips", so it can be a program name with args. set dummy ${ac_tool_prefix}dvips; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DX_DVIPS+y} then : printf %s "(cached) " >&6 else $as_nop case $DX_DVIPS in [\\/]* | ?:[\\/]*) ac_cv_path_DX_DVIPS="$DX_DVIPS" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_DX_DVIPS="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DX_DVIPS=$ac_cv_path_DX_DVIPS if test -n "$DX_DVIPS"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DX_DVIPS" >&5 printf "%s\n" "$DX_DVIPS" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_DX_DVIPS"; then ac_pt_DX_DVIPS=$DX_DVIPS # Extract the first word of "dvips", so it can be a program name with args. set dummy dvips; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_DX_DVIPS+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_DX_DVIPS in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_DX_DVIPS="$ac_pt_DX_DVIPS" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_DX_DVIPS="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_DX_DVIPS=$ac_cv_path_ac_pt_DX_DVIPS if test -n "$ac_pt_DX_DVIPS"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_DX_DVIPS" >&5 printf "%s\n" "$ac_pt_DX_DVIPS" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_DX_DVIPS" = x; then DX_DVIPS="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DX_DVIPS=$ac_pt_DX_DVIPS fi else DX_DVIPS="$ac_cv_path_DX_DVIPS" fi if test "$DX_FLAG_ps$DX_DVIPS" = 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: dvips not found - will not generate doxygen PostScript documentation" >&5 printf "%s\n" "$as_me: WARNING: dvips not found - will not generate doxygen PostScript documentation" >&2;} DX_FLAG_ps=0 fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}egrep", so it can be a program name with args. set dummy ${ac_tool_prefix}egrep; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DX_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop case $DX_EGREP in [\\/]* | ?:[\\/]*) ac_cv_path_DX_EGREP="$DX_EGREP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_DX_EGREP="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DX_EGREP=$ac_cv_path_DX_EGREP if test -n "$DX_EGREP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DX_EGREP" >&5 printf "%s\n" "$DX_EGREP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_DX_EGREP"; then ac_pt_DX_EGREP=$DX_EGREP # Extract the first word of "egrep", so it can be a program name with args. set dummy egrep; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_DX_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_DX_EGREP in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_DX_EGREP="$ac_pt_DX_EGREP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_DX_EGREP="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_DX_EGREP=$ac_cv_path_ac_pt_DX_EGREP if test -n "$ac_pt_DX_EGREP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_DX_EGREP" >&5 printf "%s\n" "$ac_pt_DX_EGREP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_DX_EGREP" = x; then DX_EGREP="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DX_EGREP=$ac_pt_DX_EGREP fi else DX_EGREP="$ac_cv_path_DX_EGREP" fi if test "$DX_FLAG_ps$DX_EGREP" = 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: egrep not found - will not generate doxygen PostScript documentation" >&5 printf "%s\n" "$as_me: WARNING: egrep not found - will not generate doxygen PostScript documentation" >&2;} DX_FLAG_ps=0 fi : fi if test "$DX_FLAG_ps" = 1; then : else : fi # PDF file generation: # Check whether --enable-doxygen-pdf was given. if test ${enable_doxygen_pdf+y} then : enableval=$enable_doxygen_pdf; case "$enableval" in #( y|Y|yes|Yes|YES) DX_FLAG_pdf=1 test "$DX_FLAG_doc" = "1" \ || as_fn_error $? "doxygen-pdf requires doxygen-doc" "$LINENO" 5 ;; #( n|N|no|No|NO) DX_FLAG_pdf=0 ;; #( *) as_fn_error $? "invalid value '$enableval' given to doxygen-pdf" "$LINENO" 5 ;; esac else $as_nop DX_FLAG_pdf=0 test "$DX_FLAG_doc" = "1" || DX_FLAG_pdf=0 fi if test "$DX_FLAG_pdf" = 1; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pdflatex", so it can be a program name with args. set dummy ${ac_tool_prefix}pdflatex; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DX_PDFLATEX+y} then : printf %s "(cached) " >&6 else $as_nop case $DX_PDFLATEX in [\\/]* | ?:[\\/]*) ac_cv_path_DX_PDFLATEX="$DX_PDFLATEX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_DX_PDFLATEX="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DX_PDFLATEX=$ac_cv_path_DX_PDFLATEX if test -n "$DX_PDFLATEX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DX_PDFLATEX" >&5 printf "%s\n" "$DX_PDFLATEX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_DX_PDFLATEX"; then ac_pt_DX_PDFLATEX=$DX_PDFLATEX # Extract the first word of "pdflatex", so it can be a program name with args. set dummy pdflatex; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_DX_PDFLATEX+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_DX_PDFLATEX in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_DX_PDFLATEX="$ac_pt_DX_PDFLATEX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_DX_PDFLATEX="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_DX_PDFLATEX=$ac_cv_path_ac_pt_DX_PDFLATEX if test -n "$ac_pt_DX_PDFLATEX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_DX_PDFLATEX" >&5 printf "%s\n" "$ac_pt_DX_PDFLATEX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_DX_PDFLATEX" = x; then DX_PDFLATEX="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DX_PDFLATEX=$ac_pt_DX_PDFLATEX fi else DX_PDFLATEX="$ac_cv_path_DX_PDFLATEX" fi if test "$DX_FLAG_pdf$DX_PDFLATEX" = 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: pdflatex not found - will not generate doxygen PDF documentation" >&5 printf "%s\n" "$as_me: WARNING: pdflatex not found - will not generate doxygen PDF documentation" >&2;} DX_FLAG_pdf=0 fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}makeindex", so it can be a program name with args. set dummy ${ac_tool_prefix}makeindex; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DX_MAKEINDEX+y} then : printf %s "(cached) " >&6 else $as_nop case $DX_MAKEINDEX in [\\/]* | ?:[\\/]*) ac_cv_path_DX_MAKEINDEX="$DX_MAKEINDEX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_DX_MAKEINDEX="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DX_MAKEINDEX=$ac_cv_path_DX_MAKEINDEX if test -n "$DX_MAKEINDEX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DX_MAKEINDEX" >&5 printf "%s\n" "$DX_MAKEINDEX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_DX_MAKEINDEX"; then ac_pt_DX_MAKEINDEX=$DX_MAKEINDEX # Extract the first word of "makeindex", so it can be a program name with args. set dummy makeindex; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_DX_MAKEINDEX+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_DX_MAKEINDEX in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_DX_MAKEINDEX="$ac_pt_DX_MAKEINDEX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_DX_MAKEINDEX="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_DX_MAKEINDEX=$ac_cv_path_ac_pt_DX_MAKEINDEX if test -n "$ac_pt_DX_MAKEINDEX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_DX_MAKEINDEX" >&5 printf "%s\n" "$ac_pt_DX_MAKEINDEX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_DX_MAKEINDEX" = x; then DX_MAKEINDEX="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DX_MAKEINDEX=$ac_pt_DX_MAKEINDEX fi else DX_MAKEINDEX="$ac_cv_path_DX_MAKEINDEX" fi if test "$DX_FLAG_pdf$DX_MAKEINDEX" = 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: makeindex not found - will not generate doxygen PDF documentation" >&5 printf "%s\n" "$as_me: WARNING: makeindex not found - will not generate doxygen PDF documentation" >&2;} DX_FLAG_pdf=0 fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}egrep", so it can be a program name with args. set dummy ${ac_tool_prefix}egrep; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_DX_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop case $DX_EGREP in [\\/]* | ?:[\\/]*) ac_cv_path_DX_EGREP="$DX_EGREP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_DX_EGREP="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi DX_EGREP=$ac_cv_path_DX_EGREP if test -n "$DX_EGREP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DX_EGREP" >&5 printf "%s\n" "$DX_EGREP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_DX_EGREP"; then ac_pt_DX_EGREP=$DX_EGREP # Extract the first word of "egrep", so it can be a program name with args. set dummy egrep; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_DX_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_DX_EGREP in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_DX_EGREP="$ac_pt_DX_EGREP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_DX_EGREP="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_DX_EGREP=$ac_cv_path_ac_pt_DX_EGREP if test -n "$ac_pt_DX_EGREP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_DX_EGREP" >&5 printf "%s\n" "$ac_pt_DX_EGREP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_DX_EGREP" = x; then DX_EGREP="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DX_EGREP=$ac_pt_DX_EGREP fi else DX_EGREP="$ac_cv_path_DX_EGREP" fi if test "$DX_FLAG_pdf$DX_EGREP" = 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: egrep not found - will not generate doxygen PDF documentation" >&5 printf "%s\n" "$as_me: WARNING: egrep not found - will not generate doxygen PDF documentation" >&2;} DX_FLAG_pdf=0 fi : fi if test "$DX_FLAG_pdf" = 1; then : else : fi # LaTeX generation for PS and/or PDF: if test "$DX_FLAG_ps" = 1 || test "$DX_FLAG_pdf" = 1; then DX_ENV="$DX_ENV GENERATE_LATEX='YES'" GENERATE_LATEX=YES else DX_ENV="$DX_ENV GENERATE_LATEX='NO'" GENERATE_LATEX=NO fi # Paper size for PS and/or PDF: case "$DOXYGEN_PAPER_SIZE" in #( "") DOXYGEN_PAPER_SIZE="" ;; #( a4wide|a4|letter|legal|executive) DX_ENV="$DX_ENV PAPER_SIZE='$DOXYGEN_PAPER_SIZE'" PAPER_SIZE=$DOXYGEN_PAPER_SIZE ;; #( *) as_fn_error $? "unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'" "$LINENO" 5 ;; esac # Rules: if test $DX_FLAG_html -eq 1 then : DX_SNIPPET_html="## ------------------------------- ## ## Rules specific for HTML output. ## ## ------------------------------- ## DX_CLEAN_HTML = \$(DX_DOCDIR)/html\\ \$(DX_DOCDIR)/html " else $as_nop DX_SNIPPET_html="" fi if test $DX_FLAG_chi -eq 1 then : DX_SNIPPET_chi=" DX_CLEAN_CHI = \$(DX_DOCDIR)/\$(PACKAGE).chi\\ \$(DX_DOCDIR)/\$(PACKAGE).chi" else $as_nop DX_SNIPPET_chi="" fi if test $DX_FLAG_chm -eq 1 then : DX_SNIPPET_chm="## ------------------------------ ## ## Rules specific for CHM output. ## ## ------------------------------ ## DX_CLEAN_CHM = \$(DX_DOCDIR)/chm\\ \$(DX_DOCDIR)/chm\ ${DX_SNIPPET_chi} " else $as_nop DX_SNIPPET_chm="" fi if test $DX_FLAG_man -eq 1 then : DX_SNIPPET_man="## ------------------------------ ## ## Rules specific for MAN output. ## ## ------------------------------ ## DX_CLEAN_MAN = \$(DX_DOCDIR)/man\\ \$(DX_DOCDIR)/man " else $as_nop DX_SNIPPET_man="" fi if test $DX_FLAG_rtf -eq 1 then : DX_SNIPPET_rtf="## ------------------------------ ## ## Rules specific for RTF output. ## ## ------------------------------ ## DX_CLEAN_RTF = \$(DX_DOCDIR)/rtf\\ \$(DX_DOCDIR)/rtf " else $as_nop DX_SNIPPET_rtf="" fi if test $DX_FLAG_xml -eq 1 then : DX_SNIPPET_xml="## ------------------------------ ## ## Rules specific for XML output. ## ## ------------------------------ ## DX_CLEAN_XML = \$(DX_DOCDIR)/xml\\ \$(DX_DOCDIR)/xml " else $as_nop DX_SNIPPET_xml="" fi if test $DX_FLAG_ps -eq 1 then : DX_SNIPPET_ps="## ----------------------------- ## ## Rules specific for PS output. ## ## ----------------------------- ## DX_CLEAN_PS = \$(DX_DOCDIR)/\$(PACKAGE).ps\\ \$(DX_DOCDIR)/\$(PACKAGE).ps DX_PS_GOAL = doxygen-ps doxygen-ps: \$(DX_CLEAN_PS) \$(DX_DOCDIR)/\$(PACKAGE).ps: \$(DX_DOCDIR)/\$(PACKAGE).tag \$(DX_V_LATEX)cd \$(DX_DOCDIR)/latex; \\ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\ \$(DX_LATEX) refman.tex; \\ \$(DX_MAKEINDEX) refman.idx; \\ \$(DX_LATEX) refman.tex; \\ countdown=5; \\ while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\ refman.log > /dev/null 2>&1 \\ && test \$\$countdown -gt 0; do \\ \$(DX_LATEX) refman.tex; \\ countdown=\`expr \$\$countdown - 1\`; \\ done; \\ \$(DX_DVIPS) -o ../\$(PACKAGE).ps refman.dvi " else $as_nop DX_SNIPPET_ps="" fi if test $DX_FLAG_pdf -eq 1 then : DX_SNIPPET_pdf="## ------------------------------ ## ## Rules specific for PDF output. ## ## ------------------------------ ## DX_CLEAN_PDF = \$(DX_DOCDIR)/\$(PACKAGE).pdf\\ \$(DX_DOCDIR)/\$(PACKAGE).pdf DX_PDF_GOAL = doxygen-pdf doxygen-pdf: \$(DX_CLEAN_PDF) \$(DX_DOCDIR)/\$(PACKAGE).pdf: \$(DX_DOCDIR)/\$(PACKAGE).tag \$(DX_V_LATEX)cd \$(DX_DOCDIR)/latex; \\ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\ \$(DX_PDFLATEX) refman.tex; \\ \$(DX_MAKEINDEX) refman.idx; \\ \$(DX_PDFLATEX) refman.tex; \\ countdown=5; \\ while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\ refman.log > /dev/null 2>&1 \\ && test \$\$countdown -gt 0; do \\ \$(DX_PDFLATEX) refman.tex; \\ countdown=\`expr \$\$countdown - 1\`; \\ done; \\ mv refman.pdf ../\$(PACKAGE).pdf " else $as_nop DX_SNIPPET_pdf="" fi if test $DX_FLAG_ps -eq 1 -o $DX_FLAG_pdf -eq 1 then : DX_SNIPPET_latex="## ------------------------------------------------- ## ## Rules specific for LaTeX (shared for PS and PDF). ## ## ------------------------------------------------- ## DX_V_LATEX = \$(_DX_v_LATEX_\$(V)) _DX_v_LATEX_ = \$(_DX_v_LATEX_\$(AM_DEFAULT_VERBOSITY)) _DX_v_LATEX_0 = @echo \" LATEX \" \$@; DX_CLEAN_LATEX = \$(DX_DOCDIR)/latex\\ \$(DX_DOCDIR)/latex " else $as_nop DX_SNIPPET_latex="" fi if test $DX_FLAG_doc -eq 1 then : DX_SNIPPET_doc="## --------------------------------- ## ## Format-independent Doxygen rules. ## ## --------------------------------- ## ${DX_SNIPPET_html}\ ${DX_SNIPPET_chm}\ ${DX_SNIPPET_man}\ ${DX_SNIPPET_rtf}\ ${DX_SNIPPET_xml}\ ${DX_SNIPPET_ps}\ ${DX_SNIPPET_pdf}\ ${DX_SNIPPET_latex}\ DX_V_DXGEN = \$(_DX_v_DXGEN_\$(V)) _DX_v_DXGEN_ = \$(_DX_v_DXGEN_\$(AM_DEFAULT_VERBOSITY)) _DX_v_DXGEN_0 = @echo \" DXGEN \" \$<; .PHONY: doxygen-run doxygen-doc \$(DX_PS_GOAL) \$(DX_PDF_GOAL) .INTERMEDIATE: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL) doxygen-run: \$(DX_DOCDIR)/\$(PACKAGE).tag doxygen-doc: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL) \$(DX_DOCDIR)/\$(PACKAGE).tag: \$(DX_CONFIG) \$(pkginclude_HEADERS) \$(A""M_V_at)rm -rf \$(DX_DOCDIR) \$(DX_V_DXGEN)\$(DX_ENV) DOCDIR=\$(DX_DOCDIR) \$(DX_DOXYGEN) \$(DX_CONFIG) \$(A""M_V_at)echo Timestamp >\$@ DX_CLEANFILES = \\ \$(DX_DOCDIR)/doxygen_sqlite3.db \\ \$(DX_DOCDIR)/\$(PACKAGE).tag \\ -r \\ \$(DX_CLEAN_HTML) \\ \$(DX_CLEAN_CHM) \\ \$(DX_CLEAN_CHI) \\ \$(DX_CLEAN_MAN) \\ \$(DX_CLEAN_RTF) \\ \$(DX_CLEAN_XML) \\ \$(DX_CLEAN_PS) \\ \$(DX_CLEAN_PDF) \\ \$(DX_CLEAN_LATEX)" else $as_nop DX_SNIPPET_doc="" fi DX_RULES="${DX_SNIPPET_doc}" #For debugging: #echo DX_FLAG_doc=$DX_FLAG_doc #echo DX_FLAG_dot=$DX_FLAG_dot #echo DX_FLAG_man=$DX_FLAG_man #echo DX_FLAG_html=$DX_FLAG_html #echo DX_FLAG_chm=$DX_FLAG_chm #echo DX_FLAG_chi=$DX_FLAG_chi #echo DX_FLAG_rtf=$DX_FLAG_rtf #echo DX_FLAG_xml=$DX_FLAG_xml #echo DX_FLAG_pdf=$DX_FLAG_pdf #echo DX_FLAG_ps=$DX_FLAG_ps #echo DX_ENV=$DX_ENV cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_OPENMPT123_TRUE}" && test -z "${ENABLE_OPENMPT123_FALSE}"; then as_fn_error $? "conditional \"ENABLE_OPENMPT123\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_EXAMPLES_TRUE}" && test -z "${ENABLE_EXAMPLES_FALSE}"; then as_fn_error $? "conditional \"ENABLE_EXAMPLES\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_TESTS_TRUE}" && test -z "${ENABLE_TESTS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_TESTS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PORTAUDIO_TRUE}" && test -z "${HAVE_PORTAUDIO_FALSE}"; then as_fn_error $? "conditional \"HAVE_PORTAUDIO\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PORTAUDIOCPP_TRUE}" && test -z "${HAVE_PORTAUDIOCPP_FALSE}"; then as_fn_error $? "conditional \"HAVE_PORTAUDIOCPP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by libopenmpt $as_me 0.8.1+release.autotools, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Configuration commands: $config_commands Report bugs to . libopenmpt home page: ." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ libopenmpt config.status 0.8.1+release.autotools configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' FILECMD='`$ECHO "$FILECMD" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' lt_ar_flags='`$ECHO "$lt_ar_flags" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ FILECMD \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ lt_cv_nm_interface \ nm_file_list_spec \ lt_cv_truncate_bin \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib \ compiler_lib_search_dirs \ predep_objects \ postdep_objects \ predeps \ postdeps \ compiler_lib_search_path \ LD_CXX \ reload_flag_CXX \ compiler_CXX \ lt_prog_compiler_no_builtin_flag_CXX \ lt_prog_compiler_pic_CXX \ lt_prog_compiler_wl_CXX \ lt_prog_compiler_static_CXX \ lt_cv_prog_compiler_c_o_CXX \ export_dynamic_flag_spec_CXX \ whole_archive_flag_spec_CXX \ compiler_needs_object_CXX \ with_gnu_ld_CXX \ allow_undefined_flag_CXX \ no_undefined_flag_CXX \ hardcode_libdir_flag_spec_CXX \ hardcode_libdir_separator_CXX \ exclude_expsyms_CXX \ include_expsyms_CXX \ file_list_spec_CXX \ compiler_lib_search_dirs_CXX \ predep_objects_CXX \ postdep_objects_CXX \ predeps_CXX \ postdeps_CXX \ compiler_lib_search_path_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ configure_time_dlsearch_path \ configure_time_lt_sys_library_path \ reload_cmds_CXX \ old_archive_cmds_CXX \ old_archive_from_new_cmds_CXX \ old_archive_from_expsyms_cmds_CXX \ archive_cmds_CXX \ archive_expsym_cmds_CXX \ module_cmds_CXX \ module_expsym_cmds_CXX \ export_symbols_cmds_CXX \ prelink_cmds_CXX \ postlink_cmds_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "libopenmpt/libopenmpt.pc") CONFIG_FILES="$CONFIG_FILES libopenmpt/libopenmpt.pc" ;; "Doxyfile") CONFIG_FILES="$CONFIG_FILES Doxyfile" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 printf "%s\n" "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in #( *\'*) : eval set x "$CONFIG_FILES" ;; #( *) : set x $CONFIG_FILES ;; #( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; "libtool":C) # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 # Copyright (C) 2014 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # The names of the tagged configurations supported by this script. available_tags='CXX ' # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shared archive member basename,for filename based shared library versioning on AIX. shared_archive_member_spec=$shared_archive_member_spec # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # A file(cmd) program that detects file types. FILECMD=$lt_FILECMD # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive (by configure). lt_ar_flags=$lt_ar_flags # Flags to create an archive. AR_FLAGS=\${ARFLAGS-"\$lt_ar_flags"} # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm into a list of symbols to manually relocate. global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # The name lister interface. nm_interface=$lt_lt_cv_nm_interface # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and where our libraries should be installed. lt_sysroot=$lt_sysroot # Command to truncate a binary pipe. lt_truncate_bin=$lt_lt_cv_truncate_bin # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Detected run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path # Explicit LT_SYS_LIBRARY_PATH set during ./configure time. configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \$shlibpath_var if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects postdep_objects=$lt_postdep_objects predeps=$lt_predeps postdeps=$lt_postdeps # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain=$ac_aux_dir/ltmain.sh # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? $SED '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" cat <<_LT_EOF >> "$ofile" # ### BEGIN LIBTOOL TAG CONFIG: CXX # The linker used to build libraries. LD=$lt_LD_CXX # How to create reloadable object files. reload_flag=$lt_reload_flag_CXX reload_cmds=$lt_reload_cmds_CXX # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds_CXX # A language specific compiler. CC=$lt_compiler_CXX # Is the compiler the GNU compiler? with_gcc=$GCC_CXX # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_CXX # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_CXX # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_CXX # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_CXX # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object_CXX # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds_CXX archive_expsym_cmds=$lt_archive_expsym_cmds_CXX # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds_CXX module_expsym_cmds=$lt_module_expsym_cmds_CXX # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld_CXX # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_CXX # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_CXX # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct_CXX # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \$shlibpath_var if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute_CXX # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L_CXX # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic_CXX # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath_CXX # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_CXX # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols_CXX # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_CXX # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_CXX # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_CXX # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds_CXX # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds_CXX # Specify filename containing input files. file_list_spec=$lt_file_list_spec_CXX # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_CXX # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects_CXX postdep_objects=$lt_postdep_objects_CXX predeps=$lt_predeps_CXX postdeps=$lt_postdeps_CXX # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_CXX # ### END LIBTOOL TAG CONFIG: CXX _LT_EOF ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi libopenmpt-0.8.1+release.autotools/sounddsp/0000755000175000017500000000000015023302362016171 500000000000000libopenmpt-0.8.1+release.autotools/sounddsp/AGC.h0000644000175000017500000000131414052666041016663 00000000000000/* * AGC.h * ----- * Purpose: Automatic Gain Control * Notes : Ugh... This should really be removed at some point. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" OPENMPT_NAMESPACE_BEGIN #ifndef NO_AGC class CAGC { private: UINT m_nAGC; std::size_t m_nAGCRecoverCount; UINT m_Timeout; public: CAGC(); void Initialize(bool bReset, DWORD MixingFreq); public: void Process(int *MixSoundBuffer, int *RearSoundBuffer, std::size_t count, std::size_t nChannels); void Adjust(UINT oldVol, UINT newVol); }; #endif // NO_AGC OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/sounddsp/EQ.h0000644000175000017500000000302414056615252016600 00000000000000/* * EQ.h * ---- * Purpose: Mixing code for equalizer. * Notes : Ugh... This should really be removed at some point. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/soundbase/MixSample.hpp" #include #include OPENMPT_NAMESPACE_BEGIN #ifndef NO_EQ inline constexpr std::size_t MAX_EQ_CHANNELS = 4; inline constexpr std::size_t MAX_EQ_BANDS = 6; struct EQBANDSTATE { float x1 = 0.0f; float x2 = 0.0f; float y1 = 0.0f; float y2 = 0.0f; }; struct EQBANDSETTINGS { float a0; float a1; float a2; float b1; float b2; float Gain; float CenterFrequency; }; class CEQ { private: std::array, MAX_EQ_CHANNELS> m_ChannelState; std::array m_Bands; template void ProcessTemplate(TMixSample *frontBuffer, TMixSample *rearBuffer, std::size_t countFrames, std::size_t numChannels); public: CEQ(); void Initialize(bool bReset, uint32 MixingFreq); void Process(MixSampleInt *frontBuffer, MixSampleInt *rearBuffer, std::size_t countFrames, std::size_t numChannels); void Process(MixSampleFloat *frontBuffer, MixSampleFloat *rearBuffer, std::size_t countFrames, std::size_t numChannels); void SetEQGains(const uint32 *pGains, const uint32 *pFreqs, bool bReset, uint32 MixingFreq); }; #endif // !NO_EQ OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/sounddsp/Reverb.h0000644000175000017500000001577114072325166017534 00000000000000/* * Reverb.h * -------- * Purpose: Mixing code for reverb. * Notes : Ugh... This should really be removed at some point. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" #ifndef NO_REVERB #include "../soundlib/Mixer.h" // For MIXBUFFERSIZE OPENMPT_NAMESPACE_BEGIN //////////////////////////////////////////////////////////////////////// // Reverberation ///////////////////////////////////////////////////////////////////////////// // // SW Reverb structures // // Length-1 (in samples) of the reflections delay buffer: 32K, 371ms@22kHz #define SNDMIX_REFLECTIONS_DELAY_MASK 0x1fff #define SNDMIX_PREDIFFUSION_DELAY_MASK 0x7f // 128 samples #define SNDMIX_REVERB_DELAY_MASK 0xfff // 4K samples (92ms @ 44kHz) union LR16 { struct { int16 l, r; } c; int32 lr; }; struct SWRvbReflection { uint32 Delay, DelayDest; LR16 Gains[2]; // g_ll, g_rl, g_lr, g_rr }; struct SWRvbRefDelay { uint32 nDelayPos, nPreDifPos, nRefOutPos; int32 lMasterGain; // reflections linear master gain LR16 nCoeffs; // room low-pass coefficients LR16 History; // room low-pass history LR16 nPreDifCoeffs; // prediffusion coefficients LR16 ReflectionsGain; // master reflections gain SWRvbReflection Reflections[8]; // Up to 8 SW Reflections LR16 RefDelayBuffer[SNDMIX_REFLECTIONS_DELAY_MASK + 1]; // reflections delay buffer LR16 PreDifBuffer[SNDMIX_PREDIFFUSION_DELAY_MASK + 1]; // pre-diffusion LR16 RefOut[SNDMIX_REVERB_DELAY_MASK + 1]; // stereo output of reflections }; struct SNDMIX_REVERB_PROPERTIES; // Late reverberation // Tank diffusers lengths #define RVBDIF1L_LEN (149*2) // 6.8ms #define RVBDIF1R_LEN (223*2) // 10.1ms #define RVBDIF2L_LEN (421*2) // 19.1ms #define RVBDIF2R_LEN (647*2) // 29.3ms // Tank delay lines lengths #define RVBDLY1L_LEN (683*2) // 30.9ms #define RVBDLY1R_LEN (811*2) // 36.7ms #define RVBDLY2L_LEN (773*2) // 35.1ms #define RVBDLY2R_LEN (1013*2) // 45.9ms // Tank delay lines mask #define RVBDLY_MASK 2047 // Min/Max reflections delay #define RVBMINREFDELAY 96 // 96 samples #define RVBMAXREFDELAY 7500 // 7500 samples // Min/Max reverb delay #define RVBMINRVBDELAY 128 // 256 samples (11.6ms @ 22kHz) #define RVBMAXRVBDELAY 3800 // 1900 samples (86ms @ 24kHz) struct SWLateReverb { uint32 nReverbDelay; // Reverb delay (in samples) uint32 nDelayPos; // Delay line position LR16 nDifCoeffs[2]; // Reverb diffusion LR16 nDecayDC[2]; // Reverb DC decay LR16 nDecayLP[2]; // Reverb HF decay LR16 LPHistory[2]; // Low-pass history LR16 Dif2InGains[2]; // 2nd diffuser input gains LR16 RvbOutGains[2]; // 4x2 Reverb output gains int32 lMasterGain; // late reverb master gain int32 lDummyAlign; // Tank Delay lines LR16 Diffusion1[RVBDLY_MASK + 1]; // {dif1_l, dif1_r} LR16 Diffusion2[RVBDLY_MASK + 1]; // {dif2_l, dif2_r} LR16 Delay1[RVBDLY_MASK + 1]; // {dly1_l, dly1_r} LR16 Delay2[RVBDLY_MASK + 1]; // {dly2_l, dly2_r} }; #define ENVIRONMENT_NUMREFLECTIONS 8 struct EnvironmentReflection { int16 GainLL, GainRR, GainLR, GainRL; // +/- 32K scale uint32 Delay; // In samples }; struct EnvironmentReverb { int32 ReverbLevel; // Late reverb gain (mB) int32 ReflectionsLevel; // Master reflections gain (mB) int32 RoomHF; // Room gain HF (mB) uint32 ReverbDecay; // Reverb tank decay (0-7fff scale) int32 PreDiffusion; // Reverb pre-diffusion amount (+/- 32K scale) int32 TankDiffusion; // Reverb tank diffusion (+/- 32K scale) uint32 ReverbDelay; // Reverb delay (in samples) float flReverbDamping; // HF tank gain [0.0, 1.0] int32 ReverbDecaySamples; // Reverb decay time (in samples) EnvironmentReflection Reflections[ENVIRONMENT_NUMREFLECTIONS]; }; class CReverbSettings { public: uint32 m_nReverbDepth = 8; // 50% uint32 m_nReverbType = 0; }; class CReverb { public: CReverbSettings m_Settings; private: const SNDMIX_REVERB_PROPERTIES *m_currentPreset = nullptr; bool gnReverbSend = false; uint32 gnReverbSamples = 0; uint32 gnReverbDecaySamples = 0; // Internal reverb state bool g_bLastInPresent = 0; bool g_bLastOutPresent = 0; int g_nLastRvbIn_xl = 0; int g_nLastRvbIn_xr = 0; int g_nLastRvbIn_yl = 0; int g_nLastRvbIn_yr = 0; int g_nLastRvbOut_xl = 0; int g_nLastRvbOut_xr = 0; int32 gnDCRRvb_Y1[2] = { 0, 0 }; int32 gnDCRRvb_X1[2] = { 0, 0 }; // Reverb mix buffers SWRvbRefDelay g_RefDelay; SWLateReverb g_LateReverb; public: CReverb(); public: void Initialize(bool bReset, MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol, uint32 MixingFreq); // can be called multiple times or never (if no data is sent to reverb) void TouchReverbSendBuffer(MixSampleInt *MixReverbBuffer, MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol, uint32 nSamples); // call once after all data has been sent. void Process(MixSampleInt *MixSoundBuffer, MixSampleInt *MixReverbBuffer, MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol, uint32 nSamples); private: void Shutdown(MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol); // Pre/Post resampling and filtering uint32 ReverbProcessPreFiltering1x(int32 *pWet, uint32 nSamples); uint32 ReverbProcessPreFiltering2x(int32 *pWet, uint32 nSamples); void ReverbProcessPostFiltering1x(const int32 *pRvb, int32 *pDry, uint32 nSamples); void ReverbProcessPostFiltering2x(const int32 *pRvb, int32 *pDry, uint32 nSamples); void ReverbDCRemoval(int32 *pBuffer, uint32 nSamples); void ReverbDryMix(int32 *pDry, int32 *pWet, int lDryVol, uint32 nSamples); // Process pre-diffusion and pre-delay static void ProcessPreDelay(SWRvbRefDelay *pPreDelay, const int32 *pIn, uint32 nSamples); // Process reflections static void ProcessReflections(SWRvbRefDelay *pPreDelay, LR16 *pRefOut, int32 *pMixOut, uint32 nSamples); // Process Late Reverb (SW Reflections): stereo reflections output, 32-bit reverb output, SW reverb gain static void ProcessLateReverb(SWLateReverb *pReverb, LR16 *pRefOut, int32 *pMixOut, uint32 nSamples); }; ///////////////////////////////////////////////////////////////////////////////// // // I3DL2 reverb presets // struct SNDMIX_REVERB_PROPERTIES { int32 lRoom; // [-10000, 0] default: -10000 mB int32 lRoomHF; // [-10000, 0] default: 0 mB float flDecayTime; // [0.1, 20.0] default: 1.0 s float flDecayHFRatio; // [0.1, 2.0] default: 0.5 int32 lReflections; // [-10000, 1000] default: -10000 mB float flReflectionsDelay; // [0.0, 0.3] default: 0.02 s int32 lReverb; // [-10000, 2000] default: -10000 mB float flReverbDelay; // [0.0, 0.1] default: 0.04 s float flDiffusion; // [0.0, 100.0] default: 100.0 % float flDensity; // [0.0, 100.0] default: 100.0 % }; enum : uint32 { NUM_REVERBTYPES = 29 }; mpt::ustring GetReverbPresetName(uint32 preset); const SNDMIX_REVERB_PROPERTIES *GetReverbPreset(uint32 preset); OPENMPT_NAMESPACE_END #endif // NO_REVERB libopenmpt-0.8.1+release.autotools/sounddsp/Reverb.cpp0000644000175000017500000012050514767346611020070 00000000000000/* * Reverb.cpp * ---------- * Purpose: Mixing code for reverb. * Notes : Ugh... This should really be removed at some point. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #ifndef NO_REVERB #include "Reverb.h" #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) #include "../common/mptCPU.h" #endif #include "../soundlib/MixerLoops.h" #include "mpt/base/numbers.hpp" #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) #if MPT_COMPILER_MSVC #include #endif #include #endif #endif // NO_REVERB OPENMPT_NAMESPACE_BEGIN #ifndef NO_REVERB #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) // Load two 32-bit values static MPT_FORCEINLINE __m128i Load64SSE(const int32 *x) { return _mm_loadl_epi64(reinterpret_cast(x)); } // Load four 16-bit values static MPT_FORCEINLINE __m128i Load64SSE(const LR16 (&x)[2]) { return _mm_loadl_epi64(&reinterpret_cast(x)); } // Store two 32-bit or four 16-bit values from register static MPT_FORCEINLINE void Store64SSE(int32 *dst, __m128i src) { return _mm_storel_epi64(reinterpret_cast<__m128i *>(dst), src); } static MPT_FORCEINLINE void Store64SSE(LR16 (&dst)[2], __m128i src) { return _mm_storel_epi64(&reinterpret_cast<__m128i &>(dst), src); } #endif CReverb::CReverb() { // Reverb mix buffers MemsetZero(g_RefDelay); MemsetZero(g_LateReverb); } static int32 OnePoleLowPassCoef(int32 scale, double g, double F_c, double F_s) { if(g > 0.999999) return 0; g *= g; double scale_over_1mg = scale / (1.0 - g); double cosw = std::cos((2.0 * mpt::numbers::pi) * F_c / F_s); return mpt::saturate_round((1.0 - (std::sqrt((g + g) * (1.0 - cosw) - g * g * (1.0 - cosw * cosw)) + g * cosw)) * scale_over_1mg); } static double mBToLinear(int32 value_mB) { if(!value_mB) return 1; if(value_mB <= -100000) return 0; const double val = value_mB * 3.321928094887362304 / (100.0 * 20.0); // log2(10)/(100*20) return std::pow(2.0, val - static_cast(0.5 + val)); } static int32 mBToLinear(int32 scale, int32 value_mB) { return mpt::saturate_round(mBToLinear(value_mB) * scale); } static constexpr std::pair ReverbPresets[NUM_REVERBTYPES] = { // Examples simulating General MIDI 2'musical' reverb presets // Name (Decay time) Description // Plate (1.3s) A plate reverb simulation. {{ -1000, -200, 1.30f,0.90f, 0,0.002f, 0,0.010f,100.0f, 75.0f }, "GM Plate"}, // Small Room (1.1s) A small size room with a length of 5m or so. {{ -1000, -600, 1.10f,0.83f, -400,0.005f, 500,0.010f,100.0f,100.0f }, "GM Small Room"}, // Medium Room (1.3s) A medium size room with a length of 10m or so. {{ -1000, -600, 1.30f,0.83f, -1000,0.010f, -200,0.020f,100.0f,100.0f }, "GM Medium Room"}, // Large Room (1.5s) A large size room suitable for live performances. {{ -1000, -600, 1.50f,0.83f, -1600,0.020f, -1000,0.040f,100.0f,100.0f }, "GM Large Room"}, // Medium Hall (1.8s) A medium size concert hall. {{ -1000, -600, 1.80f,0.70f, -1300,0.015f, -800,0.030f,100.0f,100.0f }, "GM Medium Hall"}, // Large Hall (1.8s) A large size concert hall suitable for a full orchestra. {{ -1000, -600, 1.80f,0.70f, -2000,0.030f, -1400,0.060f,100.0f,100.0f }, "GM Large Hall"}, {{ -1000, -100, 1.49f,0.83f, -2602,0.007f, 200,0.011f,100.0f,100.0f }, "Generic"}, {{ -1000,-6000, 0.17f,0.10f, -1204,0.001f, 207,0.002f,100.0f,100.0f }, "Padded Cell"}, {{ -1000, -454, 0.40f,0.83f, -1646,0.002f, 53,0.003f,100.0f,100.0f }, "Room"}, {{ -1000,-1200, 1.49f,0.54f, -370,0.007f, 1030,0.011f,100.0f, 60.0f }, "Bathroom"}, {{ -1000,-6000, 0.50f,0.10f, -1376,0.003f, -1104,0.004f,100.0f,100.0f }, "Living Room"}, {{ -1000, -300, 2.31f,0.64f, -711,0.012f, 83,0.017f,100.0f,100.0f }, "Stone Room"}, {{ -1000, -476, 4.32f,0.59f, -789,0.020f, -289,0.030f,100.0f,100.0f }, "Auditorium"}, {{ -1000, -500, 3.92f,0.70f, -1230,0.020f, -2,0.029f,100.0f,100.0f }, "Concert Hall"}, {{ -1000, 0, 2.91f,1.30f, -602,0.015f, -302,0.022f,100.0f,100.0f }, "Cave"}, {{ -1000, -698, 7.24f,0.33f, -1166,0.020f, 16,0.030f,100.0f,100.0f }, "Arena"}, {{ -1000,-1000,10.05f,0.23f, -602,0.020f, 198,0.030f,100.0f,100.0f }, "Hangar"}, {{ -1000,-4000, 0.30f,0.10f, -1831,0.002f, -1630,0.030f,100.0f,100.0f }, "Carpeted Hallway"}, {{ -1000, -300, 1.49f,0.59f, -1219,0.007f, 441,0.011f,100.0f,100.0f }, "Hallway"}, {{ -1000, -237, 2.70f,0.79f, -1214,0.013f, 395,0.020f,100.0f,100.0f }, "Stone Corridor"}, {{ -1000, -270, 1.49f,0.86f, -1204,0.007f, -4,0.011f,100.0f,100.0f }, "Alley"}, {{ -1000,-3300, 1.49f,0.54f, -2560,0.162f, -613,0.088f, 79.0f,100.0f }, "Forest"}, {{ -1000, -800, 1.49f,0.67f, -2273,0.007f, -2217,0.011f, 50.0f,100.0f }, "City"}, {{ -1000,-2500, 1.49f,0.21f, -2780,0.300f, -2014,0.100f, 27.0f,100.0f }, "Mountains"}, {{ -1000,-1000, 1.49f,0.83f,-10000,0.061f, 500,0.025f,100.0f,100.0f }, "Quarry"}, {{ -1000,-2000, 1.49f,0.50f, -2466,0.179f, -2514,0.100f, 21.0f,100.0f }, "Plain"}, {{ -1000, 0, 1.65f,1.50f, -1363,0.008f, -1153,0.012f,100.0f,100.0f }, "Parking Lot"}, {{ -1000,-1000, 2.81f,0.14f, 429,0.014f, 648,0.021f, 80.0f, 60.0f }, "Sewer Pipe"}, {{ -1000,-4000, 1.49f,0.10f, -449,0.007f, 1700,0.011f,100.0f,100.0f }, "Underwater"}, }; mpt::ustring GetReverbPresetName(uint32 preset) { return (preset < NUM_REVERBTYPES) ? mpt::ToUnicode(mpt::Charset::ASCII, ReverbPresets[preset].second) : mpt::ustring{}; } const SNDMIX_REVERB_PROPERTIES *GetReverbPreset(uint32 preset) { return (preset < NUM_REVERBTYPES) ? &ReverbPresets[preset].first : nullptr; } ////////////////////////////////////////////////////////////////////////// // // I3DL2 environmental reverb support // struct REFLECTIONPRESET { int32 lDelayFactor; int16 sGainLL, sGainRR, sGainLR, sGainRL; }; const REFLECTIONPRESET gReflectionsPreset[ENVIRONMENT_NUMREFLECTIONS] = { // %Delay, ll, rr, lr, rl {0, 9830, 6554, 0, 0}, {10, 6554, 13107, 0, 0}, {24, -9830, 13107, 0, 0}, {36, 13107, -6554, 0, 0}, {54, 16384, 16384, -1638, -1638}, {61, -13107, 8192, -328, -328}, {73, -11468, -11468, -3277, 3277}, {87, 13107, -9830, 4916, -4916} }; //////////////////////////////////////////////////////////////////////////////////// // // Implementation // MPT_FORCEINLINE int32 ftol(float f) { return static_cast(f); } static void I3dl2_to_Generic( const SNDMIX_REVERB_PROPERTIES *pReverb, EnvironmentReverb *pRvb, float flOutputFreq, int32 lMinRefDelay, int32 lMaxRefDelay, int32 lMinRvbDelay, int32 lMaxRvbDelay, int32 lTankLength) { float flDelayFactor, flDelayFactorHF, flDecayTimeHF; int32 lDensity, lTailDiffusion; // Common parameters pRvb->ReverbLevel = pReverb->lReverb; pRvb->ReflectionsLevel = pReverb->lReflections; pRvb->RoomHF = pReverb->lRoomHF; // HACK: Somewhat normalize the reverb output level int32 lMaxLevel = (pRvb->ReverbLevel > pRvb->ReflectionsLevel) ? pRvb->ReverbLevel : pRvb->ReflectionsLevel; if (lMaxLevel < -600) { lMaxLevel += 600; pRvb->ReverbLevel -= lMaxLevel; pRvb->ReflectionsLevel -= lMaxLevel; } // Pre-Diffusion factor (for both reflections and late reverb) lDensity = 8192 + ftol(79.31f * pReverb->flDensity); pRvb->PreDiffusion = lDensity; // Late reverb diffusion lTailDiffusion = ftol((0.15f + pReverb->flDiffusion * (0.36f*0.01f)) * 32767.0f); if (lTailDiffusion > 0x7f00) lTailDiffusion = 0x7f00; pRvb->TankDiffusion = lTailDiffusion; // Verify reflections and reverb delay parameters float flRefDelay = pReverb->flReflectionsDelay; if (flRefDelay > 0.100f) flRefDelay = 0.100f; int32 lReverbDelay = ftol(pReverb->flReverbDelay * flOutputFreq); int32 lReflectionsDelay = ftol(flRefDelay * flOutputFreq); int32 lReverbDecayTime = ftol(pReverb->flDecayTime * flOutputFreq); if (lReflectionsDelay < lMinRefDelay) { lReverbDelay -= (lMinRefDelay - lReflectionsDelay); lReflectionsDelay = lMinRefDelay; } if (lReflectionsDelay > lMaxRefDelay) { lReverbDelay += (lReflectionsDelay - lMaxRefDelay); lReflectionsDelay = lMaxRefDelay; } // Adjust decay time when adjusting reverb delay if (lReverbDelay < lMinRvbDelay) { lReverbDecayTime -= (lMinRvbDelay - lReverbDelay); lReverbDelay = lMinRvbDelay; } if (lReverbDelay > lMaxRvbDelay) { lReverbDecayTime += (lReverbDelay - lMaxRvbDelay); lReverbDelay = lMaxRvbDelay; } pRvb->ReverbDelay = lReverbDelay; pRvb->ReverbDecaySamples = lReverbDecayTime; // Setup individual reflections delay and gains for (uint32 iRef=0; iRefReflections[iRef]; ref.Delay = lReflectionsDelay + (gReflectionsPreset[iRef].lDelayFactor * lReverbDelay + 50)/100; ref.GainLL = gReflectionsPreset[iRef].sGainLL; ref.GainRL = gReflectionsPreset[iRef].sGainRL; ref.GainLR = gReflectionsPreset[iRef].sGainLR; ref.GainRR = gReflectionsPreset[iRef].sGainRR; } // Late reverb decay time if (lTankLength < 10) lTankLength = 10; flDelayFactor = (lReverbDecayTime <= lTankLength) ? 1.0f : ((float)lTankLength / (float)lReverbDecayTime); pRvb->ReverbDecay = ftol(std::pow(0.001f, flDelayFactor) * 32768.0f); // Late Reverb Decay HF flDecayTimeHF = (float)lReverbDecayTime * pReverb->flDecayHFRatio; flDelayFactorHF = (flDecayTimeHF <= (float)lTankLength) ? 1.0f : ((float)lTankLength / flDecayTimeHF); pRvb->flReverbDamping = std::pow(0.001f, flDelayFactorHF); } void CReverb::Shutdown(MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol) { gnReverbSend = false; gnRvbLOfsVol = 0; gnRvbROfsVol = 0; // Clear out all reverb state g_bLastInPresent = false; g_bLastOutPresent = false; g_nLastRvbIn_xl = g_nLastRvbIn_xr = 0; g_nLastRvbIn_yl = g_nLastRvbIn_yr = 0; g_nLastRvbOut_xl = g_nLastRvbOut_xr = 0; MemsetZero(gnDCRRvb_X1); MemsetZero(gnDCRRvb_Y1); // Zero internal buffers MemsetZero(g_LateReverb.Diffusion1); MemsetZero(g_LateReverb.Diffusion2); MemsetZero(g_LateReverb.Delay1); MemsetZero(g_LateReverb.Delay2); MemsetZero(g_RefDelay.RefDelayBuffer); MemsetZero(g_RefDelay.PreDifBuffer); MemsetZero(g_RefDelay.RefOut); } void CReverb::Initialize(bool bReset, MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol, uint32 MixingFreq) { if (m_Settings.m_nReverbType >= NUM_REVERBTYPES) m_Settings.m_nReverbType = 0; const SNDMIX_REVERB_PROPERTIES *rvbPreset = &ReverbPresets[m_Settings.m_nReverbType].first; if ((rvbPreset != m_currentPreset) || (bReset)) { // Reverb output frequency is half of the dry output rate float flOutputFrequency = (float)MixingFreq; EnvironmentReverb rvb; // Reset reverb parameters m_currentPreset = rvbPreset; I3dl2_to_Generic(rvbPreset, &rvb, flOutputFrequency, RVBMINREFDELAY, RVBMAXREFDELAY, RVBMINRVBDELAY, RVBMAXRVBDELAY, ( RVBDIF1L_LEN + RVBDIF1R_LEN + RVBDIF2L_LEN + RVBDIF2R_LEN + RVBDLY1L_LEN + RVBDLY1R_LEN + RVBDLY2L_LEN + RVBDLY2R_LEN) / 2); // Store reverb decay time (in samples) for reverb auto-shutdown gnReverbDecaySamples = rvb.ReverbDecaySamples; // Room attenuation at high frequencies int32 nRoomLP; nRoomLP = OnePoleLowPassCoef(32768, mBToLinear(rvb.RoomHF), 5000, static_cast(flOutputFrequency)); g_RefDelay.nCoeffs.c.l = (int16)nRoomLP; g_RefDelay.nCoeffs.c.r = (int16)nRoomLP; // Pre-Diffusion factor (for both reflections and late reverb) g_RefDelay.nPreDifCoeffs.c.l = (int16)(rvb.PreDiffusion*2); g_RefDelay.nPreDifCoeffs.c.r = (int16)(rvb.PreDiffusion*2); // Setup individual reflections delay and gains for (uint32 iRef=0; iRef<8; iRef++) { SWRvbReflection &ref = g_RefDelay.Reflections[iRef]; ref.DelayDest = rvb.Reflections[iRef].Delay; ref.Delay = ref.DelayDest; ref.Gains[0].c.l = rvb.Reflections[iRef].GainLL; ref.Gains[0].c.r = rvb.Reflections[iRef].GainRL; ref.Gains[1].c.l = rvb.Reflections[iRef].GainLR; ref.Gains[1].c.r = rvb.Reflections[iRef].GainRR; } g_LateReverb.nReverbDelay = rvb.ReverbDelay; // Reflections Master Gain uint32 lReflectionsGain = 0; if (rvb.ReflectionsLevel > -9000) { lReflectionsGain = mBToLinear(32768, rvb.ReflectionsLevel); } g_RefDelay.lMasterGain = lReflectionsGain; // Late reverb master gain uint32 lReverbGain = 0; if (rvb.ReverbLevel > -9000) { lReverbGain = mBToLinear(32768, rvb.ReverbLevel); } g_LateReverb.lMasterGain = lReverbGain; // Late reverb diffusion uint32 nTailDiffusion = rvb.TankDiffusion; if (nTailDiffusion > 0x7f00) nTailDiffusion = 0x7f00; g_LateReverb.nDifCoeffs[0].c.l = (int16)nTailDiffusion; g_LateReverb.nDifCoeffs[0].c.r = (int16)nTailDiffusion; g_LateReverb.nDifCoeffs[1].c.l = (int16)nTailDiffusion; g_LateReverb.nDifCoeffs[1].c.r = (int16)nTailDiffusion; g_LateReverb.Dif2InGains[0].c.l = 0x7000; g_LateReverb.Dif2InGains[0].c.r = 0x1000; g_LateReverb.Dif2InGains[1].c.l = 0x1000; g_LateReverb.Dif2InGains[1].c.r = 0x7000; // Late reverb decay time int32 nReverbDecay = rvb.ReverbDecay; Limit(nReverbDecay, 0, 0x7ff0); g_LateReverb.nDecayDC[0].c.l = (int16)nReverbDecay; g_LateReverb.nDecayDC[0].c.r = 0; g_LateReverb.nDecayDC[1].c.l = 0; g_LateReverb.nDecayDC[1].c.r = (int16)nReverbDecay; // Late Reverb Decay HF float fReverbDamping = rvb.flReverbDamping * rvb.flReverbDamping; int32 nDampingLowPass; nDampingLowPass = OnePoleLowPassCoef(32768, static_cast(fReverbDamping), 5000, static_cast(flOutputFrequency)); Limit(nDampingLowPass, 0x100, 0x7f00); g_LateReverb.nDecayLP[0].c.l = (int16)nDampingLowPass; g_LateReverb.nDecayLP[0].c.r = 0; g_LateReverb.nDecayLP[1].c.l = 0; g_LateReverb.nDecayLP[1].c.r = (int16)nDampingLowPass; } if (bReset) { gnReverbSamples = 0; Shutdown(gnRvbROfsVol, gnRvbLOfsVol); } // Wait at least 5 seconds before shutting down the reverb if (gnReverbDecaySamples < MixingFreq*5) { gnReverbDecaySamples = MixingFreq*5; } } void CReverb::TouchReverbSendBuffer(MixSampleInt *MixReverbBuffer, MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol, uint32 nSamples) { if(!gnReverbSend) { // and we did not clear the buffer yet, do it now because we will get new data StereoFill(MixReverbBuffer, nSamples, gnRvbROfsVol, gnRvbLOfsVol); } gnReverbSend = true; // we will have to process reverb } // Reverb void CReverb::Process(MixSampleInt *MixSoundBuffer, MixSampleInt *MixReverbBuffer, MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol, uint32 nSamples) { if((!gnReverbSend) && (!gnReverbSamples)) { // no data is sent to reverb and reverb decayed completely return; } if(!gnReverbSend) { // no input data in MixReverbBuffer, so the buffer got not cleared in TouchReverbSendBuffer(), do it now for decay StereoFill(MixReverbBuffer, nSamples, gnRvbROfsVol, gnRvbLOfsVol); } uint32 nIn, nOut; // Dynamically adjust reverb master gains int32 lMasterGain; lMasterGain = ((g_RefDelay.lMasterGain * m_Settings.m_nReverbDepth) >> 4); if (lMasterGain > 0x7fff) lMasterGain = 0x7fff; g_RefDelay.ReflectionsGain.c.l = (int16)lMasterGain; g_RefDelay.ReflectionsGain.c.r = (int16)lMasterGain; lMasterGain = ((g_LateReverb.lMasterGain * m_Settings.m_nReverbDepth) >> 4); if (lMasterGain > 0x10000) lMasterGain = 0x10000; g_LateReverb.RvbOutGains[0].c.l = (int16)((lMasterGain+0x7f) >> 3); // l->l g_LateReverb.RvbOutGains[0].c.r = (int16)((lMasterGain+0xff) >> 4); // r->l g_LateReverb.RvbOutGains[1].c.l = (int16)((lMasterGain+0xff) >> 4); // l->r g_LateReverb.RvbOutGains[1].c.r = (int16)((lMasterGain+0x7f) >> 3); // r->r // Process Dry/Wet Mix int32 lMaxRvbGain = (g_RefDelay.lMasterGain > g_LateReverb.lMasterGain) ? g_RefDelay.lMasterGain : g_LateReverb.lMasterGain; if (lMaxRvbGain > 32768) lMaxRvbGain = 32768; int32 lDryVol = (36 - m_Settings.m_nReverbDepth)>>1; if (lDryVol < 8) lDryVol = 8; if (lDryVol > 16) lDryVol = 16; lDryVol = 16 - (((16-lDryVol) * lMaxRvbGain) >> 15); ReverbDryMix(MixSoundBuffer, MixReverbBuffer, lDryVol, nSamples); // Downsample 2x + 1st stage of lowpass filter nIn = ReverbProcessPreFiltering1x(MixReverbBuffer, nSamples); nOut = nIn; // Main reverb processing: split into small chunks (needed for short reverb delays) // Reverb Input + Low-Pass stage #2 + Pre-diffusion if (nIn > 0) ProcessPreDelay(&g_RefDelay, MixReverbBuffer, nIn); // Process Reverb Reflections and Late Reverberation int32 *pRvbOut = MixReverbBuffer; uint32 nRvbSamples = nOut; while (nRvbSamples > 0) { uint32 nPosRef = g_RefDelay.nRefOutPos & SNDMIX_REVERB_DELAY_MASK; uint32 nPosRvb = (nPosRef - g_LateReverb.nReverbDelay) & SNDMIX_REVERB_DELAY_MASK; uint32 nmax1 = (SNDMIX_REVERB_DELAY_MASK+1) - nPosRef; uint32 nmax2 = (SNDMIX_REVERB_DELAY_MASK+1) - nPosRvb; nmax1 = (nmax1 < nmax2) ? nmax1 : nmax2; uint32 n = nRvbSamples; if (n > nmax1) n = nmax1; if (n > 64) n = 64; // Reflections output + late reverb delay ProcessReflections(&g_RefDelay, &g_RefDelay.RefOut[nPosRef], pRvbOut, n); // Late Reverberation ProcessLateReverb(&g_LateReverb, &g_RefDelay.RefOut[nPosRvb], pRvbOut, n); // Update delay positions g_RefDelay.nRefOutPos = (g_RefDelay.nRefOutPos + n) & SNDMIX_REVERB_DELAY_MASK; g_RefDelay.nDelayPos = (g_RefDelay.nDelayPos + n) & SNDMIX_REFLECTIONS_DELAY_MASK; pRvbOut += n*2; nRvbSamples -= n; } // Adjust nDelayPos, in case nIn != nOut g_RefDelay.nDelayPos = (g_RefDelay.nDelayPos - nOut + nIn) & SNDMIX_REFLECTIONS_DELAY_MASK; // Upsample 2x ReverbProcessPostFiltering1x(MixReverbBuffer, MixSoundBuffer, nSamples); // Automatically shut down if needed if(gnReverbSend) gnReverbSamples = gnReverbDecaySamples; // reset decay counter else if(gnReverbSamples > nSamples) gnReverbSamples -= nSamples; // decay else // decayed { Shutdown(gnRvbROfsVol, gnRvbLOfsVol); gnReverbSamples = 0; } gnReverbSend = false; // no input data in MixReverbBuffer } void CReverb::ReverbDryMix(int32 * MPT_RESTRICT pDry, int32 * MPT_RESTRICT pWet, int lDryVol, uint32 nSamples) { for (uint32 i=0; i>4) * lDryVol; pDry[i*2+1] += (pWet[i*2+1]>>4) * lDryVol; } } uint32 CReverb::ReverbProcessPreFiltering2x(int32 * MPT_RESTRICT pWet, uint32 nSamples) { uint32 nOutSamples = 0; int lowpass = g_RefDelay.nCoeffs.c.l; int y1_l = g_nLastRvbIn_yl, y1_r = g_nLastRvbIn_yr; uint32 n = nSamples; if (g_bLastInPresent) { int x1_l = g_nLastRvbIn_xl, x1_r = g_nLastRvbIn_xr; int x2_l = pWet[0], x2_r = pWet[1]; x1_l = (x1_l+x2_l)>>13; x1_r = (x1_r+x2_r)>>13; y1_l = x1_l + (((x1_l - y1_l)*lowpass)>>15); y1_r = x1_r + (((x1_r - y1_r)*lowpass)>>15); pWet[0] = y1_l; pWet[1] = y1_r; pWet+=2; n--; nOutSamples = 1; g_bLastInPresent = false; } if (n & 1) { n--; g_nLastRvbIn_xl = pWet[n*2]; g_nLastRvbIn_xr = pWet[n*2+1]; g_bLastInPresent = true; } n >>= 1; for (uint32 i=0; i>13; int x1_r = pWet[i*4+1]; int x2_r = pWet[i*4+3]; x1_r = (x1_r+x2_r)>>13; y1_l = x1_l + (((x1_l - y1_l)*lowpass)>>15); y1_r = x1_r + (((x1_r - y1_r)*lowpass)>>15); pWet[i*2] = y1_l; pWet[i*2+1] = y1_r; } g_nLastRvbIn_yl = y1_l; g_nLastRvbIn_yr = y1_r; return nOutSamples + n; } uint32 CReverb::ReverbProcessPreFiltering1x(int32 * MPT_RESTRICT pWet, uint32 nSamples) { int lowpass = g_RefDelay.nCoeffs.c.l; int y1_l = g_nLastRvbIn_yl, y1_r = g_nLastRvbIn_yr; for (uint32 i=0; i> 12; int x_r = pWet[i*2+1] >> 12; y1_l = x_l + (((x_l - y1_l)*lowpass)>>15); y1_r = x_r + (((x_r - y1_r)*lowpass)>>15); pWet[i*2] = y1_l; pWet[i*2+1] = y1_r; } g_nLastRvbIn_yl = y1_l; g_nLastRvbIn_yr = y1_r; return nSamples; } void CReverb::ReverbProcessPostFiltering2x(const int32 * MPT_RESTRICT pRvb, int32 * MPT_RESTRICT pDry, uint32 nSamples) { uint32 n0 = nSamples, n; int x1_l = g_nLastRvbOut_xl, x1_r = g_nLastRvbOut_xr; if (g_bLastOutPresent) { pDry[0] += x1_l; pDry[1] += x1_r; pDry += 2; n0--; g_bLastOutPresent = false; } n = n0 >> 1; for (uint32 i=0; i>1; pDry[i*4+1] += (x_r + x1_r)>>1; pDry[i*4+2] += x_l; pDry[i*4+3] += x_r; x1_l = x_l; x1_r = x_r; } if (n0 & 1) { int x_l = pRvb[n*2], x_r = pRvb[n*2+1]; pDry[n*4] += (x_l + x1_l)>>1; pDry[n*4+1] += (x_r + x1_r)>>1; x1_l = x_l; x1_r = x_r; g_bLastOutPresent = true; } g_nLastRvbOut_xl = x1_l; g_nLastRvbOut_xr = x1_r; } #define DCR_AMOUNT 9 // Stereo Add + DC removal void CReverb::ReverbProcessPostFiltering1x(const int32 * MPT_RESTRICT pRvb, int32 * MPT_RESTRICT pDry, uint32 nSamples) { #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { __m128i nDCRRvb_Y1 = Load64SSE(gnDCRRvb_Y1); __m128i nDCRRvb_X1 = Load64SSE(gnDCRRvb_X1); __m128i in = _mm_set1_epi32(0); while(nSamples--) { in = Load64SSE(pRvb); pRvb += 2; // x(n-1) - x(n) __m128i diff = _mm_sub_epi32(nDCRRvb_X1, in); nDCRRvb_X1 = _mm_add_epi32(nDCRRvb_Y1, _mm_sub_epi32(_mm_srai_epi32(diff, DCR_AMOUNT + 1), diff)); __m128i out = _mm_add_epi32(Load64SSE(pDry), nDCRRvb_X1); nDCRRvb_Y1 = _mm_sub_epi32(nDCRRvb_X1, _mm_srai_epi32(nDCRRvb_X1, DCR_AMOUNT)); nDCRRvb_X1 = in; Store64SSE(pDry, out); pDry += 2; } Store64SSE(gnDCRRvb_X1, in); Store64SSE(gnDCRRvb_Y1, nDCRRvb_Y1); return; } #endif int32 X1L = gnDCRRvb_X1[0], X1R = gnDCRRvb_X1[1]; int32 Y1L = gnDCRRvb_Y1[0], Y1R = gnDCRRvb_Y1[1]; int32 inL = 0, inR = 0; while(nSamples--) { inL = pRvb[0]; inR = pRvb[1]; pRvb += 2; int32 outL = pDry[0], outR = pDry[1]; // x(n-1) - x(n) X1L -= inL; X1R -= inR; X1L = X1L / (1 << (DCR_AMOUNT + 1)) - X1L; X1R = X1R / (1 << (DCR_AMOUNT + 1)) - X1R; Y1L += X1L; Y1R += X1R; // add to dry mix outL += Y1L; outR += Y1R; Y1L -= Y1L / (1 << DCR_AMOUNT); Y1R -= Y1R / (1 << DCR_AMOUNT); X1L = inL; X1R = inR; pDry[0] = outL; pDry[1] = outR; pDry += 2; } gnDCRRvb_Y1[0] = Y1L; gnDCRRvb_Y1[1] = Y1R; gnDCRRvb_X1[0] = inL; gnDCRRvb_X1[1] = inR; } void CReverb::ReverbDCRemoval(int32 * MPT_RESTRICT pBuffer, uint32 nSamples) { #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { __m128i nDCRRvb_Y1 = Load64SSE(gnDCRRvb_Y1); __m128i nDCRRvb_X1 = Load64SSE(gnDCRRvb_X1); while(nSamples--) { __m128i in = Load64SSE(pBuffer); __m128i diff = _mm_sub_epi32(nDCRRvb_X1, in); __m128i out = _mm_add_epi32(nDCRRvb_Y1, _mm_sub_epi32(_mm_srai_epi32(diff, DCR_AMOUNT + 1), diff)); Store64SSE(pBuffer, out); pBuffer += 2; nDCRRvb_Y1 = _mm_sub_epi32(out, _mm_srai_epi32(out, DCR_AMOUNT)); nDCRRvb_X1 = in; } Store64SSE(gnDCRRvb_X1, nDCRRvb_X1); Store64SSE(gnDCRRvb_Y1, nDCRRvb_Y1); return; } #endif int32 X1L = gnDCRRvb_X1[0], X1R = gnDCRRvb_X1[1]; int32 Y1L = gnDCRRvb_Y1[0], Y1R = gnDCRRvb_Y1[1]; int32 inL = 0, inR = 0; while(nSamples--) { inL = pBuffer[0]; inR = pBuffer[1]; // x(n-1) - x(n) X1L -= inL; X1R -= inR; X1L = X1L / (1 << (DCR_AMOUNT + 1)) - X1L; X1R = X1R / (1 << (DCR_AMOUNT + 1)) - X1R; Y1L += X1L; Y1R += X1R; pBuffer[0] = Y1L; pBuffer[1] = Y1R; pBuffer += 2; Y1L -= Y1L / (1 << DCR_AMOUNT); Y1R -= Y1R / (1 << DCR_AMOUNT); X1L = inL; X1R = inR; } gnDCRRvb_Y1[0] = Y1L; gnDCRRvb_Y1[1] = Y1R; gnDCRRvb_X1[0] = inL; gnDCRRvb_X1[1] = inR; } ////////////////////////////////////////////////////////////////////////// // // Pre-Delay: // // 1. Saturate and low-pass the reverb input (stage 2 of roomHF) // 2. Process pre-diffusion // 3. Insert the result in the reflections delay buffer // // Save some typing static MPT_FORCEINLINE int32 Clamp16(int32 x) { return Clamp(x, std::numeric_limits::min(), std::numeric_limits::max()); } void CReverb::ProcessPreDelay(SWRvbRefDelay * MPT_RESTRICT pPreDelay, const int32 * MPT_RESTRICT pIn, uint32 nSamples) { uint32 preDifPos = pPreDelay->nPreDifPos; uint32 delayPos = pPreDelay->nDelayPos - 1; #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { __m128i coeffs = _mm_cvtsi32_si128(pPreDelay->nCoeffs.lr); __m128i history = _mm_cvtsi32_si128(pPreDelay->History.lr); __m128i preDifCoeffs = _mm_cvtsi32_si128(pPreDelay->nPreDifCoeffs.lr); while(nSamples--) { __m128i in32 = Load64SSE(pIn); // 16-bit unsaturated reverb input [ r | l ] __m128i inSat = _mm_packs_epi32(in32, in32); // [ r | l | r | l ] (16-bit saturated) pIn += 2; // Low-pass __m128i lp = _mm_mulhi_epi16(_mm_subs_epi16(history, inSat), coeffs); __m128i preDif = _mm_cvtsi32_si128(pPreDelay->PreDifBuffer[preDifPos].lr); history = _mm_adds_epi16(_mm_adds_epi16(lp, lp), inSat); // Pre-Diffusion preDifPos = (preDifPos + 1) & SNDMIX_PREDIFFUSION_DELAY_MASK; delayPos = (delayPos + 1) & SNDMIX_REFLECTIONS_DELAY_MASK; __m128i preDif2 = _mm_subs_epi16(history, _mm_mulhi_epi16(preDif, preDifCoeffs)); pPreDelay->PreDifBuffer[preDifPos].lr = _mm_cvtsi128_si32(preDif2); pPreDelay->RefDelayBuffer[delayPos].lr = _mm_cvtsi128_si32(_mm_adds_epi16(_mm_mulhi_epi16(preDifCoeffs, preDif2), preDif)); } pPreDelay->nPreDifPos = preDifPos; pPreDelay->History.lr = _mm_cvtsi128_si32(history); return; } #endif const int32 coeffsL = pPreDelay->nCoeffs.c.l, coeffsR = pPreDelay->nCoeffs.c.r; const int32 preDifCoeffsL = pPreDelay->nPreDifCoeffs.c.l, preDifCoeffsR = pPreDelay->nPreDifCoeffs.c.r; int16 historyL = pPreDelay->History.c.l, historyR = pPreDelay->History.c.r; while(nSamples--) { int32 inL = Clamp16(pIn[0]); int32 inR = Clamp16(pIn[1]); pIn += 2; // Low-pass int32 lpL = (Clamp16(historyL - inL) * coeffsL) / 65536; int32 lpR = (Clamp16(historyR - inR) * coeffsR) / 65536; historyL = mpt::saturate_cast(Clamp16(lpL + lpL) + inL); historyR = mpt::saturate_cast(Clamp16(lpR + lpR) + inR); // Pre-Diffusion int32 preDifL = pPreDelay->PreDifBuffer[preDifPos].c.l; int32 preDifR = pPreDelay->PreDifBuffer[preDifPos].c.r; preDifPos = (preDifPos + 1) & SNDMIX_PREDIFFUSION_DELAY_MASK; delayPos = (delayPos + 1) & SNDMIX_REFLECTIONS_DELAY_MASK; int16 preDif2L = mpt::saturate_cast(historyL - preDifL * preDifCoeffsL / 65536); int16 preDif2R = mpt::saturate_cast(historyR - preDifR * preDifCoeffsR / 65536); pPreDelay->PreDifBuffer[preDifPos].c.l = preDif2L; pPreDelay->PreDifBuffer[preDifPos].c.r = preDif2R; pPreDelay->RefDelayBuffer[delayPos].c.l = mpt::saturate_cast(preDifCoeffsL * preDif2L / 65536 + preDifL); pPreDelay->RefDelayBuffer[delayPos].c.r = mpt::saturate_cast(preDifCoeffsR * preDif2R / 65536 + preDifR); } pPreDelay->nPreDifPos = preDifPos; pPreDelay->History.c.l = historyL; pPreDelay->History.c.r = historyR; } //////////////////////////////////////////////////////////////////// // // ProcessReflections: // First stage: // - process 4 reflections, output to pRefOut // - output results to pRefOut // Second stage: // - process another 3 reflections // - sum with pRefOut // - apply reflections master gain and accumulate in the given output // void CReverb::ProcessReflections(SWRvbRefDelay * MPT_RESTRICT pPreDelay, LR16 * MPT_RESTRICT pRefOut, int32 * MPT_RESTRICT pOut, uint32 nSamples) { #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { union { __m128i xmm; int16 i[8]; } pos; const LR16 *refDelayBuffer = pPreDelay->RefDelayBuffer; #define GETDELAY(x) static_cast(pPreDelay->Reflections[x].Delay) __m128i delayPos = _mm_set_epi16(GETDELAY(7), GETDELAY(6), GETDELAY(5), GETDELAY(4), GETDELAY(3), GETDELAY(2), GETDELAY(1), GETDELAY(0)); #undef GETDELAY delayPos = _mm_sub_epi16(_mm_set1_epi16(static_cast(pPreDelay->nDelayPos - 1)), delayPos); __m128i gain12 = _mm_unpacklo_epi64(Load64SSE(pPreDelay->Reflections[0].Gains), Load64SSE(pPreDelay->Reflections[1].Gains)); __m128i gain34 = _mm_unpacklo_epi64(Load64SSE(pPreDelay->Reflections[2].Gains), Load64SSE(pPreDelay->Reflections[3].Gains)); __m128i gain56 = _mm_unpacklo_epi64(Load64SSE(pPreDelay->Reflections[4].Gains), Load64SSE(pPreDelay->Reflections[5].Gains)); __m128i gain78 = _mm_unpacklo_epi64(Load64SSE(pPreDelay->Reflections[6].Gains), Load64SSE(pPreDelay->Reflections[7].Gains)); // For 28-bit final output: 16+15-3 = 28 __m128i refGain = _mm_srai_epi32(_mm_set_epi32(0, 0, pPreDelay->ReflectionsGain.c.r, pPreDelay->ReflectionsGain.c.l), 3); __m128i delayInc = _mm_set1_epi16(1), delayMask = _mm_set1_epi16(SNDMIX_REFLECTIONS_DELAY_MASK); while(nSamples--) { delayPos = _mm_and_si128(_mm_add_epi16(delayInc, delayPos), delayMask); _mm_storeu_si128(&pos.xmm, delayPos); __m128i ref12 = _mm_set_epi32(refDelayBuffer[pos.i[1]].lr, refDelayBuffer[pos.i[1]].lr, refDelayBuffer[pos.i[0]].lr, refDelayBuffer[pos.i[0]].lr); __m128i ref34 = _mm_set_epi32(refDelayBuffer[pos.i[3]].lr, refDelayBuffer[pos.i[3]].lr, refDelayBuffer[pos.i[2]].lr, refDelayBuffer[pos.i[2]].lr); __m128i ref56 = _mm_set_epi32(refDelayBuffer[pos.i[5]].lr, refDelayBuffer[pos.i[5]].lr, refDelayBuffer[pos.i[4]].lr, refDelayBuffer[pos.i[4]].lr); __m128i ref78 = _mm_set_epi32(0, 0, refDelayBuffer[pos.i[6]].lr, refDelayBuffer[pos.i[6]].lr); // First stage __m128i refOut1 = _mm_add_epi32(_mm_madd_epi16(ref12, gain12), _mm_madd_epi16(ref34, gain34)); refOut1 = _mm_srai_epi32(_mm_add_epi32(refOut1, _mm_shuffle_epi32(refOut1, _MM_SHUFFLE(1, 0, 3, 2))), 15); // Second stage __m128i refOut2 = _mm_add_epi32(_mm_madd_epi16(ref56, gain56), _mm_madd_epi16(ref78, gain78)); refOut2 = _mm_srai_epi32(_mm_add_epi32(refOut2, _mm_shuffle_epi32(refOut2, _MM_SHUFFLE(1, 0, 3, 2))), 15); // Saturate to 16-bit and sum stages __m128i refOut = _mm_adds_epi16(_mm_packs_epi32(refOut1, refOut1), _mm_packs_epi32(refOut2, refOut2)); pRefOut->lr = _mm_cvtsi128_si32(refOut); pRefOut++; __m128i out = _mm_madd_epi16(_mm_unpacklo_epi16(refOut, refOut), refGain); // Apply reflections gain // At this, point, this is the only output of the reverb Store64SSE(pOut, out); pOut += 2; } return; } #endif int pos[7]; for(int i = 0; i < 7; i++) pos[i] = pPreDelay->nDelayPos - pPreDelay->Reflections[i].Delay - 1; // For 28-bit final output: 16+15-3 = 28 int16 refGain = pPreDelay->ReflectionsGain.c.l / (1 << 3); while(nSamples--) { // First stage int32 refOutL = 0, refOutR = 0; for(int i = 0; i < 4; i++) { pos[i] = (pos[i] + 1) & SNDMIX_REFLECTIONS_DELAY_MASK; int16 refL = pPreDelay->RefDelayBuffer[pos[i]].c.l, refR = pPreDelay->RefDelayBuffer[pos[i]].c.r; refOutL += refL * pPreDelay->Reflections[i].Gains[0].c.l + refR * pPreDelay->Reflections[i].Gains[0].c.r; refOutR += refL * pPreDelay->Reflections[i].Gains[1].c.l + refR * pPreDelay->Reflections[i].Gains[1].c.r; } int16 stage1l = mpt::saturate_cast(refOutL / (1 << 15)); int16 stage1r = mpt::saturate_cast(refOutR / (1 << 15)); // Second stage refOutL = 0; refOutR = 0; for(int i = 4; i < 7; i++) { pos[i] = (pos[i] + 1) & SNDMIX_REFLECTIONS_DELAY_MASK; int16 refL = pPreDelay->RefDelayBuffer[pos[i]].c.l, refR = pPreDelay->RefDelayBuffer[pos[i]].c.r; refOutL += refL * pPreDelay->Reflections[i].Gains[0].c.l + refR * pPreDelay->Reflections[i].Gains[0].c.r; refOutR += refL * pPreDelay->Reflections[i].Gains[1].c.l + refR * pPreDelay->Reflections[i].Gains[1].c.r; } pOut[0] = (pRefOut->c.l = mpt::saturate_cast(stage1l + refOutL / (1 << 15))) * refGain; pOut[1] = (pRefOut->c.r = mpt::saturate_cast(stage1r + refOutR / (1 << 15))) * refGain; pRefOut++; pOut += 2; } } ////////////////////////////////////////////////////////////////////////// // // Late reverberation (with SW reflections) // void CReverb::ProcessLateReverb(SWLateReverb * MPT_RESTRICT pReverb, LR16 * MPT_RESTRICT pRefOut, int32 * MPT_RESTRICT pMixOut, uint32 nSamples) { // Calculate delay line offset from current delay position #define DELAY_OFFSET(x) ((delayPos - (x)) & RVBDLY_MASK) #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { int delayPos = pReverb->nDelayPos & RVBDLY_MASK; __m128i rvbOutGains = Load64SSE(pReverb->RvbOutGains); __m128i difCoeffs = Load64SSE(pReverb->nDifCoeffs); __m128i decayLP = Load64SSE(pReverb->nDecayLP); __m128i lpHistory = Load64SSE(pReverb->LPHistory); while(nSamples--) { __m128i refIn = _mm_cvtsi32_si128(pRefOut->lr); // 16-bit stereo input pRefOut++; __m128i delay2 = _mm_unpacklo_epi32( _mm_cvtsi32_si128(pReverb->Delay2[DELAY_OFFSET(RVBDLY2L_LEN)].lr), _mm_cvtsi32_si128(pReverb->Delay2[DELAY_OFFSET(RVBDLY2R_LEN)].lr)); // Unsigned to avoid sign extension uint16 diff1L = pReverb->Diffusion1[DELAY_OFFSET(RVBDIF1L_LEN)].c.l; uint16 diff1R = pReverb->Diffusion1[DELAY_OFFSET(RVBDIF1R_LEN)].c.r; int32 diffusion1 = diff1L | (diff1R << 16); // diffusion1 history uint16 diff2L = pReverb->Diffusion2[DELAY_OFFSET(RVBDIF2L_LEN)].c.l; uint16 diff2R = pReverb->Diffusion2[DELAY_OFFSET(RVBDIF2R_LEN)].c.r; int32 diffusion2 = diff2L | (diff2R << 16); // diffusion2 history __m128i lpDecay = _mm_mulhi_epi16(_mm_subs_epi16(lpHistory, delay2), decayLP); lpHistory = _mm_adds_epi16(_mm_adds_epi16(lpDecay, lpDecay), delay2); // Low-passed decay // Apply decay gain __m128i histDecay = _mm_srai_epi32(_mm_madd_epi16(Load64SSE(pReverb->nDecayDC), lpHistory), 15); __m128i histDecayPacked = _mm_shuffle_epi32(_mm_packs_epi32(histDecay, histDecay), _MM_SHUFFLE(2, 0, 2, 0)); __m128i histDecayIn = _mm_adds_epi16(histDecayPacked, _mm_srai_epi16(_mm_unpacklo_epi32(refIn, refIn), 2)); __m128i histDecayInDiff = _mm_subs_epi16(histDecayIn, _mm_mulhi_epi16(_mm_cvtsi32_si128(diffusion1), difCoeffs)); pReverb->Diffusion1[delayPos].lr = _mm_cvtsi128_si32(histDecayInDiff); __m128i delay1Out = _mm_adds_epi16(_mm_mulhi_epi16(difCoeffs, histDecayInDiff), _mm_cvtsi32_si128(diffusion1)); // Insert the diffusion output in the reverb delay line pReverb->Delay1[delayPos].lr = _mm_cvtsi128_si32(delay1Out); __m128i histDecayInDelay = _mm_adds_epi16(histDecayIn, _mm_unpacklo_epi32(delay1Out, delay1Out)); // Input to second diffuser __m128i delay1 = _mm_unpacklo_epi32( _mm_cvtsi32_si128(pReverb->Delay1[DELAY_OFFSET(RVBDLY1L_LEN)].lr), _mm_cvtsi32_si128(pReverb->Delay1[DELAY_OFFSET(RVBDLY1R_LEN)].lr)); __m128i delay1Gains = _mm_srai_epi32(_mm_madd_epi16(delay1, Load64SSE(pReverb->Dif2InGains)), 15); __m128i delay1GainsSat = _mm_shuffle_epi32(_mm_packs_epi32(delay1Gains, delay1Gains), _MM_SHUFFLE(2, 0, 2, 0)); __m128i histDelay1 = _mm_subs_epi16(_mm_adds_epi16(histDecayInDelay, delay1), delay1GainsSat); // accumulate with reverb output __m128i diff2out = _mm_subs_epi16(delay1GainsSat, _mm_mulhi_epi16(_mm_cvtsi32_si128(diffusion2), difCoeffs)); __m128i diff2outCoeffs = _mm_mulhi_epi16(difCoeffs, diff2out); pReverb->Diffusion2[delayPos].lr = _mm_cvtsi128_si32(diff2out); __m128i mixOut = Load64SSE(pMixOut); __m128i delay2out = _mm_adds_epi16(diff2outCoeffs, _mm_cvtsi32_si128(diffusion2)); pReverb->Delay2[delayPos].lr = _mm_cvtsi128_si32(delay2out); delayPos = (delayPos + 1) & RVBDLY_MASK; // Accumulate with reverb output __m128i out = _mm_add_epi32(_mm_madd_epi16(_mm_adds_epi16(histDelay1, delay2out), rvbOutGains), mixOut); Store64SSE(pMixOut, out); pMixOut += 2; } Store64SSE(pReverb->LPHistory, lpHistory); pReverb->nDelayPos = delayPos; return; } #endif int delayPos = pReverb->nDelayPos & RVBDLY_MASK; while(nSamples--) { int16 refInL = pRefOut->c.l, refInR = pRefOut->c.r; pRefOut++; int32 delay2LL = pReverb->Delay2[DELAY_OFFSET(RVBDLY2L_LEN)].c.l, delay2LR = pReverb->Delay2[DELAY_OFFSET(RVBDLY2L_LEN)].c.r; int32 delay2RL = pReverb->Delay2[DELAY_OFFSET(RVBDLY2R_LEN)].c.l, delay2RR = pReverb->Delay2[DELAY_OFFSET(RVBDLY2R_LEN)].c.r; int32 diff1L = pReverb->Diffusion1[DELAY_OFFSET(RVBDIF1L_LEN)].c.l; int32 diff1R = pReverb->Diffusion1[DELAY_OFFSET(RVBDIF1R_LEN)].c.r; int32 diff2L = pReverb->Diffusion2[DELAY_OFFSET(RVBDIF2L_LEN)].c.l; int32 diff2R = pReverb->Diffusion2[DELAY_OFFSET(RVBDIF2R_LEN)].c.r; int32 lpDecayLL = Clamp16(pReverb->LPHistory[0].c.l - delay2LL) * pReverb->nDecayLP[0].c.l / 65536; int32 lpDecayLR = Clamp16(pReverb->LPHistory[0].c.r - delay2LR) * pReverb->nDecayLP[0].c.r / 65536; int32 lpDecayRL = Clamp16(pReverb->LPHistory[1].c.l - delay2RL) * pReverb->nDecayLP[1].c.l / 65536; int32 lpDecayRR = Clamp16(pReverb->LPHistory[1].c.r - delay2RR) * pReverb->nDecayLP[1].c.r / 65536; // Low-passed decay pReverb->LPHistory[0].c.l = mpt::saturate_cast(Clamp16(lpDecayLL + lpDecayLL) + delay2LL); pReverb->LPHistory[0].c.r = mpt::saturate_cast(Clamp16(lpDecayLR + lpDecayLR) + delay2LR); pReverb->LPHistory[1].c.l = mpt::saturate_cast(Clamp16(lpDecayRL + lpDecayRL) + delay2RL); pReverb->LPHistory[1].c.r = mpt::saturate_cast(Clamp16(lpDecayRR + lpDecayRR) + delay2RR); // Apply decay gain int32 histDecayL = Clamp16((int32)pReverb->nDecayDC[0].c.l * pReverb->LPHistory[0].c.l / (1 << 15)); int32 histDecayR = Clamp16((int32)pReverb->nDecayDC[1].c.r * pReverb->LPHistory[1].c.r / (1 << 15)); int32 histDecayInL = Clamp16(histDecayL + refInL / 4); int32 histDecayInR = Clamp16(histDecayR + refInR / 4); int32 histDecayInDiffL = Clamp16(histDecayInL - diff1L * pReverb->nDifCoeffs[0].c.l / 65536); int32 histDecayInDiffR = Clamp16(histDecayInR - diff1R * pReverb->nDifCoeffs[0].c.r / 65536); pReverb->Diffusion1[delayPos].c.l = static_cast(histDecayInDiffL); pReverb->Diffusion1[delayPos].c.r = static_cast(histDecayInDiffR); int32 delay1L = Clamp16(pReverb->nDifCoeffs[0].c.l * histDecayInDiffL / 65536 + diff1L); int32 delay1R = Clamp16(pReverb->nDifCoeffs[0].c.r * histDecayInDiffR / 65536 + diff1R); // Insert the diffusion output in the reverb delay line pReverb->Delay1[delayPos].c.l = static_cast(delay1L); pReverb->Delay1[delayPos].c.r = static_cast(delay1R); int32 histDecayInDelayL = Clamp16(histDecayInL + delay1L); int32 histDecayInDelayR = Clamp16(histDecayInR + delay1R); // Input to second diffuser int32 delay1LL = pReverb->Delay1[DELAY_OFFSET(RVBDLY1L_LEN)].c.l, delay1LR = pReverb->Delay1[DELAY_OFFSET(RVBDLY1L_LEN)].c.r; int32 delay1RL = pReverb->Delay1[DELAY_OFFSET(RVBDLY1R_LEN)].c.l, delay1RR = pReverb->Delay1[DELAY_OFFSET(RVBDLY1R_LEN)].c.r; int32 delay1GainsL = Clamp16((delay1LL * pReverb->Dif2InGains[0].c.l + delay1LR * pReverb->Dif2InGains[0].c.r) / (1 << 15)); int32 delay1GainsR = Clamp16((delay1RL * pReverb->Dif2InGains[1].c.l + delay1RR * pReverb->Dif2InGains[1].c.r) / (1 << 15)); // accumulate with reverb output int32 histDelay1LL = Clamp16(Clamp16(histDecayInDelayL + delay1LL) - delay1GainsL); int32 histDelay1LR = Clamp16(Clamp16(histDecayInDelayR + delay1LR) - delay1GainsR); int32 histDelay1RL = Clamp16(Clamp16(histDecayInDelayL + delay1RL) - delay1GainsL); int32 histDelay1RR = Clamp16(Clamp16(histDecayInDelayR + delay1RR) - delay1GainsR); int32 diff2outL = Clamp16(delay1GainsL - diff2L * pReverb->nDifCoeffs[0].c.l / 65536); int32 diff2outR = Clamp16(delay1GainsR - diff2R * pReverb->nDifCoeffs[0].c.r / 65536); int32 diff2outCoeffsL = pReverb->nDifCoeffs[0].c.l * diff2outL / 65536; int32 diff2outCoeffsR = pReverb->nDifCoeffs[0].c.r * diff2outR / 65536; pReverb->Diffusion2[delayPos].c.l = static_cast(diff2outL); pReverb->Diffusion2[delayPos].c.r = static_cast(diff2outR); int32 delay2outL = Clamp16(diff2outCoeffsL + diff2L); int32 delay2outR = Clamp16(diff2outCoeffsR + diff2R); pReverb->Delay2[delayPos].c.l = static_cast(delay2outL); pReverb->Delay2[delayPos].c.r = static_cast(delay2outR); delayPos = (delayPos + 1) & RVBDLY_MASK; // Accumulate with reverb output pMixOut[0] += Clamp16(histDelay1LL + delay2outL) * pReverb->RvbOutGains[0].c.l + Clamp16(histDelay1LR + delay2outR) * pReverb->RvbOutGains[0].c.r; pMixOut[1] += Clamp16(histDelay1RL + Clamp16(diff2outCoeffsL)) * pReverb->RvbOutGains[1].c.l + Clamp16(histDelay1RR + Clamp16(diff2outCoeffsR)) * pReverb->RvbOutGains[1].c.r; pMixOut += 2; } pReverb->nDelayPos = delayPos; #undef DELAY_OFFSET } #else MPT_MSVC_WORKAROUND_LNK4221(Reverb) #endif // NO_REVERB OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/sounddsp/DSP.cpp0000644000175000017500000002655614053010430017253 00000000000000/* * DSP.cpp * ----------- * Purpose: Mixing code for various DSPs (EQ, Mega-Bass, ...) * Notes : Ugh... This should really be removed at some point. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "DSP.h" #include "openmpt/soundbase/MixSample.hpp" #include OPENMPT_NAMESPACE_BEGIN #ifndef NO_DSP // Bass Expansion #define DEFAULT_XBASS_RANGE 14 // (x+2)*20 Hz (320Hz) #define DEFAULT_XBASS_DEPTH 6 // 1+(3>>(x-4)) (+6dB) //////////////////////////////////////////////////////////////////// // DSP Effects internal state static void X86_StereoDCRemoval(int *, uint32 count, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l, int32 &nDCRFlt_Y1r, int32 &nDCRFlt_X1r); static void X86_MonoDCRemoval(int *, uint32 count, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l); /////////////////////////////////////////////////////////////////////////////////// // // Biquad setup // #define PI 3.14159265358979323f static inline float Sgn(float x) { return (x >= 0) ? 1.0f : -1.0f; } static void ShelfEQ(int32 scale, int32 &outA1, int32 &outB0, int32 &outB1, int32 F_c, int32 F_s, float gainDC, float gainFT, float gainPI) { float a1, b0, b1; float gainFT2, gainDC2, gainPI2; float alpha, beta0, beta1, rho; float wT, quad; wT = PI * F_c / F_s; gainPI2 = gainPI * gainPI; gainFT2 = gainFT * gainFT; gainDC2 = gainDC * gainDC; quad = gainPI2 + gainDC2 - (gainFT2*2); alpha = 0; if (quad != 0) { float lambda = (gainPI2 - gainDC2) / quad; alpha = (float)(lambda - Sgn(lambda)*sqrt(lambda*lambda - 1.0f)); } beta0 = 0.5f * ((gainDC + gainPI) + (gainDC - gainPI) * alpha); beta1 = 0.5f * ((gainDC - gainPI) + (gainDC + gainPI) * alpha); rho = (float)((sin((wT*0.5f) - (PI/4.0f))) / (sin((wT*0.5f) + (PI/4.0f)))); quad = 1.0f / (1.0f + rho*alpha); b0 = ((beta0 + rho*beta1) * quad); b1 = ((beta1 + rho*beta0) * quad); a1 = - ((rho + alpha) * quad); outA1 = mpt::saturate_round(a1 * scale); outB0 = mpt::saturate_round(b0 * scale); outB1 = mpt::saturate_round(b1 * scale); } CSurroundSettings::CSurroundSettings() : m_nProLogicDepth(12), m_nProLogicDelay(20) { } CMegaBassSettings::CMegaBassSettings() : m_nXBassDepth(DEFAULT_XBASS_DEPTH), m_nXBassRange(DEFAULT_XBASS_RANGE) { } CSurround::CSurround() { // Surround Encoding: 1 delay line + low-pass filter + high-pass filter nSurroundSize = 0; nSurroundPos = 0; nDolbyDepth = 0; // Surround Biquads nDolbyHP_Y1 = 0; nDolbyHP_X1 = 0; nDolbyLP_Y1 = 0; nDolbyHP_B0 = 0; nDolbyHP_B1 = 0; nDolbyHP_A1 = 0; nDolbyLP_B0 = 0; nDolbyLP_B1 = 0; nDolbyLP_A1 = 0; MemsetZero(SurroundBuffer); } CMegaBass::CMegaBass() { // Bass Expansion: low-pass filter nXBassFlt_Y1 = 0; nXBassFlt_X1 = 0; nXBassFlt_B0 = 0; nXBassFlt_B1 = 0; nXBassFlt_A1 = 0; // DC Removal Biquad nDCRFlt_Y1lf = 0; nDCRFlt_X1lf = 0; nDCRFlt_Y1rf = 0; nDCRFlt_X1rf = 0; nDCRFlt_Y1lb = 0; nDCRFlt_X1lb = 0; nDCRFlt_Y1rb = 0; nDCRFlt_X1rb = 0; } void CSurround::Initialize(bool bReset, DWORD MixingFreq) { MPT_UNREFERENCED_PARAMETER(bReset); if (!m_Settings.m_nProLogicDelay) m_Settings.m_nProLogicDelay = 20; // Pro-Logic Surround nSurroundPos = nSurroundSize = 0; { memset(SurroundBuffer, 0, sizeof(SurroundBuffer)); nSurroundSize = (MixingFreq * m_Settings.m_nProLogicDelay) / 1000; if (nSurroundSize > SURROUNDBUFFERSIZE) nSurroundSize = SURROUNDBUFFERSIZE; nDolbyDepth = m_Settings.m_nProLogicDepth; if (nDolbyDepth < 1) nDolbyDepth = 1; if (nDolbyDepth > 16) nDolbyDepth = 16; // Setup biquad filters ShelfEQ(1024, nDolbyHP_A1, nDolbyHP_B0, nDolbyHP_B1, 200, MixingFreq, 0, 0.5f, 1); ShelfEQ(1024, nDolbyLP_A1, nDolbyLP_B0, nDolbyLP_B1, 7000, MixingFreq, 1, 0.75f, 0); nDolbyHP_X1 = nDolbyHP_Y1 = 0; nDolbyLP_Y1 = 0; // Surround Level nDolbyHP_B0 = (nDolbyHP_B0 * nDolbyDepth) >> 5; nDolbyHP_B1 = (nDolbyHP_B1 * nDolbyDepth) >> 5; // +6dB nDolbyLP_B0 *= 2; nDolbyLP_B1 *= 2; } } void CMegaBass::Initialize(bool bReset, DWORD MixingFreq) { // Bass Expansion Reset { int32 a1 = 0, b0 = 1024, b1 = 0; int nXBassCutOff = 50 + (m_Settings.m_nXBassRange+2) * 20; int nXBassGain = m_Settings.m_nXBassDepth; nXBassGain = std::clamp(nXBassGain, 2, 8); nXBassCutOff = std::clamp(nXBassCutOff, 60, 600); ShelfEQ(1024, a1, b0, b1, nXBassCutOff, MixingFreq, 1.0f + (1.0f/16.0f) * (0x300 >> nXBassGain), 1.0f, 0.0000001f); if (nXBassGain > 5) { b0 >>= (nXBassGain-5); b1 >>= (nXBassGain-5); } nXBassFlt_A1 = a1; nXBassFlt_B0 = b0; nXBassFlt_B1 = b1; //Log("b0=%d b1=%d a1=%d\n", b0, b1, a1); } if (bReset) { nXBassFlt_X1 = 0; nXBassFlt_Y1 = 0; nDCRFlt_X1lf = 0; nDCRFlt_X1rf = 0; nDCRFlt_Y1lf = 0; nDCRFlt_Y1rf = 0; nDCRFlt_X1lb = 0; nDCRFlt_X1rb = 0; nDCRFlt_Y1lb = 0; nDCRFlt_Y1rb = 0; } } // 2-channel surround void CSurround::ProcessStereoSurround(int * MixSoundBuffer, int count) { int *pr = MixSoundBuffer, hy1 = nDolbyHP_Y1; for (int r=count; r; r--) { // Delay int secho = SurroundBuffer[nSurroundPos]; SurroundBuffer[nSurroundPos] = (pr[0]+pr[1]+256) >> 9; // High-pass int v0 = (nDolbyHP_B0 * secho + nDolbyHP_B1 * nDolbyHP_X1 + nDolbyHP_A1 * hy1) >> 10; nDolbyHP_X1 = secho; // Low-pass int v = (nDolbyLP_B0 * v0 + nDolbyLP_B1 * hy1 + nDolbyLP_A1 * nDolbyLP_Y1) >> (10-8); hy1 = v0; nDolbyLP_Y1 = v >> 8; // Add echo pr[0] += v; pr[1] -= v; if (++nSurroundPos >= nSurroundSize) nSurroundPos = 0; pr += 2; } nDolbyHP_Y1 = hy1; } // 4-channels surround void CSurround::ProcessQuadSurround(int * MixSoundBuffer, int * MixRearBuffer, int count) { int *pr = MixSoundBuffer, hy1 = nDolbyHP_Y1; for (int r=count; r; r--) { int vl = pr[0] >> 1; int vr = pr[1] >> 1; pr[(uint32)(MixRearBuffer-MixSoundBuffer)] += vl; pr[((uint32)(MixRearBuffer-MixSoundBuffer))+1] += vr; // Delay int secho = SurroundBuffer[nSurroundPos]; SurroundBuffer[nSurroundPos] = (vr+vl+256) >> 9; // High-pass int v0 = (nDolbyHP_B0 * secho + nDolbyHP_B1 * nDolbyHP_X1 + nDolbyHP_A1 * hy1) >> 10; nDolbyHP_X1 = secho; // Low-pass int v = (nDolbyLP_B0 * v0 + nDolbyLP_B1 * hy1 + nDolbyLP_A1 * nDolbyLP_Y1) >> (10-8); hy1 = v0; nDolbyLP_Y1 = v >> 8; // Add echo pr[(uint32)(MixRearBuffer-MixSoundBuffer)] += v; pr[((uint32)(MixRearBuffer-MixSoundBuffer))+1] += v; if (++nSurroundPos >= nSurroundSize) nSurroundPos = 0; pr += 2; } nDolbyHP_Y1 = hy1; } void CSurround::Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels) { if(nChannels >= 2) // Dolby Pro-Logic Surround { if (nChannels > 2) ProcessQuadSurround(MixSoundBuffer, MixRearBuffer, count); else ProcessStereoSurround(MixSoundBuffer, count); } } void CMegaBass::Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels) { if(nChannels >= 2) { X86_StereoDCRemoval(MixSoundBuffer, count, nDCRFlt_Y1lf, nDCRFlt_X1lf, nDCRFlt_Y1rf, nDCRFlt_X1rf); if(nChannels > 2) X86_StereoDCRemoval(MixRearBuffer, count, nDCRFlt_Y1lb, nDCRFlt_X1lb, nDCRFlt_Y1rb, nDCRFlt_X1rb); int *px = MixSoundBuffer; int *py = MixRearBuffer; int x1 = nXBassFlt_X1; int y1 = nXBassFlt_Y1; if(nChannels > 2) for (int x=count; x; x--) { int x_m = (px[0]+px[1]+py[0]+py[1]+0x100)>>9; y1 = (nXBassFlt_B0 * x_m + nXBassFlt_B1 * x1 + nXBassFlt_A1 * y1) >> (10-8); x1 = x_m; px[0] += y1; px[1] += y1; py[0] += y1; py[1] += y1; y1 = (y1+0x80) >> 8; px += 2; py += 2; } else for (int x=count; x; x--) { int x_m = (px[0]+px[1]+0x100)>>9; y1 = (nXBassFlt_B0 * x_m + nXBassFlt_B1 * x1 + nXBassFlt_A1 * y1) >> (10-8); x1 = x_m; px[0] += y1; px[1] += y1; y1 = (y1+0x80) >> 8; px += 2; } nXBassFlt_X1 = x1; nXBassFlt_Y1 = y1; } else { X86_MonoDCRemoval(MixSoundBuffer, count, nDCRFlt_Y1lf, nDCRFlt_X1lf); int *px = MixSoundBuffer; int x1 = nXBassFlt_X1; int y1 = nXBassFlt_Y1; for (int x=count; x; x--) { int x_m = (px[0]+0x80)>>8; y1 = (nXBassFlt_B0 * x_m + nXBassFlt_B1 * x1 + nXBassFlt_A1 * y1) >> (10-8); x1 = x_m; px[0] += y1; y1 = (y1+0x40) >> 8; px++; } nXBassFlt_X1 = x1; nXBassFlt_Y1 = y1; } } ////////////////////////////////////////////////////////////////////////// // // DC Removal // #define DCR_AMOUNT 9 static void X86_StereoDCRemoval(int *pBuffer, uint32 nSamples, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l, int32 &nDCRFlt_Y1r, int32 &nDCRFlt_X1r) { int y1l = nDCRFlt_Y1l, x1l = nDCRFlt_X1l; int y1r = nDCRFlt_Y1r, x1r = nDCRFlt_X1r; while(nSamples--) { int inL = pBuffer[0]; int inR = pBuffer[1]; int diffL = x1l - inL; int diffR = x1r - inR; x1l = inL; x1r = inR; int outL = diffL / (1 << (DCR_AMOUNT + 1)) - diffL + y1l; int outR = diffR / (1 << (DCR_AMOUNT + 1)) - diffR + y1r; pBuffer[0] = outL; pBuffer[1] = outR; pBuffer += 2; y1l = outL - outL / (1 << DCR_AMOUNT); y1r = outR - outR / (1 << DCR_AMOUNT); } nDCRFlt_Y1l = y1l; nDCRFlt_X1l = x1l; nDCRFlt_Y1r = y1r; nDCRFlt_X1r = x1r; } static void X86_MonoDCRemoval(int *pBuffer, uint32 nSamples, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l) { int y1l = nDCRFlt_Y1l, x1l = nDCRFlt_X1l; while(nSamples--) { int inM = pBuffer[0]; int diff = x1l - inM; x1l = inM; pBuffer[0] = inM = diff / (1 << (DCR_AMOUNT + 1)) - diff + y1l; pBuffer++; y1l = inM - inM / (1 << DCR_AMOUNT); } nDCRFlt_Y1l = y1l; nDCRFlt_X1l = x1l; } ///////////////////////////////////////////////////////////////// // Clean DSP Effects interface // [XBass level 0(quiet)-100(loud)], [cutoff in Hz 20-100] void CMegaBass::SetXBassParameters(uint32 nDepth, uint32 nRange) { if (nDepth > 100) nDepth = 100; uint32 gain = nDepth / 20; if (gain > 4) gain = 4; m_Settings.m_nXBassDepth = 8 - gain; // filter attenuation 1/256 .. 1/16 uint32 range = nRange / 5; if (range > 5) range -= 5; else range = 0; if (nRange > 16) nRange = 16; m_Settings.m_nXBassRange = 21 - range; // filter average on 0.5-1.6ms } // [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-50ms] void CSurround::SetSurroundParameters(uint32 nDepth, uint32 nDelay) { uint32 gain = (nDepth * 16) / 100; if (gain > 16) gain = 16; if (gain < 1) gain = 1; m_Settings.m_nProLogicDepth = gain; if (nDelay < 4) nDelay = 4; if (nDelay > 50) nDelay = 50; m_Settings.m_nProLogicDelay = nDelay; } BitCrushSettings::BitCrushSettings() : m_Bits(8) { return; } BitCrush::BitCrush() { } void BitCrush::Initialize(bool bReset, DWORD MixingFreq) { MPT_UNREFERENCED_PARAMETER(bReset); MPT_UNREFERENCED_PARAMETER(MixingFreq); } void BitCrush::Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels) { if(m_Settings.m_Bits <= 0) { return; } if(m_Settings.m_Bits > MixSampleIntTraits::mix_precision_bits) { return; } unsigned int mask = ~((1u << (MixSampleIntTraits::mix_precision_bits - m_Settings.m_Bits)) - 1u); if(nChannels == 4) { for(int frame = 0; frame < count; ++frame) { MixSoundBuffer[frame*2 + 0] &= mask; MixSoundBuffer[frame*2 + 1] &= mask; MixRearBuffer[frame*2 + 0] &= mask; MixRearBuffer[frame*2 + 1] &= mask; } } else if(nChannels == 2) { for(int frame = 0; frame < count; ++frame) { MixSoundBuffer[frame*2 + 0] &= mask; MixSoundBuffer[frame*2 + 1] &= mask; } } else if(nChannels == 1) { for(int frame = 0; frame < count; ++frame) { MixSoundBuffer[frame] &= mask; } } } #else MPT_MSVC_WORKAROUND_LNK4221(DSP) #endif // NO_DSP OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/sounddsp/EQ.cpp0000644000175000017500000001353714767226027017154 00000000000000/* * EQ.cpp * ------ * Purpose: Mixing code for equalizer. * Notes : Ugh... This should really be removed at some point. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "EQ.h" #include "mpt/audio/span.hpp" #include "mpt/base/numbers.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/soundbase/MixSample.hpp" #include "openmpt/soundbase/MixSampleConvert.hpp" #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE) #include "../common/mptCPU.h" #endif #include #include #include #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE) && defined(MPT_ARCH_INTRINSICS_X86_SSE) #if MPT_COMPILER_MSVC #include #endif #include #endif OPENMPT_NAMESPACE_BEGIN #ifndef NO_EQ static constexpr float EQ_BANDWIDTH = 2.0f; static constexpr std::array gEqLinearToDB = { 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52, 55, 58, 61, 64, 76, 88, 100, 112, 124, 136, 148, 160, 172, 184, 196, 208, 220, 232, 244, 256 }; static constexpr std::array gEQDefaults = {{ // Default: Flat EQ {0,0,0,0,0, 1, 120}, {0,0,0,0,0, 1, 600}, {0,0,0,0,0, 1, 1200}, {0,0,0,0,0, 1, 3000}, {0,0,0,0,0, 1, 6000}, {0,0,0,0,0, 1, 10000} }}; template static void EQFilter(Tbuf & buf, const std::array &bands, std::array, MAX_EQ_CHANNELS> &states) { for(std::size_t frame = 0; frame < buf.size_frames(); ++frame) { for(std::size_t channel = 0; channel < channels; ++channel) { float sample = mix_sample_cast(buf(channel, frame)); for(std::size_t b = 0; b < std::size(bands); ++b) { const EQBANDSETTINGS &band = bands[b]; if(band.Gain != 1.0f) { EQBANDSTATE &bandState = states[channel][b]; float x = sample; float y = band.a1 * bandState.x1 + band.a2 * bandState.x2 + band.a0 * x + band.b1 * bandState.y1 + band.b2 * bandState.y2; bandState.x2 = bandState.x1; bandState.y2 = bandState.y1; bandState.x1 = x; bandState.y1 = y; sample = y; } } buf(channel, frame) = mix_sample_cast(sample); } } } template void CEQ::ProcessTemplate(TMixSample *frontBuffer, TMixSample *rearBuffer, std::size_t countFrames, std::size_t numChannels) { #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE) && defined(MPT_ARCH_INTRINSICS_X86_SSE) unsigned int old_csr = 0; if(CPU::HasFeatureSet(CPU::feature::sse) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { old_csr = _mm_getcsr(); _mm_setcsr((old_csr & ~(_MM_DENORMALS_ZERO_MASK | _MM_FLUSH_ZERO_MASK)) | _MM_DENORMALS_ZERO_ON | _MM_FLUSH_ZERO_ON); } #endif if(numChannels == 1) { mpt::audio_span_interleaved buf{ frontBuffer, 1, countFrames }; EQFilter<1>(buf, m_Bands, m_ChannelState); } else if(numChannels == 2) { mpt::audio_span_interleaved buf{ frontBuffer, 2, countFrames }; EQFilter<2>(buf, m_Bands, m_ChannelState); } else if(numChannels == 4) { std::array buffers = { &frontBuffer[0], &frontBuffer[1], &rearBuffer[0], &rearBuffer[1] }; mpt::audio_span_planar_strided buf{ buffers.data(), 4, countFrames, 2 }; EQFilter<4>(buf, m_Bands, m_ChannelState); } #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE) && defined(MPT_ARCH_INTRINSICS_X86_SSE) if(CPU::HasFeatureSet(CPU::feature::sse) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { _mm_setcsr(old_csr); } #endif } void CEQ::Process(MixSampleInt *frontBuffer, MixSampleInt *rearBuffer, std::size_t countFrames, std::size_t numChannels) { ProcessTemplate(frontBuffer, rearBuffer, countFrames, numChannels); } void CEQ::Process(MixSampleFloat *frontBuffer, MixSampleFloat *rearBuffer, std::size_t countFrames, std::size_t numChannels) { ProcessTemplate(frontBuffer, rearBuffer, countFrames, numChannels); } CEQ::CEQ() : m_Bands(gEQDefaults) { return; } void CEQ::Initialize(bool bReset, uint32 MixingFreq) { float fMixingFreq = static_cast(MixingFreq); // Gain = 0.5 (-6dB) .. 2 (+6dB) for(std::size_t band = 0; band < MAX_EQ_BANDS; ++band) { float k, k2, r, f; float v0, v1; bool b = bReset; f = m_Bands[band].CenterFrequency / fMixingFreq; if(f > 0.45f) { m_Bands[band].Gain = 1.0f; } k = f * mpt::numbers::pi_v; k = k + k*f; k2 = k*k; v0 = m_Bands[band].Gain; v1 = 1; if(m_Bands[band].Gain < 1.0f) { v0 *= (0.5f/EQ_BANDWIDTH); v1 *= (0.5f/EQ_BANDWIDTH); } else { v0 *= (1.0f/EQ_BANDWIDTH); v1 *= (1.0f/EQ_BANDWIDTH); } r = (1 + v0*k + k2) / (1 + v1*k + k2); if(r != m_Bands[band].a0) { m_Bands[band].a0 = r; b = true; } r = 2 * (k2 - 1) / (1 + v1*k + k2); if(r != m_Bands[band].a1) { m_Bands[band].a1 = r; b = true; } r = (1 - v0*k + k2) / (1 + v1*k + k2); if(r != m_Bands[band].a2) { m_Bands[band].a2 = r; b = true; } r = - 2 * (k2 - 1) / (1 + v1*k + k2); if(r != m_Bands[band].b1) { m_Bands[band].b1 = r; b = true; } r = - (1 - v1*k + k2) / (1 + v1*k + k2); if(r != m_Bands[band].b2) { m_Bands[band].b2 = r; b = true; } if(b) { for(std::size_t channel = 0; channel < MAX_EQ_CHANNELS; ++channel) { m_ChannelState[channel][band] = EQBANDSTATE{}; } } } } void CEQ::SetEQGains(const uint32 *pGains, const uint32 *pFreqs, bool bReset, uint32 MixingFreq) { for(std::size_t i = 0; i < MAX_EQ_BANDS; ++i) { m_Bands[i].Gain = static_cast(gEqLinearToDB[std::clamp(pGains[i], static_cast(0), static_cast(std::size(gEqLinearToDB) - 1))]) / 64.0f; m_Bands[i].CenterFrequency = static_cast(pFreqs[i]); } Initialize(bReset, MixingFreq); } #else MPT_MSVC_WORKAROUND_LNK4221(EQ) #endif // !NO_EQ OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/sounddsp/DSP.h0000644000175000017500000000562114052666041016724 00000000000000/* * DSP.h * ----- * Purpose: Mixing code for various DSPs (EQ, Mega-Bass, ...) * Notes : Ugh... This should really be removed at some point. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "openmpt/all/BuildSettings.hpp" OPENMPT_NAMESPACE_BEGIN #ifndef NO_DSP // Buffer Sizes #define SURROUNDBUFFERSIZE 2048 // 50ms @ 48kHz class CSurroundSettings { public: uint32 m_nProLogicDepth; uint32 m_nProLogicDelay; public: CSurroundSettings(); }; class CMegaBassSettings { public: uint32 m_nXBassDepth; uint32 m_nXBassRange; public: CMegaBassSettings(); }; struct BitCrushSettings { int m_Bits; BitCrushSettings(); }; class CSurround { public: CSurroundSettings m_Settings; // Surround Encoding: 1 delay line + low-pass filter + high-pass filter int32 nSurroundSize; int32 nSurroundPos; int32 nDolbyDepth; // Surround Biquads int32 nDolbyHP_Y1; int32 nDolbyHP_X1; int32 nDolbyLP_Y1; int32 nDolbyHP_B0; int32 nDolbyHP_B1; int32 nDolbyHP_A1; int32 nDolbyLP_B0; int32 nDolbyLP_B1; int32 nDolbyLP_A1; int32 SurroundBuffer[SURROUNDBUFFERSIZE]; public: CSurround(); public: void SetSettings(const CSurroundSettings &settings) { m_Settings = settings; } // [XBass level 0(quiet)-100(loud)], [cutoff in Hz 10-100] bool SetXBassParameters(uint32 nDepth, uint32 nRange); // [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-40ms] void SetSurroundParameters(uint32 nDepth, uint32 nDelay); void Initialize(bool bReset, DWORD MixingFreq); void Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels); private: void ProcessStereoSurround(int * MixSoundBuffer, int count); void ProcessQuadSurround(int * MixSoundBuffer, int * MixRearBuffer, int count); }; class CMegaBass { public: CMegaBassSettings m_Settings; // Bass Expansion: low-pass filter int32 nXBassFlt_Y1; int32 nXBassFlt_X1; int32 nXBassFlt_B0; int32 nXBassFlt_B1; int32 nXBassFlt_A1; // DC Removal Biquad int32 nDCRFlt_Y1lf; int32 nDCRFlt_X1lf; int32 nDCRFlt_Y1rf; int32 nDCRFlt_X1rf; int32 nDCRFlt_Y1lb; int32 nDCRFlt_X1lb; int32 nDCRFlt_Y1rb; int32 nDCRFlt_X1rb; public: CMegaBass(); public: void SetSettings(const CMegaBassSettings &settings) { m_Settings = settings; } // [XBass level 0(quiet)-100(loud)], [cutoff in Hz 10-100] void SetXBassParameters(uint32 nDepth, uint32 nRange); void Initialize(bool bReset, DWORD MixingFreq); void Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels); }; class BitCrush { public: BitCrushSettings m_Settings; public: BitCrush(); public: void SetSettings(const BitCrushSettings &settings) { m_Settings = settings; } void Initialize(bool bReset, DWORD MixingFreq); void Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels); }; #endif // NO_DSP OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/sounddsp/AGC.cpp0000644000175000017500000000631414616245151017224 00000000000000/* * AGC.cpp * ------- * Purpose: Automatic Gain Control * Notes : Ugh... This should really be removed at some point. * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "../sounddsp/AGC.h" OPENMPT_NAMESPACE_BEGIN ////////////////////////////////////////////////////////////////////////////////// // Automatic Gain Control #ifndef NO_AGC #define AGC_PRECISION 10 #define AGC_UNITY (1 << AGC_PRECISION) // Limiter #define MIXING_LIMITMAX (0x08100000) #define MIXING_LIMITMIN (-MIXING_LIMITMAX) static UINT ProcessAGC(int *pBuffer, int *pRearBuffer, std::size_t nSamples, std::size_t nChannels, int nAGC) { if(nChannels == 1) { while(nSamples--) { int val = (int)(((int64)*pBuffer * (int32)nAGC) >> AGC_PRECISION); if(val < MIXING_LIMITMIN || val > MIXING_LIMITMAX) nAGC--; *pBuffer = val; pBuffer++; } } else { if(nChannels == 2) { while(nSamples--) { int fl = (int)(((int64)pBuffer[0] * (int32)nAGC) >> AGC_PRECISION); int fr = (int)(((int64)pBuffer[1] * (int32)nAGC) >> AGC_PRECISION); bool dec = false; dec = dec || (fl < MIXING_LIMITMIN || fl > MIXING_LIMITMAX); dec = dec || (fr < MIXING_LIMITMIN || fr > MIXING_LIMITMAX); if(dec) nAGC--; pBuffer[0] = fl; pBuffer[1] = fr; pBuffer += 2; } } else if(nChannels == 4) { while(nSamples--) { int fl = (int)(((int64)pBuffer[0] * (int32)nAGC) >> AGC_PRECISION); int fr = (int)(((int64)pBuffer[1] * (int32)nAGC) >> AGC_PRECISION); int rl = (int)(((int64)pRearBuffer[0] * (int32)nAGC) >> AGC_PRECISION); int rr = (int)(((int64)pRearBuffer[1] * (int32)nAGC) >> AGC_PRECISION); bool dec = false; dec = dec || (fl < MIXING_LIMITMIN || fl > MIXING_LIMITMAX); dec = dec || (fr < MIXING_LIMITMIN || fr > MIXING_LIMITMAX); dec = dec || (rl < MIXING_LIMITMIN || rl > MIXING_LIMITMAX); dec = dec || (rr < MIXING_LIMITMIN || rr > MIXING_LIMITMAX); if(dec) nAGC--; pBuffer[0] = fl; pBuffer[1] = fr; pRearBuffer[0] = rl; pRearBuffer[1] = rr; pBuffer += 2; pRearBuffer += 2; } } } return nAGC; } CAGC::CAGC() { Initialize(true, 48000); } void CAGC::Process(int *MixSoundBuffer, int *RearSoundBuffer, std::size_t count, std::size_t nChannels) { UINT agc = ProcessAGC(MixSoundBuffer, RearSoundBuffer, count, nChannels, m_nAGC); // Some kind custom law, so that the AGC stays quite stable, but slowly // goes back up if the sound level stays below a level inversely proportional // to the AGC level. (J'me comprends) if((agc >= m_nAGC) && (m_nAGC < AGC_UNITY)) { m_nAGCRecoverCount += count; if(m_nAGCRecoverCount >= m_Timeout) { m_nAGCRecoverCount = 0; m_nAGC++; } } else { m_nAGC = agc; m_nAGCRecoverCount = 0; } } void CAGC::Adjust(UINT oldVol, UINT newVol) { m_nAGC = m_nAGC * oldVol / newVol; if (m_nAGC > AGC_UNITY) m_nAGC = AGC_UNITY; } void CAGC::Initialize(bool bReset, DWORD MixingFreq) { if(bReset) { m_nAGC = AGC_UNITY; m_nAGCRecoverCount = 0; } m_Timeout = (MixingFreq >> (AGC_PRECISION-8)) >> 1; } #else MPT_MSVC_WORKAROUND_LNK4221(AGC) #endif // NO_AGC OPENMPT_NAMESPACE_END libopenmpt-0.8.1+release.autotools/configure.ac0000644000175000017500000002323215023302262016541 00000000000000AC_INIT([libopenmpt], [0.8.1+release.autotools], [https://bugs.openmpt.org/], [libopenmpt], [https://lib.openmpt.org/]) AC_PREREQ([2.69]) # we do want 2.70, but distributions are not ready yet #AC_PREREQ([2.70]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_FILES([Makefile libopenmpt/libopenmpt.pc Doxyfile]) AM_INIT_AUTOMAKE([1.11 -Wall -Werror foreign subdir-objects]) AC_USE_SYSTEM_EXTENSIONS AM_PROG_AR LT_INIT AC_SYS_LARGEFILE PKG_PROG_PKG_CONFIG([0.24]) AC_PROG_CC AM_PROG_CC_C_O AC_PROG_CXX AC_PROG_INSTALL # We need C++17 support. AX_CXX_COMPILE_STDCXX([23], [noext], [optional]) AS_IF([test "x$HAVE_CXX23" != "x1"], [ AX_CXX_COMPILE_STDCXX([20], [noext], [optional]) AS_IF([test "x$HAVE_CXX20" != "x1"], [ AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory]) ],[] ) ],[] ) GLOBAL_CPPFLAGS= GLOBAL_CFLAGS= GLOBAL_CXXFLAGS= AC_LANG_PUSH([C]) AX_CHECK_COMPILE_FLAG([-fvisibility=hidden], [GLOBAL_CFLAGS="$GLOBAL_CFLAGS -fvisibility=hidden"]) AX_CFLAGS_WARN_ALL AC_LANG_POP([C]) AC_LANG_PUSH([C++]) AX_CHECK_COMPILE_FLAG([-fvisibility=hidden], [GLOBAL_CXXFLAGS="$GLOBAL_CXXFLAGS -fvisibility=hidden"]) AX_CXXFLAGS_WARN_ALL AC_LANG_POP([C++]) AX_CXX_EXCEPTIONS AX_CXX_RTTI AX_PTHREAD([ LIBS="$PTHREAD_LIBS $LIBS" GLOBAL_CFLAGS="$GLOBAL_CFLAGS $PTHREAD_CFLAGS" GLOBAL_CXXFLAGS="$GLOBAL_CXXFLAGS $PTHREAD_CFLAGS" #CC="$PTHREAD_CC" #CXX="$PTHREAD_CXX" ], [] ) # work-around # This is somewhat pessimistic, but necessary for GCC 8 or earlier, # which we still support and where we cannot use #pragma GCC optimize. AC_LANG_PUSH([C]) AX_CHECK_COMPILE_FLAG([-fno-ipa-ra], [GLOBAL_CFLAGS="$GLOBAL_CFLAGS -fno-ipa-ra"]) AX_CFLAGS_WARN_ALL AC_LANG_POP([C]) AC_LANG_PUSH([C++]) AX_CHECK_COMPILE_FLAG([-fno-ipa-ra], [GLOBAL_CXXFLAGS="$GLOBAL_CXXFLAGS -fno-ipa-ra"]) AX_CXXFLAGS_WARN_ALL AC_LANG_POP([C++]) AC_SUBST([GLOBAL_CPPFLAGS]) AC_SUBST([GLOBAL_CFLAGS]) AC_SUBST([GLOBAL_CXXFLAGS]) LIBOPENMPT_LTVER_CURRENT=5 LIBOPENMPT_LTVER_REVISION=5 LIBOPENMPT_LTVER_AGE=5 AC_SUBST([LIBOPENMPT_LTVER_CURRENT]) AC_SUBST([LIBOPENMPT_LTVER_REVISION]) AC_SUBST([LIBOPENMPT_LTVER_AGE]) AC_DEFINE([MPT_SVNURL], ["https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.8.1"], [svn version]) AC_DEFINE([MPT_SVNVERSION], ["23497"], [svn version]) AC_DEFINE([MPT_SVNDATE], ["2025-06-14T13:04:39.042416Z"], [svn date]) AC_DEFINE([MPT_PACKAGE], [true], [is package]) AC_ARG_VAR(CXXSTDLIB_PCLIBSPRIVATE, [C++ standard library (or libraries) required for static linking. This will be put in the pkg-config file libopenmpt.pc Libs.private field and used for nothing else.]) AC_CANONICAL_HOST # work-around NetBSD toolchain not understanding transitive shared object dependencies at all AS_CASE([$host_os], [netbsd*], [LIBS="$LIBS -lstdc++"], [] ) AS_CASE([$host_os], [mingw32*],[ LIBOPENMPT_WIN32_LIBS= LIBOPENMPT_LIBS_PRIVATE_WIN32= LIBOPENMPTTEST_WIN32_LIBS="-lole32 -lrpcrt4" OPENMPT123_WIN32_LIBS=-lwinmm WIN32_CPPFLAGS="-D_UNICODE -DNOMINMAX" WIN32_CXXFLAGS="-municode -mthreads" WIN32_CFLAGS="-municode -mthreads" WIN32_CONSOLE_CXXFLAGS=-mconsole WIN32_CONSOLE_CFLAGS=-mconsole ], [ LIBOPENMPT_WIN32_LIBS= LIBOPENMPT_LIBS_PRIVATE_WIN32= LIBOPENMPTTEST_WIN32_LIBS= OPENMPT123_WIN32_LIBS= WIN32_CPPFLAGS= WIN32_CXXFLAGS= WIN32_CFLAGS= WIN32_CONSOLE_CXXFLAGS= WIN32_CONSOLE_CFLAGS= ] ) AC_SUBST([LIBOPENMPT_WIN32_LIBS]) AC_SUBST([LIBOPENMPTTEST_WIN32_LIBS]) AC_SUBST([OPENMPT123_WIN32_LIBS]) AC_SUBST([WIN32_CPPFLAGS]) AC_SUBST([WIN32_CXXFLAGS]) AC_SUBST([WIN32_CFLAGS]) AC_SUBST([WIN32_CONSOLE_CXXFLAGS]) AC_SUBST([WIN32_CONSOLE_CFLAGS]) LIBOPENMPT_REQUIRES_PRIVATE= LIBOPENMPT_LIBS_PRIVATE= # Required libopenmpt dependency: zlib ZLIB_PKG= AC_ARG_WITH([zlib], AS_HELP_STRING([--without-zlib], [Disable use of zlib.])) AS_IF([test "x$with_zlib" != "xno"], [ PKG_CHECK_MODULES([ZLIB], [zlib], [ ZLIB_PKG=zlib ZLIB_CFLAGS="-DMPT_WITH_ZLIB $ZLIB_CFLAGS" ], [AC_MSG_ERROR([Unable to find zlib.])]) ] ) # Required libopenmpt dependency: mpg123 MPG123_PKG= AC_ARG_WITH([mpg123], AS_HELP_STRING([--without-mpg123], [Disable use of libmpg123.])) AS_IF([test "x$with_mpg123" != "xno"], [ PKG_CHECK_MODULES([MPG123], [libmpg123 >= 1.14.0], [ MPG123_PKG=libmpg123 MPG123_CFLAGS="-DMPT_WITH_MPG123 $MPG123_CFLAGS" ], [AC_MSG_ERROR([Unable to find libmpg123.])]) ] ) # Required libopenmpt dependency: ogg OGG_PKG= AC_ARG_WITH([ogg], AS_HELP_STRING([--without-ogg], [Disable use of libogg.])) AS_IF([test "x$with_ogg" != "xno"], [ PKG_CHECK_MODULES([OGG], [ogg], [ OGG_PKG=ogg OGG_CFLAGS="-DMPT_WITH_OGG $OGG_CFLAGS" ], [AC_MSG_ERROR([Unable to find libogg.])]) ] ) # Required libopenmpt dependency: vorbis VORBIS_PKG= AC_ARG_WITH([vorbis], AS_HELP_STRING([--without-vorbis], [Disable use of libvorbis.])) AS_IF([test "x$with_vorbis" != "xno"], [ PKG_CHECK_MODULES([VORBIS], [vorbis], [ VORBIS_PKG=vorbis VORBIS_CFLAGS="-DMPT_WITH_VORBIS $VORBIS_CFLAGS" ], [AC_MSG_ERROR([Unable to find libvorbis.])]) ] ) # Required libopenmpt dependency: vorbisfile VORBISFILE_PKG= AC_ARG_WITH([vorbisfile], AS_HELP_STRING([--without-vorbisfile], [Disable use of libvorbisfile.])) AS_IF([test "x$with_vorbisfile" != "xno"], [ PKG_CHECK_MODULES([VORBISFILE], [vorbisfile], [ VORBISFILE_PKG=vorbisfile VORBISFILE_CFLAGS="-DMPT_WITH_VORBISFILE $VORBISFILE_CFLAGS" ], [AC_MSG_ERROR([Unable to find libvorbisfile.])]) ] ) LIBOPENMPT_REQUIRES_PRIVATE="$ZLIB_PKG $MPG123_PKG $OGG_PKG $VORBIS_PKG $VORBISFILE_PKG" LIBOPENMPT_LIBS_PRIVATE="$CXXSTDLIB_PCLIBSPRIVATE $LIBOPENMPT_LIBS_PRIVATE_WIN32" AC_SUBST([LIBOPENMPT_REQUIRES_PRIVATE]) AC_SUBST([LIBOPENMPT_LIBS_PRIVATE]) # openmpt123 AC_ARG_ENABLE([openmpt123], AS_HELP_STRING([--disable-openmpt123], [Disable the openmpt123 command line player.])) AM_CONDITIONAL([ENABLE_OPENMPT123], [test "x$enable_openmpt123" != "xno"]) # examples AC_ARG_ENABLE([examples], AS_HELP_STRING([--disable-examples], [Disable the example programs.])) AM_CONDITIONAL([ENABLE_EXAMPLES], [test "x$enable_examples" != "xno"]) # tests AC_ARG_ENABLE([tests], AS_HELP_STRING([--disable-tests], [Disable the test suite.])) AM_CONDITIONAL([ENABLE_TESTS], [test "x$enable_tests" != "xno"]) # Optional openmpt123 dependency AC_ARG_WITH([pulseaudio], AS_HELP_STRING([--with-pulseaudio], [Enable use of libpulse and libpulse-simple (enabled by default on Linux).])) AS_IF([test "x$enable_openmpt123" != "xno"],[ AS_CASE([$host_os], [linux*],[ AS_IF([test "x$with_pulseaudio" != "xno"], [ PKG_CHECK_MODULES([PULSEAUDIO], [libpulse libpulse-simple], [ have_pulseaudio=1 PULSEAUDIO_CFLAGS="-DMPT_WITH_PULSEAUDIO $PULSEAUDIO_CFLAGS" ], [ have_pulseaudio=0 AC_MSG_ERROR([Unable to find libpulse and/or libpulse-simple.]) ] ) ], [ have_pulseaudio=0 ] ) ;; *) AS_IF([test "x$with_pulseaudio" = "xyes"], [ PKG_CHECK_MODULES([PULSEAUDIO], [libpulse libpulse-simple], [ have_pulseaudio=1 PULSEAUDIO_CFLAGS="-DMPT_WITH_PULSEAUDIO $PULSEAUDIO_CFLAGS" ], [ have_pulseaudio=0 AC_MSG_ERROR([Unable to find libpulse and/or libpulse-simple.]) ] ) ], [ have_pulseaudio=0 ] ) ], [] ) ],[have_pulseaudio=0]) # Optional openmpt123 and examples dependency AC_ARG_WITH([portaudio], AS_HELP_STRING([--without-portaudio], [Disable use of libportaudio.])) AS_IF([test "x$enable_openmpt123$enable_examples" != "xnono"],[ AS_IF([test "x$with_portaudio" != "xno"], [ PKG_CHECK_MODULES([PORTAUDIO], [portaudio-2.0], [ have_portaudio=1 PORTAUDIO_CFLAGS="-DMPT_WITH_PORTAUDIO $PORTAUDIO_CFLAGS" ], [ have_portaudio=0 AC_MSG_ERROR([Unable to find libportaudio.]) ] ) ], [ have_portaudio=0 ] ) ],[have_portaudio=0]) AM_CONDITIONAL([HAVE_PORTAUDIO], [test x$have_portaudio = x1]) # Optional examples dependency: PortAudio C++ AC_ARG_WITH([portaudiocpp], AS_HELP_STRING([--without-portaudiocpp], [Disable use of libportaudiocpp.])) AS_IF([test "x$enable_examples" != "xno"],[ AS_IF([test "x$with_portaudiocpp" != "xno"], [ PKG_CHECK_MODULES([PORTAUDIOCPP], [portaudiocpp], [ have_portaudiocpp=1 PORTAUDIOCPP_CFLAGS="-DMPT_WITH_PORTAUDIOCPP $PORTAUDIOCPP_CFLAGS" ], [ have_portaudiocpp=0 AC_MSG_ERROR([Unable to find libportaudiocpp.]) ] ) ], [ have_portaudiocpp=0 ] ) ],[have_portaudiocpp=0]) AM_CONDITIONAL([HAVE_PORTAUDIOCPP], [test x$have_portaudiocpp = x1]) # Optional disabled openmpt123 dependency: libsdl2 AC_ARG_WITH([sdl2], AS_HELP_STRING([--with-sdl2], [Enable use of libsdl2.])) AS_IF([test "x$enable_openmpt123" != "xno"],[ AS_IF([test "x$with_sdl2" = "xyes"], [ PKG_CHECK_MODULES([SDL2], [sdl2 >= 2.0.4], [SDL2_CFLAGS="-DMPT_WITH_SDL2 $SDL2_CFLAGS"], [AC_MSG_ERROR([Unable to find libsdl2.])]) ] ) ]) # Optional openmpt123 dependency: libsndfile AC_ARG_WITH([sndfile], AS_HELP_STRING([--without-sndfile], [Disable use of libsndfile.])) AS_IF([test "x$enable_openmpt123" != "xno"],[ AS_IF([test "x$with_sndfile" != "xno"], [ PKG_CHECK_MODULES([SNDFILE], [sndfile], [SNDFILE_CFLAGS="-DMPT_WITH_SNDFILE $SNDFILE_CFLAGS"], [AC_MSG_ERROR([Unable to find libsndfile.])]) ] ) ]) # Optional openmpt123 dependency: libFLAC AC_ARG_WITH([flac], AS_HELP_STRING([--without-flac], [Disable use of libflac.])) AS_IF([test "x$enable_openmpt123" != "xno"],[ AS_IF([test "x$with_flac" != "xno"], [ PKG_CHECK_MODULES([FLAC], [flac >= 1.3.0], [FLAC_CFLAGS="-DMPT_WITH_FLAC $FLAC_CFLAGS"], [AC_MSG_ERROR([Unable to find libflac >= 1.3.0.])]) ] ) ]) DX_DOXYGEN_FEATURE(ON) DX_DOT_FEATURE(OFF) DX_HTML_FEATURE(ON) DX_MAN_FEATURE(OFF) DX_CHM_FEATURE(OFF) DX_CHI_FEATURE(OFF) DX_RTF_FEATURE(OFF) DX_XML_FEATURE(OFF) DX_PDF_FEATURE(OFF) DX_PS_FEATURE(OFF) DX_INIT_DOXYGEN([libopenmpt], [Doxyfile], [doxygen-doc]) AC_OUTPUT libopenmpt-0.8.1+release.autotools/doc/0000755000175000017500000000000015023302363015100 500000000000000libopenmpt-0.8.1+release.autotools/doc/openmpt_styleguide.md0000644000175000017500000000153413673126612021277 00000000000000 OpenMPT Style Guide =================== ### OpenMPT **Note:** **This applies to all source code *except* for `libopenmpt/` and `openmpt123/`** **directories.** **Use libopenmpt style otherwise.** (see below for an example) * Place curly braces at the beginning of the line, not at the end * Generally make use of the custom index types like `SAMPLEINDEX` or `ORDERINDEX` when referring to samples, orders, etc. * When changing playback behaviour, make sure that you use the function `CSoundFile::IsCompatibleMode()` so that modules made with previous versions of MPT still sound correct (if the change is extremely small, this might be unnecessary) * `CamelCase` function and variable names are preferred. #### OpenMPT code example ~~~~{.cpp} void Foo::Bar(int foobar) { while(true) { // some code } } ~~~~ libopenmpt-0.8.1+release.autotools/doc/module_formats.md0000644000175000017500000001465314635620211020376 00000000000000Adding support for new module formats ===================================== This document describes the basics of writing a new module loader and related work that has to be done. We will not discuss in detail how to write the loader, have a look at existing loaders to get an idea how they work in general. General hints ------------- * We strive for quality over quantity. The goal is not to support as many module formats as possible, but to support them as well as possible. * Write defensive code. Guard against out-of-bound values, division by zero and similar stuff. libopenmpt is constantly fuzz-tested to catch any crashes, but of course we want our code to be reliable from the start. * Every format should have its own `MODTYPE` flag, unless it can be reasonably represented as a subset of another format (like Ice Tracker ICE files being a subset of ProTracker MOD). * When reading binary structs from the file, use our data types with defined endianness, which can be found in `common/Endianness.h`: * Big-Endian: (u)int8/16/24/32/64be, float32be, float64be * Little-Endian: (u)int8/16/24/32/64le, float32le, float64le Entire structs containing integers with defined endianness can be read in one go if they are tagged with `MPT_BINARY_STRUCT` (see existing loaders for an example). * `CSoundFile::ChnSettings` **MUST NOT** be resized after a pattern has been created, as existing patterns will be interpreted incorrectly. For module formats that support per-pattern channel amounts, the maximum number of channels must be determined beforehand. * Strings can be safely handled using: * `FileReader::ReadString` and friends for reading them directly from a file * `mpt::String::ReadBuf` for reading them from a struct or char array These functions take care of string padding (zero / space padding) and will avoid reading past the end of the string if there is no terminating null character. * Do not use non-const static variables in your loader. Loaders need to be thread-safe for libopenmpt. * `FileReader` instances may be used to treat a portion of a file as its own independent file (through `FileReader::ReadChunk`). This can be useful with "embedded files" such as WAV or Ogg samples (see MO3 or SymMOD for examples). Container formats such as UMX are another good example for this usage. * Samples *either* use middle-C frequency *or* finetune + transpose. For the few weird formats that use both, it may make sense to translate everything into middle-C frequency. * Add the new `MODTYPE` to `CSoundFile::UseFinetuneAndTranspose` if applicable, and see if any effect handlers in `soundlib/Snd_fx.cpp` need to know the new `MODTYPE`. * Do not rely on hard-coded magic numbers. For example, when comparing if an index is valid for a given array, do not hard-code the array size but rather use `std::size` (or `mpt::array_size` in contexts where `std::size` is not usable) or, for ensuring that char arrays are null-terminated, `mpt::String::SetNullTerminator`. Similarly, do not assume any specific quantities for OpenMPT's constants like MAX_SAMPLES, MAX_PATTERN_ROWS, etc. These may change at any time. * Pay attention to off-by-one errors when comparing against MAX_SAMPLES and MAX_INSTRUMENTS, since sample and instrument numbers are 1-based. Prefer using `CSoundFile::CanAddMoreSamples` and `CSoundFile::CanAddMoreInstruments` to check if a given amount of samples or instruments can be added to the file rather than doing the calculations yourself. * Placement of the loader function in the `ModuleFormatLoaders` array in Sndfile.cpp depends on various factors. In general, module formats that have very bad magic numbers (and thus might cause other formats to get mis-interpreted) should be placed at the bottom of the list. Two notable examples are 669 files, where the first two bytes of the file are "if" (which may e.g. cause a song title starting with if ..." in various other formats to be interpreted as a 669 module), and of course Ultimate SoundTracker modules, which have no magic bytes at all. * Avoid use of functions tagged with `[[deprecated]]`. Probing ------- libopenmpt provides fast probing functions that can be used by library users to quickly check if a file is most likely playable with libopenmpt, even if only a fraction of the file is available (e.g. when streaming from the internet). In order to satisfy these requirements, probing functions should do as little work as possible (e.g. only parse the header of the file), but as much as required to tell with some certainty that the file is really of a certain mod format. However, probing functions should not rely on having access to more than the first `CSoundFile::ProbeRecommendedSize` bytes of the file. * Probing functions **must not** allocate any memory on the heap. * Probing functions **must not** return ProbeFailure or ProbeWantMoreData for any file that would normally be accepted by the loader. In particular, this means that any header checks must not be any more aggressive than they would be in the real loader (hence it is a good idea to not copy-paste this code but rather put it in a reusable function), and the minimum additional size passed to `CSoundFile::ProbeAdditionalSize` must not be higher than the biggest size that would cause a hard failure (i.e. returning `false`) in the module loader. * Probing functions **may** return ProbeSuccess for files that would be rejected by a loader after a more thorough inspection. For example, probing functions do not need to verify that all required chunks of an IFF-like file format are actually present, if the header makes it obvious enough that the file is highly likely to be a module. Adding loader to the build systems and various other locations -------------------------------------------------------------- Apart from writing the module loader itself, there are a couple of other places that need to be updated: * Add loader file to `build/android_ndk/Android.mk`. * Add loader file to `build/autotools/Makefile.am`. * Run `build/regenerate_vs_projects.sh` / `build/regenerate_vs_projects.cmd` (depending on your platform) * Add file extension to `installer/filetypes-*.iss`. * Add file extension to `CTrackApp::OpenModulesDialog` in `mptrack/Mptrack.cpp` as required (e.g. if it's a compressed container format or if it's relevant enough to be mentioned). * Add format information to `soundlib/Tables.cpp`. * Add magic bytes to `contrib/fuzzing/all_formats.dict`. libopenmpt-0.8.1+release.autotools/doc/libopenmpt/0000755000175000017500000000000015023302363017251 500000000000000libopenmpt-0.8.1+release.autotools/doc/libopenmpt/dependencies.md0000644000175000017500000001066315022364672022161 00000000000000 Dependencies {#dependencies} ============ Dependencies ------------ ### libopenmpt * Supported compilers for building libopenmpt: * **Microsoft Visual Studio 2019** or higher, running on a amd64 build system (other target systems are supported) Please note that we do not support building with a later Visual Studio installation with an earlier compiler version. This is because, while later Visual Studio versions allow installing earlier compilers to be available via the later version's environment, in this configuration, the earlier compiler will still use the later C and C++ runtime's headers and implementation, which significantly increases the matrix of possible configurations to test. * **Microsoft Visual Studio 2017 XP targeting toolset** * **GCC 7.1** or higher * **Clang 6** or higher * **MinGW-W64 7.1 (posix threading model)** or higher * **MinGW-W64 13.1 (mcfgthread threading model)** or higher * **MinGW-W64 7.1 (win32 threading model)** up to **MinGW-W64 13.0 (win32 threading model)** * **emscripten 3.1.51** or higher * **DJGPP GCC 7.1** or higher * any other **C++23, C++20, or C++17 compliant** compiler libopenmpt makes the following assumptions about the C++ implementation used for building: * `std::numeric_limits::digits == 8` (enforced by static_assert) * existence of `std::uintptr_t` (enforced by static_assert) * in C++23/C++20 mode, `std::endian::little != std::endian::big` (enforced by static_assert) * `wchar_t` encoding is either UTF-16 or UTF-32 (implicitly assumed) * representation of basic source character set is ASCII (implicitly assumed) * representation of basic source character set is identical in char and `wchar_t` (implicitly assumed) libopenmpt does not rely on any specific implementation defined or undefined behaviour (if it does, that's a bug in libopenmpt). In particular: * `char` can be `signed` or `unsigned` * shifting signed values is implementation defined * `signed` integer overflow is undefined * `float` and `double` can be non-IEEE754 libopenmpt can optionally support certain incomplete C++ implementations: * platforms without `wchar_t` support (like DJGPP) * platforms without working `std::random_device` (like Emscripten when running in `AudioWorkletProcessor` context) * platforms without working `std::high_resolution_clock` (like Emscripten when running in `AudioWorkletProcessor` context) * Required compilers to use libopenmpt: * Any **C89** / **C99** / **C11** / **C17** / **C23** compatible compiler should work with the C API as long as a **C99** compatible **stdint.h** is available. * Any **C++23**, **C++20**, or **C++17** compatible compiler should work with the C++ API. * **J2B** support requires an inflate (deflate decompression) implementation: * **zlib** (or **miniz** can be used internally) * **MO3** support requires: * **libmpg123 >= 1.14.0** (or **minimp3** can be used internally) * **libogg**, **libvorbis**, and **libvorbisfile** (or **stb_vorbis** can be used internally) * Building on Unix-like systems requires: * **GNU make** * **pkg-config** * The Autotools-based build system requires: * **pkg-config 0.24** or higher * **zlib** * **doxygen** ### openmpt123 * Live sound output requires one of: * **PulseAudio** * **SDL 2** * **PortAudio v19** * **Win32** * **liballegro 4.2** on DJGPP/DOS Optional dependencies --------------------- ### libopenmpt * **doxygen 1.8** or higher is required to build the documentation. ### openmpt123 * Rendering to PCM files can use: * **FLAC 1.3** or higher * **libsndfile** * **Win32** for WAVE * raw PCM has no external dependencies * **help2man** is required to build the documentation. Source packages --------------- Building the source packages additionally requires: * 7z (7-zip) * autoconf * autoconf-archive * automake * awk (mawk) * git * gzip * help2man * libtool * subversion * tar * xpath (libxml-xpath-perl) * zip libopenmpt-0.8.1+release.autotools/doc/libopenmpt/packaging.md0000644000175000017500000000350114277233115021446 00000000000000Packaging {#packaging} ========= Packaging --------- ### Packaging recommendations for distribution package maintainers * libopenmpt (since 0.3) uses SemVer 2.0.0 versioning. See [semver.org](https://semver.org/spec/v2.0.0.html). Clause 4 is ignored for libopenmpt, which means that libopenmpt will also provide API/ABI compatibility semantics for pre-1.0.0 versions as required by SemVer 2.0.0 only for post-1.0.0 versions. The SemVer versioning scheme is incompatible with Debian/Ubuntu package versions, however it can easily be processed to be compatible by replacing '-' (hyphen) with '~' (tilde). It is recommended that you use this exact transformation if required. * Use the autotools source package. * Use the default set of dependencies required by the autotools package. * Read \ref libopenmpt_c_staticlinking and thus possibly pass `CXXSTDLIB_PCLIBSPRIVATE` variable to `configure` if appropriate and/or desired. * Run the test suite in your build process. * Send any build system improvement patches upstream. * Do not include the libmodplug emulation layer in the default libopenmpt binary package. Either do not package it at all, or provide a separate package named libopenmpt-modplug or libmodplug-openmpt (or similar), which depends on libopenmpt, provides libmodplug, and conflicts with original libmodplug. * Split openmpt123 into its own binary package because it has more dependencies than libopenmpt itself. * Consider providing an additional openmpt123 package (in addition to the default openmpt123 package with all audio output drivers), built with fewer audio output drivers so it does not transitively depend on X11. Name that package and its executable openmpt123-nox (or whatever else may be common practice in your distribution). libopenmpt-0.8.1+release.autotools/doc/libopenmpt/tests.md0000644000175000017500000000155513135616236020674 00000000000000 Tests {#tests} ===== libopenmpt provides some basic unit tests that check the platform for general sanity and do some basic internal functionality testing. The test suite requires a special libopenmpt build that includes file saving functionality which is not included in normal builds. This is handled by all provided build systems automatically. ### Running Tests #### On Unix-like systems Compile with make $YOURMAKEOPTIONS clean make $YOURMAKEOPTIONS and run make $YOURMAKEOPTIONS check As the build system retains no state between make invocations, you have to provide your make options on every make invocation. #### Autotools-based build system ./configure make check #### On Windows Using Visual Studio 20??, compile build\vs20??\libopenmpt_test.sln and run bin\$ARCH\libopenmpt_test.exe from the root of the source tree. libopenmpt-0.8.1+release.autotools/doc/libopenmpt/gettingstarted.md0000644000175000017500000002136614736713747022601 00000000000000 Getting Started {#gettingstarted} =============== How to compile -------------- ### libopenmpt and openmpt123 - Autotools Grab a `libopenmpt-VERSION-autotools.tar.gz` tarball. ./configure make make check sudo make install Cross-compilation is generally supported (although only tested for targetting MinGW-w64). Note that some MinGW-w64 distributions come with the `win32` threading model enabled by default instead of the `posix` threading model. The `win32` threading model lacks proper support for C++11 `` and `` as well as thread-safe magic statics. It is recommended to use the `posix` threading model for libopenmpt for this reason. On Debian, the appropriate configure command is `./configure --host=x86_64-w64-mingw32 CC=x86_64-w64-mingw32-gcc-posix CXX=x86_64-w64-mingw32-g++-posix` for 64bit, or `./configure --host=i686-w64-mingw32 CC=i686-w64-mingw32-gcc-posix CXX=i686-w64-mingw32-g++-posix` for 32bit. Other MinGW-w64 distributions may differ. - Visual Studio: - You will find solutions for Visual Studio in the matching `build/vsVERSIONwinWINDOWSVERSION/` folder. Minimal projects that target Windows 10 UWP are available in `build/vsVERSIONuwp/`. Most projects are supported with any of the mentioned Visual Studio verions, with the following exceptions: - in_openmpt: Requires Visual Studio with MFC. - xmp-openmpt: Requires Visual Studio with MFC. - libopenmpt requires the compile host system to be amd64 or ARM64 when building with Visual Studio. - In order to build libopenmpt for Windows XP, the Visual Studio 2017 XP targeting toolset as well as the Windows 8.1 SDK need to be installed. The SDK is optionally included with Visual Studio 2017, but must be separately installed with later Visual Studio versions. The Windows 8.1 SDK is available from or directly from . - You will need the Winamp 5 SDK and the XMPlay SDK if you want to compile the plugins for these 2 players. They can be downloaded automatically on Windows 7 or later by just running the `build/download_externals.cmd` script. If you do not want to or cannot use this script, you may follow these manual steps instead: - Winamp 5 SDK: To build libopenmpt as a winamp input plugin, copy the contents of `WA5.55_SDK.exe` to include/winamp/. Please visit [winamp.com](http://wiki.winamp.com/wiki/Plug-in_Developer) to download the SDK. You can disable in_openmpt in the solution configuration. - XMPlay SDK: To build libopenmpt with XMPlay input plugin support, copy the contents of xmp-sdk.zip into include/xmplay/. Please visit [un4seen.com](https://www.un4seen.com/xmplay.html) to download the SDK. You can disable xmp-openmpt in the solution configuration. - Makefile The makefile supports different build environments and targets via the `CONFIG=` parameter directly to the make invocation. Use `make CONFIG=$newconfig clean` when switching between different configs because the makefile cleans only intermediates and target that are active for the current config and no configuration state is kept around across invocations. - native build: Simply run make which will try to guess the compiler based on your operating system. - gcc or clang (on Unix-like systems, including Mac OS X with MacPorts, and Haiku (32-bit Hybrid and 64-bit)): The Makefile requires pkg-config for native builds. For sound output in openmpt123, PortAudio or SDL is required. openmpt123 can optionally use libflac and libsndfile to render PCM files to disk. When you want to use gcc, run: make CONFIG=gcc When you want to use clang, it is recommended to do: make CONFIG=clang - MinGW-w64: make CONFIG=mingw-w64 \ MINGW_FLAVOUR=[|-posix|-win32] \ WINDOWS_ARCH=[x86|amd64] \ WINDOWS_FAMILY=[|desktop-app|app|phone-app|pc-app] \ WINDOWS_VERSION=[win95|win98|winme|winnt4|win2000|winxp|winxp64|winvista|win7|win8|win8.1|win10] - emscripten (on Unix-like systems): Run: # generates WebAssembly with JavaScript fallback make CONFIG=emscripten EMSCRIPTEN_TARGET=all or # generates WebAssembly make CONFIG=emscripten EMSCRIPTEN_TARGET=wasm or # generates JavaScript with compatibility for older VMs make CONFIG=emscripten EMSCRIPTEN_TARGET=js Running the test suite on the command line is also supported by using node.js. Depending on how your distribution calls the `node.js` binary, you might have to edit `build/make/config-emscripten.mk`. - DJGPP / DOS Cross-compilation from Linux systems is supported with DJGPP GCC via make CONFIG=djgpp `openmpt123` can use liballegro 4.2 for sound output on DJGPP/DOS. liballegro needs to be downloaded into the `libopenmpt` source tree. ./build/download_externals.sh # download liballegro source make CONFIG=djgpp USE_ALLEGRO42=1 - afl++: To compile libopenmpt with fuzzing instrumentation using afl++, run: make CONFIG=afl For more detailed instructions, read `contrib/fuzzing/readme.md`. - other compilers: To compile libopenmpt with other compliant compilers, run: make CONFIG=generic The `Makefile` supports some customizations. You might want to read the top which should get you some possible make settings, like e.g. `make DYNLINK=0` or similar. Cross compiling or different compiler would best be implemented via new `config-*.mk` files. The `Makefile` also supports building doxygen documentation by using make doc Binaries and documentation can be installed systen-wide with make PREFIX=/yourprefix install make PREFIX=/yourprefix install-doc Some systems (i.e. Linux) require running sudo ldconfig in order for the system linker to be able to pick up newly installed libraries. `PREFIX` defaults to `/usr/local`. A `DESTDIR=` parameter is also supported. - Android NDK See `build/android_ndk/README.AndroidNDK.txt`. ### Building libopenmpt with any other build system libopenmpt is very simple to build with any build system of your choice. The only required information is listed below. We currently only support building libopenmpt itself this way, but the test suite and openmpt123 may follow later. - language: - C++17 / C++20 / C++23 - defines: - LIBOPENMPT_BUILD - private include directories: - . - common - src - files: - common/*.cpp - sounddsp/*.cpp - soundlib/*.cpp - soundlib/plugins/*.cpp - soundlib/plugins/dmo/*.cpp - libopenmpt/*.cpp - public include directories: - . - public header files: - libopenmpt/libopenmpt.h - libopenmpt/libopenmpt.hpp - libopenmpt/libopenmpt_config.h - libopenmpt/libopenmpt_ext.h - libopenmpt/libopenmpt_ext.hpp - libopenmpt/libopenmpt_version.h - libopenmpt/libopenmpt_stream_callbacks_buffer.h - libopenmpt/libopenmpt_stream_callbacks_fd.h - libopenmpt/libopenmpt_stream_callbacks_file_mingw.h - libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h - libopenmpt/libopenmpt_stream_callbacks_file_posix.h - libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h - dependencies: - zlib: - pkg-config - zlib - defines - MPT_WITH_ZLIB - libmpg123: - pkg-config - mpg123 - defines - MPT_WITH_MPG123 - libogg: - pkg-config - ogg - defines - MPT_WITH_OGG - libvorbis: - pkg-config - vorbis - defines - MPT_WITH_VORBIS - libvorbisfile: - pkg-config - vorbisfile - defines - MPT_WITH_VORBISFILE - dll: - build: - defines - LIBOPENMPT_BUILD_DLL - use: - defines - LIBOPENMPT_USE_DLL libopenmpt-0.8.1+release.autotools/doc/libopenmpt/index.dox0000644000175000017500000000274714613471325021037 00000000000000 /*! * \mainpage Contents * * libopenmpt is a cross-platform C++ and C library to decode tracked music files (modules) into a raw PCM audio stream. * * libopenmpt is based on the player code of the OpenMPT project (Open ModPlug Tracker, https://openmpt.org/) * * \section toc Contents * - \ref md_README "README" * - \ref dependencies "Dependencies" * - \ref gettingstarted "Getting Started" * - \ref packaging "Packaging" * - \ref md_doc_contributing "Contributing" * - \ref md_doc_libopenmpt_styleguide "libopenmpt Style Guide" * - \ref md_doc_openmpt_styleguide "OpenMPT Style Guide" * - \ref tests "Tests" * - \ref changelog "Changelog" * - \ref md_doc_module_formats "Implementing new Module Formats" * - Issue Tracker * \subsection toc_apis APIs * - libopenmpt * - \ref libopenmpt "Common Details" * - libopenmpt C++ * - \ref libopenmpt_cpp_overview "Overview" * - \ref libopenmpt_cpp "Details" * - libopenmpt C * - \ref libopenmpt_c_overview "Overview" * - \ref libopenmpt_c "Details" * - libopenmpt_ext C++ * - \ref libopenmpt_ext_cpp_overview "Overview" * - \ref libopenmpt_ext_cpp "Details" * - libopenmpt_ext C * - \ref libopenmpt_ext_c_overview "Overview" * - \ref libopenmpt_ext_c "Details" * * \section toc_website Website * https://lib.openmpt.org/ * * \section toc_license License * \include LICENSE * */ libopenmpt-0.8.1+release.autotools/doc/libopenmpt/changelog.md0000644000175000017500000021103615023271504021447 00000000000000 Changelog {#changelog} ========= For fully detailed change log, please see the source repository directly. This is just a high-level summary. ### libopenmpt 0.8.1 (2025-06-14) * [**Bug**] Work-around broken user locale support on Haiku by always assuming UTF8. * [**Bug**] libopenmpt_test did not build from the MSVC source packages. * [**Bug**] openmpt123: Allow for converting to libsndfile formats which list the file extension only in the subformat (i.e. MP3 with libsndfile 1.1.0 or later). * [**Change**] `TCB` was added to the list of supported file extensions. ModLand and Fujiology use this extension for TCB Tracker modules, instead of the canonical `MOD` extension. * IT: Fixed various interactions between Note Cut effect and portamentos. * MED: When triggering a synth note with a Synth Jump command on the same row, the initial speed command was not executed. * S3M: Old ModPlug Tracker versions allowed to use the 28th character of sample names to be used. Such sample names are now read correctly again. * Building with libmpg123 1.33.0 in PORTABLE_API mode now works. * mpg123: Update to v1.33.0 (2025-06-07). * miniz: Update to v3.0.2 (2023-01-15). ### libopenmpt 0.8.0 (2025-05-31) * [**New**] Can now read PumaTracker (`PUMA`) modules. * [**New**] Can now read Face The Music (`FTM`) modules. * [**New**] Can now read Future Composer (`FC` / `FC13` / `FC14` / `SMOD`) modules. * [**New**] Can now read Game Music Creator (`GMC`) modules. * [**New**] Can now read Chuck Biscuits / Black Artist (`CBA`) modules from the Expoze musicdisk by Heretics * [**New**] Can now read Real Tracker 2 (`RTM`) modules. * [**New**] Can now read Images Music System (`IMS`) modules. * [**New**] Can now read ChipTracker (`MOD`) modules. * [**New**] Can now read TCB Tracker (`MOD`) modules. * [**New**] Can now read EasyTrax (`ETX`) modules. * [**New**] Can now load UNIC Tracker v1 (`UNIC`) files. * [**New**] MED: Synthesized and hybrid instruments are now supported. * [**New**] GT2: Better support for old "envelopes", in particular adding support for the previously missing tremor / tremolo / vibrato. * [**New**] NST: His Master's Noise "Mupp" instruments are now supported, as well as command 7 "mega-arp". * [**New**] `Makefile CONFIG=djgpp` now supports building LGPL libraries as DXE (use `ENABLE_DXE=0` to disable). * [**New**] New `Makefile` `CONFIG=mingw-w64` option `WINDOWS_CRT=[crtdll,msvcrt,ucrt]` to select the toolchain CRT library. * [**New**] 32bit ARM builds now support Windows 8 (Windows RT) again. * [**New**] libopenmpt: New APIs for determining whether order list entrys or pattern indices have a special meaning: `openmpt::module::is_order_skip_entry()`, `openmpt::module::is_pattern_skip_item()`, `openmpt::module::is_order_stop_entry()`, `openmpt::module::is_pattern_stop_item()` (C++), and `openmpt_module_is_order_skip_entry()`, `openmpt_module_is_pattern_skip_item()`, `openmpt_module_is_order_stop_entry()`, `openmpt_module_is_pattern_stop_item()` (C). * [**New**] libopenmpt: New APIs for retrieving pattern time signature information: `openmpt::module::get_pattern_rows_per_beat()`, `openmpt::module::get_pattern_rows_per_measure()` (C++), and `openmpt_module_get_pattern_rows_per_beat()`, `openmpt_module_get_pattern_rows_per_measure()` (C). * [**New**] libopenmpt: New APIs for retrieving the restart / loop position: `openmpt::module::get_restart_order()`, `openmpt::module::get_restart_row()` (C++), and `openmpt_module_get_restart_order()`, `openmpt_module_get_restart_row()` (C). * [**New**] libopenmpt: New API for retrieving the playback time at a given order / row combination: `openmpt::module::get_time_at_position()` (C++), and `openmpt_module_get_time_at_position()` (C). * [**Change**] DOS builds now use zlib, libmpg123, libogg, and libvorbis instead of miniz, minimp3, and stb_vorbis by default. * [**Change**] `Makefile CONFIG=djgpp` now sets `ALLOW_LGPL=1` by default. * [**Change**] `build/download_externals.sh` now verifies the integrity of any downloaded files and uses curl instead of wget. * [**Regression**] Support for Emscripten versions older than 3.1.51 has been removed. * [**Regression**] Using `EMSCRIPTEN_PORTS=1` with Emscripten older than 3.1.54 now requires additionally specifying `ANCIENT=1`. * When formatting pattern data, effect letters in the volume column are now always formatted correctly, regardless of the module format. * IT: Various playback fixes. * IT: When using tone portamento to another sample after the previous sample's sustain loop has been released, the new sample should also not play its sustain loop. * IT: When triggering an empty instrument note slot, completely ignore the pattern cell - do not reset the currently playing instrument's envelopes, and also don't process any effects - including global ones. * IT: Offset with instrument number but no note should play offset effect with previous note. * IT: Fixed various combinations of volume column and effect column portamento effects. * IT: Implemented a quirk in command Lxx that always executes a portamento down when no tone portamento has been set up before, sometimes causing the target note to be reached immediately, or sliding the note down very subtly. * IT: Envelope Carry should not be influenced by a previous note-off. * XM: When a key-off is encountered before auto-vibrato reaches full depth, the depth is reset. * S3M: Combined slides (Kxy / Lxy) are no longer run on the first tick of a row in files made with Scream Tracker. * MOD: Groo's "The Ultimate Beeper" now plays like in ProTracker. * DTM: Portamentos are now also evaluated on the first tick of the row. * MO3: If multiple sample slots shared the same Ogg Vorbis sample, only one sample slot was loaded. * MED: Various playback fixes. * SymMOD: Files containing more than 127 channels are no longer rejected. * Better support for automatic slide commands (commands that keep sliding on following rows) in various formats. * The pattern channel limit was raised from 127 to 192 for some formats. * openmpt123: Multi-threaded encoding is enabled with libFLAC 1.5.0 or newer. * xmp-openmpt: Memory consumption during file loading has been reduced. * zlib: v1.3.1 (2024-01-22). * mpg123: v1.32.10 (2024-12-14). * ogg: v1.3.5 (2021-06-04). * vorbis: v1.3.7 (2020-07-04). * miniz: v2.2.0 (2021-06-27). * minimp3: fork commit 2116754771b79347ad2f39127abace2a093c383e (2024-08-15). * stb_vorbis: v1.22 commit 5a0bb8b1c1b1ca3f4e2485f4114c1c8ea021b781 (2021-07-12). * pugixml: v1.15 (2025-01-10). * flac: v1.5.0 (2025-02-11). * portaudio: v19.7.0 (2021-04-06). ### libopenmpt 0.7.0 (2023-04-30) * [**New**] `667` files from Composer 667 are now supported. * [**New**] `GTK` and `GT2` files from Gramouf Tracker are now supported. * [**New**] Can now read a variant of the DSMI AMF format called DMF, as found in various DOS games distributed by Webfoot (Tronic, H2O, PowBall, etc.). * [**New**] `DSM` files from Dynamic Studio are now supported. * [**New**] `XMF` files from the DOS game Imperium Galactica are now supported. * [**New**] Can now read the hacked MOD format (`DMF`) from the game "Apocalypse Abyss". * [**New**] libopenmpt: New APIs for getting the current tempo as a floating point value: `openmpt::module::get_current_tempo2()` (C++), and `openmpt_module_get_current_tempo2()` (C). * [**New**] C API: New stream callbacks for various platform extensions to the C stdio interface: `openmpt_stream_get_file_posix_lfs64_callbacks()` in `libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h` for explicit `off64_t` on Posix systems, `openmpt_stream_get_file_posix_callbacks()` in `libopenmpt/libopenmpt_stream_callbacks_file_posix.h` for `off_t` on Posix systems, `openmpt_stream_get_file_msvcrt_callbacks()` in `libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h` for 64bit file support on Windows systems with the Microsoft C runtime, and `openmpt_stream_get_file_mingw_callbacks()` in `libopenmpt/libopenmpt_stream_callbacks_file_mingw.h` for 64bit file support when targetting MinGW. The old `openmpt_stream_get_file_callbacks()` has been deprecated in favour of a stricly standard conforming `openmpt_stream_get_file_callbacks2()` in the same `libopenmpt/libopenmpt_stream_callbacks_file.h` header. `libopenmpt/libopenmpt.h` defines `LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_LFS64`, `LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX`, `LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT`, and `LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW` respectively in order to allow for checking header availability. * [**New**] C API: New stream callbacks for memory buffers. `openmpt_stream_get_buffer_callbacks()` and `openmpt_stream_buffer_init()` are deprecated. Use `openmpt_stream_get_buffer_callbacks2()` and `openmpt_stream_buffer_init2()` instead. The new variants do not support loading only a file prefix and checking for overflow any more. This was only useful when using the old `openmpt_could_open_probability2()` style interface from the libopenmpt 0.2 API, which has been superseded by `openmpt_probe_file_header()`, `openmpt_probe_file_header_without_filesize()`, and `openmpt_probe_file_header_from_stream()` in libopenmpt 0.3.0. * [**New**] libopenmpt_ext: New interface `interactive3` adding `openmpt::ext::interactive3::set_current_tempo2()` (C++) and `openmpt_module_ext_interface_interactive3.set_current_tempo2()` (C) which allow setting non-integer tempo values. * [**New**] New `Makefile` option `CONFIG=mingw-w64` which consolidates all MinGW-w64 build configurations with the following options: `MINGW_FLAVOUR=[|-posix|-win32]`, `WINDOWS_ARCH=[x86|amd64]`, `WINDOWS_FAMILY=[|desktop-app|app|phone-app|pc-app]`, and `WINDOWS_VERSION=[win95|win98|winme|winnt4|win2000|winxp|winxp64|winvista|win7|win8|win8.1|win10|win11]`. * [**New**] New `Makefile` option `CONFIG=mingw` which consolidates all MinGW build configurations with the following options: `MINGW_FLAVOUR=[|-posix|-win32]`, and `WINDOWS_VERSION=[win95|win98|winme|winnt4|win2000|winxp]`. * [**New**] Building with MSYS2 is now fully supported for Makefile and Autotools build systems. * [**New**] `Makefile` `CONFIG=djgpp` now supports `CPU=` option to build optimized for a particular CPU. See `build/make/config-djgpp.mk` for all available options. `FLAVOURED_DIR=1` places the CPU-specific optimized builds in separate folders below `bin/`. * [**New**] Building with a MinGW32 CRTDLL toolchain is now supported via `Makefile` option `CONFIG=mingw32crt`. * [**New**] `Makefile` now uses `PKG_CONFIG` as path to `pkg-config`. * [**New**] The C++ API is now also enabled for Emscripten builds by default. * [**New**] Support for GCC 7 has been restored. * [**New**] Support for Clang 6 has been restored. * [**New**] Support for Android NDK 18 has been restored. * [**New**] openmpt123: `--banner [0|1|2]` allows changing the openmpt123 banner style to hidden, shown, or verbose, respectively. * [**New**] openmpt123: `--assume-terminal` allows skipping the openmpt123 terminal check, and thus allows running the UI with non-terminal stdin, which can be useful for some very basic remote control functionality. * [**Change**] xmp-openmpt: The Amiga resampler emulation is now enabled by default. * [**Change**] in_openmpt: The Amiga resampler emulation is now enabled by default. * [**Change**] The official Windows builds (x86, amd64, arm, arm64) now require Windows 10 21H2 (or later). The official legacy Windows builds (x86-legacy, amd64-legacy) are unchanged and still require Windows 7 (or later). * [**Change**] `"date"` metadata will now exlude the UTC time zone signifier `Z` if the precise time zone is unknown. * [**Change**] ctl `seek.sync_samples` now defaults to 1. * [**Change**] `Makefile` `CONFIG=generic` is gone. Please use `CONFIG=standard` instead. * [**Change**] `Makefile` `CONFIG=macosx` and `CONFIG=haiku` have been removed. The OS is auto-detected. * [**Change**] `Makefile` options `CONFIG=mingw64-win32`, `CONFIG=mingw64-win64`, `CONFIG=mingw64-winrt-x86`, `CONFIG=mingw64-winrt-amd64`, and `CONFIG=mingw-win9x` have been replaced by `CONFIG=mingw-w64`, and `CONFIG=mingw`. * [**Change**] Autotools now default to C++20 and only fall back to C++17 when C++20 is not supported. * [**Change**] `Makefile` now defaults to C++20 and only falls back to C++17 when C++20 is not supported by the compiler. * [**Change**] `Makefile` now defaults to C17 and only falls back to C11 when C17 is not supported by the compiler. * [**Change**] `Makefile` `CONFIG=djgpp` option `USE_ALLEGRO42` now defaults to `1` and implies building a liballegro42 locally. This requires executing `build/download_externals.sh` before building to download the liballegro42 sources. * [**Change**] in_openmpt: The Winamp input plugin in_openmpt is now deprecated for use with the latest Winamp or WACUP releases. Please use the native implementations available in Winamp >=5.9.0 or WACUP instead. This does not mean that in_openmpt/in_mod will not receive further development, it just means that the responsibility now lies with the player implementors themselves. We will still maintain the status quo of our in_openmpt input plugin for users of earlier Winamp version, or users on older systems, or users of compatible players. * [**Change**] The POSIX fd file callbacks implementation now handles `EINTR` and retries the `read()` call. * [**Regression**] Full support for Visual Studio 2017 has been removed. We still support targeting Windows XP with Visual Studio 2017. * [**Regression**] Support for mingw-std-threads has been removed. If you require a thread-safe libopenmpt, please build with POSIX threading model and/or complain to MinGW/GCC about not properly supporting C++11 features in 2023. * [**Regression**] Support for Emscripten versions older than 3.1.1 has been removed. * [**Regression**] C API: `openmpt_stream_get_file_callbacks()` used to provide 64bit file access on some platforms where long is 32bit. This never worked reliably for all platforms though. The behaviour is now changed to always stick to what standard C supports with `fseek` and `ftell`, where the offset type is long. `openmpt_stream_get_file_callbacks()` is deprecated now due to behavioral change. Please migrate to `openmpt_stream_get_file_callbacks2()`. * [**Regression**] Using the system-provided liballegro42 is no longer supported. The option `BUNDLED_ALLEGRO42=1` does not exist any more. * Reduced aliasing when downsampling with the Sinc + Low-Pass resampler. * The sample position is now rounded instead of truncated when resampling without interpolation. * Seeking with sample sync now supports portamento up / down commands as well as IMF/ PTM note slides. Tone portamento is now synchronized correctly when seeking in DBM, 669 and MED with fast slides (first tick of portamento was previously not executed). * The filter cutoff frequency is no longer rounded to integer frequency values. * MED: Tempos higher than 255 BPM can now be imported in pattern data. * MED: MMD1 files with more than 16 channels are now supported. * ULT: Import 8-bit volume commands with full precision. * IT: Initial "last note memory" of every channel is C-0, so a lone instrument number without note triggers that note. * S3M: Better approximation of old "stereo control" SAx command used in Purple Motion's PANIC.S3M. * S3M: In ScreamTracker 3.03 and later, OPL notes with tone portamento next to them are delayed until the next row and then the new pitch is used instantly. * MO3: Envelope sustain was not imported correctly if the source file was an XM. * MOD: Lone instrument number with retrigger effect swap sample immediately. * Recalling a sample's default volume using an instrument number (as opposed to regular volume commands) previously ramped the volume change smoothly over a whole tick. Now the user-configured ramp settings are used instead (as it would happen when using a volume command to achieve the same effect). * zlib: v1.2.12 (2022-03-27). * mpg123: v1.31.3 (2023-03-19). * ogg: v1.3.5 (2021-06-04). * vorbis: v1.3.7 (2020-07-04). * miniz: v2.2.0 (2021-06-27). * minimp3: commit 50d2aaf360a53653b718fead8e258d654c3a7e41 (2021-11-27). * stb_vorbis: v1.22 commit 5a0bb8b1c1b1ca3f4e2485f4114c1c8ea021b781 (2021-07-12). * FLAC: v1.4.2 (2022-10-22). * PortAudio: v19.7.0 (2021-04-06). ### libopenmpt 0.6.0 (2021-12-23) * [**New**] `MUS` files from Psycho Pinball and Micro Machines 2 are now supported. * [**New**] `SymMOD` files created with Symphonie / Symphonie Pro are now supported. * [**New**] `FMT` files created with Davey W Taylor's FM Tracker are now supported. * [**New**] `DSYM` files created with Digital Symphony are now supported. * [**New**] `STX` files (transitional format between Scream Tracker 2 and 3) are now supported. * [**New**] TakeTracker MODs with `TDZ1` to `TDZ3` magic bytes are now supported. * [**New**] openmpt123: openmpt123 will now expand file wildcards passed on the command line in Windows when built with MSVC. * [**New**] libopenmpt_ext: New interface `interactive2` adding `openmpt::ext::interactive2::note_off()`, `openmpt::ext::interactive2::note_fade()`, `openmpt::ext::interactive2::set_channel_panning()`, `openmpt::ext::interactive2::get_channel_panning()`, `openmpt::ext::interactive2::set_note_finetune()`, and `openmpt::ext::interactive2::get_note_finetune()` (C++) and `openmpt_module_ext_interface_interactive2.note_off()`, `openmpt_module_ext_interface_interactive2.note_fade()`, `openmpt_module_ext_interface_interactive2.set_channel_panning()`, `openmpt_module_ext_interface_interactive2.get_channel_panning()`, `openmpt_module_ext_interface_interactive2.set_note_finetune()`, and `openmpt_module_ext_interface_interactive2.get_note_finetune()` (C). * [**New**] `Makefile` `CONFIG=emscripten` now supports `EMSCRIPTEN_TARGET=audioworkletprocessor` which builds an ES6 module in a single file with reduced dependencies suitable to be used in an AudioWorkletProcessor. * [**New**] `Makefile` `CONFIG=emscripten` now supports `EMSCRIPTEN_PORTS=1` which uses dependencies (zlib, mp123, ogg, and vorbis) from Emscripten Ports instead of using miniz, minimp3, and stb_vorbis locally or building zlib, mp123, ogg, and vorbis locally. * [**New**] `Makefile` `CONFIG=emscripten` and `CONFIG=djgpp` can now build zlib, mpg123, and vorbis locally instead of only supporting miniz, minimp3, and stb_vorbis via `ALLOW_LGPL=1`. * [**Change**] `Makefile` `CONFIG=emscripten` now supports `EMSCRIPTEN_TARGET=all` which provides WebAssembly as well as fallback to JavaScript in a single build. * [**Change**] openmpt123: DOS builds now use the Mercury fork of `liballegro 4.2` for improved hardware compatibility. * [**Change**] libopenmpt no longer generates internal interpolation tables on library load time, but instead only on first module load time. * [**Regression**] `Makefile` `CONFIG=emscripten` does not support `EMSCRIPTEN_TARGET=asmjs` or `EMSCRIPTEN_TARGET=asmjs128m` any more because support has been removed from current Emscripten versions. * [**Regression**] Support for GCC 7 has been removed. * [**Regression**] Support for Clang 5, 6 has been removed. * [**Regression**] Support for Emscripten versions older than 1.39.7 has been removed. * [**Regression**] Building with Android NDK older than NDK r19c is not supported any more. * libopenmpt can now detect infinite pattern loops and treats them as the song end. This means that setting a repeat count other than -1 now always guarantees that playback will eventually end. The song loop counter is decremented each time it ends up at the start of the infinite loop, so the song does not restart from the beginning even if the repeat count is not 0. * `openmpt::module::set_position_seconds()` accuracy has been improved for modules with pattern loops. * Samples played at the wrong volume when rendering modules in mono. * IT: Portamentos in files with Linear Slides disabled are now more accurate. * IT: Pitch/Pan Separation was affected by note-off commands, and wasn't reset by panning commands like in Impulse Tracker. * IT: Even after libopenmpt 0.5.14 the filter reset logic was still not 100% identical to Impulse Tracker: A note triggered on tick 0 of a row with a Pattern Delay effect still caused the filter to be reset on repetitions of that row even though the note wasn't retriggered. * IT: Added read-only support for BeRoTracker commands 1 and 2 (equivalent to XM commands K and L). * XM: BeRoTracker saves smooth MIDI macros in a different way from OpenMPT. This command is now imported correctly. * XM: Emulate FT2 Tone Portamento quirk that inverts portamento direction after the target was reached (if target note was higher than previous note). * S3M files saved with Impulse Tracker and latest Schism Tracker now also compute sample playback speed in Hertz. * Depending on whether an S3M file was last saved in Scream Tracker with the Sound Blaster or Gravis Ultrasound drivers loaded, different compatibility flags are now applied. For files saved with the GUS, the sample volume factor is now also ignored (fixes volume levels in S3Ms made on the GUS, in particular if they use both samples and OPL instruments). * S3M: Enforce the lower frequency bound. * MOD: Loosened VBlank timing heuristics so that the original copy of Guitar Slinger from Dizzy Tunes II plays correctly. * FAR: Correct portamento depth is now used. * DMF / IMF: Improved accuracy of finetune commands. * MDL: Implemented finetune command. * OKT: Various accuracy improvements such as: Sharing volume between mixed channels, volume commands on mixed channels are permanent (not reset with new notes), mixed channels do not support default sample volume, 7-bit samples are actually supposed to be played as-is (not amplified to full 8-bit range), reject speed command parameters >= 20. * zlib: v1.2.11 (2017-01-15). * mpg123: v1.29.3 (2021-12-11). * ogg: v1.3.5 (2021-06-04). * vorbis: v1.3.7 (2020-07-04). * miniz: v2.2.0 (2021-06-27). * minimp3: commit 50d2aaf360a53653b718fead8e258d654c3a7e41 (2021-11-27). * stb_vorbis: v1.22 commit 5a0bb8b1c1b1ca3f4e2485f4114c1c8ea021b781 (2021-07-12). * FLAC: v1.3.3 (2019-08-04). * PortAudio: v19.7.0 (2021-04-06). ### libopenmpt 0.5.0 (2020-05-24) * [**New**] OggMod compressed FastTracker 2 XM (OXM) modules are now supported. * [**New**] The emulated Amiga type when Amiga resampler emulation is enabled can now be selected via ctl `render.resampler.emulate_amiga_type`. Possible values are: `"auto"`, `"a500"`, `"a1200"`, and an experimental option `"unfiltered"`. * [**New**] libopenmpt: New API `openmpt::module::get_current_estimated_bpm()` (C++), and `openmpt_module_get_current_estimated_bpm()` (C) which provides accurate beats per minute information for module formats with time signature and an educated guess based on speed and tempo for others. * [**New**] libopenmpt: New type-aware ctl APIs that do not require memory allocations and are thus realtime-safe: `openmpt::module::ctl_get_boolean()`, `openmpt::module::ctl_get_integer()`, `openmpt::module::ctl_get_floatingpoint()`, `openmpt::module::ctl_get_text()`, `openmpt::module::ctl_set_boolean()`, `openmpt::module::ctl_set_integer()`, `openmpt::module::ctl_set_floatingpoint()` (C++), and `openmpt_module_ctl_get_boolean()`, `openmpt_module_ctl_get_integer()`, `openmpt_module_ctl_get_floatingpoint()`, `openmpt_module_ctl_get_text()`, `openmpt_module_ctl_set_boolean()`, `openmpt_module_ctl_set_integer()`, `openmpt_module_ctl_set_floatingpoint()` (C). * [**New**] libopenmpt C++ New API `openmpt::is_extension_supported2()` which takes a `std::string_view` parameter instead of `std::string`. * [**New**] libopenmpt C++: New API `openmpt::module::module(std::vector data)`, `openmpt::module::module(const std::byte * data, std::size_t size)`, `openmpt::module::module(const std::byte * beg, const std::byte * end)`. * [**New**] libopenmpt C++: New API `openmpt::probe_file_header(flags, const std::byte * data, std::size_t size, filesize)`, `openmpt::probe_file_header(flags, const std::byte * data, std::size_t size)`. * [**New**] libopenmpt_ext C++: New API `openmpt::module_ext::module_ext(std::vector data)`, `openmpt::module_ext::module_ext(const std::byte * data, std::size_t size)`, `openmpt::module_ext::module_ext(std::vector data)`, `openmpt::module_ext::module_ext(const std::uint8_t * data, std::size_t size)`. * [**Change**] std::istream based file I/O has been speed up. * [**Change**] Dependency on iconv on Linux has been removed. * [**Regression**] libmodplug: The libmodplug emulation layer has been removed from the libopenmpt tree. Please use the separate `libopenmpt-modplug` package instead. * [**Regression**] foo_openmpt: foo_openmpt is discontinued. Please use Kode54's fork foo_openmpt54: . * [**Regression**] Support for building with C++11 or C++14 has been removed. C++17 is now required to build libopenmpt. * [**Regression**] Support for client code using C++11 or C++ 14 has been removed. C++17 is now required to build libopenmpt client applications. * [**Regression**] Support for Visual Studio 2015 has been removed. * [**Regression**] Support for GCC 4.8, 4.9, 5, 6 has been removed. * [**Regression**] Support for Clang 3.6, 3.7, 3.8, 3.9, 4 has been removed. * [**Regression**] Support for Emscripten versions older than 1.39.1 has been removed. * [**Regression**] Building with Android NDK older than NDK r18b is not supported any more. * [**Regression**] openmpt123: Support for SDL1 (but not SDL2) output has been removed. * [**Regression**] openmpt123: Support for SDL2 older than 2.0.4 has been removed. * [**Regression**] Windows XP and Windows Vista are no longer supported. * [**Regression**] It is no longer possible to optionally use iconv for character set conversions. * [**Bug**] openmpt123: openmpt123 now honors the current locale and outputs text appropriately. * [**Bug**] openmpt123: Piping text output to other than console window targets on Windows has been fixed. * Greatly improved MED import. Synthesized instruments are still not supported but support was added for: Multisampled instruments, delta samples, more pattern commands, Hold and Decay, multiple songs and many other small changes. * Improved OPL channel allocation when more than 18 notes are active, so that channels that have completely faded out are prioritized over channels that have already been released but have not faded out yet. * Interactively triggering an OPL instrument could cause the first pattern channel to no longer be played back correctly. * Fix some inaccuracies in OPL emulator. * Fix overflow of OPL amplification happening at a synth volume level of 510. * End-of-sample pop reduction of surround channels was applied to front channels instead, causing a pop on the front channels instead of removing it on the back channels. * IT: Disable retrigger with short notes quirk for modules saved with Chibi Tracker, as it does not implement that quirk. * IT: Instrument and sample panning should not override channel panning for following notes. * IT: SBx is now prioritized over Bxx commands that are to the left of it. * IT: Duplicate Check Type "Sample" should only be applied if the instruments match, too. * IT: Duplicate Check Type "Note" should compare pattern notes, but it was comparing the new pattern note against the old translated note. * IT: Various fixes for envelope resetting. * IT / S3M: When combining SBx and EEx effects, don't skip the first row of the loop like in FastTracker 2. * S3M: Empty pattern commands now affect effect memory as well. * S3M: Offset beyond loop end wraps around to loop start like in Scream Tracker 3 + GUS (previously it just keep playing from the loop start, which is neither what GUS nor Sound Blaster drivers do). * S3M: Notes cannot be retriggered after they have been cut. * S3M: Fix portamento after note cut (fixes antediluvian_song.s3m). * S3M / MOD: Previous note offset is no longer used for retriggered notes if there was no instrument number next to the Qxy effect. * MOD: Sample swapping now also works if the sample that is being swapped from does not loop. Swapping to a non-looped sample now stops playback once the swapped-from sample reaches its (loop) end. * MOD: Fix early song ending due to ProTracker pattern jump quirk (EEx + Dxx on same row) if infinite looping is disabled. Fixes Haunted Tracks.mod by Triace. * MOD: Previous note offset is no longer used for retriggered notes if there was no instrument number next to the E9x effect. * MOD: Vibrato type "ramp down" was upside down. * XM: If a file contains patterns longer than 1024 rows, they are now clamped to 1024 rows instead of 64 rows. * XM: Do not reset note-off status on portamento if there is no instrument number. * mpg123: v1.26rc3. * ogg: v1.3.4. * vorbis: v1.3.6. * zlib: v1.2.11. * minimp3: commit 55da78cbeea5fb6757f8df672567714e1e8ca3e9 (2020-03-04). * stb_vorbis: v1.19 commit 37b9b20fdec06c75a0493e0bb59e2d0f288bfb51 (2020-02-05). * miniz: v2.1.0. * FLAC: v1.3.3. * PortAudio: commit 799a6834a58592eadc5712cba73b35956dc51579 (2020-03-26). ### libopenmpt 0.4.0 (2018-12-23) * [**New**] libopenmpt now includes emulation of the OPL chip and thus plays OPL instruments in S3M, C67 and MPTM files. OPL chip emulation volume can be changed with the new ctl `render.opl.volume_factor`. * [**New**] libopenmpt now supports CDFM / Composer 670 module files. * [**New**] Autotools `configure` and plain `Makefile` now honor the variable `CXXSTDLIB_PCLIBSPRIVATE` which serves the sole purpose of listing the standard library (or libraries) required for static linking. The contents of this variable will be put in `libopenmpt.pc` `Libs.private` and used for nothing else. See \ref libopenmpt_c_staticlinking . * [**New**] foo_openmpt: foo_openmpt now also works on Windows XP. * [**New**] libopenmpt Emscripten builds now ship with MP3 support by default, based on minimp3 by Lion (github.com/lieff). * [**New**] libopenmpt: New ctl `play.at_end` can be used to change what happens when the song end is reached: * "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames. This is the default and identical to the behaviour in previous libopenmpt versions. * "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start. This can be used for custom loop logic, such as loop auto-detection and longer fadeouts. * "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames. * [**New**] Add new metadata fields `"originaltype"` and `"originaltype_long"` which allow more clearly reflecting what is going on with converted formats like MO3 and GDM. * [**New**] `Makefile` `CONFIG=emscripten` now can generate WebAssembly via the additional option `EMSCRIPTEN_TARGET=wasm`. * [**New**] Compiling for DOS is now experimentally supported via DJGPP GCC 7.2 or later. * [**Change**] minimp3: Instead of the LGPL-2.1-licensed minimp3 by KeyJ, libopenmpt now uses the CC0-1.0-licensed minimp3 by Lion (github.com/lieff) as a fallback if libmpg123 is unavailable. The `USE_MINIMP3` `Makefile` option is gone and minimp3 will be used automatically in the `Makefile` build system if libmpg123 is not available. * [**Change**] openmpt123: openmpt123 now rejects `--output-type` in `--ui` and `--batch` modes and also rejects `--output` in `--render` mode. These combinations of options really made no sense and were rather confusing. * [**Change**] Android NDK build system now uses libc++ (`c++_shared`) instead of GNU libstdc++ (`gnustl_shared`), as recommended by Android NDK r16b. * [**Change**] xmp-openmpt: `openmpt-mpg123.dll` is no longer optional and must be placed into the same directory as `xmp-openmpt.dll`. * [**Change**] in_openmpt: `openmpt-mpg123.dll` is no longer optional and must be placed either into the directory of the player itself or into the same directory as `in_openmpt.dll`. This is dependent on how the player loads its plugins. For WinAMP 5, `openmpt-mpg123.dll` needs to be in the directory which contains `winamp.exe`. `in_openmpt.dll` needs to be in the `Plugins` directory. * [**Change**] foo_openmpt: foo_openmpt is now packaged as a fb2k-component package for easier installation. * [**Change**] When building libopenmpt with MinGW-w64, it is now recommended to use the posix thread model (as opposed to the win32 threading model), because the former does support std::mutex while the latter does not. When building with win32 threading model with the Autotools build system, it is recommended to provide the `mingw-std-threads` package. Building libopenmpt with MinGW-w64 without any `std::thread`/`std::mutex` support is deprecated and support for such configurations will be removed in libopenmpt 0.5. * [**Change**] `Makefile` `CONFIG=emscripten` now has 4 `EMSCRIPTEN_TARGET=` settings: `wasm` generates WebAssembly, `asmjs128m` generates asm.js with a fixed size 128MB heap, `asmjs` generates asm.js with a fixed default size heap (as of Emscripten 1.38.11, this amounts to 16MB), `js` generates JavaScript with dynamic heap growth and with compatibility for older VMs. * [**Change**] libmodplug: Update public headers to libmodplug 0.8.8.5. This adds support for kind-of automatic MODPLUG_EXPORT decoration on Windows. * [**Regression**] Support for Clang 3.4, 3.5 has been removed. * [**Regression**] Building with Android NDK older than NDK r16b is not supported any more. * [**Regression**] Support for Emscripten versions older than 1.38.5 has been removed. * [**Regression**] Support for libmpg123 older than 1.14.0 has been removed. * [**Regression**] Using MediaFoundation to decode MP3 samples is no longer supported. Use libmpg123 or minimp3 instead. * [**Regression**] libmodplug: Support for emulating libmodplug 0.8.7 API/ABI has been removed. * [**Bug**] xmp-openmpt: Sample rate and number of output channels were not applied correctly when using per-file settings. * [**Bug**] Internal mixer state was not initialized properly when initially rendering in 44100kHz stereo format. * [**Bug**] openmpt123: Prevent libsdl2 and libsdl from being enabled at the same time because they conflict with each other. * [**Bug**] libmodplug: Setting `SNDMIX_NORESAMPLING` in the C++ API always resulted in linear interpolation instead of nearest neighbour * IT: In Compatible Gxx mode, allow sample changes next to a tone portamento effect if a previous sample has already stopped playing. * IT: Fix broken volume envelopes with negative values as found in breakdwn.it by Elysis. * MOD: Slides and delayed notes are executed on every repetition of a row with row delay (fixes "ode to protracker"). * XM: If the sustain point of the panning envelope is reached before key-off, it is never released. * XM: Do not default recall volume / panning for delayed instrument-less notes * XM :E60 loop bug was not considered in song length calucation. * S3M: Notes without instrument number use previous note's sample offset. * Tighten M15 and MOD file rejection heuristics. * J2B: Ignore frequency limits from file header. Fixes Medivo.j2b, broken since libopenmpt-0.2.6401-beta17. * STM: More accurate tempo calculation. * STM: Better support for early format revisions (no such files have been found in the wild, though). * STM: Last character of sample name was missing. * SFX: Work around bad conversions of the "Operation Stealth" soundtrack by turning pattern breaks into note stops. * IMF: Filter cutoff was upside down and the cutoff range was too small. * ParamEq plugin center frequency was not limited correctly. * Keep track of active SFx macro during seeking. * The "note cut" duplicate note action did not volume-ramp the previously playing sample. * A song starting with non-existing patterns could not be played. * DSM: Support restart position and 16-bit samples. * DTM: Import global volume. * MOD: Support notes in octave 2, like in FastTracker 2 (fixes DOPE.MOD). * Do not apply Amiga playback heuristics to MOD files that have clearly been written with a PC tracker. * MPTM: More logical release node behaviour. * Subsong search is now less thorough. It could previously find many subsongs that are technically correct (unplayed rows at the beginning of patterns that have been jumped over due to pattern breaks), but so far no real-world module that would require such a thorough subsong detection was found. The old mechanism caused way more false positives than intended with real-world modules, though. * Restrict the unpacked size of compressed DMF, IT, MDL and MO3 samples to avoid huge allocations with malformed small files. ### libopenmpt 0.3 (2017-09-27) * [**New**] New error handling functionality in the C API, which in particular allows distinguishing potentially transient out-of-memory errors from parse errors during module loading. * [**New**] New API `openmpt::module::get_selected_subsong()` (C++) and `openmpt_module_get_selected_subsong()` (C). * [**New**] Faster file header probing API `openmpt::probe_file_header()` and `openmpt::probe_file_header_get_recommended_size` (C++), and `openmpt_probe_file_header()`, `openmpt_probe_file_header_without_filesize()`, `openmpt_probe_file_header_from_stream()` and `openmpt_probe_file_header_get_recommended_size()` (C). * [**New**] New API `openmpt::could_open_probability()` (C++) and `openmpt_could_open_probability()` (C). This fixes a spelling error in the old 0.2 API. * [**New**] openmpt123: openmpt123 can now open M3U, M3U8, M3UEXT, M3U8EXT and PLSv2 playlists via the `--playlist` option. * [**New**] openmpt123: openmpt123 now supports very fast file header probing via the `--probe` option. * [**New**] Libopenmpt now supports building for Windows 10 Universal (Windows Store 8.2) APIs with MSVC, and also for the older Windows Runtime APIs with MinGW-w64. * [**New**] New API header `libopenmpt_ext.h` which implements the libopenmpt extension APIs also for the C interface. * [**New**] The Reverb effect (S99 in S3M/IT/MPTM, and X99 in XM) is now implemented in libopenmpt. * [**New**] For Amiga modules, a new resampler based on the Amiga's sound characteristics has been added. It can be activated by passing the `render.resampler.emulate_amiga` ctl with a value of `1`. Non-Amiga modules are not affected by this, and setting the ctl overrides the resampler choice specified by `OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH` or `openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH`. Support for the MOD command E0x (Set LED Filter) is also available when the Amiga resampler is enabled. * [**Change**] libopenmpt versioning changed and follows the more conventional major.minor.patch as well as the recommendations of the [SemVer](http://semver.org/) scheme now. In addition to the SemVer requirements, pre-1.0.0 versions will also honor API and ABI stability in libopenmpt (i.e. libopenmpt ignores SemVer Clause 4). * [**Change**] The output directories of the MSVC build system were changed to `bin/vs2015-shared/x86-64-win7/` (and similar) layout which allows building in the same tree with different compiler versions without overwriting other outputs. * [**Change**] The emscripten build now exports libopenmpt as 'libopenmpt' instead of the default 'Module'. * [**Change**] Android: The build system changed. The various Android.mk files have been merged into a single one which can be controlled using command line options. * [**Change**] The `Makefile` build system now passes `std=c++11` to the compiler by default. Older compilers may still work if you pass `STDCXX=c++0x` to the `make` invocation. * [**Change**] The `Makefile` option `ANCIENT=1` is gone. * [**Change**] The optional dependencies on `libltdl` or `libdl` are gone. They are no longer needed for any functionality. * [**Regression**] Compiling client code using the C++ API now requires a compiler running in C++11 mode. * [**Regression**] Support for GCC 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7 has been removed. * [**Regression**] Support for Clang 3.0, 3.1, 3.2, 3.3 has been removed. * [**Regression**] Support for Emscripten versions older than 1.31.0 has been removed. * [**Regression**] Support for Android NDK versions older than 11 has been removed. * [**Regression**] Visual Studio 2008, 2010, 2012, 2013 support has been removed. * [**Regression**] Dynamic run-time loading of libmpg123 is no longer supported. Libmpg123 must be linked at link-time now. * [**Regression**] xmp-openmpt: xmp-openmpt now requires XMPlay 3.8 or later and compiling xmp-openmpt requires an appropriate XMPlay SDK with `XMPIN_FACE` >= `4`. * [**Regression**] Support for libmpg123 older than 1.13.0 has been removed. * [**Regression**] Un4seen unmo3 support has been removed. * [**Bug**] C++ API: `openmpt::exception` did not define copy and move constructors or copy and move assignment operators in libopenmpt 0.2. The compiler-generated ones were not adequate though. libopenmpt 0.3 adds the appropriate special member functions. This adds the respective symbol names to the exported ABI, which, depending on the compiler, might or might not have been there in libopenmpt 0.2. The possibly resulting possible ODR violation only affects cases that did crash in the libopenmpt 0.2 API anyway due to memory double-free, and does not cause any further problems in practice for all known platforms and compilers. * [**Bug**] The C API could crash instead of failing gracefully in out-of-memory situations. * [**Bug**] The test suite could fail on MacOSX or FreeBSD in non-fatal ways when no locale was active. * [**Bug**] `libopenmpt_stream_callbacks_fd.h` and `libopenmpt_stream_callbacks_file.h` were missing in Windows development packages. * [**Bug**] libopenmpt on Windows did not properly guard against current working directory DLL injection attacks. * [**Bug**] localtime() was used to determine the version of Schism Tracker used to save IT and S3M files. This function is not guaranteed to be thread-safe by the standard and is now no longer used. * [**Bug**] Possible crashes with malformed IT, ITP, AMS, MDL, MED, MPTM, PSM and Startrekker files. * [**Bug**] Possible hangs with malformed DBM, MPTM and PSM files. * [**Bug**] Possible hangs with malformed files containing cyclic plugin routings. * [**Bug**] Excessive loading times with malformed ITP / truncated AMS files. * [**Bug**] Plugins did not work correctly when changing the sample rate between two render calls. * [**Bug**] Possible NULL-pointer dereference read during obscure out-of-memory situations while handling exceptions in the C API. * [**Bug**] libmodplug: `libmodplug.pc` was wrong. * [**Bug**] Cross-compiling libopenmpt with autotools for Windows now properly sets `-municode` and `-mconsole` as well as all required Windows system libraries. * [**Bug**] foo_openmpt: Interpolation filter and volume ramping settings were confused in previous versions. This version resets both to the defaults. * [**Bug**] libmodplug: The CSoundFile::Read function in the emulated libmodplug C++ API returned the wrong value, causing qmmp (and possibly other software) to crash. * Support for SoundTracker Pro II (STP) and Digital Tracker (DTM) modules. * Increased accuracy of the sample position and sample rate to drift less when playing very long samples. * Various playback improvements for IT and XM files. * Channel frequency could wrap around after some excessive portamento / down in some formats since libopenmpt 0.2-beta17. * Playback improvements for S3M files made with Impulse Tracker and Schism Tracker. * ParamEq plugin emulation didn't do anything at full gain (+15dB). * All standard DMO effects are now also emulated on non-Windows and non-MSVC systems. * Added `libopenmpt_stream_callbacks_buffer.h` which adds `openmpt_stream_callbacks` support for in-memory buffers, possibly even only using a truncated prefix view into a bigger file which is useful for probing. * Avoid enabling some ProTracker-specific quirks for MOD files most likely created with ScreamTracker 3. * Tremolo effect only had half the intended strength in MOD files. * Pattern loops ending on the last row a pattern were not executed correctly in S3M files. * Work-around for reading MIDI macros and plugin settings in some malformed IT files written by old UNMO3 versions. * Improve tracker detection in IT format. * Playback fixes for 8-channel MED files * Do not set note volume to 0 on out-of-range offset in XM files. * Better import of some slide commands in SFX files. * Sample 15 in "Crew Generation" by Necros requires short loops at the beginning of the sample to not be ignored. Since we need to ignore them in some (non-ProTracker) modules, we heuristically disable the old loop sanitization behaviour based on the module channel count. * Both normal and percentage offset in PLM files were handled as percentage offset. * MT2 files with instruments that had both sample and plugin assignments were not read correctly. * Some valid FAR files were rejected erroneously. * Support for VBlank timing flag and comment field in PT36 files. * Improved accuracy of vibrato command in DIGI / DBM files. * STM: Add support for "WUZAMOD!" magic bytes and allow some slightly malformed STM files to load which were previously rejected. * Detect whether "hidden" patterns in the order list of SoundTracker modules should be taken into account or not. * Tighten heuristics for rejecting invalid 669, M15, MOD and ICE files and loosen them in other places to allow some valid MOD files to load. * Improvements to seeking: Channel panning was not always updated from instruments / samples when seeking, and out-of-range global volume was not applied correctly in some formats. * seek.sync_samples=1 did not apply PTM reverse offset effect and the volume slide part of combined volume slide + vibrato commands. * If the order list was longer than 256 items and there was a pattern break effect without a position jump on the last pattern of the sequence, it did not jump to the correct restart order. * `Makefile` has now explicit support for FreeBSD with no special option or configuration required. * openmpt123: Improved section layout in man page. * libmodplug: Added all missing C++ API symbols that are accessible via the public libmodplug header file. * Autotools build system now has options `--disable-openmpt123`, `--disable-tests` and `--disable-examples` which may be desireable when cross-compiling. * Windows binary packages now ship with libmpg123 included. ### libopenmpt 0.2-beta20 (2016-08-07) * [**Bug**] PSM loader was broken on big-endian platforms since forever. * [**Bug**] `load.skip_samples` ctl did not work for PSM16 modules. * There is a new `subsong` ctl, which can return the currently selected subsong. * More accurate ProTracker arpeggio wrap-around emulation. * More accurate sample tuning in PSM16 files. * Samples in DSM files were sometimes detuned and some pattern commands were not imported correctly. * More accurate import of MDL 7-bit panning command. * Only import pattern commands supported by the UltraTracker version that was used to save ULT files. Add support for command 5-C (end loop). * DMF sample loop lengths were off by one. * Unis 669 pan slide effect was too deep. * Several valid (but slightly corrupted possibly due to disk failures or data transfer errors) SoundTracker files were no longer loading since libopenmpt 0.2-beta18. ### libopenmpt 0.2-beta19 (2016-07-23) * [**Change**] libopenmpt now uses C++14 `[[deprecated]]` attribute instead of compiler-specific solutions when appropriate. * [**Change**] libopenmpt C++ header now uses C++11 `noexcept` instead of C++98 `throw()` exception specification when supported. `throw()` is deprecated since C++11. This does not change API or ABI as they are equivalent. Use `LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT` to override the default. * [**Change**] The preprocessor macro `LIBOPENMPT_ANCIENT_COMPILER_STDINT` is gone. Please use `LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT instead`. Additionally, the typedefs moved from illegal namespace ::std into somewhat less dangerous namespace ::openmpt::std. You can test `#ifdef LIBOPENMPT_QUIRK_NO_CSTDINT` client-side to check whether `libopenmpt.hpp` used the non-standard types. (Note: Of all supported compilers, this change only affects the 3 compilers with only limited support: MSVC 2008, GCC 4.1, GCC 4.2.) * [**Bug**] xmp-openmpt: Crash when viewing sample texts. * The public libopenmpt C++ header has auto-detection logic for the used C++ standard now. In case your client code compiler misreports the standard version or you want to override it for other reasons, `#define LIBOPENMPT_ASSUME_CPLUSPLUS` to the value of the standard version you desire to be used. There is also a macro for each individual aspect, like `LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT`, `LIBOPENMPT_ASSUME_CPLUSPLUS_DEPRECATED`, `LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT` which take precedence over the general macro. * Portamento with sample swap behaviour was wrong for ProTracker MODs. * Rewritten loader and various playback fixes for MDL files. * libopenmpt 0.2-beta18 broke import of many pattern commands in DBM, DMF and ULT files. * ADPCM samples in MOD files were broken since libopenmpt 0.2-beta17. ### libopenmpt 0.2-beta18 (2016-07-11) * [**Change**] openmpt123: Add PulseAudio output support. Autotools and `Makefile` build systems now depend on `libpulse` and `libpulse-simple` by default. Disable with `--without-pulseaudio` or `NO_PULSEAUDIO=1` respectively. When enabled, PulseAudio will be the default output driver, * [**Change**] xmp-openmpt: Settings are now stored in xmplay.ini like with every other plugin. * [**Regression**] openmpt123: Support for FLAC < 1.3.0 has been removed. FLAC before 1.3.0 is broken beyond repair as it provides `assert.h` in the include path. * [**Bug**] Generated pkg-config file libopenmpt.pc by both `Makefile` and Autotools build systems was totally broken. * [**Bug**] libopenmpt no longer uses the non-thread-safe global std::rand() function. * [**Bug**] Sample loops in GDM modules did not work when using Emscripten. * [**Bug**] XM and MO3 loaders could crash due to unaligned memory accesses. * [**Bug**] Fixed incorrect handling of custom MPTM tunings on big endian platforms. * [**Bug**] Fixed various problems found with clang 3.8 static analyzer, address sanitizer and undefined behaviour sanitizer. * [**Bug**] File header probing functionality was broken for most formats. * [**Bug**] With non-seekable streams, the entire file was almost always cached even if it was not of any supported module type. * Seeking in allsubsongs-mode now works correctly. * openmpt123: Added subsong support. * Various playback fixes for 669, IT, MT2 and MTM files. * Some MOD files with more than 128 patterns (e.g. NIETNU.MOD) were not loaded correctly. * A new example `libopenmpt_example_c_probe` has been added which demonstrates the usage and flexibility of openmpt_could_open_propability() in the C API under various constraints. ### libopenmpt 0.2-beta17 (2016-05-21) * [**Change**] The Makefile and Autotools build systems now require to explicitly specify `NO_LTDL=1` or `--without-ltdl` respectively if no support for dynamic loading of third party libraries via libtool libltdl is desired. * [**Change**] In the Makefile build system option `USE_MO3` and the Autotools build system option `--enable-mo3` are gone. Dynamic loading of un4seen unmo3 is now always enabled when dynamic loading is possible and built-in MO3 support is not possible because either a MP3 or a Vorbis decoder is missing. * [**Change**] The MSVC build system changed. The `libopenmptDLL` project is gone. Use the new `ReleaseShared` configuration of the `libopenmpt` project instead. libopenmpt now links against zlib by default. A separate project with smaller footprint linking against miniz is still available as `libopenmpt-small`. * [**Change**] The constants used to query library information from `openmpt_get_string()` and `openmpt::string::get()` (i.e. OPENMPT_STRING_FOO and openmpt::string::FOO) have been deprecated because having syntactic constants for theses keys makes extending the API in a backwards and forwards compatible way harder than it should be. Please just use the string literals directly. * [**Change**] Deprecated API identifiers will now cause deprecation warnings with MSVC, GCC and clang. `#define LIBOPENMPT_NO_DEPRECATE` to disable the warnings. * [**Change**] openmpt123: `--[no-]shuffle` option has been renamed to `--[no-]randomize`. A new `--[no-]shuffle` option has been added which shuffles randomly through the playlist as opposed to randomizing the playlist upfront. * [**Change**] Support for Un4seen unmo3 has generally been deprecated in favour of the new internal mo3 decoder. Un4seen unmo3 support will be removed on 2018-01-01. * [**Bug**] Memory consumption during loading has been reduced by about 1/3 in case a seekable input stream is provided (either via C API callback open functions or via C++ API iostream constructors). * [**Bug**] Some samples in AMS modules were detuned when using Emscripten. * [**Bug**] Possible crash with excessive portamento down in some formats. * [**Bug**] Possible crashes with malformed AMF, AMS, DBM, IT, MDL, MED, MPTM, MT2, PSM and MMCMP-, XPK- and PP20-compressed files. * [**Bug**] `openmpt::module::format_pattern_row_channel` with `width == 0` was returning an empty string instead of an string with unconstrained length. * Support for ProTracker 3.6 IFF-style modules and SoundFX / MultiMedia Sound (SFX / MMS) modules. * libopenmpt now has support for DMO plugins on Windows when built with MSVC. Additionally, the DMO Compression, Distortion, Echo, Gargle, ParamEQ and WavesReverb DSPs are emulated on on all other platforms. * libopenmpt now supports the DigiBooster Echo DSP. * To avoid any of the aforementioned plugins to be used, the load.skip_plugins ctl can be passed when loading a module. * libopenmpt got native MO3 support with MP3 decoding either via libmpg123 or MediaFoundation (on Windows 7 and up) and Vorbis decoding via libogg, libvorbis, libvorbisfile or stb_vorbis. * libopenmpt MSVC builds with Visual Studio 2010 or later on Windows 7 or later now use an internal MO3 decoder with libogg, libvorbis, libvorbisfile, and libmpg123 or minimp3 or MediaFoundation suppport by default. Visual Studio 2008 builds still use unmo3.dll by default but also support the built-in decoder in which case libmpg123 is required. * libopenmpt with Makefile or Autotools build system can now also use glibc/libdl instead of libtool/libltdl for dynamic loading of third-party libraries. Options `NO_DL=1` and `--without-dl` have been added respectively. * The `Makefile` build system got 4 new options NO_MPG123, NO_OGG, NO_VORBIS, NO_VORBISFILE. The default is to use the new dependencies automatically. * The `Autotools` build system got 4 new options --without-mpg123, --without-ogg, --without-vorbis, --without-vorbisfile. The default is to use the new dependencies automatically. * Makefile and Android builds got support for using minimp3 instead of libmpg123. For Android, use `Android-minimp3-stbvorbis.mk`, for Makefile use `USE_MINIMP3=1`. You have to download [minimp3](http://keyj.emphy.de/minimp3/) yourself and put its contents into `include/minimp3/`. * `"source_url"`, `"source_date"` and `"build_compiler"` keys have been added to `openmpt_string_get()` and `openmpt::string::get()`. * openmpt123: Add new `--[no-]restart]` option which restarts the playlist when finished. * Improved Ultimate SoundTracker version detection heuristics. * Playing a sample at a sample rate close to the mix rate could lead to small clicks when using vibrato. * More fine-grained internal legacy module compatibility settings to correctly play back modules made with older versions of OpenMPT and a few other trackers. * The tail of compressed MDL samples was slightly off. * Some probably hex-edited XM files (e.g. cybernostra weekend.xm) were not loaded correctly. * Countless other playback fixes for MOD, XM, S3M, IT and MT2 files. ### libopenmpt 0.2-beta16 (2015-11-22) * [**Change**] The Autotools build system does strict checking of all dependencies now. Instead of best effort auto-magic detection of all potentially optional dependencies, the default set of dependencies is now enforced unless each individual dependency gets explicitely disabled via `--without-foo` or `--disable-foo` `./configure` switches. Run `./configure --help` for the full list of options. * [**Bug**] Some MOD files were erroneously detected as 669 files. * [**Bug**] Some malformed AMF files could result in very long loading times. * [**Bug**] Fixed crashes in IMF and MT2 loaders. * [**Bug**] MTM files generated by UNMO3 were not loaded properly. * Improved MTM playback. * `make CONFIG=haiku` for Haiku has been added. * Language bindings for FreeBASIC have been added (see `libopenmpt/bindings/`). ### libopenmpt 0.2-beta15 (2015-10-31) * [**Change**] openmpt123: SDL2 is now supported and preferred to SDL1 if available with the `Makefile` build system. * [**Bug**] Emscripten support for older emscripten versions broke in -beta14. These are now supported again when using `make CONFIG=emscripten-old`. * [**Bug**] Fixed crashes in MED loader. * Playback improvements and loader fixes for MOD, MT2 and MED. ### libopenmpt 0.2-beta14 (2015-09-13) * [**Change**] The C++ API example now uses the PortAudio C++ bindings instead of the C API. * [**Change**] Default compiler options for Emscripten have been changed to more closely match the Emscripten recommendations. * [**Bug**] Client code compilation with C89 compilers was broken in beta13. * [**Bug**] Test suite failed on certain Emscripten/node.js combinations. * [**Bug**] Fixed various crashes or hangs in DMF, OKT, PLM, IT and MPTM loaders. * Implemented error handling in the libopenmpt API examples. * Various playback improvements and fixes for OKT, IT and MOD. ### libopenmpt 0.2-beta13 (2015-08-16) * [**Change**] The MSVC build system has been redone. Solutions are now located in `build/vsVERSION/`. * [**Bug**] get_current_channel_vu_left and get_current_channel_vu_right only return the volume of the front left and right channels now. get_current_channel_vu_rear_left and get_current_channel_vu_rear_right do now actually work and return non-zero values. * [**Bug**] Fix crashes and hangs in MED and MDL loaders and with some truncated compressed IT samples. * [**Bug**] Fix crash when playing extremely high-pitched samples. * Completed C and C++ documentation * Added new key for openmpt::module::get_metadata, "message_raw", which returns an empty string if there is no song message rather than a list of instrument names. * in_openmpt: Support for compiling with VS2008. * xmp-openmpt: Support for compiling with VS2008. * in_openmpt: Add a more readable file information window. ### libopenmpt 0.2-beta12 (2015-04-19) * Playback fix when row delay effect is used together with offset command. * A couple of fixes for the seek.sync_samples=1 case. * IT compatibility fix for IT note delay. * ProTracker MOD playback compatibility improvement. ### libopenmpt 0.2-beta11 (2015-04-18) * [**Change**] openmpt_stream_seek_func() now gets called with OPENMPT_STREAM_SEEK_SET, OPENMPT_STREAM_SEEK_CUR and OPENMPT_STREAM_SEEK_END whence parameter instead of SEEK_SET, SEEK_CUR and SEEK_END. These are defined to 0, 1 and 2 respectively which corresponds to the definition in all common C libraries. If your C library uses different constants, this theoretically breaks binary compatibility. The old libopenmpt code, however, never actually called the seek function, thus, there will be no problem in practice. * [**Change**] openmpt123: When both SDL1.2 and PortAudio are available, SDL is now the preferred backend because SDL is more widespread and better tested on all kinds of different platforms, and in general, SDL is just more reliable. * [**Bug**] libopenmpt now also compiles with GCC 4.3. * libopenmpt now supports PLM (Disorder Tracker 2) files. * Various playback improvements and fixes for IT, S3M, XM, MOD, PTM and 669 files. ### libopenmpt 0.2-beta10 (2015-02-17) * [**Change**] Makefile configuration filenames changed from `build/make/Makefile.config.*` to `build/make/config-*.mk`. * [**Change**] libopenmpt for Android now supports unmo3 from un4seen. See `build/android_ndk/README.AndroidNDK.txt` for details. * [**Bug**] Fix out-of-bounds read in mixer code for ProTracker-compatible MOD files which was introduced back in r4223 / beta6. * Vibrato effect was too weak in beta8 and beta9 in IT linear slide mode. * Very small fine portamento was wrong in beta8 and beta9 in IT linear slide mode. * Tiny IT playback compatibility improvements. * STM playback improvements. ### libopenmpt 0.2-beta9 (2014-12-21) * [**Bug**] libopenmpt_ext.hpp was missing from the Windows binary zip files. ### libopenmpt 0.2-beta8 (2014-12-21) * [**Change**] foo_openmpt: Settings are now accessible via foobar2000 advanced settings. * [**Change**] Autotools based build now supports libunmo3. Specify --enable-unmo3. * [**Change**] Support for dynamic loading of libunmo3 on MacOS X. * [**Change**] libopenmpt now uses libltld (from libtool) for dynamic loading of libunmo3 on all non-Windows platforms. * [**Change**] Support for older compilers: * GCC 4.1.x to 4.3.x (use `make ANCIENT=1`) * Microsoft Visual Studio 2008 (with latest Service Pack) (see `build/vs2008`) * [**Change**] libopenmpt_ext.hpp is now distributed by default. The API is still considered experimental and not guaranteed to stay API or ABI compatible. * [**Change**] xmp-openmpt / in_openmpt: No more libopenmpt_settings.dll. The settings dialog now uses a statically linked copy of MFC. * [**Bug**] The -autotools tarballs were not working at all. * Vastly improved MT2 loader. * Improved S3M playback compatibility. * Added openmpt::ext::interactive, an extension which adds a whole bunch of new functionality to change playback in some way or another. * Added possibility to sync sample playback when using openmpt::module::set_position_* by setting the ctl value seek.sync_samples=1 * Support for "hidden" subsongs has been added. They are accessible through the same interface as ordinary subsongs, i.e. use openmpt::module::select_subsong to switch between any kind of subsongs. * All subsongs can now be played consecutively by passing -1 as the subsong index in openmpt::module::select_subsong. * Added documentation for a couple of more functions. ### libopenmpt 0.2-beta7 (2014-09-07) * [**Change**] libopenmpt now has an GNU Autotools based build system (in addition to all previously supported ways of building libopenmpt). Autotools support is packaged separately as tarballs ending in `-autotools.tar.gz`. * [**Bug**] The distributed windows .zip file did not include pugixml. * [**Regression**] openmpt123: Support for writing WavPack (.wv) files has been removed. Reasoning: 1. WavPack support was incomplete and did not include support for writing WavPack metadata at all. 2. openmpt123 already supports libSndFile which can be used to write uncompressed lossless WAV files which can then be encoded to whatever format the user desires with other tools. ### libopenmpt 0.2-beta6 (2014-09-06) * [**Change**] openmpt123: SDL is now also used by default if availble, in addition to PortAudio. * [**Change**] Support for emscripten is no longer experimental. * [**Change**] libopenmpt itself can now also be compiled with VS2008. * [**Bug**] Fix all known crashes on platforms that do not support unaligned memory access. * [**Bug**] openmpt123: Effect column was always missing in pattern display. ### libopenmpt 0.2-beta5 (2014-06-15) * [**Change**] Add unmo3 support for non-Windows builds. * [**Change**] Namespace all internal functions in order to allow statically linking against libopenmpt without risking duplicate symbols. * [**Change**] Iconv is now completely optional and only used on Linux systems by default. * [**Change**] Added libopenmpt_example_c_stdout.c, an example without requiring PortAudio. * [**Change**] Add experimental support for building libopenmpt with emscripten. * [**Bug**] Fix ping-pong loop behaviour which broke in 0.2-beta3. * [**Bug**] Fix crashes when accessing invalid patterns through libopenmpt API. * [**Bug**] Makefile: Support building with missing optional dependencies without them being stated explicitely. * [**Bug**] openmpt123: Crash when quitting while playback is stopped. * [**Bug**] openmpt123: Crash when writing output to a file in interactive UI mode. * [**Bug**] openmpt123: Wrong FLAC output filename in --render mode. * Various smaller playback accuracy improvements. ### libopenmpt 0.2-beta4 (2014-02-25) * [**Bug**] Makefile: Dependency tracking for the test suite did not work. ### libopenmpt 0.2-beta3 (2014-02-21) * [**Change**] The test suite is now built by default with Makefile based builds. Use `TEST=0` to skip building the tests. `make check` runs the test suite. * [**Bug**] Crash in MOD and XM loaders on architectures not supporting unaligned memory access. * [**Bug**] MMCMP, PP20 and XPK unpackers should now work on non-x86 hardware and implement proper bounds checking. * [**Bug**] openmpt_module_get_num_samples() returned the wrong value. * [**Bug**] in_openmpt: DSP plugins did not work properly. * [**Bug**] in_openmpt/xmp-openmpt: Setting name for stereo separation was misspelled. This version will revert your stereo separation settings to default. * [**Bug**] Crash when loading some corrupted modules with stereo samples. * Support building on Android NDK. * Avoid clicks in sample loops when using interpolation. * IT filters are now done in integer instead of floating point. This improves performance, especially on architectures with no or a slow FPU. * MOD pattern break handling fixes. * Various XM playback improvements. * Improved and switchable dithering when using 16bit integer API. ### libopenmpt 0.2-beta2 (2014-01-12) * [**Bug**] MT2 loader crash. * [**Bug**] Saving settings in in_openmpt and xmp-openmpt did not work. * [**Bug**] Load libopenmpt_settings.dll also from below Plugins directory in Winamp. * DBM playback improvements. ### libopenmpt 0.2-beta1 (2013-12-31) * First release. libopenmpt-0.8.1+release.autotools/doc/libopenmpt_styleguide.md0000644000175000017500000000557713673126612022001 00000000000000 libopenmpt Style Guide ====================== ### libopenmpt **Note:** **This applies to `libopenmpt/` and `openmpt123/` directories only.** **Use OpenMPT style otherwise.** The code generally tries to follow these conventions, but they are not strictly enforced and there are valid reasons to diverge from these conventions. Using common sense is recommended. - In general, the most important thing is to keep style consistent with directly surrounding code. - Use C++ std types when possible, prefer `std::size_t` and `std::int32_t` over `long` or `int`. Do not use C99 std types (e.g. no pure `int32_t`) - Qualify namespaces explicitly, do not use `using`. Members of `namespace openmpt` can be named without full namespace qualification. - Prefer the C++ version in `namespace std` if the same functionality is provided by the C standard library as well. Also, include the C++ version of C standard library headers (e.g. use `` instead of ``. - Do not use ANY locale-dependant C functions. For locale-dependant C++ functionaly (especially iostream), always imbue the `std::locale::classic()` locale. - Prefer kernel_style_names over CamelCaseNames. - If a folder (or one of its parent folders) contains .clang-format, use clang-format v3.5 for indenting C++ and C files, otherwise: - `{` are placed at the end of the opening line. - Enclose even single statements in curly braces. - Avoid placing single statements on the same line as the `if`. - Opening parentheses are separated from keywords with a space. - Opening parentheses are not separated from function names. - Place spaces around operators and inside parentheses. - Align `:` and `,` when inheriting or initializing members in a constructor. - The pointer `*` is separated from both the type and the variable name. - Use tabs for identation, spaces for formatting. Tabs should only appear at the very beginning of a line. Do not assume any particular width of the TAB character. If width is important for formatting reasons, use spaces. - Use empty lines at will. - API documentation is done with doxygen. Use general C doxygen for the C API. Use QT-style doxygen for the C++ API. #### libopenmpt indentation example ~~~~{.cpp} namespace openmpt { // This is totally meaningless code and just illustrates indentation. class foo : public base , public otherbase { private: std::int32_t x; std::int16_t y; public: foo() : x(0) , y(-1) { return; } int bar() const; }; // class foo int foo::bar() const { for ( int i = 0; i < 23; ++i ) { switch ( x ) { case 2: something( y ); break; default: something( ( y - 1 ) * 2 ); break; } } if ( x == 12 ) { return -1; } else if ( x == 42 ) { return 1; } return 42; } } // namespace openmpt ~~~~ libopenmpt-0.8.1+release.autotools/doc/contributing.md0000644000175000017500000000446014570672527020077 00000000000000 Contributing ============ OpenMPT, libopenmpt, openmpt123, xmp-openmpt and in_openmpt are developed in the Subversion repository at [https://source.openmpt.org/browse/openmpt/trunk/OpenMPT/](https://source.openmpt.org/browse/openmpt/trunk/OpenMPT/). Patches can be provided either against this Subversion repository or against our GitHub mirror at [https://github.com/OpenMPT/openmpt/](https://github.com/OpenMPT/openmpt/). We do not have a developer mailing list. Discussions about new features or problems can happen at: * [Issue Tracker](https://bugs.openmpt.org/), preferred for specific bug reports or bug fixes and feature development discussion * [Forum](https://forum.openmpt.org/), preferred for long-term discussion of new features or specific questions about development * [IRC channel (`Libera.Chat/#openmpt`)](ircs://irc.libera.chat:6697/#openmpt), preferred for shorter questions * [GitHub pull requests](https://github.com/OpenMPT/openmpt/pulls), please only use for rather tiny fixes, see below For patch submissions, please also see [OpenMPT style guide](openmpt_styleguide.md) and [libopenmpt style guide](libopenmpt_styleguide.md). ### Contributing via GitHub As OpenMPT is developed in a Subversion repository and the GitHub repository is just mirrored from that, we cannot directly take pull requests via GitHub. We recognize that, especially for tiny bug fixes, the burden to choose a different way than GitHub for contributing can be too high. Thus, we will of course react, give feedback, and take patches also via GitHub pull requests. However, as the GitHub repository is strictly downstream from our Subversion repository (and this will not change, due to considerable complications when synchronizing this two-way), we cannot directly merge pull requests on GitHub. We will merge contributions to our Subversion repository, which will then in turn be mirrored to GitHub automatically, after which we will close the pull request. Authorship attribution in git relies on the email address used in the commit header, which is not how it usually works in Subversion. We will thus add an additional line to the commit message in the form of `Patch-by: John Doe `. If you prefer to be attributed with your nickname and/or without your email address, that would also be fine for us. libopenmpt-0.8.1+release.autotools/Doxyfile.in0000644000175000017500000035375015023302262016401 00000000000000# Doxyfile 1.9.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). # # Note: # # Use doxygen to compare the used configuration file with the template # configuration file: # doxygen -x [configFile] # Use doxygen to compare the used configuration file with the template # configuration file without replacing the environment variables: # doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the configuration # file that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = libopenmpt # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "cross-platform C++ and C library to decode tracked music files" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = bin/docs # If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 # sub-directories (in 2 levels) under the output directory of each output format # and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to # control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO # Controls the number of sub-directories that will be created when # CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every # level increment doubles the number of directories, resulting in 4096 # directories at level 8 which is the default and also the maximum value. The # sub-directories are organized in 2 levels, the first level always has a fixed # numer of 16 directories. # Minimum value: 0, maximum value: 8, default value: 8. # This tag requires that the tag CREATE_SUBDIRS is set to YES. CREATE_SUBDIRS_LEVEL = 8 # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, # Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English # (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, # Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with # English messages), Korean, Korean-en (Korean with English messages), Latvian, # Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, # Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, # Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = . # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line # such as # /*************** # as being the beginning of a Javadoc-style comment "banner". If set to NO, the # Javadoc-style will behave just like regular comments and it will not be # interpreted by doxygen. # The default value is: NO. JAVADOC_BANNER = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # By default Python docstrings are displayed as preformatted text and doxygen's # special commands cannot be used. By setting PYTHON_DOCSTRING to NO the # doxygen's special commands can be used and the contents of the docstring # documentation blocks is shown as doxygen documentation. # The default value is: YES. PYTHON_DOCSTRING = YES # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 2 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". Note that you cannot put \n's in the value part of an alias # to insert newlines (in the resulting output). You can put ^^ in the value part # of an alias to insert a newline as if a physical newline was in the original # file. When you need a literal { or } or , in the value part of an alias you # have to escape them by means of a backslash (\), this can lead to conflicts # with the commands \{ and \} for these it is advised to use the version @{ and # @} or use a double escape (\\{ and \\}) ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice # sources only. Doxygen will then generate output that is more tailored for that # language. For instance, namespaces will be presented as modules, types will be # separated into more groups, etc. # The default value is: NO. OPTIMIZE_OUTPUT_SLICE = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, # Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, # VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the # default for Fortran type files). For instance to make doxygen treat .inc files # as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. When specifying no_extension you should add # * to the FILE_PATTERNS. # # Note see also the list of default file extension mappings. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. # Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 # The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing # speed. At this moment only the input processing can be done using multiple # threads. Since this is still an experimental feature the default is set to 1, # which effectively disables parallel processing. Please report any issues you # encounter. Generating dot graphs in parallel is controlled by the # DOT_NUM_THREADS setting. # Minimum value: 0, maximum value: 32, default value: 1. NUM_PROC_THREADS = 1 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual # methods of a class will be included in the documentation. # The default value is: NO. EXTRACT_PRIV_VIRTUAL = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If this flag is set to YES, the name of an unnamed parameter in a declaration # will be determined by the corresponding definition. By default unnamed # parameters remain unnamed in the output. # The default value is: YES. RESOLVE_UNNAMED_PARAMS = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # declarations. If set to NO, these declarations will be included in the # documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # With the correct setting of option CASE_SENSE_NAMES doxygen will better be # able to match the capabilities of the underlying filesystem. In case the # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that # are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_HEADERFILE tag is set to YES then the documentation for a class # will show which file needs to be included to use the class. # The default value is: YES. SHOW_HEADERFILE = YES # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. See also section "Changing the # layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as documenting some parameters in # a documented function twice, or documenting parameters that don't exist or # using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete # function parameter documentation. If set to NO, doxygen will accept that some # parameters have no documentation without warning. # The default value is: YES. WARN_IF_INCOMPLETE_DOC = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong parameter # documentation, but not about the absence of documentation. If EXTRACT_ALL is # set to YES then this flag will automatically be disabled. See also # WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. # Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # In the $text part of the WARN_FORMAT command it is possible that a reference # to a more specific place is given. To make it easier to jump to this place # (outside of doxygen) the user can define a custom "cut" / "paste" string. # Example: # WARN_LINE_FORMAT = "'vi $file +$line'" # See also: WARN_FORMAT # The default value is: at line $line of file $file. WARN_LINE_FORMAT = "at line $line of file $file" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). In case the file specified cannot be opened for writing the # warning and error messages are written to standard error. When as file - is # specified the warning and error messages are written to standard output # (stdout). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = doc/libopenmpt/index.dox \ README.md \ doc/libopenmpt/dependencies.md \ doc/libopenmpt/gettingstarted.md \ doc/libopenmpt/packaging.md \ doc/contributing.md \ doc/libopenmpt_styleguide.md \ doc/openmpt_styleguide.md \ doc/libopenmpt/tests.md \ doc/libopenmpt/changelog.md \ doc/module_formats.md \ libopenmpt/libopenmpt.hpp \ libopenmpt/libopenmpt.h \ libopenmpt/libopenmpt_stream_callbacks_buffer.h \ libopenmpt/libopenmpt_stream_callbacks_fd.h \ libopenmpt/libopenmpt_stream_callbacks_file.h \ libopenmpt/libopenmpt_stream_callbacks_file_mingw.h \ libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h \ libopenmpt/libopenmpt_stream_callbacks_file_posix.h \ libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h \ libopenmpt/libopenmpt_config.h \ libopenmpt/libopenmpt_version.h \ libopenmpt/libopenmpt_ext.hpp \ libopenmpt/libopenmpt_ext.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, # *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C # comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, # *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # ANamespace::AClass, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = LIBOPENMPT_API \ LIBOPENMPT_CXX_API \ LIBOPENMPT_API_HELPER_EXPORT \ LIBOPENMPT_API_HELPER_IMPORT \ LIBOPENMPT_API_HELPER_PUBLIC \ LIBOPENMPT_API_HELPER_LOCAL \ OPENMPT_API_VERSION_HELPER_STRINGIZE \ OPENMPT_API_VERSION_STRINGIZE \ openmpt::detail # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = examples/ \ LICENSE # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # clang parser (see: # http://clang.llvm.org/) for more accurate parsing at the cost of reduced # performance. This can be particularly helpful with template rich C++ code for # which doxygen's built-in parser lacks the necessary type information. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO # If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS # tag is set to YES then doxygen will add the directory of each input to the # include path. # The default value is: YES. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_ADD_INC_PATHS = YES # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_OPTIONS = # If clang assisted parsing is enabled you can provide the clang parser with the # path to the directory containing a file called compile_commands.json. This # file is the compilation database (see: # http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the # options used when the source files were built. This is equivalent to # specifying the -p option to a clang tool, such as clang-check. These options # will then be passed to the parser. Any options specified with CLANG_OPTIONS # will be added as well. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. CLANG_DATABASE_PATH = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML # page. Disable this option to support browsers that do not have JavaScript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_MENUS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: # https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To # create a documentation set, doxygen will generate a Makefile in the HTML # output directory. Running make will produce the docset in that directory and # running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag determines the URL of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDURL = # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # on Windows. In the beginning of 2021 Microsoft took the original page, with # a.o. the download links, offline the HTML help workshop was already many years # in maintenance mode). You can download the HTML help workshop from the web # archives at Installation executable (see: # http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo # ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location (absolute path # including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to # run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine tune the look of the index (see "Fine-tuning the output"). As an # example, the default style sheet generated by doxygen has an example that # shows how to put an image at the root of the tree instead of the PROJECT_NAME. # Since the tree basically has the same information as the tab index, you could # consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = YES # When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the # FULL_SIDEBAR option determines if the side bar is limited to only the treeview # area (value NO) or if it should extend to the full height of the window (value # YES). Setting this to YES gives a layout similar to # https://docs.readthedocs.io with more room for contents, but less room for the # project logo, title, and description. If either GENERATE_TREEVIEW or # DISABLE_INDEX is set to NO, this option has no effect. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. FULL_SIDEBAR = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email # addresses. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. OBFUSCATE_EMAILS = YES # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for # the HTML output. These images will generally look nicer at scaled resolutions. # Possible values are: png (the default) and svg (looks nicer but requires the # pdf2svg or inkscape tool). # The default value is: png. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FORMULA_FORMAT = png # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. FORMULA_MACROFILE = # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # With MATHJAX_VERSION it is possible to specify the MathJax version to be used. # Note that the different versions of MathJax have different requirements with # regards to the different settings, so it is possible that also other MathJax # settings have to be changed when switching between the different MathJax # versions. # Possible values are: MathJax_2 and MathJax_3. # The default value is: MathJax_2. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_VERSION = MathJax_2 # When MathJax is enabled you can set the default output format to be used for # the MathJax output. For more details about the output format see MathJax # version 2 (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 # (see: # http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best # compatibility. This is the name for Mathjax version 2, for MathJax version 3 # this will be translated into chtml), NativeMML (i.e. MathML. Only supported # for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This # is the name for Mathjax version 3, for MathJax version 2 this will be # translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. The default value is: # - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 # - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # for MathJax version 2 (see # https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # For example for MathJax version 3 (see # http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): # MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /