void CPL_cb_SetWindowToReflectList()
{
	CP_HPLAYLISTITEM hCursor;
	CP_HPLAYLISTITEM hSelected;
	
	if (globals.m_hPlaylistViewControl)
		CLV_BeginBatch(globals.m_hPlaylistViewControl);
		
	// Unselect active item
	hSelected = CPL_GetActiveItem(globals.m_hPlaylist);
	
	// Add items to list
	CLV_RemoveAllItems(globals.m_hPlaylistViewControl);
	
	for (hCursor = CPL_GetFirstItem(globals.m_hPlaylist); hCursor; hCursor = CPLI_Next(hCursor))
		CPL_cb_OnPlaylistAppend(hCursor);
		
	// Set active item
	if (hSelected)
		CPL_cb_OnPlaylistActivationChange(hSelected, TRUE);
		
	if (globals.m_hPlaylistViewControl)
		CLV_EndBatch(globals.m_hPlaylistViewControl);
}
void CPP_OMFL_RefillBuffers(CPs_OutputModule* pModule)
{
	BOOL bMoreData;
	DWORD dwBufferLength = CPC_OUTPUTBLOCKSIZE;
	BYTE lpData[CPC_OUTPUTBLOCKSIZE];
	
	CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
	CP_CHECKOBJECT(pContext);
	
	
	// Open a file out
	
	if (!pContext->m_hFile)
	{
		CPs_FileInfo pFileInfo;
		CP_HPLAYLISTITEM hCurrent = CPL_GetActiveItem(globals.m_hPlaylist);
		const char *pathname = CPLI_GetPath(hCurrent);
		char newpath[MAX_PATH];
		int rec_rate;
		int rec_bits;
		UINT temp;
		WAVEFORMATEX wfs;
		char *dot;
		
		pModule->m_pCoDec->GetFileInfo(pModule->m_pCoDec, &pFileInfo);
		rec_rate = pFileInfo.m_iFreq_Hz;
		rec_bits = pFileInfo.m_b16bit == TRUE ? 16 : 8;
		
		// saving internet stream
		
		if (_strnicmp(pathname, CIC_HTTPHEADER, strlen(CIC_HTTPHEADER)) == 0)
		{
			strcpy(newpath, "Stream.wav");
			pFileInfo.m_iFileLength_Secs = 0xffffffff;
		}
		
		else
		{
			// replace the extension with .wav
			strcpy(newpath, pathname);
			dot = strrchr(newpath, '.');
			
			if (dot)
				*dot = '\0';
			
			strcat(newpath, ".wav");
		}
		
		// Trap error
		
		while (!pContext->m_hFile)
		{
			OPENFILENAME fn;
			char filefilter[] =
				"WAV files (*.wav)\0*.wav\0"
				"All Files (*.*)\0*.*\0";
			BOOL    returnval;
			fn.lStructSize = sizeof(OPENFILENAME);
			fn.hwndOwner = (HWND) GetWindowLong(windows.wnd_main, DWLP_USER);
			fn.hInstance = NULL;
			fn.lpstrFilter = filefilter;
			fn.lpstrCustomFilter = NULL;
			fn.nMaxCustFilter = 0;
			fn.nFilterIndex = 0;
			fn.lpstrFile = newpath;
			fn.nMaxFile = MAX_PATH * 200;
			fn.lpstrFileTitle = NULL;
			fn.nMaxFileTitle = 0;
			fn.lpstrInitialDir = options.last_used_directory;
			fn.lpstrTitle = NULL;
			fn.Flags = OFN_ENABLESIZING |
					   OFN_HIDEREADONLY | OFN_EXPLORER;
			fn.nFileOffset = 0;
			fn.nFileExtension = 0;
			fn.lpstrDefExt = NULL;
			fn.lCustData = 0;
			fn.lpfnHook = NULL;
			fn.lpTemplateName = NULL;
			returnval = GetSaveFileName(&fn);
			
			if (!returnval)
				return;
			
			pContext->m_hFile = fopen(fn.lpstrFile, "wb");
			
			if (pContext->m_hFile)
				break;
		}
		
		// Wave header stuff
		
		// prep wave format header
		wfs.wFormatTag = WAVE_FORMAT_PCM;
		wfs.nChannels = pFileInfo.m_bStereo == TRUE ? 2 : 1;
		wfs.nSamplesPerSec = rec_rate;
		wfs.nBlockAlign = (short)(rec_bits / 8 * wfs.nChannels);
		wfs.nAvgBytesPerSec = rec_rate * wfs.nBlockAlign;
		wfs.wBitsPerSample = rec_bits;
		wfs.cbSize = 0;
		
		// RIFF header block
		fwrite("RIFF", 4, 1, pContext->m_hFile);
		temp =  sizeof(wfs) + 20 + (pFileInfo.m_iFileLength_Secs * wfs.nAvgBytesPerSec);
		fwrite(&temp, 4, 1, pContext->m_hFile);
		fwrite("WAVE", 4, 1, pContext->m_hFile);
		
		// 'fmt ' block
		fwrite("fmt ", 4, 1, pContext->m_hFile);
		temp = sizeof(wfs);
		fwrite(&temp, 4, 1, pContext->m_hFile);
		fwrite(&wfs, sizeof(wfs), 1, pContext->m_hFile);
		
		// 'data' block
		fwrite("data", 4, 1, pContext->m_hFile);
		temp = pFileInfo.m_iFileLength_Secs * wfs.nAvgBytesPerSec;
		fwrite(&temp, 4, 1, pContext->m_hFile);
	}
	
	
	
	// Scan ring buffer and fill any empty blocks - any blocks that become free
	// while this loop is running will retrigger the event - the worse that can
	// happen is that we enter this loop with no blocks free
	
	// Get block from CoDec and then just send it to the device (how easy is this!)
	bMoreData = pModule->m_pCoDec->GetPCMBlock(pModule->m_pCoDec, lpData, &dwBufferLength);
	
	
	// If there is EQ then apply it
	{
		// Note that the EQ module is initailised and uninitialsed by the engine
		CPs_EqualiserModule* pEQModule = (CPs_EqualiserModule*)pModule->m_pEqualiser;
		pEQModule->ApplyEQToBlock_Inplace(pEQModule, lpData, dwBufferLength);
	}
	
	if (dwBufferLength > 0)
		fwrite(lpData, dwBufferLength, 1, pContext->m_hFile);
		
	// Nothing to send
	if (bMoreData == FALSE)
	{
		pModule->m_pCoDec->CloseFile(pModule->m_pCoDec);
		pModule->m_pCoDec = NULL;
		
		if (pContext->m_hFile) 
			fclose(pContext->m_hFile);
		
		pContext->m_hFile = NULL;
	}
	
	if (!pContext->m_bPaused)
		SetEvent(pModule->m_evtBlockFree);
}
BOOL CPlaylistWindow_OffsetSelectedItems(const int iOffset)
{
	int iNumItemsInList;
	int iStartItem, iTermItem, iItemInc, iItemIDX;
	int iScanStartItem, iScanTermItem;
	CP_HPLAYLISTITEM hActive;
	int iNewFocusItemIDX;
	
	if (iOffset == 0)
		return FALSE;
		
	// Determine which direction to move in list
	iNumItemsInList = CLV_GetItemCount(globals.m_hPlaylistViewControl);
	
	if (iOffset < 0)
	{
		iStartItem = 0;
		iTermItem = iNumItemsInList;
		iItemInc = 1;
		
		iScanStartItem = 0;
		iScanTermItem = -iOffset;
	}
	
	else
	{
		iStartItem = iNumItemsInList - 1;
		iTermItem = -1;
		iItemInc = -1;
		
		iScanStartItem = iNumItemsInList - 1;
		iScanTermItem = iScanStartItem - iOffset;
	}
	
	// Ensure that the selection can move intact (ie there are no selected items that could
	// be "scrolled off" the list
	
	for (iItemIDX = iScanStartItem; iItemIDX != iScanTermItem; iItemIDX += iItemInc)
	{
		if (CLV_IsItemSelected(globals.m_hPlaylistViewControl, iItemIDX))
			return FALSE;
	}
	
	iNewFocusItemIDX = CLV_GetFocusItem(globals.m_hPlaylistViewControl) + iOffset;
	
	CLV_SetFocusItem(globals.m_hPlaylistViewControl, iNewFocusItemIDX);
	CLV_EnsureVisible(globals.m_hPlaylistViewControl, iNewFocusItemIDX);
	
	
	// Go through all the items scanning the -ve offset item and swapping it
	// in if needed
	
	for (iItemIDX = iStartItem; iItemIDX != iTermItem; iItemIDX += iItemInc)
	{
		// Work out the item to probe
		const int iProbeItemIDX = iItemIDX - iOffset;
		CP_HPLAYLISTITEM hItem, hItem_Probe, hReindexCursor;
		CP_HPLAYLISTITEM hReindexStart, hReindexEnd;
		int iReindexItemIDX;
		
		// If this probe item is unselected (or out of bounds) - set the current item's selection
		// to unselected and try the next item
		
		if (iProbeItemIDX < 0 || iProbeItemIDX >= iNumItemsInList
				|| CLV_IsItemSelected(globals.m_hPlaylistViewControl, iProbeItemIDX) == FALSE)
		{
			CLV_SetItemSelected(globals.m_hPlaylistViewControl, iItemIDX, FALSE);
			continue;
		}
		
		// The probe item is selected - move that item over to this item
		// - If the item is moving down it needs to be inserted after - otherwise it
		// needs to be inserted before
		hItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iItemIDX);
		
		hItem_Probe = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iProbeItemIDX);
		
		if (iOffset > 0)
		{
			// Get start reindex item
			hReindexStart = CPLI_Next(hItem_Probe);
			
			if (hReindexStart == NULL)
				hReindexStart = CPL_GetFirstItem(globals.m_hPlaylist);
				
			CPL_InsertItemAfter(globals.m_hPlaylist, hItem, hItem_Probe);
			
			// Get end reindex item
			hReindexEnd = CPLI_Next(hItem_Probe);
			
			// Perform reindexing
			iReindexItemIDX = iProbeItemIDX;
			
			for (hReindexCursor = hReindexStart; hReindexCursor != hReindexEnd; hReindexCursor = CPLI_Next(hReindexCursor))
			{
				CPLI_SetCookie(hReindexCursor, iReindexItemIDX);
				CPL_cb_OnItemUpdated(hReindexCursor);
				iReindexItemIDX++;
			}
		}
		
		else
		{
			// Get start reindex item
			hReindexStart = CPLI_Prev(hItem_Probe);
			
			if (hReindexStart == NULL)
				hReindexStart = CPL_GetLastItem(globals.m_hPlaylist);
				
			CPL_InsertItemBefore(globals.m_hPlaylist, hItem, hItem_Probe);
			
			// Get end reindex item
			hReindexEnd = CPLI_Prev(hItem_Probe);
			
			// Perform reindexing
			iReindexItemIDX = iProbeItemIDX;
			
			for (hReindexCursor = hReindexStart; hReindexCursor != hReindexEnd; hReindexCursor = CPLI_Prev(hReindexCursor))
			{
				CPLI_SetCookie(hReindexCursor, iReindexItemIDX);
				CPL_cb_OnItemUpdated(hReindexCursor);
				iReindexItemIDX--;
			}
		}
		
		// Set the item's selection
		CLV_SetItemSelected(globals.m_hPlaylistViewControl, iItemIDX, TRUE);
	}
	
	// Set the "active" item in the list
	hActive = CPL_GetActiveItem(globals.m_hPlaylist);
	
	return TRUE;
}