Esempio n. 1
0
bool CZipArchive::ExtractFile(std::size_t index)
//----------------------------------------------
{
	mz_zip_archive *zip = static_cast<mz_zip_archive*>(zipFile);

	if(index >= contents.size())
	{
		return false;
	}

	mz_uint bestFile = index;

	mz_zip_archive_file_stat stat;
	MemsetZero(stat);
	mz_zip_reader_file_stat(zip, bestFile, &stat);
	if(stat.m_uncomp_size >= std::numeric_limits<std::size_t>::max())
	{
		return false;
	}
	try
	{
		data.resize(static_cast<std::size_t>(stat.m_uncomp_size));
	} catch(...)
	{
		return false;
	}
	if(!mz_zip_reader_extract_to_mem(zip, bestFile, &data[0], static_cast<std::size_t>(stat.m_uncomp_size), 0))
	{
		return false;
	}
	comment = mpt::ToWide(mpt::CharsetCP437, std::string(stat.m_comment, stat.m_comment + stat.m_comment_size));
	return true;
}
Esempio n. 2
0
bool COwnerVstEditor::OpenEditor(CWnd *parent)
//--------------------------------------------
{
	Create(IDD_PLUGINEDITOR, parent);

	// Some plugins (e.g. ProteusVX) need to be planted into another control or else they will break our window proc, making the window unusable.
	m_plugWindow.Create(nullptr, WS_CHILD | WS_VISIBLE, CRect(0, 0, 100, 100), this);

	// Set editor window size
	ERect rect;
	MemsetZero(rect);
	ERect *pRect = nullptr;
	CVstPlugin &vstPlug = static_cast<CVstPlugin &>(m_VstPlugin);
	vstPlug.Dispatch(effEditGetRect, 0, 0, &pRect, 0);
	if(pRect) rect = *pRect;
	vstPlug.Dispatch(effEditOpen, 0, 0, m_plugWindow.m_hWnd, 0);
	vstPlug.Dispatch(effEditGetRect, 0, 0, &pRect, 0);
	if(pRect) rect = *pRect;
	if(rect.right > rect.left && rect.bottom > rect.top)
	{
		// Plugin provided valid window size.
		SetSize(rect.right - rect.left, rect.bottom - rect.top);
	}

	vstPlug.Dispatch(effEditTop, 0,0, NULL, 0);
	vstPlug.Dispatch(effEditIdle, 0,0, NULL, 0);

	// Set knob mode to linear (2) instead of circular (0) for those plugins that support it (e.g. Steinberg VB-1)
	vstPlug.Dispatch(effSetEditKnobMode, 0, 2, nullptr, 0.0f);

	return CAbstractVstEditor::OpenEditor(parent);
}
Esempio n. 3
0
SoundDevice::DynamicCaps CWaveDevice::GetDeviceDynamicCaps(const std::vector<uint32> & /*baseSampleRates*/ )
//--------------------------------------------------------------------------------------------------------
{
	MPT_TRACE();
	SoundDevice::DynamicCaps caps;
	WAVEOUTCAPSW woc;
	MemsetZero(woc);
	if(GetDeviceIndex() > 0)
	{
		if(waveOutGetDevCapsW(GetDeviceIndex() - 1, &woc, sizeof(woc)) == MMSYSERR_NOERROR)
		{
			if(woc.dwFormats & (WAVE_FORMAT_96M08 | WAVE_FORMAT_96M16	| WAVE_FORMAT_96S08 | WAVE_FORMAT_96S16))
			{
				caps.supportedExclusiveSampleRates.push_back(96000);
			}
			if(woc.dwFormats & (WAVE_FORMAT_48M08 | WAVE_FORMAT_48M16	| WAVE_FORMAT_48S08 | WAVE_FORMAT_48S16))
			{
				caps.supportedExclusiveSampleRates.push_back(48000);
			}
			if(woc.dwFormats & (WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16	| WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16))
			{
				caps.supportedExclusiveSampleRates.push_back(44100);
			}
			if(woc.dwFormats & (WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16	| WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16))
			{
				caps.supportedExclusiveSampleRates.push_back(22050);
			}
			if(woc.dwFormats & (WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16	| WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16))
			{
				caps.supportedExclusiveSampleRates.push_back(11025);
			}
		}
	}
	return caps;
}
Esempio n. 4
0
bool VSTPresets::SaveFile(std::ostream &f, CVstPlugin &plugin, bool bank)
//-----------------------------------------------------------------------
{
	if(!bank)
	{
		SaveProgram(f, plugin);
	} else
	{
		bool writeChunk = plugin.ProgramsAreChunks();
		ChunkHeader header;
		header.chunkMagic = cMagic;
		header.version = 2;
		header.fxID = plugin.GetUID();
		header.fxVersion = plugin.GetVersion();

		// Write unfinished header... We need to update the size once we're done writing.
		Write(header, f);

		uint32 numProgs = std::max(plugin.GetNumPrograms(), VstInt32(1)), curProg = plugin.GetCurrentProgram();
		WriteBE(numProgs, f);
		WriteBE(curProg, f);
		char reserved[124];
		MemsetZero(reserved);
		Write(reserved, f);

		if(writeChunk)
		{
			char *chunk = nullptr;
			uint32 chunkSize = mpt::saturate_cast<uint32>(plugin.Dispatch(effGetChunk, 0, 0, &chunk, 0));
			if(chunkSize && chunk)
			{
				WriteBE(chunkSize, f);
				f.write(chunk, chunkSize);
			} else
			{
				// The plugin returned no chunk! Gracefully go back and save parameters instead...
				writeChunk = false;
			}
		}
		if(!writeChunk)
		{
			for(uint32 p = 0; p < numProgs; p++)
			{
				plugin.SetCurrentProgram(p);
				SaveProgram(f, plugin);
			}
			plugin.SetCurrentProgram(curProg);
		}

		// Now we know the correct chunk size.
		std::streamoff end = f.tellp();
		header.byteSize = static_cast<VstInt32>(end - 8);
		header.fxMagic = writeChunk ? chunkBankMagic : bankMagic;
		header.ConvertEndianness();
		f.seekp(0);
		Write(header, f);
	}

	return true;
}
Esempio n. 5
0
bool FillWaveFormatExtensible(WAVEFORMATEXTENSIBLE &WaveFormat, const SoundDevice::Settings &m_Settings)
//------------------------------------------------------------------------------------------------------
{
	MemsetZero(WaveFormat);
	if(!m_Settings.sampleFormat.IsValid()) return false;
	WaveFormat.Format.wFormatTag = m_Settings.sampleFormat.IsFloat() ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
	WaveFormat.Format.nChannels = (WORD)m_Settings.Channels;
	WaveFormat.Format.nSamplesPerSec = m_Settings.Samplerate;
	WaveFormat.Format.nAvgBytesPerSec = (DWORD)m_Settings.GetBytesPerSecond();
	WaveFormat.Format.nBlockAlign = (WORD)m_Settings.GetBytesPerFrame();
	WaveFormat.Format.wBitsPerSample = (WORD)m_Settings.sampleFormat.GetBitsPerSample();
	WaveFormat.Format.cbSize = 0;
	if((WaveFormat.Format.wBitsPerSample > 16 && m_Settings.sampleFormat.IsInt()) || (WaveFormat.Format.nChannels > 2))
	{
		WaveFormat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
		WaveFormat.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
		WaveFormat.Samples.wValidBitsPerSample = WaveFormat.Format.wBitsPerSample;
		switch(WaveFormat.Format.nChannels)
		{
		case 1:  WaveFormat.dwChannelMask = SPEAKER_FRONT_CENTER; break;
		case 2:  WaveFormat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break;
		case 3:  WaveFormat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_CENTER; break;
		case 4:  WaveFormat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
		default: WaveFormat.dwChannelMask = 0; return false; break;
		}
		const GUID guid_MEDIASUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x0, 0xAA, 0x0, 0x38, 0x9B, 0x71};
		const GUID guid_MEDIASUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71};
		WaveFormat.SubFormat = m_Settings.sampleFormat.IsFloat() ? guid_MEDIASUBTYPE_IEEE_FLOAT : guid_MEDIASUBTYPE_PCM;
	}
	return true;
}
Esempio n. 6
0
CWaveConvert::CWaveConvert(CWnd *parent, modplug::tracker::orderindex_t nMinOrder, modplug::tracker::orderindex_t nMaxOrder):
    CDialog(IDD_WAVECONVERT, parent)
//-----------------------------------------------------------------------------------
{
    m_bGivePlugsIdleTime = false;
    m_bNormalize = false;
    m_bHighQuality = false;
    m_bSelectPlay = false;
    if(nMinOrder != modplug::tracker::OrderIndexInvalid && nMaxOrder != modplug::tracker::OrderIndexInvalid)
    {
        // render selection
        m_nMinOrder = nMinOrder;
        m_nMaxOrder = nMaxOrder;
        m_bSelectPlay = true;
    } else
    {
        m_nMinOrder = m_nMaxOrder = 0;
    }
    m_dwFileLimit = 0;
    m_dwSongLimit = 0;
    MemsetZero(WaveFormat);
    WaveFormat.Format.wFormatTag = WAVE_FORMAT_PCM;
    WaveFormat.Format.nChannels = 2;
    WaveFormat.Format.nSamplesPerSec = 44100;
    WaveFormat.Format.wBitsPerSample = 16;
    WaveFormat.Format.nBlockAlign = (WaveFormat.Format.wBitsPerSample * WaveFormat.Format.nChannels) / 8;
    WaveFormat.Format.nAvgBytesPerSec = WaveFormat.Format.nSamplesPerSec * WaveFormat.Format.nBlockAlign;
}
Esempio n. 7
0
// Reset MIDI macro config to default values.
void MIDIMacroConfig::Reset()
//---------------------------
{
	MemsetZero(szMidiGlb);
	MemsetZero(szMidiSFXExt);
	MemsetZero(szMidiZXXExt);

	strcpy(szMidiGlb[MIDIOUT_START], "FF");
	strcpy(szMidiGlb[MIDIOUT_STOP], "FC");
	strcpy(szMidiGlb[MIDIOUT_NOTEON], "9c n v");
	strcpy(szMidiGlb[MIDIOUT_NOTEOFF], "9c n 0");
	strcpy(szMidiGlb[MIDIOUT_PROGRAM], "Cc p");
	// SF0: Z00-Z7F controls cutoff
	CreateParameteredMacro(0, sfx_cutoff);
	// Z80-Z8F controls resonance
	CreateFixedMacro(zxx_reso4Bit);
}
Esempio n. 8
0
ModInstrument::ModInstrument(SAMPLEINDEX sample)
//----------------------------------------------
{
	nFadeOut = 256;
	dwFlags.reset();
	nGlobalVol = 64;
	nPan = 32 * 4;

	nNNA = NNA_NOTECUT;
	nDCT = DCT_NONE;
	nDNA = DNA_NOTECUT;

	nPanSwing = 0;
	nVolSwing = 0;
	SetCutoff(0, false);
	SetResonance(0, false);

	wMidiBank = 0;
	nMidiProgram = 0;
	nMidiChannel = 0;
	nMidiDrumKey = 0;
	midiPWD = 2;

	nPPC = NOTE_MIDDLEC - 1;
	nPPS = 0;

	nMixPlug = 0;
	nVolRampUp = 0;
	nResampling = SRCMODE_DEFAULT;
	nCutSwing = 0;
	nResSwing = 0;
	nFilterMode = FLTMODE_UNCHANGED;
	wPitchToTempoLock = 0;
	nPluginVelocityHandling = PLUGIN_VELOCITYHANDLING_CHANNEL;
	nPluginVolumeHandling = PLUGIN_VOLUMEHANDLING_IGNORE;

	pTuning = CSoundFile::GetDefaultTuning();

	AssignSample(sample);
	ResetNoteMap();

	MemsetZero(name);
	MemsetZero(filename);
}
Esempio n. 9
0
CZipArchive::CZipArchive(FileReader &file) : ArchiveBase(file)
//------------------------------------------------------------
{
	zipFile = new mz_zip_archive();
	
	mz_zip_archive *zip = static_cast<mz_zip_archive*>(zipFile);
	
	MemsetZero(*zip);
	if(!mz_zip_reader_init_mem(zip, file.GetRawData(), file.GetLength(), 0))
	{
		delete zip;
		zip = nullptr;
		zipFile = nullptr;
	}

	if(!zip)
	{
		return;
	}

	for(mz_uint i = 0; i < mz_zip_reader_get_num_files(zip); ++i)
	{
		ArchiveFileInfo info;
		info.type = ArchiveFileInvalid;
		mz_zip_archive_file_stat stat;
		MemsetZero(stat);
		if(mz_zip_reader_file_stat(zip, i, &stat))
		{
			info.type = ArchiveFileNormal;
			info.name = mpt::PathString::FromWide(mpt::ToWide(mpt::CharsetCP437, stat.m_filename));
			info.size = stat.m_uncomp_size;
		}
		if(mz_zip_reader_is_file_a_directory(zip, i))
		{
			info.type = ArchiveFileSpecial;
		} else if(mz_zip_reader_is_file_encrypted(zip, i))
		{
			info.type = ArchiveFileSpecial;
		}
		contents.push_back(info);
	}

}
Esempio n. 10
0
void CWaveDevice::StopFromSoundThread()
//-------------------------------------
{
	MPT_TRACE();
	if(m_hWaveOut)
	{
		CheckResult(waveOutPause(m_hWaveOut));
		m_JustStarted = false;
		{
			MPT_LOCK_GUARD<mpt::mutex> guard(m_PositionWraparoundMutex);
			MemsetZero(m_PositionLast);
			m_PositionWrappedCount = 0;
		}
	}
}
Esempio n. 11
0
void CWaveDevice::StartFromSoundThread()
//--------------------------------------
{
	MPT_TRACE();
	if(m_hWaveOut)
	{
		{
			MPT_LOCK_GUARD<mpt::mutex> guard(m_PositionWraparoundMutex);
			MemsetZero(m_PositionLast);
			m_PositionWrappedCount = 0;
		}
		m_JustStarted = true;
		// Actual starting is done in InternalFillAudioBuffer to avoid crackling with tiny buffers.
	}
}
Esempio n. 12
0
// 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<uint8>(std::min(mptSmp.nVolume / 4u, 64u));
	pan = static_cast<uint8>(std::min(mptSmp.nPan, uint16(255)));

	// Sample Frequency
	if((fromType & (MOD_TYPE_MOD | MOD_TYPE_XM)))
	{
		finetune = mptSmp.nFineTune;
		relnote = mptSmp.RelativeTone;
	} else
	{
		int f2t = ModSample::FrequencyToTranspose(mptSmp.nC5Speed);
		relnote = (int8)(f2t >> 7);
		finetune = (int8)(f2t & 0x7F);
	}

	flags = 0;
	if(mptSmp.uFlags[CHN_LOOP])
	{
		flags |= mptSmp.uFlags[CHN_PINGPONGLOOP] ? XMSample::sampleBidiLoop : XMSample::sampleLoop;
	}

	// Sample Length and Loops
	length = mpt::saturate_cast<uint32>(mptSmp.nLength);
	loopStart = mpt::saturate_cast<uint32>(mptSmp.nLoopStart);
	loopLength = mpt::saturate_cast<uint32>(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;
	}
}
Esempio n. 13
0
bool COwnerVstEditor::SetSize(int contentWidth, int contentHeight)
//----------------------------------------------------------------
{
	if(contentWidth < 0 || contentHeight < 0 || !m_hWnd)
	{
		return false;
	}

	CRect rcWnd, rcClient;

	// Get border / menu size.
	GetWindowRect(&rcWnd);
	GetClientRect(&rcClient);

	MENUBARINFO mbi;
	MemsetZero(mbi);
	mbi.cbSize = sizeof(mbi);
	GetMenuBarInfo(m_hWnd, OBJID_MENU, 0, &mbi);
	int menuHeight = mbi.rcBar.bottom - mbi.rcBar.top;

	// Preliminary setup, which might have to be adjusted for small (narrow) plugin GUIs again,
	// since the menu might be two lines high...
	const int windowWidth = rcWnd.Width() - rcClient.Width() + contentWidth;
	const int windowHeight = rcWnd.Height() - rcClient.Height() + contentHeight;
	SetWindowPos(NULL, 0, 0,
		windowWidth, windowHeight,
		SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
	m_plugWindow.SetWindowPos(NULL, 0, 0,
		contentWidth, contentHeight,
		SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);

	// Check if the height of the menu bar has changed.
	GetMenuBarInfo(m_hWnd, OBJID_MENU, 0, &mbi);

	const int menuHeightDiff = (mbi.rcBar.bottom - mbi.rcBar.top) - menuHeight;

	if(menuHeightDiff != 0)
	{
		// Menu height changed, resize window so that the whole content area can be viewed again.
		SetWindowPos(NULL, 0, 0,
			windowWidth, windowHeight + menuHeightDiff,
			SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
	}

	return true;
}
Esempio n. 14
0
// Create a DIB for the current device from our PNG.
bool PNG::Bitmap::ToDIB(CBitmap &bitmap, CDC *dc) const
//-----------------------------------------------------
{
	BITMAPINFOHEADER bi;
	MemsetZero(bi);
	bi.biSize = sizeof(BITMAPINFOHEADER);
	bi.biWidth = width;
	bi.biHeight = -(int32_t)height;
	bi.biPlanes = 1;
	bi.biBitCount = 32;
	bi.biCompression = BI_RGB;
	bi.biSizeImage = width * height * 4;

	if(dc == nullptr) dc = CDC::FromHandle(GetDC(NULL));
	return bitmap.CreateCompatibleBitmap(dc, width, height)
		&& SetDIBits(dc->GetSafeHdc(), bitmap, 0, height, GetPixels(), reinterpret_cast<BITMAPINFO *>(&bi), DIB_RGB_COLORS);
}
Esempio n. 15
0
bool CWaveDevice::CheckResult(MMRESULT result)
//--------------------------------------------
{
	if(result == MMSYSERR_NOERROR)
	{
		return true;
	}
	if(!m_Failed)
	{ // only show the first error
		m_Failed = true;
		WCHAR errortext[MAXERRORLENGTH + 1];
		MemsetZero(errortext);
		waveOutGetErrorTextW(result, errortext, MAXERRORLENGTH);
		SendDeviceMessage(LogError, mpt::format(MPT_USTRING("WaveOut error: 0x%1: %2"))(mpt::ufmt::hex0<8>(result), mpt::ToUnicode(errortext)));
	}
	RequestClose();
	return false;
}
Esempio n. 16
0
void MultimediaClock::SetPeriod(uint32 ms)
{
	TIMECAPS caps;
	MemsetZero(caps);
	if(timeGetDevCaps(&caps, sizeof(caps)) != MMSYSERR_NOERROR)
	{
		return;
	}
	if((caps.wPeriodMax == 0) || (caps.wPeriodMin > caps.wPeriodMax))
	{
		return;
	}
	ms = Clamp<uint32>(ms, caps.wPeriodMin, caps.wPeriodMax);
	if(timeBeginPeriod(ms) != MMSYSERR_NOERROR)
	{
		return;
	}
	m_CurrentPeriod = ms;
}
Esempio n. 17
0
std::vector<SoundDevice::Info> CWaveDevice::EnumerateDevices(SoundDevice::SysInfo /* sysInfo */ )
//-----------------------------------------------------------------------------------------------
{
	MPT_TRACE();
	std::vector<SoundDevice::Info> devices;
	UINT numDevs = waveOutGetNumDevs();
	for(UINT index = 0; index <= numDevs; ++index)
	{
		SoundDevice::Info info;
		info.type = TypeWAVEOUT;
		info.internalID = mpt::ufmt::dec(index);
		info.apiName = MPT_USTRING("WaveOut");
		info.useNameAsIdentifier = true;
		WAVEOUTCAPSW woc;
		MemsetZero(woc);
		if(waveOutGetDevCapsW((index == 0) ? WAVE_MAPPER : (index - 1), &woc, sizeof(woc)) == MMSYSERR_NOERROR)
		{
			info.name = mpt::ToUnicode(woc.szPname);
			info.extraData[MPT_USTRING("DriverID")] = mpt::format(MPT_USTRING("%1:%2"))(mpt::ufmt::hex0<4>(woc.wMid), mpt::ufmt::hex0<4>(woc.wPid));
			info.extraData[MPT_USTRING("DriverVersion")] = mpt::format(MPT_USTRING("%3.%4"))(mpt::ufmt::dec((static_cast<uint32>(woc.vDriverVersion) >> 24) & 0xff), mpt::ufmt::dec((static_cast<uint32>(woc.vDriverVersion) >>  0) & 0xff));
		} else if(index == 0)
Esempio n. 18
0
bool CWaveDevice::InternalClose()
//-------------------------------
{
	MPT_TRACE();
	if(m_hWaveOut)
	{
		waveOutReset(m_hWaveOut);
		m_JustStarted = false;
		InterlockedExchange(&m_nBuffersPending, 0);
		m_nWriteBuffer = 0;
		m_nDoneBuffer = 0;
		while(m_nPreparedHeaders > 0)
		{
			m_nPreparedHeaders--;
			waveOutUnprepareHeader(m_hWaveOut, &m_WaveBuffers[m_nPreparedHeaders], sizeof(WAVEHDR));
		}
		waveOutClose(m_hWaveOut);
		m_hWaveOut = NULL;
	}
	#ifdef _DEBUG
		if(m_DriverBugs.load())
		{
				SendDeviceMessage(LogError, MPT_USTRING("Errors were detected while playing sound:\n") + GetStatistics().text);
		}
	#endif
	m_DriverBugs = 0;
	m_Failed = false;
	if(m_ThreadWakeupEvent)
	{
		CloseHandle(m_ThreadWakeupEvent);
		m_ThreadWakeupEvent = NULL;
	}
	{
		MPT_LOCK_GUARD<mpt::mutex> guard(m_PositionWraparoundMutex);
		MemsetZero(m_PositionLast);
		m_PositionWrappedCount = 0;
	}
	return true;
}
Esempio n. 19
0
void WavesReverb::Resume()
//------------------------
{
	m_isResumed = true;
	// Recalculate delays
	uint32 delay0 = Util::Round<uint32>(m_SndFile.GetSampleRate() * 0.045);
	uint32 delay1 = Util::Round<uint32>(delay0 * 1.189207077026367);	// 2^0.25
	uint32 delay2 = Util::Round<uint32>(delay1 * 1.189207077026367);
	uint32 delay3 = Util::Round<uint32>(delay2 * 1.189207077026367);
	uint32 delay4 = Util::Round<uint32>((delay0 + delay2) * 0.1154666692018509);
	uint32 delay5 = Util::Round<uint32>((delay1 + delay3) * 0.1154666692018509);
	// Comb delays
	m_delay[0] = (delay0 - delay4) * 4;
	m_delay[1] = (delay2 - delay4) * 4;
	m_delay[2] = (delay1 - delay5) * 4;
	m_delay[3] = (delay3 - delay5) * 4;
	// Allpass delays
	m_delay[4] = delay4 * 2;
	m_delay[5] = delay5 * 2;

	RecalculateWavesReverbParams();
	MemsetZero(m_state);
}
Esempio n. 20
0
PLUGINDEX CModDoc::RemovePlugs(const std::vector<bool> &keepMask)
//---------------------------------------------------------------
{
	//Remove all plugins whose keepMask[plugindex] is false.
	PLUGINDEX nRemoved = 0;
	const PLUGINDEX maxPlug = static_cast<PLUGINDEX>(MIN(MAX_MIXPLUGINS, keepMask.size()));

	CriticalSection cs;
	for(PLUGINDEX nPlug = 0; nPlug < maxPlug; nPlug++)
	{
		SNDMIXPLUGIN &plug = m_SndFile.m_MixPlugins[nPlug];
		if(keepMask[nPlug])
		{
			continue;
		}

		if(plug.pMixPlugin || plug.IsValidPlugin())
		{
			nRemoved++;
		}

		delete[] plug.pPluginData;
		plug.pPluginData = nullptr;

		if(plug.pMixPlugin)
		{
			plug.pMixPlugin->Release();
			plug.pMixPlugin = nullptr;
		}
		MemsetZero(plug.Info);
		plug.nPluginDataSize = 0;
		plug.fDryRatio = 0;
		plug.defaultProgram = 0;
	}

	return nRemoved;
}
Esempio n. 21
0
// Convert OpenMPT's internal sample representation to an XMInstrument.
uint16 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<uint16>(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);

	// Create sample assignment table
	std::vector<SAMPLEINDEX> sampleList = GetSampleList(mptIns, compatibilityExport);
	for(size_t i = 0; i < CountOf(sampleMap); i++)
	{
		if(mptIns.Keyboard[i + 12] > 0)
		{
			std::vector<SAMPLEINDEX>::iterator sample = std::find(sampleList.begin(), sampleList.end(), mptIns.Keyboard[i + 12]);
			if(sample != sampleList.end())
			{
				// Yep, we want to export this sample.
				sampleMap[i] = static_cast<uint8>(sample - sampleList.begin());
			}
		}
	}

	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));

	return static_cast<uint16>(sampleList.size());
}
Esempio n. 22
0
bool CSoundFile::ReadITQ(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
	file.Rewind();

	ITFileHeader fileHeader;
	if(!file.ReadConvertEndianness(fileHeader)
		|| (memcmp(fileHeader.id, "ITQM", 4))
		|| fileHeader.insnum > 0xFF
		|| fileHeader.smpnum >= MAX_SAMPLES
		|| !file.CanRead(fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4))
	{
		return false;
	} else if(loadFlags == onlyVerifyHeader)
	{
		return true;
	}

	InitializeGlobals();

	bool interpretModPlugMade = false;

	// OpenMPT crap at the end of file
	file.Seek(file.GetLength() - 4);
	size_t mptStartPos = file.ReadUint32LE();
	if(mptStartPos >= file.GetLength() || mptStartPos < 0x100)
	{
		mptStartPos = file.GetLength();
	}

	if(!memcmp(fileHeader.id, "tpm.", 4))
	{
		// Legacy MPTM files (old 1.17.02.xx releases)
		ChangeModTypeTo(MOD_TYPE_MPT);
	} else
	{
		if(mptStartPos <= file.GetLength() - 3 && fileHeader.cwtv > 0x888 && fileHeader.cwtv <= 0xFFF)
		{
			file.Seek(mptStartPos);
			ChangeModTypeTo(file.ReadMagic("228") ? MOD_TYPE_MPT : MOD_TYPE_IT);
		} else
		{
			ChangeModTypeTo(MOD_TYPE_IT);
		}

		if(GetType() == MOD_TYPE_IT)
		{
			// Which tracker was used to made 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.
				m_dwLastSavedWithVersion = (fileHeader.cwtv & 0x0FFF) << 16;
				if(!memcmp(fileHeader.reserved, "OMPT", 4))
					interpretModPlugMade = true;
			} else if(fileHeader.cmwt == 0x888 || fileHeader.cwtv == 0x888)
			{
				// OpenMPT 1.17 and 1.18 (raped IT format)
				// Exact version number will be determined later.
				interpretModPlugMade = true;
			} else if(fileHeader.cwtv == 0x0217 && fileHeader.cmwt == 0x0200 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4))
			{
				if(memchr(fileHeader.chnpan, 0xFF, sizeof(fileHeader.chnpan)) != NULL)
				{
					// ModPlug Tracker 1.16 (semi-raped IT format)
					m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 16, 00, 00);
					madeWithTracker = "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).
					m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 17, 00, 00);
					madeWithTracker = "OpenMPT 1.17 (compatibility export)";
				}
				interpretModPlugMade = true;
			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0202 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4))
			{
				// ModPlug Tracker b3.3 - 1.09, instruments 557 bytes apart
				m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 09, 00, 00);
				madeWithTracker = "ModPlug tracker b3.3 - 1.09";
				interpretModPlugMade = true;
			}
		} else // case: type == MOD_TYPE_MPT
		{
			if (fileHeader.cwtv >= verMptFileVerLoadLimit)
			{
				AddToLog(str_LoadingIncompatibleVersion);
				return false;
			}
			else if (fileHeader.cwtv > verMptFileVer)
			{
				AddToLog(str_LoadingMoreRecentVersion);
			}
		}
	}

	if(GetType() == MOD_TYPE_IT) mptStartPos = file.GetLength();

	// Read row highlights
	if((fileHeader.special & ITFileHeader::embedPatternHighlights))
	{
		// MPT 1.09, 1.07 and most likely other old MPT 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.
		if(m_dwLastSavedWithVersion == 0 || m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 17, 03, 02))
		{
			m_nDefaultRowsPerBeat = fileHeader.highlight_minor;
			m_nDefaultRowsPerMeasure = fileHeader.highlight_major;
		}
#ifdef _DEBUG
		if((fileHeader.highlight_minor | fileHeader.highlight_major) == 0)
		{
			Log("IT Header: Row highlight is 0");
		}
#endif
	}

	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_EMBEDMIDICFG, (fileHeader.flags & ITFileHeader::reqEmbeddedMIDIConfig) || (fileHeader.special & ITFileHeader::embedMIDIConfiguration));
	m_SongFlags.set(SONG_EXFILTERRANGE, (fileHeader.flags & ITFileHeader::extendedFilterRange) != 0);

	mpt::String::Read<mpt::String::spacePadded>(songName, fileHeader.songname);

	// Global Volume
	m_nDefaultGlobalVolume = fileHeader.globalvol << 1;
	if(m_nDefaultGlobalVolume > MAX_GLOBAL_VOLUME) m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME;
	if(fileHeader.speed) m_nDefaultSpeed = fileHeader.speed;
	m_nDefaultTempo = std::max(uint8(32), fileHeader.tempo); // Tempo 31 is possible. due to conflicts with the rest of the engine, let's just clamp it to 32.
	m_nSamplePreAmp = std::min(fileHeader.mv, uint8(128));

	// Reading Channels Pan Positions
	for(CHANNELINDEX i = 0; i < 64; i++) if(fileHeader.chnpan[i] != 0xFF)
	{
		ChnSettings[i].Reset();
		ChnSettings[i].nVolume = Clamp(fileHeader.chnvol[i], uint8(0), uint8(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 orders
	file.Seek(sizeof(ITFileHeader));
	if(GetType() == MOD_TYPE_IT)
	{
		Order.ReadAsByte(file, fileHeader.ordnum);
	} else
	{
		if(fileHeader.cwtv > 0x88A && fileHeader.cwtv <= 0x88D)
		{
			Order.Deserialize(file);
		} else
		{
			Order.ReadAsByte(file, fileHeader.ordnum);
			// Replacing 0xFF and 0xFE with new corresponding indexes
			Order.Replace(0xFE, Order.GetIgnoreIndex());
			Order.Replace(0xFF, Order.GetInvalidPatIndex());
		}
	}

	// Reading instrument, sample and pattern offsets
	std::vector<uint32> insPos, smpPos, patPos;
	file.ReadVectorLE(insPos, fileHeader.insnum);
	file.ReadVectorLE(smpPos, fileHeader.smpnum);
	file.ReadVectorLE(patPos, fileHeader.patnum);

	// 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 = Util::MaxValueOfType(minPtr);
	for(uint16 n = 0; n < fileHeader.insnum; n++)
	{
		if(insPos[n] > 0)
		{
			minPtr = std::min(minPtr, insPos[n]);
		}
	}

	for(uint16 n = 0; n < fileHeader.smpnum; n++)
	{
		if(smpPos[n] > 0)
		{
			minPtr = std::min(minPtr, smpPos[n]);
		}
	}

	for(uint16 n = 0; n < fileHeader.patnum; n++)
	{
		if(patPos[n] > 0)
		{
			minPtr = std::min(minPtr, patPos[n]);
		}
	}

	if(fileHeader.special & ITFileHeader::embedSongMessage)
	{
		minPtr = std::min(minPtr, fileHeader.msgoffset);
	}

	// 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 end 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.reserve(nflt);
			for(size_t n = 0; n < nflt; n++)
			{
				FileHistory mptHistory;
				ITHistoryStruct itHistory;
				file.ReadConvertEndianness(itHistory);
				itHistory.ConvertToMPT(mptHistory);
				m_FileHistory.push_back(mptHistory);
			}
		} else
		{
			// Oops, we were not supposed to read this.
			file.SkipBack(2);
		}
	} else if(fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0 && fileHeader.cmwt == 0x0214 && fileHeader.cwtv == 0x0214 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4) && (fileHeader.special & (ITFileHeader::embedEditHistory | ITFileHeader::embedPatternHighlights)) == 0)
	{
		// Another non-conforming application is unmo3 < v2.4.0.1, which doesn't set the special bit
		// at all, but still writes the two edit history length bytes (zeroes)...
		if(file.ReadUint16LE() != 0)
		{
			// These were not zero bytes -> We're in the wrong place!
			file.SkipBack(2);
			madeWithTracker = "UNMO3";
		}
	}

	// Reading MIDI Output & Macros
	if(m_SongFlags[SONG_EMBEDMIDICFG] && file.Read(m_MidiCfg))
	{
			m_MidiCfg.Sanitize();
	}

	// 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.
	if(fileHeader.cwtv < 0x0214)
	{
		MemsetZero(m_MidiCfg.szMidiSFXExt);
		MemsetZero(m_MidiCfg.szMidiZXXExt);
		m_SongFlags.set(SONG_EMBEDMIDICFG);
	}

	if(file.ReadMagic("MODU"))
	{
		madeWithTracker = "BeRoTracker";
	}

	// Read pattern names: "PNAM"
	FileReader patNames;
	if(file.ReadMagic("PNAM"))
	{
		patNames = file.GetChunk(file.ReadUint32LE());
	}

	m_nChannels = GetModSpecifications().channelsMin;
	// Read channel names: "CNAM"
	if(file.ReadMagic("CNAM"))
	{
		FileReader chnNames = file.GetChunk(file.ReadUint32LE());
		const CHANNELINDEX readChns = std::min(MAX_BASECHANNELS, static_cast<CHANNELINDEX>(chnNames.GetLength() / MAX_CHANNELNAME));
		m_nChannels = readChns;

		for(CHANNELINDEX i = 0; i < readChns; i++)
		{
			chnNames.ReadString<mpt::String::maybeNullTerminated>(ChnSettings[i].szName, MAX_CHANNELNAME);
		}
	}

	// Read mix plugins information
	if(file.CanRead(9))
	{
		LoadMixPlugins(file);
	}

	// Read Song Message
	if(fileHeader.special & ITFileHeader::embedSongMessage)
	{
		if(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:
			songMessage.Read(file, fileHeader.msglength, SongMessage::leAutodetect);
		}
	}

	// Reading Instruments
	m_nInstruments = 0;
	if(fileHeader.flags & ITFileHeader::instrumentMode)
	{
		m_nInstruments = std::min(fileHeader.insnum, INSTRUMENTINDEX(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::off_t lastSampleOffset = 0;
	if(fileHeader.smpnum > 0)
	{
		lastSampleOffset = smpPos[fileHeader.smpnum - 1] + sizeof(ITSample);
	}

	//// #ITQ

	// Reading Samples
	m_nSamples = std::min(fileHeader.smpnum, SAMPLEINDEX(MAX_SAMPLES - 1));
	size_t nbytes = 0; // size of sample data in file

	for(SAMPLEINDEX i = 0; i < GetNumSamples(); i++)
	{
		ITQSample sampleHeader;
		if(smpPos[i] > 0 && file.Seek(smpPos[i]) && file.ReadConvertEndianness(sampleHeader))
		{
			if(!memcmp(sampleHeader.id, "ITQS", 4))
			{
				size_t sampleOffset = sampleHeader.ConvertToMPT(Samples[i + 1]);

				mpt::String::Read<mpt::String::spacePadded>(m_szNames[i + 1], sampleHeader.name);

				if((loadFlags & loadSampleData) && file.Seek(sampleOffset))
				{
					Samples[i+1].originalSize = sampleHeader.nbytes;
					sampleHeader.GetSampleFormatITQ(fileHeader.cwtv).ReadSample(Samples[i + 1], file);
					lastSampleOffset = std::max(lastSampleOffset, file.GetPosition());
				}
			}
		}
	}
	m_nSamples = std::max(SAMPLEINDEX(1), GetNumSamples());

	m_nMinPeriod = 8;
	m_nMaxPeriod = 0xF000;

	PATTERNINDEX numPats = std::min(static_cast<PATTERNINDEX>(patPos.size()), GetModSpecifications().patternsMax);

	if(numPats != patPos.size())
	{
		// Hack: Notify user here if file contains more patterns than what can be read.
		AddToLog(mpt::String::Print(str_PatternSetTruncationNote, patPos.size(), numPats));
	}

	if(!(loadFlags & loadPatternData))
	{
		numPats = 0;
	}

	// Checking for number of used channels, which is not explicitely specified in the file.
	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 < GetModSpecifications().patternRowsMin
			|| numRows > GetModSpecifications().patternRowsMax
			|| !file.Skip(4))
			continue;

		FileReader patternData = file.GetChunk(len);
		ROWINDEX row = 0;
		std::vector<uint8> chnMask(GetNumChannels());

		while(row < numRows && patternData.AreBytesLeft())
		{
			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 >= GetNumChannels() && ch < MAX_BASECHANNELS)
				{
					m_nChannels = ch + 1;
				}
			}
			// Now we actually update the pattern-row entry the note,instrument etc.
			// Note
			if(chnMask[ch] & 1) patternData.Skip(1);
			// Instrument
			if(chnMask[ch] & 2) patternData.Skip(1);
			// Volume
			if(chnMask[ch] & 4) patternData.Skip(1);
			// Effect
			if(chnMask[ch] & 8) patternData.Skip(2);
		}
	}

	// Compute extra instruments settings position
	if(lastSampleOffset > 0)
	{
		file.Seek(lastSampleOffset);
	}

	// Load instrument and song extensions.
	LoadExtendedInstrumentProperties(file, &interpretModPlugMade);
	if(interpretModPlugMade)
	{
		m_nMixLevels = mixLevels_original;
	}
	// We need to do this here, because if there no samples (so lastSampleOffset = 0), we need to look after the last pattern (sample data normally follows pattern data).
	// And we need to do this before reading the patterns because m_nChannels might be modified by LoadExtendedSongProperties. *sigh*
	LoadExtendedSongProperties(GetType(), file, &interpretModPlugMade);
	m_nTempoMode = tempo_mode_modern;

	// Reading Patterns
	Patterns.ResizeArray(std::max(MAX_PATTERNS, numPats));
	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(mpt::String::Print("Allocating patterns failed starting from pattern %1", 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(numRows < GetModSpecifications().patternRowsMin
			|| numRows > GetModSpecifications().patternRowsMax
			|| !file.Skip(4)
			|| Patterns.Insert(pat, numRows))
			continue;
			
		FileReader patternData = file.GetChunk(len);

		// Now (after the Insert() call), we can read the pattern name.
		CopyPatternName(Patterns[pat], patNames);

		std::vector<uint8> chnMask(GetNumChannels());
		std::vector<ModCommand> lastValue(GetNumChannels(), ModCommand::Empty());

		ModCommand *m = Patterns[pat];
		ROWINDEX row = 0;
		while(row < numRows && patternData.AreBytesLeft())
		{
			uint8 b = patternData.ReadUint8();
			if(!b)
			{
				row++;
				m += 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::Empty());
				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.

			if((chnMask[ch] & 0x10) && (ch < m_nChannels))
			{
				m[ch].note = lastValue[ch].note;
			}
			if((chnMask[ch] & 0x20) && (ch < m_nChannels))
			{
				m[ch].instr = lastValue[ch].instr;
			}
			if((chnMask[ch] & 0x40) && (ch < m_nChannels))
			{
				m[ch].volcmd = lastValue[ch].volcmd;
				m[ch].vol = lastValue[ch].vol;
			}
			if((chnMask[ch] & 0x80) && (ch < m_nChannels))
			{
				m[ch].command = lastValue[ch].command;
				m[ch].param = lastValue[ch].param;
			}
			if(chnMask[ch] & 1)	// Note
			{
				uint8 note = patternData.ReadUint8();
				if(ch < m_nChannels)
				{
					if(note < 0x80) note++;
					if(!(GetType() & MOD_TYPE_MPT))
					{
						if(note > NOTE_MAX && note < 0xFD) note = NOTE_FADE;
						else if(note == 0xFD) note = NOTE_NONE;
					}
					m[ch].note = note;
					lastValue[ch].note = note;
				}
			}
			if(chnMask[ch] & 2)
			{
				uint8 instr = patternData.ReadUint8();
				if(ch < m_nChannels)
				{
					m[ch].instr = instr;
					lastValue[ch].instr = instr;
				}
			}
			if(chnMask[ch] & 4)
			{
				uint8 vol = patternData.ReadUint8();
				if(ch < m_nChannels)
				{
					// 0-64: Set Volume
					if(vol <= 64) { m[ch].volcmd = VOLCMD_VOLUME; m[ch].vol = vol; } else
					// 128-192: Set Panning
					if(vol >= 128 && vol <= 192) { m[ch].volcmd = VOLCMD_PANNING; m[ch].vol = vol - 128; } else
					// 65-74: Fine Volume Up
					if(vol < 75) { m[ch].volcmd = VOLCMD_FINEVOLUP; m[ch].vol = vol - 65; } else
					// 75-84: Fine Volume Down
					if(vol < 85) { m[ch].volcmd = VOLCMD_FINEVOLDOWN; m[ch].vol = vol - 75; } else
					// 85-94: Volume Slide Up
					if(vol < 95) { m[ch].volcmd = VOLCMD_VOLSLIDEUP; m[ch].vol = vol - 85; } else
					// 95-104: Volume Slide Down
					if(vol < 105) { m[ch].volcmd = VOLCMD_VOLSLIDEDOWN; m[ch].vol = vol - 95; } else
					// 105-114: Pitch Slide Up
					if(vol < 115) { m[ch].volcmd = VOLCMD_PORTADOWN; m[ch].vol = vol - 105; } else
					// 115-124: Pitch Slide Down
					if(vol < 125) { m[ch].volcmd = VOLCMD_PORTAUP; m[ch].vol = vol - 115; } else
					// 193-202: Portamento To
					if(vol >= 193 && vol <= 202) { m[ch].volcmd = VOLCMD_TONEPORTAMENTO; m[ch].vol = vol - 193; } else
					// 203-212: Vibrato depth
					if(vol >= 203 && vol <= 212)
					{
						m[ch].volcmd = VOLCMD_VIBRATODEPTH; m[ch].vol = vol - 203;
						// Old versions of ModPlug saved this as vibrato speed instead, so let's fix that.
						if(m[ch].vol && m_dwLastSavedWithVersion && m_dwLastSavedWithVersion <= MAKE_VERSION_NUMERIC(1, 17, 02, 54))
							m[ch].volcmd = VOLCMD_VIBRATOSPEED;
					} else
					// 213-222: Unused (was velocity)
					// 223-232: Offset
					if(vol >= 223 && vol <= 232) { m[ch].volcmd = VOLCMD_OFFSET; m[ch].vol = vol - 223; }
					lastValue[ch].volcmd = m[ch].volcmd;
					lastValue[ch].vol = m[ch].vol;
				}
			}
			// Reading command/param
			if(chnMask[ch] & 8)
			{
				uint8 cmd = patternData.ReadUint8();
				uint8 param = patternData.ReadUint8();
				if(ch < m_nChannels)
				{
					if(cmd)
					{
						m[ch].command = cmd;
						m[ch].param = param;
						S3MConvert(m[ch], true);
						lastValue[ch].command = m[ch].command;
						lastValue[ch].param = m[ch].param;
					}
				}
			}
		}
	}

	UpgradeModFlags();

	if(!m_dwLastSavedWithVersion && fileHeader.cwtv == 0x0888)
	{
		// There are some files with OpenMPT extensions, but the "last saved with" field contains 0.
		// Was there an OpenMPT version that wrote 0 there, or are they hacked?
		m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 17, 00, 00);
	}

	if(m_dwLastSavedWithVersion && madeWithTracker.empty())
	{
		madeWithTracker = "OpenMPT " + MptVersion::ToStr(m_dwLastSavedWithVersion);
		if(memcmp(fileHeader.reserved, "OMPT", 4) && (fileHeader.cwtv & 0xF000) == 0x5000)
		{
			madeWithTracker += " (compatibility export)";
		} else if(MptVersion::IsTestBuild(m_dwLastSavedWithVersion))
		{
			madeWithTracker += " (test build)";
		}
	} else
	{
		switch(fileHeader.cwtv >> 12)
		{
		case 0:
			if(!madeWithTracker.empty())
			{
				// BeRoTracker has been detected above.
			} 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 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4))
			{
				madeWithTracker = "OpenSPC conversion";
			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0200 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4))
			{
				// ModPlug Tracker 1.00a5, instruments 560 bytes apart
				m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 00, 00, A5);
				madeWithTracker = "ModPlug tracker 1.00a5";
				interpretModPlugMade = true;
			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && !memcmp(fileHeader.reserved, "CHBI", 4))
			{
				madeWithTracker = "ChibiTracker";
			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && !(fileHeader.special & 3) && !memcmp(fileHeader.reserved, "\0\0\0\0", 4) && !strcmp(Samples[1].filename, "XXXXXXXX.YYY"))
			{
				madeWithTracker = "CheeseTracker";
			} else
			{
				if(fileHeader.cmwt > 0x0214)
				{
					madeWithTracker = "Impulse Tracker 2.15";
				} else if(fileHeader.cwtv > 0x0214)
				{
					// Patched update of IT 2.14 (0x0215 - 0x0217 == p1 - p3)
					// p4 (as found on modland) adds the ITVSOUND driver, but doesn't seem to change
					// anything as far as file saving is concerned.
					madeWithTracker = mpt::String::Print("Impulse Tracker 2.14p%1", fileHeader.cwtv - 0x0214);
				} else
				{
					madeWithTracker = mpt::String::Print("Impulse Tracker %1.%2", (fileHeader.cwtv & 0x0F00) >> 8, mpt::fmt::hex0<2>((fileHeader.cwtv & 0xFF)));
				}
			}
			break;
		case 1:
			madeWithTracker = GetSchismTrackerVersion(fileHeader.cwtv);
			break;
		case 6:
			madeWithTracker = "BeRoTracker";
			break;
		case 7:
			madeWithTracker = mpt::String::Print("ITMCK %1.%2.%3", (fileHeader.cwtv >> 8) & 0x0F, (fileHeader.cwtv >> 4) & 0x0F, fileHeader.cwtv & 0x0F);
			break;
		}
	}

	if(GetType() == MOD_TYPE_IT)
	{
		// Set appropriate mod flags if the file was not made with MPT.
		if(!interpretModPlugMade)
		{
			SetModFlag(MSF_MIDICC_BUGEMULATION, false);
			SetModFlag(MSF_OLDVOLSWING, false);
			SetModFlag(MSF_COMPATIBLE_PLAY, true);
		}
	} else
	{
		//START - mpt specific:
		//Using member cwtv on pifh as the version number.
		const uint16 version = fileHeader.cwtv;
		if(version > 0x889 && file.Seek(mptStartPos))
		{
			std::istringstream iStrm(std::string(file.GetRawData(), file.BytesLeft()));

			if(version >= 0x88D)
			{
				srlztn::SsbRead ssb(iStrm);
				ssb.BeginRead("mptm", MptVersion::num);
				ssb.ReadItem(GetTuneSpecificTunings(), "0", 1, &ReadTuningCollection);
				ssb.ReadItem(*this, "1", 1, &ReadTuningMap);
				ssb.ReadItem(Order, "2", 1, &ReadModSequenceOld);
				ssb.ReadItem(Patterns, FileIdPatterns, strlen(FileIdPatterns), &ReadModPatterns);
				ssb.ReadItem(Order, FileIdSequences, strlen(FileIdSequences), &ReadModSequences);

				if(ssb.m_Status & srlztn::SNT_FAILURE)
				{
					AddToLog("Unknown error occured while deserializing file.");
				}
			} else //Loading for older files.
			{
				if(GetTuneSpecificTunings().Deserialize(iStrm))
				{
					AddToLog("Error occured - loading failed while trying to load tune specific tunings.");
				} else
				{
					ReadTuningMap(iStrm, *this);
				}
			}
		} //version condition(MPT)
	}

	return true;
}
Esempio n. 23
0
VSTPresets::ErrorCode VSTPresets::LoadFile(FileReader &file, CVstPlugin &plugin)
//------------------------------------------------------------------------------
{
	const bool firstChunk = file.GetPosition() == 0;
	ChunkHeader header;
	if(!file.ReadConvertEndianness(header) || header.chunkMagic != cMagic)
	{
		return invalidFile;
	}
	if(header.fxID != plugin.GetUID())
	{
		return wrongPlugin;
	}

	if(header.fxMagic == fMagic || header.fxMagic == chunkPresetMagic)
	{
		// Program
		PlugParamIndex numParams = file.ReadUint32BE();

		VstPatchChunkInfo info;
		info.version = 1;
		info.pluginUniqueID = header.fxID;
		info.pluginVersion = header.fxVersion;
		info.numElements = numParams;
		MemsetZero(info.future);
		plugin.Dispatch(effBeginLoadProgram, 0, 0, &info, 0.0f);
		plugin.Dispatch(effBeginSetProgram, 0, 0, nullptr, 0.0f);

		char prgName[28];
		file.ReadString<mpt::String::maybeNullTerminated>(prgName, 28);
		plugin.Dispatch(effSetProgramName, 0, 0, prgName, 0.0f);

		if(header.fxMagic == fMagic)
		{
			if(plugin.GetNumParameters() != numParams)
			{
				return wrongParameters;
			}
			for(PlugParamIndex p = 0; p < numParams; p++)
			{
				plugin.SetParameter(p, file.ReadFloatBE());
			}
		} else
		{
			FileReader chunk = file.ReadChunk(file.ReadUint32BE());
			plugin.Dispatch(effSetChunk, 1, chunk.GetLength(), const_cast<char *>(chunk.GetRawData()), 0);
		}
		plugin.Dispatch(effEndSetProgram, 0, 0, nullptr, 0.0f);
	} else if((header.fxMagic == bankMagic || header.fxMagic == chunkBankMagic) && firstChunk)
	{
		// Bank - only read if it's the first chunk in the file, not if it's a sub chunk.
		uint32 numProgs = file.ReadUint32BE();
		uint32 currentProgram = file.ReadUint32BE();
		file.Skip(124);

		VstPatchChunkInfo info;
		info.version = 1;
		info.pluginUniqueID = header.fxID;
		info.pluginVersion = header.fxVersion;
		info.numElements = numProgs;
		MemsetZero(info.future);
		plugin.Dispatch(effBeginLoadBank, 0, 0, &info, 0.0f);

		if(header.fxMagic == bankMagic)
		{
			VstInt32 oldCurrentProgram = plugin.GetCurrentProgram();
			for(uint32 p = 0; p < numProgs; p++)
			{
				plugin.Dispatch(effBeginSetProgram, 0, 0, nullptr, 0.0f);
				plugin.Dispatch(effSetProgram, 0, 0, nullptr, 0.0f);
				ErrorCode retVal = LoadFile(file, plugin);
				if(retVal != noError)
				{
					return retVal;
				}
				plugin.Dispatch(effEndSetProgram, 0, 0, nullptr, 0.0f);
			}
			plugin.SetCurrentProgram(oldCurrentProgram);
		} else
		{
			FileReader chunk = file.ReadChunk(file.ReadUint32BE());
			plugin.Dispatch(effSetChunk, 0, chunk.GetLength(), const_cast<char *>(chunk.GetRawData()), 0);
		}
		if(header.version >= 2)
		{
			plugin.SetCurrentProgram(currentProgram);
		}
	}

	return noError;
}
Esempio n. 24
0
bool module_renderer::ReadXM(const uint8_t *lpStream, const uint32_t dwMemLength)
//--------------------------------------------------------------------
{
    XMFILEHEADER xmheader;
    XMSAMPLEHEADER xmsh;
    XMSAMPLESTRUCT xmss;
    uint32_t dwMemPos;

    bool bMadeWithModPlug = false, bProbablyMadeWithModPlug = false, bProbablyMPT109 = false, bIsFT2 = false;

    m_nChannels = 0;
    if ((!lpStream) || (dwMemLength < 0xAA)) return false; // the smallest XM I know is 174 Bytes
    if (_strnicmp((LPCSTR)lpStream, "Extended Module", 15)) return false;

    // look for null-terminated song name - that's most likely a tune made with modplug
    for(int i = 0; i < 20; i++)
        if(lpStream[17 + i] == 0) bProbablyMadeWithModPlug = true;
    assign_without_padding(this->song_name, reinterpret_cast<const char *>(lpStream + 17), 20);

    // load and convert header
    memcpy(&xmheader, lpStream + 58, sizeof(XMFILEHEADER));
    xmheader.size = LittleEndian(xmheader.size);
    xmheader.xmversion = LittleEndianW(xmheader.xmversion);
    xmheader.orders = LittleEndianW(xmheader.orders);
    xmheader.restartpos = LittleEndianW(xmheader.restartpos);
    xmheader.channels = LittleEndianW(xmheader.channels);
    xmheader.patterns = LittleEndianW(xmheader.patterns);
    xmheader.instruments = LittleEndianW(xmheader.instruments);
    xmheader.flags = LittleEndianW(xmheader.flags);
    xmheader.speed = LittleEndianW(xmheader.speed);
    xmheader.tempo = LittleEndianW(xmheader.tempo);

    m_nType = MOD_TYPE_XM;
    m_nMinPeriod = 27;
    m_nMaxPeriod = 54784;

    if (xmheader.orders > MAX_ORDERS) return false;
    if ((!xmheader.channels) || (xmheader.channels > MAX_BASECHANNELS)) return false;
    if (xmheader.channels > 32) bMadeWithModPlug = true;
    m_nRestartPos = xmheader.restartpos;
    m_nChannels = xmheader.channels;
    m_nInstruments = bad_min(xmheader.instruments, MAX_INSTRUMENTS - 1);
    m_nSamples = 0;
    m_nDefaultSpeed = CLAMP(xmheader.speed, 1, 31);
    m_nDefaultTempo = CLAMP(xmheader.tempo, 32, 512);

    if(xmheader.flags & 1) m_dwSongFlags |= SONG_LINEARSLIDES;
    if(xmheader.flags & 0x1000) m_dwSongFlags |= SONG_EXFILTERRANGE;

    Order.ReadAsByte(lpStream + 80, xmheader.orders, dwMemLength - 80);

    dwMemPos = xmheader.size + 60;

    // set this here already because XMs compressed with BoobieSqueezer will exit the function early
    SetModFlag(MSF_COMPATIBLE_PLAY, true);

    if(xmheader.xmversion >= 0x0104)
    {
        if (dwMemPos + 8 >= dwMemLength) return true;
        dwMemPos = ReadXMPatterns(lpStream, dwMemLength, dwMemPos, &xmheader, this);
        if(dwMemPos == 0) return true;
    }

    vector<bool> samples_used; // for removing unused samples
    modplug::tracker::sampleindex_t unused_samples = 0; // dito

    // Reading instruments
    for (modplug::tracker::instrumentindex_t iIns = 1; iIns <= m_nInstruments; iIns++)
    {
        XMINSTRUMENTHEADER pih;
        uint8_t flags[32];
        uint32_t samplesize[32];
        UINT samplemap[32];
        uint16_t nsamples;

        if (dwMemPos + sizeof(uint32_t) >= dwMemLength) return true;
        uint32_t ihsize = LittleEndian(*((uint32_t *)(lpStream + dwMemPos)));
        if (dwMemPos + ihsize > dwMemLength) return true;

        MemsetZero(pih);
        memcpy(&pih, lpStream + dwMemPos, bad_min(sizeof(pih), ihsize));

        if ((Instruments[iIns] = new modinstrument_t) == nullptr) continue;
        memcpy(Instruments[iIns], &m_defaultInstrument, sizeof(modinstrument_t));
        Instruments[iIns]->nPluginVelocityHandling = PLUGIN_VELOCITYHANDLING_CHANNEL;
        Instruments[iIns]->nPluginVolumeHandling = PLUGIN_VOLUMEHANDLING_IGNORE;

        memcpy(Instruments[iIns]->name, pih.name, 22);
        SpaceToNullStringFixed<22>(Instruments[iIns]->name);

        memset(&xmsh, 0, sizeof(XMSAMPLEHEADER));

        if ((nsamples = pih.samples) > 0)
        {
            /* we have samples, so let's read the rest of this instrument
               the header that is being read here is not the sample header, though,
               it's rather the instrument settings. */

            if (dwMemPos + ihsize >= dwMemLength)
                return true;

            memcpy(&xmsh,
                lpStream + dwMemPos + sizeof(XMINSTRUMENTHEADER),
                bad_min(ihsize - sizeof(XMINSTRUMENTHEADER), sizeof(XMSAMPLEHEADER)));

            xmsh.shsize = LittleEndian(xmsh.shsize);
            if(xmsh.shsize == 0 && bProbablyMadeWithModPlug) bMadeWithModPlug = true;

            for (int i = 0; i < 24; ++i) {
                xmsh.venv[i] = LittleEndianW(xmsh.venv[i]);
                xmsh.penv[i] = LittleEndianW(xmsh.penv[i]);
            }
            xmsh.volfade = LittleEndianW(xmsh.volfade);
            xmsh.midiprogram = LittleEndianW(xmsh.midiprogram);
            xmsh.pitchwheelrange = LittleEndianW(xmsh.pitchwheelrange);

            if(xmsh.midichannel != 0 || xmsh.midienabled != 0 || xmsh.midiprogram != 0 || xmsh.mutecomputer != 0 || xmsh.pitchwheelrange != 0)
                bIsFT2 = true; // definitely not MPT. (or any other tracker)

        }

        if (LittleEndian(pih.size))
            dwMemPos += LittleEndian(pih.size);
        else
            dwMemPos += sizeof(XMINSTRUMENTHEADER);

        memset(samplemap, 0, sizeof(samplemap));
        if (nsamples > 32) return true;
        UINT newsamples = m_nSamples;

        for (UINT nmap = 0; nmap < nsamples; nmap++)
        {
            UINT n = m_nSamples + nmap + 1;
            if (n >= MAX_SAMPLES)
            {
                n = m_nSamples;
                while (n > 0)
                {
                    if (!Samples[n].sample_data)
                    {
                        for (UINT xmapchk=0; xmapchk < nmap; xmapchk++)
                        {
                            if (samplemap[xmapchk] == n) goto alreadymapped;
                        }
                        for (UINT clrs=1; clrs<iIns; clrs++) if (Instruments[clrs])
                        {
                            modinstrument_t *pks = Instruments[clrs];
                            for (UINT ks=0; ks<128; ks++)
                            {
                                if (pks->Keyboard[ks] == n) pks->Keyboard[ks] = 0;
                            }
                        }
                        break;
                    }
                alreadymapped:
                    n--;
                }
#ifndef FASTSOUNDLIB
                // Damn! Too many samples: look for duplicates
                if (!n)
                {
                    if (!unused_samples)
                    {
                        unused_samples = DetectUnusedSamples(samples_used);
                        if (!unused_samples) unused_samples = modplug::tracker::SampleIndexInvalid;
                    }
                    if ((unused_samples) && (unused_samples != modplug::tracker::SampleIndexInvalid))
                    {
                        for (UINT iext=m_nSamples; iext>=1; iext--) if (!samples_used[iext])
                        {
                            unused_samples--;
                            samples_used[iext] = true;
                            DestroySample(iext);
                            n = iext;
                            for (UINT mapchk=0; mapchk<nmap; mapchk++)
                            {
                                if (samplemap[mapchk] == n) samplemap[mapchk] = 0;
                            }
                            for (UINT clrs=1; clrs<iIns; clrs++) if (Instruments[clrs])
                            {
                                modinstrument_t *pks = Instruments[clrs];
                                for (UINT ks=0; ks<128; ks++)
                                {
                                    if (pks->Keyboard[ks] == n) pks->Keyboard[ks] = 0;
                                }
                            }
                            MemsetZero(Samples[n]);
                            break;
                        }
                    }
                }
#endif // FASTSOUNDLIB
            }
            if (newsamples < n) newsamples = n;
            samplemap[nmap] = n;
        }
        m_nSamples = newsamples;
        // Reading Volume Envelope
        modinstrument_t *pIns = Instruments[iIns];
        pIns->midi_program = pih.type;
        pIns->fadeout = xmsh.volfade;
        pIns->default_pan = 128;
        pIns->pitch_pan_center = 5*12;
        SetDefaultInstrumentValues(pIns);
        pIns->nPluginVelocityHandling = PLUGIN_VELOCITYHANDLING_CHANNEL;
        pIns->nPluginVolumeHandling = PLUGIN_VOLUMEHANDLING_IGNORE;
        if (xmsh.vtype & 1) pIns->volume_envelope.flags |= ENV_ENABLED;
        if (xmsh.vtype & 2) pIns->volume_envelope.flags |= ENV_SUSTAIN;
        if (xmsh.vtype & 4) pIns->volume_envelope.flags |= ENV_LOOP;
        if (xmsh.ptype & 1) pIns->panning_envelope.flags |= ENV_ENABLED;
        if (xmsh.ptype & 2) pIns->panning_envelope.flags |= ENV_SUSTAIN;
        if (xmsh.ptype & 4) pIns->panning_envelope.flags |= ENV_LOOP;
        if (xmsh.vnum > 12) xmsh.vnum = 12;
        if (xmsh.pnum > 12) xmsh.pnum = 12;
        pIns->volume_envelope.num_nodes = xmsh.vnum;
        if (!xmsh.vnum) pIns->volume_envelope.flags &= ~ENV_ENABLED;
        if (!xmsh.pnum) pIns->panning_envelope.flags &= ~ENV_ENABLED;
        pIns->panning_envelope.num_nodes = xmsh.pnum;
        pIns->volume_envelope.sustain_start = pIns->volume_envelope.sustain_end = xmsh.vsustain;
        if (xmsh.vsustain >= 12) pIns->volume_envelope.flags &= ~ENV_SUSTAIN;
        pIns->volume_envelope.loop_start = xmsh.vloops;
        pIns->volume_envelope.loop_end = xmsh.vloope;
        if (pIns->volume_envelope.loop_end >= 12) pIns->volume_envelope.loop_end = 0;
        if (pIns->volume_envelope.loop_start >= pIns->volume_envelope.loop_end) pIns->volume_envelope.flags &= ~ENV_LOOP;
        pIns->panning_envelope.sustain_start = pIns->panning_envelope.sustain_end = xmsh.psustain;
        if (xmsh.psustain >= 12) pIns->panning_envelope.flags &= ~ENV_SUSTAIN;
        pIns->panning_envelope.loop_start = xmsh.ploops;
        pIns->panning_envelope.loop_end = xmsh.ploope;
        if (pIns->panning_envelope.loop_end >= 12) pIns->panning_envelope.loop_end = 0;
        if (pIns->panning_envelope.loop_start >= pIns->panning_envelope.loop_end) pIns->panning_envelope.flags &= ~ENV_LOOP;
        pIns->global_volume = 64;
        for (UINT ienv=0; ienv<12; ienv++)
        {
            pIns->volume_envelope.Ticks[ienv] = (uint16_t)xmsh.venv[ienv*2];
            pIns->volume_envelope.Values[ienv] = (uint8_t)xmsh.venv[ienv*2+1];
            pIns->panning_envelope.Ticks[ienv] = (uint16_t)xmsh.penv[ienv*2];
            pIns->panning_envelope.Values[ienv] = (uint8_t)xmsh.penv[ienv*2+1];
            if (ienv)
            {
                if (pIns->volume_envelope.Ticks[ienv] < pIns->volume_envelope.Ticks[ienv-1])
                {
                    pIns->volume_envelope.Ticks[ienv] &= 0xFF;
                    pIns->volume_envelope.Ticks[ienv] += pIns->volume_envelope.Ticks[ienv-1] & 0xFF00;
                    if (pIns->volume_envelope.Ticks[ienv] < pIns->volume_envelope.Ticks[ienv-1]) pIns->volume_envelope.Ticks[ienv] += 0x100;
                }
                if (pIns->panning_envelope.Ticks[ienv] < pIns->panning_envelope.Ticks[ienv-1])
                {
                    pIns->panning_envelope.Ticks[ienv] &= 0xFF;
                    pIns->panning_envelope.Ticks[ienv] += pIns->panning_envelope.Ticks[ienv-1] & 0xFF00;
                    if (pIns->panning_envelope.Ticks[ienv] < pIns->panning_envelope.Ticks[ienv-1]) pIns->panning_envelope.Ticks[ienv] += 0x100;
                }
            }
        }
        for (UINT j=0; j<96; j++)
        {
            pIns->NoteMap[j+12] = j+1+12;
            if (xmsh.snum[j] < nsamples)
                pIns->Keyboard[j+12] = samplemap[xmsh.snum[j]];
        }
        // Reading samples
        for (UINT ins=0; ins<nsamples; ins++)
        {
            if ((dwMemPos + sizeof(xmss) > dwMemLength)
             || (dwMemPos + xmsh.shsize > dwMemLength)) return true;
            memcpy(&xmss, lpStream + dwMemPos, sizeof(xmss));
            xmss.samplen = LittleEndian(xmss.samplen);
            xmss.loopstart = LittleEndian(xmss.loopstart);
            xmss.looplen = LittleEndian(xmss.looplen);
            dwMemPos += sizeof(XMSAMPLESTRUCT);    // was: dwMemPos += xmsh.shsize; (this fixes IFULOVE.XM)
            flags[ins] = (xmss.type & 0x10) ? RS_PCM16D : RS_PCM8D;
            if (xmss.type & 0x20) flags[ins] = (xmss.type & 0x10) ? RS_STPCM16D : RS_STPCM8D;
            samplesize[ins] = xmss.samplen;
            if (!samplemap[ins]) continue;
            if (xmss.type & 0x10)
            {
                xmss.looplen >>= 1;
                xmss.loopstart >>= 1;
                xmss.samplen >>= 1;
            }
            if (xmss.type & 0x20)
            {
                xmss.looplen >>= 1;
                xmss.loopstart >>= 1;
                xmss.samplen >>= 1;
            }
            if (xmss.samplen > MAX_SAMPLE_LENGTH) xmss.samplen = MAX_SAMPLE_LENGTH;
            if (xmss.loopstart >= xmss.samplen) xmss.type &= ~3;
            xmss.looplen += xmss.loopstart;
            if (xmss.looplen > xmss.samplen) xmss.looplen = xmss.samplen;
            if (!xmss.looplen) xmss.type &= ~3;
            UINT imapsmp = samplemap[ins];
            memcpy(m_szNames[imapsmp], xmss.name, 22);
            SpaceToNullStringFixed<22>(m_szNames[imapsmp]);
            modsample_t *pSmp = &Samples[imapsmp];
            pSmp->length = (xmss.samplen > MAX_SAMPLE_LENGTH) ? MAX_SAMPLE_LENGTH : xmss.samplen;
            pSmp->loop_start = xmss.loopstart;
            pSmp->loop_end = xmss.looplen;
            if (pSmp->loop_end > pSmp->length) pSmp->loop_end = pSmp->length;
            if (pSmp->loop_start >= pSmp->loop_end)
            {
                pSmp->loop_start = pSmp->loop_end = 0;
            }
            if (xmss.type & 3) pSmp->flags |= CHN_LOOP;
            if (xmss.type & 2) pSmp->flags |= CHN_PINGPONGLOOP;
            pSmp->default_volume = xmss.vol << 2;
            if (pSmp->default_volume > 256) pSmp->default_volume = 256;
            pSmp->global_volume = 64;
            if ((xmss.res == 0xAD) && (!(xmss.type & 0x30)))
            {
                flags[ins] = RS_ADPCM4;
                samplesize[ins] = (samplesize[ins]+1)/2 + 16;
            }
            pSmp->nFineTune = xmss.finetune;
            pSmp->RelativeTone = (int)xmss.relnote;
            pSmp->default_pan = xmss.pan;
            pSmp->flags |= CHN_PANNING;
            pSmp->vibrato_type = xmsh.vibtype;
            pSmp->vibrato_sweep = xmsh.vibsweep;
            pSmp->vibrato_depth = xmsh.vibdepth;
            pSmp->vibrato_rate = xmsh.vibrate;
            memcpy(pSmp->legacy_filename, xmss.name, 22);
            SpaceToNullStringFixed<21>(pSmp->legacy_filename);

            if ((xmss.type & 3) == 3)    // MPT 1.09 and maybe newer / older versions set both flags for bidi loops
                bProbablyMPT109 = true;
        }
Esempio n. 25
0
bool module_renderer::SaveITProject(LPCSTR lpszFileName)
//-------------------------------------------------
{
    // Check song type

    if(!(m_dwSongFlags & SONG_ITPROJECT)) return false;

    UINT i,j = 0;
    for(i = 0 ; i < m_nInstruments ; i++) { if(m_szInstrumentPath[i][0] != '\0' || !Instruments[i+1]) j++; }
    if(m_nInstruments && j != m_nInstruments) return false;

    // Open file

    FILE *f;

    if((!lpszFileName) || ((f = fopen(lpszFileName, "wb")) == NULL)) return false;


    // File ID

    uint32_t id = ITP_FILE_ID;
    fwrite(&id, 1, sizeof(id), f);

    id = ITP_VERSION;
    fwrite(&id, 1, sizeof(id), f);

    // Song name

    // name string length
    id = 27;
    fwrite(&id, 1, sizeof(id), f);

    // song name
    char namebuf[27];
    copy_with_padding(namebuf, 27, this->song_name);
    fwrite(namebuf, 1, 27, f);

    // Song comments

    // comment string length
    id = m_lpszSongComments ? strlen(m_lpszSongComments)+1 : 0;
    fwrite(&id, 1, sizeof(id), f);

    // comment string
    if(m_lpszSongComments) fwrite(&m_lpszSongComments[0], 1, strlen(m_lpszSongComments)+1, f);

    // Song global config

    id = (m_dwSongFlags & SONG_FILE_FLAGS);
    fwrite(&id, 1, sizeof(id), f);
    id = m_nDefaultGlobalVolume;
    fwrite(&id, 1, sizeof(id), f);
    id = m_nSamplePreAmp;
    fwrite(&id, 1, sizeof(id), f);
    id = m_nDefaultSpeed;
    fwrite(&id, 1, sizeof(id), f);
    id = m_nDefaultTempo;
    fwrite(&id, 1, sizeof(id), f);

    // Song channels data

    // number of channels
    id = m_nChannels;
    fwrite(&id, 1, sizeof(id), f);

    // channel name string length
    id = MAX_CHANNELNAME;
    fwrite(&id, 1, sizeof(id), f);

    // channel config data
    for(i=0; i<m_nChannels; i++){
        id = ChnSettings[i].nPan;
        fwrite(&id, 1, sizeof(id), f);
        id = ChnSettings[i].dwFlags;
        fwrite(&id, 1, sizeof(id), f);
        id = ChnSettings[i].nVolume;
        fwrite(&id, 1, sizeof(id), f);
        fwrite(&ChnSettings[i].szName[0], 1, MAX_CHANNELNAME, f);
    }

    // Song mix plugins

    // mix plugins data length
    id = SaveMixPlugins(NULL, TRUE);
    fwrite(&id, 1, sizeof(id), f);

    // mix plugins data
    SaveMixPlugins(f, FALSE);

    // Song midi config

    // midi cfg data length
    id = sizeof(MODMIDICFG);
    fwrite(&id, 1, sizeof(id), f);

    // midi cfg
    fwrite(&m_MidiCfg, 1, sizeof(MODMIDICFG), f);

    // Song Instruments

    // number of instruments
    id = m_nInstruments;
    fwrite(&id, 1, sizeof(id), f);

    // path name string length
    id = _MAX_PATH;
    fwrite(&id, 1, sizeof(id), f);

    // instruments' path
    for(i=0; i<m_nInstruments; i++) fwrite(&m_szInstrumentPath[i][0], 1, _MAX_PATH, f);

    // Song Orders

    // order array size
    id = Order.size();
    fwrite(&id, 1, sizeof(id), f);

    // order array
    Order.WriteAsByte(f, id);

    // Song Patterns

    // number of patterns
    id = MAX_PATTERNS;
    fwrite(&id, 1, sizeof(id), f);

    // number of pattern name strings
    modplug::tracker::patternindex_t numNamedPats = Patterns.GetNumNamedPatterns();
    numNamedPats = bad_min(numNamedPats, MAX_PATTERNS);
    id = numNamedPats;
    fwrite(&id, 1, sizeof(id), f);

    // length of a pattern name string
    id = MAX_PATTERNNAME;
    fwrite(&id, 1, sizeof(id), f);
    // pattern name string
    for(modplug::tracker::patternindex_t nPat = 0; nPat < numNamedPats; nPat++)
    {
        char name[MAX_PATTERNNAME];
        MemsetZero(name);
        Patterns[nPat].GetName(name, MAX_PATTERNNAME);
        fwrite(name, 1, MAX_PATTERNNAME, f);
    }

    // modcommand data length
    id = sizeof(modplug::tracker::modevent_t);
    fwrite(&id, 1, sizeof(id), f);

    // patterns data content
    for(UINT npat=0; npat<MAX_PATTERNS; npat++){
        // pattern size (number of rows)
        id = Patterns[npat] ? Patterns[npat].GetNumRows() : 0;
        fwrite(&id, 1, sizeof(id), f);
        // pattern data
        if(Patterns[npat] && Patterns[npat].GetNumRows()) Patterns[npat].WriteITPdata(f);
        //fwrite(Patterns[npat], 1, m_nChannels * Patterns[npat].GetNumRows() * sizeof(modplug::tracker::modcommand_t), f);
    }

    // Song lonely (instrument-less) samples

    // Write original number of samples
    id = m_nSamples;
    fwrite(&id, 1, sizeof(id), f);

    vector<bool> sampleUsed(m_nSamples, false);

    // Mark samples used in instruments
    for(i=0; i<m_nInstruments; i++)
    {
        if(Instruments[i + 1] != nullptr)
        {
            modinstrument_t *p = Instruments[i + 1];
            for(j = 0; j < 128; j++)
            {
                if(p->Keyboard[j] > 0 && p->Keyboard[j] <= m_nSamples)
                    sampleUsed[p->Keyboard[j] - 1] = true;
            }
        }
    }

    // Count samples not used in any instrument
    i = 0;
    for(j = 1; j <= m_nSamples; j++)
        if(!sampleUsed[j - 1] && Samples[j].sample_data) i++;

    id = i;
    fwrite(&id, 1, sizeof(id), f);

    // Write samples not used in any instrument (help, this looks like duplicate code!)
    ITSAMPLESTRUCT itss;
    for(UINT nsmp=1; nsmp<=m_nSamples; nsmp++)
    {
        if(!sampleUsed[nsmp - 1] && Samples[nsmp].sample_data)
        {

            modsample_t *psmp = &Samples[nsmp];
            memset(&itss, 0, sizeof(itss));
            memcpy(itss.filename, psmp->legacy_filename, 12);
            memcpy(itss.name, m_szNames[nsmp], 26);

            itss.id = LittleEndian(IT_IMPS);
            itss.gvl = (uint8_t)psmp->global_volume;
            itss.flags = 0x00;

            if(psmp->flags & CHN_LOOP) itss.flags |= 0x10;
            if(psmp->flags & CHN_SUSTAINLOOP) itss.flags |= 0x20;
            if(psmp->flags & CHN_PINGPONGLOOP) itss.flags |= 0x40;
            if(psmp->flags & CHN_PINGPONGSUSTAIN) itss.flags |= 0x80;
            itss.C5Speed = psmp->c5_samplerate;
            if (!itss.C5Speed) itss.C5Speed = 8363;
            itss.length = psmp->length;
            itss.loopbegin = psmp->loop_start;
            itss.loopend = psmp->loop_end;
            itss.susloopbegin = psmp->sustain_start;
            itss.susloopend = psmp->sustain_end;
            itss.vol = (uint8_t)(psmp->default_volume >> 2);
            itss.dfp = (uint8_t)(psmp->default_pan >> 2);
            itss.vit = autovibxm2it[psmp->vibrato_type & 7];
            itss.vis = bad_min(psmp->vibrato_rate, 64);
            itss.vid = bad_min(psmp->vibrato_depth, 32);
            itss.vir = bad_min(psmp->vibrato_sweep, 255); //(psmp->vibrato_sweep < 64) ? psmp->vibrato_sweep * 4 : 255;
            if (psmp->flags & CHN_PANNING) itss.dfp |= 0x80;
            if ((psmp->sample_data) && (psmp->length)) itss.cvt = 0x01;
            UINT flags = RS_PCM8S;

            if(psmp->flags & CHN_STEREO)
            {
                flags = RS_STPCM8S;
                itss.flags |= 0x04;
            }
            if(psmp->flags & CHN_16BIT)
            {
                itss.flags |= 0x02;
                flags = (psmp->flags & CHN_STEREO) ? RS_STPCM16S : RS_PCM16S;
            }

            id = nsmp;
            fwrite(&id, 1, sizeof(id), f);

            itss.samplepointer = NULL;
            fwrite(&itss, 1, sizeof(ITSAMPLESTRUCT), f);

            id = WriteSample(NULL, psmp, flags);
            fwrite(&id, 1, sizeof(id), f);
            WriteSample(f, psmp, flags);
        }
    }
Esempio n. 26
0
void CViewComments::OnUpdate(CView *pSender, LPARAM lHint, CObject *)
//-------------------------------------------------------------------
{
	//CHAR s[256], stmp[256];
	CHAR s[512], stmp[256]; //rewbs.fix3082
	CModDoc *pModDoc = GetDocument();
	LV_COLUMN lvc;
	LV_ITEM lvi, lvi2;

	if ((!pModDoc) || (pSender == this) || (!(m_ItemList.m_hWnd))) return;
	if (lHint & HINT_MPTOPTIONS)
	{
		m_ToolBar.UpdateStyle();
		lHint &= ~HINT_MPTOPTIONS;
	}
	lHint &= (HINT_MODTYPE
		|HINT_SMPNAMES|HINT_SAMPLEINFO
		|HINT_INSNAMES|HINT_INSTRUMENT
		/*|HINT_PATNAMES|HINT_PATTERNROW*/); // pattern stuff currently unused
	if (!lHint) return;

	const CSoundFile &sndFile = pModDoc->GetrSoundFile();

	m_ToolBar.ChangeBitmap(IDC_LIST_INSTRUMENTS, sndFile.GetNumInstruments() ? IMAGE_INSTRUMENTS : IMAGE_INSTRMUTE);

	m_ItemList.SetRedraw(FALSE);
	// Add sample headers
	if ((m_nListId != m_nCurrentListId) || (lHint & HINT_MODTYPE))
	{
		UINT ichk = 0;
		m_ItemList.DeleteAllItems();
		while ((m_ItemList.DeleteColumn(0)) && (ichk < 25)) ichk++;
		m_nCurrentListId = m_nListId;
		// Add Sample Headers
		if (m_nCurrentListId == IDC_LIST_SAMPLES)
		{
			UINT nCol = 0;
			for (UINT iSmp=0; iSmp<SMPLIST_COLUMNS; iSmp++)
			{
				MemsetZero(lvc);
				lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
				lvc.fmt = (iSmp) ? LVCFMT_RIGHT : LVCFMT_LEFT;
				lvc.pszText = (LPTSTR)gSampleHeaders[iSmp].pszName;
				lvc.cx = gSampleHeaders[iSmp].cx;
				lvc.iSubItem = iSmp;
				m_ItemList.InsertColumn(nCol, &lvc);
				nCol++;
			}
		} else
		// Add Instrument Headers
		if (m_nCurrentListId == IDC_LIST_INSTRUMENTS)
		{
			UINT nCol = 0;
			for (UINT i=0; i<INSLIST_COLUMNS; i++)
			{
				MemsetZero(lvc);
				lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
				lvc.fmt = (i) ? LVCFMT_RIGHT : LVCFMT_LEFT;
				lvc.pszText = (LPTSTR)gInstrumentHeaders[i].pszName;
				lvc.cx = gInstrumentHeaders[i].cx;
				lvc.iSubItem = i;
				m_ItemList.InsertColumn(nCol, &lvc);
				nCol++;
			}
		} else
		lHint |= HINT_MODTYPE;
	}
	// Add Items
	UINT nCount = m_ItemList.GetItemCount();
	// Add Samples
	if ((m_nCurrentListId == IDC_LIST_SAMPLES) && (lHint & (HINT_MODTYPE|HINT_SMPNAMES|HINT_SAMPLEINFO)))
	{
		SAMPLEINDEX nMax = static_cast<SAMPLEINDEX>(nCount);
		if (nMax < sndFile.GetNumSamples()) nMax = sndFile.GetNumSamples();
		for (SAMPLEINDEX iSmp = 0; iSmp < nMax; iSmp++)
		{
			if (iSmp < sndFile.GetNumSamples())
			{
				UINT nCol = 0;
				for (UINT iCol=0; iCol<SMPLIST_COLUMNS; iCol++)
				{
					const ModSample &sample = sndFile.GetSample(iSmp + 1);
					s[0] = 0;
					switch(iCol)
					{
					case SMPLIST_SAMPLENAME:
						mpt::String::Copy(s, sndFile.m_szNames[iSmp + 1]);
						break;
					case SMPLIST_SAMPLENO:
						wsprintf(s, "%02d", iSmp + 1);
						break;
					case SMPLIST_SIZE:
						if (sample.nLength)
						{
							if(sample.GetSampleSizeInBytes() >= 1024)
								wsprintf(s, "%d KB", sample.GetSampleSizeInBytes() >> 10);
							else
								wsprintf(s, "%d B", sample.GetSampleSizeInBytes());
						}
						break;
					case SMPLIST_TYPE:
						if(sample.nLength)
						{
							wsprintf(s, "%d Bit", sample.GetElementarySampleSize() * 8);
						}
						break;
					case SMPLIST_INSTR:
						if (sndFile.GetNumInstruments())
						{
							bool first = true;
							for (INSTRUMENTINDEX i = 1; i <= sndFile.GetNumInstruments(); i++)
							{
								if (sndFile.IsSampleReferencedByInstrument(iSmp + 1, i))
								{
									if (!first) strcat(s, ",");
									first = false;

									wsprintf(stmp, "%d", i);
									strcat(s, stmp);

									if (strlen(s) > sizeof(s) - 10)
									{
										strcat(s, "...");
										break;
									}
								}
							}
						}
						break;
					case SMPLIST_MIDDLEC:
						if (sample.nLength)
						{
							wsprintf(s, "%d Hz", sample.GetSampleRate(sndFile.GetType()));
						}
						break;
					case SMPLIST_FILENAME:
						memcpy(s, sample.filename, sizeof(sample.filename));
						s[CountOf(sample.filename)] = 0;
						break;
					}
					lvi.mask = LVIF_TEXT;
					lvi.iItem = iSmp;
					lvi.iSubItem = nCol;
					lvi.pszText = (LPTSTR)s;
					if ((iCol) || (iSmp < nCount))
					{
						bool bOk = true;
						if (iSmp < nCount)
						{
							lvi2 = lvi;
							lvi2.pszText = (LPTSTR)stmp;
							lvi2.cchTextMax = sizeof(stmp);
							stmp[0] = 0;
							m_ItemList.GetItem(&lvi2);
							if (!strcmp(s, stmp)) bOk = false;
						}
						if (bOk) m_ItemList.SetItem(&lvi);
					} else
					{
						m_ItemList.InsertItem(&lvi);
					}
					nCol++;
				}
			} else
Esempio n. 27
0
bool CWaveDevice::InternalOpen()
//------------------------------
{
	MPT_TRACE();
	if(m_Settings.InputChannels > 0)
	{
		return false;
	}
	WAVEFORMATEXTENSIBLE wfext;
	if(!FillWaveFormatExtensible(wfext, m_Settings))
	{
		return false;
	}
	WAVEFORMATEX *pwfx = &wfext.Format;
	UINT nWaveDev = GetDeviceIndex();
	nWaveDev = (nWaveDev > 0) ? nWaveDev - 1 : WAVE_MAPPER;
	m_ThreadWakeupEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	if(m_ThreadWakeupEvent == INVALID_HANDLE_VALUE)
	{
		InternalClose();
		return false;
	}
	m_Failed = false;
	m_DriverBugs = 0;
	m_hWaveOut = NULL;
	if(waveOutOpen(&m_hWaveOut, nWaveDev, pwfx, (DWORD_PTR)WaveOutCallBack, (DWORD_PTR)this, CALLBACK_FUNCTION | (m_Settings.ExclusiveMode ? WAVE_FORMAT_DIRECT : 0)) != MMSYSERR_NOERROR)
	{
		InternalClose();
		return false;
	}
	if(waveOutPause(m_hWaveOut) != MMSYSERR_NOERROR)
	{
		InternalClose();
		return false;
	}
	m_nWaveBufferSize = Util::Round<int32>(m_Settings.UpdateInterval * pwfx->nAvgBytesPerSec);
	m_nWaveBufferSize = Util::AlignUp<uint32>(m_nWaveBufferSize, pwfx->nBlockAlign);
	m_nWaveBufferSize = mpt::clamp(m_nWaveBufferSize, static_cast<uint32>(WAVEOUT_MINBUFFERFRAMECOUNT * pwfx->nBlockAlign), static_cast<uint32>(Util::AlignDown<uint32>(WAVEOUT_MAXBUFFERSIZE, pwfx->nBlockAlign)));
	std::size_t numBuffers = Util::Round<int32>(m_Settings.Latency * pwfx->nAvgBytesPerSec / m_nWaveBufferSize);
	numBuffers = mpt::clamp(numBuffers, WAVEOUT_MINBUFFERS, WAVEOUT_MAXBUFFERS);
	m_nPreparedHeaders = 0;
	m_WaveBuffers.resize(numBuffers);
	m_WaveBuffersData.resize(numBuffers);
	for(std::size_t buf = 0; buf < numBuffers; ++buf)
	{
		MemsetZero(m_WaveBuffers[buf]);
		m_WaveBuffersData[buf].resize(m_nWaveBufferSize);
		m_WaveBuffers[buf].dwFlags = 0;
		m_WaveBuffers[buf].lpData = &m_WaveBuffersData[buf][0];
		m_WaveBuffers[buf].dwBufferLength = m_nWaveBufferSize;
		if(waveOutPrepareHeader(m_hWaveOut, &m_WaveBuffers[buf], sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
		{
			break;
		}
		m_WaveBuffers[buf].dwFlags |= WHDR_DONE;
		m_nPreparedHeaders++;
	}
	if(!m_nPreparedHeaders)
	{
		InternalClose();
		return false;
	}
	m_nBuffersPending = 0;
	m_nWriteBuffer = 0;
	m_nDoneBuffer = 0;
	{
		MPT_LOCK_GUARD<mpt::mutex> guard(m_PositionWraparoundMutex);
		MemsetZero(m_PositionLast);
		m_PositionWrappedCount = 0;
	}
	SetWakeupEvent(m_ThreadWakeupEvent);
	SetWakeupInterval(m_nWaveBufferSize * 1.0 / m_Settings.GetBytesPerSecond());
	m_Flags.NeedsClippedFloat = GetSysInfo().WindowsVersion.IsAtLeast(mpt::Windows::Version::WinVista);
	return true;
}
Esempio n. 28
0
void CSelectPluginDlg::OnOK()
//---------------------------
{
	if(m_pPlugin==nullptr) { CDialog::OnOK(); return; }

	bool changed = false;
	CVstPluginManager *pManager = theApp.GetPluginManager();
	VSTPluginLib *pNewPlug = GetSelectedPlugin();
	VSTPluginLib *pFactory = nullptr;
	IMixPlugin *pCurrentPlugin = nullptr;
	if (m_pPlugin) pCurrentPlugin = m_pPlugin->pMixPlugin;
	if ((pManager) && (pManager->IsValidPlugin(pNewPlug))) pFactory = pNewPlug;

	if (pFactory)
	{
		// Plugin selected
		if ((!pCurrentPlugin) || &pCurrentPlugin->GetPluginFactory() != pFactory)
		{
			CriticalSection cs;

			// Destroy old plugin, if there was one.
			m_pPlugin->Destroy();

			// Initialize plugin info
			MemsetZero(m_pPlugin->Info);
			m_pPlugin->Info.dwPluginId1 = pFactory->pluginId1;
			m_pPlugin->Info.dwPluginId2 = pFactory->pluginId2;
			m_pPlugin->editorX = m_pPlugin->editorY = int32_min;

#ifndef NO_VST
			if(m_pPlugin->Info.dwPluginId1 == kEffectMagic)
			{
				switch(m_pPlugin->Info.dwPluginId2)
				{
					// Enable drymix by default for these known plugins
				case CCONST('S', 'c', 'o', 'p'):
					m_pPlugin->SetWetMix();
					break;
				}
			}
#endif // NO_VST

			mpt::String::Copy(m_pPlugin->Info.szName, pFactory->libraryName.ToLocale().c_str());
			mpt::String::Copy(m_pPlugin->Info.szLibraryName, pFactory->libraryName.ToUTF8().c_str());

			cs.Leave();

			// Now, create the new plugin
			if(pManager && m_pModDoc)
			{
				pManager->CreateMixPlugin(*m_pPlugin, m_pModDoc->GetrSoundFile());
				if (m_pPlugin->pMixPlugin)
				{
					IMixPlugin *p = m_pPlugin->pMixPlugin;
					const CString name = p->GetDefaultEffectName();
					if(!name.IsEmpty())
					{
						mpt::String::Copy(m_pPlugin->Info.szName, name.GetString());
					}
					// Check if plugin slot is already assigned to any instrument, and if not, create one.
					if(p->IsInstrument() && m_pModDoc->HasInstrumentForPlugin(m_nPlugSlot) == INSTRUMENTINDEX_INVALID)
					{
						m_pModDoc->InsertInstrumentForPlugin(m_nPlugSlot);
					}
				} else
				{
					MemsetZero(m_pPlugin->Info);
				}
			}
			changed = true;
		}
	} else if(m_pPlugin->IsValidPlugin())
	{
		// No effect
		CriticalSection cs;
		m_pPlugin->Destroy();
		// Clear plugin info
		MemsetZero(m_pPlugin->Info);
		changed = true;
	}

	//remember window size:
	SaveWindowPos();

	if(changed)
	{
		if(m_pPlugin->Info.dwPluginId2)
			TrackerSettings::Instance().gnPlugWindowLast = m_pPlugin->Info.dwPluginId2;
		if(m_pModDoc)
		{
			m_pModDoc->UpdateAllViews(nullptr, PluginHint(static_cast<PLUGINDEX>(m_nPlugSlot + 1)).Info().Names());
		}
		CDialog::OnOK();
	} else
	{
		CDialog::OnCancel();
	}
}
Esempio n. 29
0
int64 CWaveDevice::InternalGetStreamPositionFrames() const
//---------------------------------------------------------
{
	// Apparently, at least with Windows XP, TIME_SAMPLES wraps aroud at 0x7FFFFFF (see
	// http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.mmedia/2005-02/0070.html
	// ).
	// We may also, additionally, default to TIME_BYTES which would wraparound the earliest.
	// We could thereby try to avoid any potential wraparound inside the driver on older
	// Windows versions, which would be, once converted into other units, really
	// difficult to detect or handle.
	static const UINT timeType = TIME_SAMPLES; // shpuld work for sane systems
	//static const std::size_t valid_bits = 32; // shpuld work for sane systems
	//static const UINT timeType = TIME_BYTES; // safest
	static const std::size_t valid_bits = 27; // safe for WinXP TIME_SAMPLES
	static const uint32 valid_mask = static_cast<uint32>((uint64(1) << valid_bits) - 1u);
	static const uint32 valid_watermark = static_cast<uint32>(uint64(1) << (valid_bits - 1u)); // half the valid range in order to be able to catch backwards fluctuations

	MMTIME mmtime;
	MemsetZero(mmtime);
	mmtime.wType = timeType;
	if(waveOutGetPosition(m_hWaveOut, &mmtime, sizeof(mmtime)) != MMSYSERR_NOERROR)
	{
		return 0;
	}
	if(mmtime.wType != TIME_MS && mmtime.wType != TIME_BYTES && mmtime.wType != TIME_SAMPLES)
	{ // unsupported time format
		return 0;
	}
	int64 offset = 0;
	{
		// handle wraparound
		MPT_LOCK_GUARD<mpt::mutex> guard(m_PositionWraparoundMutex);
		if(!m_PositionLast.wType)
		{
			// first call
			m_PositionWrappedCount = 0;
		} else if(mmtime.wType != m_PositionLast.wType)
		{
			// what? value type changed, do not try handling that for now.
			m_PositionWrappedCount = 0;
		} else
		{
			DWORD oldval = 0;
			DWORD curval = 0;
			switch(mmtime.wType)
			{
				case TIME_MS: oldval = m_PositionLast.u.ms; curval = mmtime.u.ms; break;
				case TIME_BYTES: oldval = m_PositionLast.u.cb; curval = mmtime.u.cb; break;
				case TIME_SAMPLES: oldval = m_PositionLast.u.sample; curval = mmtime.u.sample; break;
			}
			oldval &= valid_mask;
			curval &= valid_mask;
			if(((curval - oldval) & valid_mask) >= valid_watermark) // guard against driver problems resulting in time jumping backwards for short periods of time. BEWARE of integer wraparound when refactoring
			{
				curval = oldval;
			}
			switch(mmtime.wType)
			{
				case TIME_MS: mmtime.u.ms = curval; break;
				case TIME_BYTES: mmtime.u.cb = curval; break;
				case TIME_SAMPLES: mmtime.u.sample = curval; break;
			}
			if((curval ^ oldval) & valid_watermark) // MSB flipped
			{
				if(!(curval & valid_watermark)) // actually wrapped
				{
					m_PositionWrappedCount += 1;
				}
			}
		}
		m_PositionLast = mmtime;
		offset = (static_cast<uint64>(m_PositionWrappedCount) << valid_bits);
	}
	int64 result = 0;
	switch(mmtime.wType)
	{
		case TIME_MS: result += (static_cast<int64>(mmtime.u.ms & valid_mask) + offset) * m_Settings.GetBytesPerSecond() / (1000 * m_Settings.GetBytesPerFrame()); break;
		case TIME_BYTES: result += (static_cast<int64>(mmtime.u.cb & valid_mask) + offset) / m_Settings.GetBytesPerFrame(); break;
		case TIME_SAMPLES: result += (static_cast<int64>(mmtime.u.sample & valid_mask) + offset); break;
	}
	return result;
}