Пример #1
0
/* DatArchive::isDatArchive
 * Checks if the given data is a valid Shadowcaster dat archive
 *******************************************************************/
bool DatArchive::isDatArchive(MemChunk& mc)
{
	// Read dat header
	mc.seek(0, SEEK_SET);
	uint16_t num_lumps;
	uint32_t dir_offset, junk;
	mc.read(&num_lumps, 2);		// Size
	mc.read(&dir_offset, 4);	// Directory offset
	mc.read(&junk, 4);		// Unknown value
	num_lumps	= wxINT16_SWAP_ON_BE(num_lumps);
	dir_offset	= wxINT32_SWAP_ON_BE(dir_offset);
	junk		= wxINT32_SWAP_ON_BE(junk);

	if (dir_offset >= mc.getSize())
		return false;

	// Read the directory
	mc.seek(dir_offset, SEEK_SET);
	// Read lump info
	uint32_t offset = 0;
	uint32_t size = 0;
	uint16_t nameofs = 0;
	uint16_t flags = 0;

	mc.read(&offset,	4);		// Offset
	mc.read(&size,		4);		// Size
	mc.read(&nameofs,	2);		// Name offset
	mc.read(&flags,		2);		// Flags

	// Byteswap values for big endian if needed
	offset	= wxINT32_SWAP_ON_BE(offset);
	size	= wxINT32_SWAP_ON_BE(size);
	nameofs	= wxINT16_SWAP_ON_BE(nameofs);
	flags	= wxINT16_SWAP_ON_BE(flags);

	// The first lump should have a name (subsequent lumps need not have one).
	// Also, sanity check the values.
	if (nameofs == 0 || nameofs >=  mc.getSize() || offset + size >= mc.getSize())
	{
		return false;
	}

	size_t len = 1;
	size_t start = nameofs+dir_offset;
	// Sanity checks again. Make sure there is actually a name.
	if (start > mc.getSize() || mc[start] < 33)
		return false;
	for (size_t i = start; (mc[i] != 0 && i < mc.getSize()); ++i, ++len)
	{
		// Names should not contain garbage characters
		if (mc[i] < 32 || mc[i] > 126)
			return false;
	}
	// Let's be reasonable here. While names aren't limited, if it's too long, it's suspicious.
	if (len > 60)
		return false;
	return true;
}
Пример #2
0
bool MusBinInput::ReadFileHeader( MusFileHeader *header )
{
	Read( &int32, 4 ); 
	m_flag = wxINT32_SWAP_ON_BE( int32 ); 
	Read( &int32, 4 ); 
	m_vmaj = wxINT32_SWAP_ON_BE( int32 ); 
    Read( &int32, 4 ); 
	m_vmin = wxINT32_SWAP_ON_BE( int32 ); 
    Read( &int32, 4 ); 
	m_vrev = wxINT32_SWAP_ON_BE( int32 ); 
	Read( &uint16, 2 ); 
	header->nbpage = wxUINT16_SWAP_ON_BE( uint16 ); // nbpage
	Read( &uint16, 2 ); 
	header->nopage = wxUINT16_SWAP_ON_BE( uint16 ); // nopage
	Read( &uint16, 2 ); 
	header->noligne = wxUINT16_SWAP_ON_BE( uint16 ); // noligne
	Read( &uint32, 4 );
	header->xpos = wxUINT32_SWAP_ON_BE( uint32 );  // xpso
	Read( &header->param.orientation, 1 ); // param - orientation
	Read( &header->param.EpLignesPortee, 1 ); // param - epLignesPortee
    header->param.EpLignesPortee = 1;	
	Read( &header->param.EpQueueNote, 1 ); // param - epQueueNotes
    header->param.EpQueueNote = 2;
	Read( &header->param.EpBarreMesure, 1 ); // param - epBarreMesure
	Read( &header->param.EpBarreValeur, 1 ); // param - epBarreValeur
	Read( &header->param.EpBlancBarreValeur, 1 ); // param - epBlancBarreValeur
	Read( &int32, 4 );
	header->param.pageFormatHor = wxINT32_SWAP_ON_BE( int32 ); // param - pageFormatHor
	Read( &int32, 4 );
	header->param.pageFormatVer = wxINT32_SWAP_ON_BE( int32 ); // param - pageFormatVer
	Read( &int16, 2 );
	header->param.MargeSOMMET = wxINT16_SWAP_ON_BE( int16 ); // param - margeSommet
	Read( &int16, 2 );
	header->param.MargeGAUCHEIMPAIRE = wxINT16_SWAP_ON_BE( int16 ); // param - margeGaucheImpaire
	Read( &int16, 2 );
	header->param.MargeGAUCHEPAIRE = wxINT16_SWAP_ON_BE( int16 ); // param - margeGauchePaire
    
	Read( &header->param.rapportPorteesNum, 1 ); // rpPorteesNum
	Read( &header->param.rapportPorteesDen, 1 ); // rpPorteesDen
	Read( &header->param.rapportDiminNum, 1 ); // rpDiminNum
	Read( &header->param.rapportDiminDen, 1 ); // rpDiminDen	
	Read( &header->param.hampesCorr, 1 ); // hampesCorr
    header->param.hampesCorr = 1;	 
    
	if ( AxFile::FormatVersion(m_vmaj, m_vmin, m_vrev) < AxFile::FormatVersion(1, 6, 1) )
		return true; // following values where added in 1.6.1
    // 1.6.1
    Read( &int32, 4 );
    header->param.notationMode = wxINT32_SWAP_ON_BE( int32 );

	return true;
}
Пример #3
0
bool MusBinInput::ReadPage( MusPage *page )
{
	int j;

    if ( !ReadSeparator() )
		return false;

	Read( &int32, 4 );
	page->npage = wxINT32_SWAP_ON_BE( int32 );
	Read( &int16, 2 );
	page->nbrePortees = wxINT16_SWAP_ON_BE( int16 );
    Read( &page->noMasqueFixe, 1 );	
	Read( &page->noMasqueVar, 1 );
	Read( &page->reserve, 1 );
	Read( &page->defin, 1 );
	Read( &int32, 4 );
	page->indent = wxINT32_SWAP_ON_BE( int32 );	
	Read( &int32, 4 );
	page->indentDroite = wxINT32_SWAP_ON_BE( int32 ); 
	Read( &int32, 4 );
	page->lrg_lign = wxINT32_SWAP_ON_BE( int32 );
    for (j = 0; j < page->nbrePortees; j++) 
	{
		MusStaff *staff = new MusStaff();
		ReadStaff( staff );
        staff->voix = (j % 2 == 0) ? 1 : 0; // add voices
		page->m_staves.Add( staff );
	}

	return true;

}
Пример #4
0
bool CDVDongleController::decodeOut(wxFloat32* audio, unsigned int length, unsigned int& ber)
{
	wxASSERT(audio != NULL);
	wxASSERT(length == DSTAR_AUDIO_BLOCK_SIZE);

	ber = 0U;

	bool ambeFound  = false;
	bool audioFound = false;

	for (;;) {
		unsigned char buffer[DVD_AUDIO_LENGTH_BYTES];
		DVD_RESP_TYPE type = getResponse(buffer, DVD_AUDIO_LENGTH_BYTES);
		if (type == DVDRT_ERROR)
			return false;

		if (type == DVDRT_AMBE) {
			ber = ((buffer[14U] + buffer[15U] * 256U) * 100U) / 32767U;
			ambeFound = true;
		} else if (type == DVDRT_AUDIO) {
			wxInt16* q = (wxInt16*)buffer;
			for (unsigned int i = 0U; i < DSTAR_AUDIO_BLOCK_SIZE; i++) {
				wxInt16 word = wxINT16_SWAP_ON_BE(*q++);
				audio[i] = wxFloat32(word) / 32768.0F;
			}
			audioFound = true;
		}

		if (ambeFound && audioFound)
			return true;

		::wxMilliSleep(5UL);
	}
}
bool CDVAPController::setPower()
{
	unsigned int count = 0U;
	unsigned int length;
	RESP_TYPE resp;
	do {
		unsigned char buffer[10U];
		::memcpy(buffer, DVAP_REQ_POWER, DVAP_REQ_POWER_LEN);

		wxInt16 power = wxINT16_SWAP_ON_BE(m_power);
		::memcpy(buffer + 4U, &power, sizeof(wxInt16));

		int ret = m_serial.write(buffer, DVAP_REQ_POWER_LEN);
		if (ret != int(DVAP_REQ_POWER_LEN)) {
			m_serial.close();
			return false;
		}

		::wxMilliSleep(50UL);

		resp = getResponse(m_buffer, length);

		if (resp != RT_POWER) {
			count++;
			if (count >= MAX_RESPONSES) {
				wxLogError(wxT("The DVAP is not responding to the power command"));
				return false;
			}
		}
	} while (resp != RT_POWER);

	return true;
}
bool CDVAPController::setOffset()
{
	unsigned char buffer[10U];

	::memcpy(buffer, DVAP_REQ_OFFSET, DVAP_REQ_OFFSET_LEN);

	wxInt16 offset = wxINT16_SWAP_ON_BE(m_offset);
	::memcpy(buffer + 4U, &offset, sizeof(wxInt16));

	int ret = m_serial.write(buffer, DVAP_REQ_OFFSET_LEN);
	if (ret != int(DVAP_REQ_OFFSET_LEN)) {
		m_serial.close();
		return false;
	}

	unsigned int count = 0U;
	unsigned int length;
	RESP_TYPE resp;
	do {
		::wxMilliSleep(5UL);

		resp = getResponse(m_buffer, length);

		if (resp != RT_OFFSET) {
			count++;
			if (count >= MAX_RESPONSES) {
				wxLogError(wxT("The DVAP is not responding to the offset command"));
				return false;
			}
		}
	} while (resp != RT_OFFSET);

	return true;
}
Пример #7
0
bool MusBinOutput::WritePage( const MusPage *page )
{
	int j;

    if ( !WriteSeparator() )
		return false;
	int32 = wxINT32_SWAP_ON_BE( page->npage );
	Write( &int32, 4 );
	int16 = wxINT16_SWAP_ON_BE( page->nbrePortees );
	Write( &int16, 2 );
    Write( &page->noMasqueFixe, 1 );    
	Write( &page->noMasqueVar, 1 );
	Write( &page->reserve, 1 );
	Write( &page->defin, 1 );
	int32 = wxINT32_SWAP_ON_BE( page->indent );
	Write( &int32, 4 );
	int32 = wxINT32_SWAP_ON_BE( page->indentDroite );
	Write( &int32, 4 );
	int32 = wxINT32_SWAP_ON_BE( page->lrg_lign );
	Write( &int32, 4 );
	MusStaff *staff = NULL;
    for (j = 0; j < page->nbrePortees; j++) 
	{
		staff = &page->m_staves[j];
		WriteStaff( staff );
    }

	return true;

}
Пример #8
0
void CDVDongleController::encodeIn(const wxFloat32* audio, unsigned int length)
{
	wxASSERT(audio != NULL);
	wxASSERT(length == DSTAR_AUDIO_BLOCK_SIZE);

	unsigned char buffer[DVD_HEADER_LEN + DVD_AUDIO_LENGTH_BYTES];
	unsigned char* p = buffer;

	// First a dummy AMBE packet with parameter information in
	::memcpy(p, DVD_AMBE_HEADER, DVD_HEADER_LEN);
	p += DVD_HEADER_LEN;

	::memcpy(p, DVD_AMBE_ENC_DATA, DVD_AMBE_LENGTH_BYTES);

	m_controller->write(buffer, DVD_HEADER_LEN + DVD_AMBE_LENGTH_BYTES);

	// Then the Audio data to be encoded
	p = buffer;
	::memcpy(p, DVD_AUDIO_HEADER, DVD_HEADER_LEN);
	p += DVD_HEADER_LEN;

	wxInt16* q = (wxInt16*)p;

	for (unsigned int i = 0; i < DSTAR_AUDIO_BLOCK_SIZE; i++) {
		wxInt16 word = wxInt16(audio[i] * 32767.0F);
		*q++ = wxINT16_SWAP_ON_BE(word);
	}

	m_controller->write(buffer, DVD_HEADER_LEN + DVD_AUDIO_LENGTH_BYTES);
}
Пример #9
0
bool MusBinOutput::WriteFileHeader( const MusFileHeader *header )
{
	int32 = wxINT32_SWAP_ON_BE( m_flag );
	Write( &int32, 4 );
	int32 = wxINT32_SWAP_ON_BE( AxApp::s_version_major );
	Write( &int32, 4 );
	int32 = wxINT32_SWAP_ON_BE( AxApp::s_version_minor );
	Write( &int32, 4 );
	int32 = wxINT32_SWAP_ON_BE( AxApp::s_version_revision );
	Write( &int32, 4 );
	uint16 = wxUINT16_SWAP_ON_BE( header->nbpage ); // nbpage
	Write( &uint16, 2 ); 
	uint16 = wxUINT16_SWAP_ON_BE( header->nopage ); // nopage
	Write( &uint16, 2 ); 
	uint16 = wxUINT16_SWAP_ON_BE( header->noligne ); // noligne
	Write( &uint16, 2 ); 
	uint32 = wxUINT32_SWAP_ON_BE( header->xpos ); // xpso
	Write( &uint32, 4 );
	Write( &header->param.orientation, 1 ); // param - orientation
	Write( &header->param.EpLignesPortee, 1 ); // param - epLignesPortee
	Write( &header->param.EpQueueNote, 1 ); // param - epQueueNotes
	Write( &header->param.EpBarreMesure, 1 ); // param - epBarreMesure
	Write( &header->param.EpBarreValeur, 1 ); // param - epBarreValeur
	Write( &header->param.EpBlancBarreValeur, 1 ); // param - epBlancBarreValeur
	int32 = wxINT32_SWAP_ON_BE( header->param.pageFormatHor ); // param - pageFormatHor
	Write( &int32, 4 );
	int32 = wxINT32_SWAP_ON_BE( header->param.pageFormatVer ); // param - pageFormatVer
	Write( &int32, 4 );
	int16 = wxINT16_SWAP_ON_BE( header->param.MargeSOMMET ); // param - margeSommet
	Write( &int16, 2 );
	int16 = wxINT16_SWAP_ON_BE( header->param.MargeGAUCHEIMPAIRE ); // param - margeGaucheImpaire
	Write( &int16, 2 );
	int16 = wxINT16_SWAP_ON_BE( header->param.MargeGAUCHEPAIRE ); // param - margeGauchePaire
	Write( &int16, 2 );
    
	Write( &header->param.rapportPorteesNum, 1 ); // rpPorteesNum
	Write( &header->param.rapportPorteesDen, 1 ); // rpPorteesDen
	Write( &header->param.rapportDiminNum, 1 ); // rpDiminNum
	Write( &header->param.rapportDiminDen, 1 ); // rpDiminDen
	Write( &header->param.hampesCorr, 1 ); // hampesCorr
    
	int32 = wxINT32_SWAP_ON_BE( header->param.notationMode ); // param - pageFormatVer
	Write( &int32, 4 );    
    
	return true;
}
Пример #10
0
bool MusBinOutput::WritePagination( const MusPagination *pagination )
{
	int16 = wxINT16_SWAP_ON_BE( pagination->numeroInitial );
	Write( &int16, 2 );
	Write( &pagination->aussiPremierPage, 1 );
	Write( &pagination->position, 1 );
	Write( &pagination->numeroFonte, 1 );
	Write( &pagination->carStyle, 1 );
	Write( &pagination->taille, 1 );
	Write( &pagination->offsetDuBord, 1 );
	return true;
}
Пример #11
0
bool MusBinInput::ReadPagination( MusPagination *pagination )
{
	Read( &int16, 2 );
	pagination->numeroInitial = wxINT16_SWAP_ON_BE( int16 );
	Read( &pagination->aussiPremierPage, 1 );
	Read( &pagination->position, 1 );
	Read( &pagination->numeroFonte, 1 );
	Read( &pagination->carStyle, 1 );
	Read( &pagination->taille, 1 );
	Read( &pagination->offsetDuBord, 1 );
	return true;
}
Пример #12
0
// -----------------------------------------------------------------------------
// Reads in a doom-format TEXTUREx entry.
// Returns true on success, false otherwise
// -----------------------------------------------------------------------------
bool TextureXList::readTEXTUREXData(ArchiveEntry* texturex, const PatchTable& patch_table, bool add)
{
	// Check entries were actually given
	if (!texturex)
		return false;

	// Clear current textures if needed
	if (!add)
		clear();

	// Update palette
	MainEditor::setGlobalPaletteFromArchive(texturex->parent());

	// Read TEXTUREx

	// Read header
	texturex->seek(0, SEEK_SET);

	// Number of textures
	int32_t n_tex = 0;
	if (!texturex->read(&n_tex, 4))
	{
		Log::error("TEXTUREx entry is corrupt (can't read texture count)");
		return false;
	}
	n_tex = wxINT32_SWAP_ON_BE(n_tex);

	// If it's an empty TEXTUREx entry, stop here
	if (n_tex == 0)
		return true;

	// Texture definition offsets
	vector<int32_t> offsets(n_tex);
	if (!texturex->read(offsets.data(), n_tex * 4))
	{
		Log::error("TEXTUREx entry is corrupt (can't read first offset)");
		return false;
	}

	// Read the first texture definition to try to identify the format
	if (!texturex->seek(wxINT32_SWAP_ON_BE(offsets[0]), SEEK_SET))
	{
		Log::error("TEXTUREx entry is corrupt (can't read first definition)");
		return false;
	}
	// Look at the name field. Is it present or not?
	char tempname[8];
	if (!texturex->read(&tempname, 8))
	{
		Log::error("TEXTUREx entry is corrupt (can't read first name)");
		return false;
	}
	// Let's pretend it is and see what happens.
	txformat_ = Format::Normal;

	// Only the characters A-Z (uppercase), 0-9, and [ ] - _ should be used in texture names.
	for (uint8_t a = 0; a < 8; ++a)
	{
		if (a > 0 && tempname[a] == 0)
			// We found a null-terminator for the string, so we can assume it's okay.
			break;
		if (tempname[a] >= 'a' && tempname[a] <= 'z')
		{
			txformat_ = Format::Jaguar;
			// Log::info(1, "Jaguar texture");
			break;
		}
		else if (!((tempname[a] >= 'A' && tempname[a] <= '[') || (tempname[a] >= '0' && tempname[a] <= '9')
				   || tempname[a] == ']' || tempname[a] == '-' || tempname[a] == '_'))
		// We're out of character range, so this is probably not a texture name.
		{
			txformat_ = Format::Nameless;
			// Log::info(1, "Nameless texture");
			break;
		}
	}

	// Now let's see if it is the abridged Strife format or not.
	if (txformat_ == Format::Normal)
	{
		// No need to test this again since it was already tested before.
		texturex->seek(offsets[0], SEEK_SET);
		FullTexDef temp;
		if (!texturex->read(&temp, 22))
		{
			Log::error("TEXTUREx entry is corrupt (can't test definition)");
			return false;
		}
		// Test condition adapted from ZDoom; apparently the first two bytes of columndir
		// may be set to garbage values by some editors and are therefore unreliable.
		if (wxINT16_SWAP_ON_BE(temp.patchcount <= 0) || (temp.columndir[1] != 0))
			txformat_ = Format::Strife11;
	}

	// Read all texture definitions
	for (int32_t a = 0; a < n_tex; a++)
	{
		// Skip to texture definition
		if (!texturex->seek(offsets[a], SEEK_SET))
		{
			Log::error("TEXTUREx entry is corrupt (can't find definition)");
			return false;
		}

		// Read definition
		TexDef tdef;
		if (txformat_ == Format::Nameless)
		{
			NamelessTexDef nameless;
			// Auto-naming mechanism taken from DeuTex
			if (a > 99999)
			{
				Log::error("More than 100000 nameless textures");
				return false;
			}
			char temp[9] = "";
			sprintf(temp, "TEX%05d", a);
			memcpy(tdef.name, temp, 8);

			// Read texture info
			if (!texturex->read(&nameless, 8))
			{
				Log::error("TEXTUREx entry is corrupt (can't read nameless definition #{})", a);
				return false;
			}

			// Copy data to permanent structure
			tdef.flags    = nameless.flags;
			tdef.scale[0] = nameless.scale[0];
			tdef.scale[1] = nameless.scale[1];
			tdef.width    = nameless.width;
			tdef.height   = nameless.height;
		}
		else if (!texturex->read(&tdef, 16))
		{
			Log::error("TEXTUREx entry is corrupt, (can't read texture definition #{})", a);
			return false;
		}

		// Skip unused
		if (txformat_ != Format::Strife11)
		{
			if (!texturex->seek(4, SEEK_CUR))
			{
				Log::error("TEXTUREx entry is corrupt (can't skip dummy data past #{})", a);
				return false;
			}
		}

		// Create texture
		tdef.cleanupName();
		auto tex      = std::make_unique<CTexture>();
		tex->name_    = StrUtil::viewFromChars(tdef.name, 8);
		tex->size_.x  = wxINT16_SWAP_ON_BE(tdef.width);
		tex->size_.y  = wxINT16_SWAP_ON_BE(tdef.height);
		tex->scale_.x = tdef.scale[0] / 8.0;
		tex->scale_.y = tdef.scale[1] / 8.0;

		// Set flags
		if (tdef.flags & Flags::WorldPanning)
			tex->world_panning_ = true;

		// Read patches
		int16_t n_patches = 0;
		if (!texturex->read(&n_patches, 2))
		{
			Log::error("TEXTUREx entry is corrupt (can't read patchcount #{})", a);
			return false;
		}

		// Log::info(1, "Texture #{}: {} patch%s", a, n_patches, n_patches == 1 ? "" : "es");

		for (uint16_t p = 0; p < n_patches; p++)
		{
			// Read patch definition
			Patch pdef;
			if (!texturex->read(&pdef, 6))
			{
				Log::error("TEXTUREx entry is corrupt (can't read patch definition #{}:{})", a, p);
				Log::error("Lump size {}, offset {}", texturex->size(), texturex->currentPos());
				return false;
			}

			// Skip unused
			if (txformat_ != Format::Strife11)
			{
				if (!texturex->seek(4, SEEK_CUR))
				{
					Log::error("TEXTUREx entry is corrupt (can't skip dummy data past #{}:{})", a, p);
					return false;
				}
			}


			// Add it to the texture
			std::string patch;
			if (txformat_ == Format::Jaguar)
			{
				patch = StrUtil::upper(tex->name_);
			}
			else
			{
				patch = patch_table.patchName(pdef.patch);
			}
			if (patch.empty())
			{
				// Log::info(1, "Warning: Texture %s contains patch %d which is invalid - may be incorrect PNAMES
				// entry", tex->getName(), pdef.patch);
				patch = fmt::format("INVPATCH{:04d}", pdef.patch);
			}

			tex->addPatch(patch, pdef.left, pdef.top);
		}

		// Add texture to list
		addTexture(std::move(tex));
	}

	return true;
}
Пример #13
0
/* DatArchive::open
 * Reads wad format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool DatArchive::open(MemChunk& mc)
{
	// Check data was given
	if (!mc.hasData())
		return false;

	const uint8_t* mcdata = mc.getData();

	// Read dat header
	mc.seek(0, SEEK_SET);
	uint16_t num_lumps;
	uint32_t dir_offset, unknown;
	mc.read(&num_lumps, 2);		// Size
	mc.read(&dir_offset, 4);	// Directory offset
	mc.read(&unknown, 4);		// Unknown value
	num_lumps	= wxINT16_SWAP_ON_BE(num_lumps);
	dir_offset	= wxINT32_SWAP_ON_BE(dir_offset);
	unknown		= wxINT32_SWAP_ON_BE(unknown);
	string lastname(wxString::FromAscii("-noname-"));
	size_t namecount = 0;

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	// Read the directory
	mc.seek(dir_offset, SEEK_SET);
	theSplashWindow->setProgressMessage("Reading dat archive data");
	for (uint32_t d = 0; d < num_lumps; d++)
	{
		// Update splash window progress
		theSplashWindow->setProgress(((float)d / (float)num_lumps));

		// Read lump info
		uint32_t offset = 0;
		uint32_t size = 0;
		uint16_t nameofs = 0;
		uint16_t flags = 0;

		mc.read(&offset,	4);		// Offset
		mc.read(&size,		4);		// Size
		mc.read(&nameofs,	2);		// Name offset
		mc.read(&flags,		2);		// Flags (only one: RLE encoded)

		// Byteswap values for big endian if needed
		offset = wxINT32_SWAP_ON_BE(offset);
		size = wxINT32_SWAP_ON_BE(size);
		nameofs = wxINT16_SWAP_ON_BE(nameofs);
		flags = wxINT16_SWAP_ON_BE(flags);

		// If the lump data goes past the directory,
		// the data file is invalid
		if (offset + size > mc.getSize())
		{
			wxLogMessage("DatArchive::open: Dat archive is invalid or corrupt at entry %i", d);
			Global::error = "Archive is invalid and/or corrupt";
			setMuted(false);
			return false;
		}

		string myname;
		if (nameofs != 0)
		{
			size_t len = 1;
			size_t start = nameofs+dir_offset;
			for (size_t i = start; mcdata[i] != 0; ++i) { ++len; }
			lastname = myname = wxString::FromAscii(mcdata+start, len);
			namecount = 0;
		}
		else
		{
			myname = S_FMT("%s+%d", lastname, ++namecount);
		}

		// Create & setup lump
		ArchiveEntry* nlump = new ArchiveEntry(myname, size);
		nlump->setLoaded(false);
		nlump->exProp("Offset") = (int)offset;
		nlump->setState(0);

		if (flags & 1) nlump->setEncryption(ENC_SCRLE0);

		// Check for markers
		if (!nlump->getName().Cmp("startflats"))
			flats[0] = d;
		if (!nlump->getName().Cmp("endflats"))
			flats[1] = d;
		if (!nlump->getName().Cmp("startsprites"))
			sprites[0] = d;
		if (!nlump->getName().Cmp("endmonsters"))
			sprites[1] = d;
		if (!nlump->getName().Cmp("startwalls"))
			walls[0] = d;
		if (!nlump->getName().Cmp("endwalls"))
			walls[1] = d;

		// Add to entry list
		getRoot()->addEntry(nlump);
	}

	// Detect all entry types
	MemChunk edata;
	theSplashWindow->setProgressMessage("Detecting entry types");
	for (size_t a = 0; a < numEntries(); a++)
	{
		// Update splash window progress
		theSplashWindow->setProgress((((float)a / (float)num_lumps)));

		// Get entry
		ArchiveEntry* entry = getEntry(a);

		// Read entry data if it isn't zero-sized
		if (entry->getSize() > 0)
		{
			// Read the entry data
			mc.exportMemChunk(edata, getEntryOffset(entry), entry->getSize());
			entry->importMemChunk(edata);
		}

		// Detect entry type
		EntryType::detectEntryType(entry);

		// Set entry to unchanged
		entry->setState(0);
	}

	// Detect maps (will detect map entry types)
	//theSplashWindow->setProgressMessage("Detecting maps");
	//detectMaps();

	// Setup variables
	setMuted(false);
	setModified(false);
	announce("opened");

	theSplashWindow->setProgressMessage("");

	return true;
}
Пример #14
0
/* DatArchive::isDatArchive
 * Checks if the file at [filename] is a valid Shadowcaster dat archive
 *******************************************************************/
bool DatArchive::isDatArchive(string filename)
{
	// Open file for reading
	wxFile file(filename);

	// Check it opened ok
	if (!file.IsOpened())
		return false;

	// Read dat header
	file.Seek(0, wxFromStart);
	uint16_t num_lumps;
	uint32_t dir_offset, junk;
	file.Read(&num_lumps, 2);	// Size
	file.Read(&dir_offset, 4);	// Directory offset
	file.Read(&junk, 4);		// Unknown value
	num_lumps	= wxINT16_SWAP_ON_BE(num_lumps);
	dir_offset	= wxINT32_SWAP_ON_BE(dir_offset);
	junk		= wxINT32_SWAP_ON_BE(junk);

	if (dir_offset >= file.Length())
		return false;

	// Read the directory
	file.Seek(dir_offset, wxFromStart);
	// Read lump info
	uint32_t offset = 0;
	uint32_t size = 0;
	uint16_t nameofs = 0;
	uint16_t flags = 0;

	file.Read(&offset,	4);		// Offset
	file.Read(&size,	4);		// Size
	file.Read(&nameofs,	2);		// Name offset
	file.Read(&flags,	2);		// Flags

	// Byteswap values for big endian if needed
	offset	= wxINT32_SWAP_ON_BE(offset);
	size	= wxINT32_SWAP_ON_BE(size);
	nameofs = wxINT16_SWAP_ON_BE(nameofs);
	flags	= wxINT16_SWAP_ON_BE(flags);

	// The first lump should have a name (subsequent lumps need not have one).
	// Also, sanity check the values.
	if (nameofs == 0 || nameofs >=  file.Length() || offset + size >= file.Length())
	{
		return false;
	}

	string name;
	size_t len = 1;
	size_t start = nameofs+dir_offset;
	// Sanity checks again. Make sure there is actually a name.
	if (start > file.Length())
		return false;
	uint8_t temp;
	file.Seek(start, wxFromStart);
	file.Read(&temp, 1);
	if (temp < 33)
		return false;
	for (size_t i = start; i < file.Length(); ++i, ++len)
	{
		file.Read(&temp, 1);
		// Found end of name
		if (temp == 0)
			break;
		// Names should not contain garbage characters
		if (temp < 32 || temp > 126)
			return false;
	}
	// Let's be reasonable here. While names aren't limited, if it's too long, it's suspicious.
	if (len > 60)
		return false;
	return true;
}
Пример #15
0
/* DatArchive::write
 * Writes the dat archive to a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool DatArchive::write(MemChunk& mc, bool update)
{
	// Only two bytes are used for storing entry amount,
	// so abort for excessively large files:
	if (numEntries() > 65535)
		return false;

	// Determine directory offset, name offsets & individual lump offsets
	uint32_t dir_offset = 10;
	uint16_t name_offset = numEntries() * 12;
	uint32_t name_size = 0;
	string previousname = "";
	uint16_t* nameoffsets = new uint16_t[numEntries()];
	ArchiveEntry* entry = NULL;
	for (uint16_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		setEntryOffset(entry, dir_offset);
		dir_offset += entry->getSize();

		// Does the entry has a name?
		string name = entry->getName();
		if (l > 0 && previousname.length() > 0 && name.length() > previousname.length() &&
		        !previousname.compare(0, previousname.length(), name, 0, previousname.length()) &&
		        name.at(previousname.length()) == '+')
		{
			// This is a fake name
			name = "";
			nameoffsets[l] = 0;
		}
		else
		{
			// This is a true name
			previousname = name;
			nameoffsets[l] = uint16_t(name_offset + name_size);
			name_size += name.length() + 1;
		}
	}

	// Clear/init MemChunk
	mc.clear();
	mc.seek(0, SEEK_SET);
	mc.reSize(dir_offset + name_size + numEntries() * 12);

	// Write the header
	uint16_t num_lumps = wxINT16_SWAP_ON_BE(numEntries());
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);
	uint32_t unknown = 0;
	mc.write(&num_lumps, 2);
	mc.write(&dir_offset, 4);
	mc.write(&unknown, 4);

	// Write the lumps
	for (uint16_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		mc.write(entry->getData(), entry->getSize());
	}

	// Write the directory
	for (uint16_t l = 0; l < num_lumps; l++)
	{
		entry = getEntry(l);

		uint32_t offset = wxINT32_SWAP_ON_BE(getEntryOffset(entry));
		uint32_t size = wxINT32_SWAP_ON_BE(entry->getSize());
		uint16_t nameofs = wxINT16_SWAP_ON_BE(nameoffsets[l]);
		uint16_t flags = wxINT16_SWAP_ON_BE((entry->isEncrypted() == ENC_SCRLE0) ? 1 : 0);

		mc.write(&offset,	4);		// Offset
		mc.write(&size,		4);		// Size
		mc.write(&nameofs,	2);		// Name offset
		mc.write(&flags,	2);		// Flags

		if (update)
		{
			entry->setState(0);
			entry->exProp("Offset") = (int)wxINT32_SWAP_ON_BE(offset);
		}
	}

	// Write the names
	for (uint16_t l = 0; l < num_lumps; l++)
	{
		uint8_t zero = 0;
		entry = getEntry(l);
		if (nameoffsets[l])
		{
			mc.write(CHR(entry->getName()), entry->getName().length());
			mc.write(&zero, 1);
		}
	}

	// Clean-up
	delete[] nameoffsets;

	// Finished!
	return true;
}
Пример #16
0
/* TextureXList::readTEXTUREXData
 * Reads in a doom-format TEXTUREx entry. Returns true on success,
 * false otherwise
 *******************************************************************/
bool TextureXList::readTEXTUREXData(ArchiveEntry* texturex, PatchTable& patch_table, bool add) {
	// Check entries were actually given
	if (!texturex)
		return false;

	// Clear current textures if needed
	if (!add) clear();

	// Update palette
	theMainWindow->getPaletteChooser()->setGlobalFromArchive(texturex->getParent());

	// Read TEXTUREx

	// Read header
	texturex->seek(0, SEEK_SET);
	int32_t		n_tex = 0;
	int32_t*	offsets = NULL;

	// Number of textures
	if (!texturex->read(&n_tex, 4)) {
		wxLogMessage("Error: TEXTUREx entry is corrupt (can't read texture count)");
		return false;
	}
	n_tex = wxINT32_SWAP_ON_BE(n_tex);

	// If it's an empty TEXTUREx entry, stop here
	if (n_tex == 0)
		return true;

	// Texture definition offsets
	offsets = new int32_t[n_tex];
	if (!texturex->read(offsets, n_tex * 4)) {
		wxLogMessage("Error: TEXTUREx entry is corrupt (can't read first offset)");
		return false;
	}

	// Read the first texture definition to try to identify the format
	if (!texturex->seek(wxINT32_SWAP_ON_BE(offsets[0]), SEEK_SET)) {
		wxLogMessage("Error: TEXTUREx entry is corrupt (can't read first definition)");
		return false;
	}
	// Look at the name field. Is it present or not?
	char tempname[8];
	if (!texturex->read(&tempname, 8)) {
		wxLogMessage("Error: TEXTUREx entry is corrupt (can't read first name)");
		return false;
	}
	// Let's pretend it is and see what happens.
	txformat = TXF_NORMAL;

	// Only the characters A-Z (uppercase), 0-9, and [ ] - _ should be used in texture names.
	for (uint8_t a = 0; a < 8; ++a) {
		if (a > 0 && tempname[a] == 0)
			// We found a null-terminator for the string, so we can assume it's okay.
			break;
		if (tempname[a] >= 'a' && tempname[a] <= 'z') {
			txformat = TXF_JAGUAR;
			//wxLogMessage("Jaguar texture");
			break;
		}
		else if (!((tempname[a] >= 'A' && tempname[a] <= '[') ||
			  (tempname[a] >= '0' && tempname[a] <= '9') ||
			   tempname[a] == ']' || tempname[a] == '-' || tempname[a] == '_'))
			// We're out of character range, so this is probably not a texture name.
		{
			txformat = TXF_NAMELESS;
			//wxLogMessage("Nameless texture");
			break;
		}
	}

	// Now let's see if it is the abridged Strife format or not.
	if (txformat == TXF_NORMAL) {
		// No need to test this again since it was already tested before.
		texturex->seek(offsets[0], SEEK_SET);
		ftdef_t temp;
		if (!texturex->read(&temp, 22)) {
			wxLogMessage("Error: TEXTUREx entry is corrupt (can't test definition)");
			return false;
		}
		// Test condition adapted from ZDoom; apparently the first two bytes of columndir
		// may be set to garbage values by some editors and are therefore unreliable.
		if (wxINT16_SWAP_ON_BE(temp.patchcount <= 0) || (temp.columndir[1] != 0))
			txformat = TXF_STRIFE11;
	}

	// Read all texture definitions
	for (int32_t a = 0; a < n_tex; a++) {
		// Skip to texture definition
		if (!texturex->seek(offsets[a], SEEK_SET)) {
			wxLogMessage("Error: TEXTUREx entry is corrupt (can't find definition)");
			return false;
		}

		// Read definition
		tdef_t tdef;
		if (txformat == TXF_NAMELESS) {
			nltdef_t nameless;
			// Auto-naming mechanism taken from DeuTex
			if (a > 99999) {
				wxLogMessage("Error: More than 100000 nameless textures");
				return false;
			}
			char temp[9] = "";
			sprintf (temp, "TEX%05d", a);
			memcpy(tdef.name, temp, 8);

			// Read texture info
			if (!texturex->read(&nameless, 8)) {
				wxLogMessage("Error: TEXTUREx entry is corrupt (can't read nameless definition #%d)", a);
				return false;
			}

			// Copy data to permanent structure
			tdef.flags = nameless.flags;
			tdef.scale[0] = nameless.scale[0];
			tdef.scale[1] = nameless.scale[1];
			tdef.width = nameless.width;
			tdef.height = nameless.height;
		}
		else if (!texturex->read(&tdef, 16)) {
			wxLogMessage("Error: TEXTUREx entry is corrupt, (can't read texture definition #%d)", a);
			return false;
		}

		// Skip unused
		if (txformat != TXF_STRIFE11) {
			if (!texturex->seek(4, SEEK_CUR)) {
				wxLogMessage("Error: TEXTUREx entry is corrupt (can't skip dummy data past #%d)", a);
				return false;
			}
		}

		// Create texture
		CTexture* tex = new CTexture();
		tex->name = wxString::FromAscii(tdef.name, 8);
		tex->width = wxINT16_SWAP_ON_BE(tdef.width);
		tex->height = wxINT16_SWAP_ON_BE(tdef.height);
		tex->scale_x = tdef.scale[0]/8.0;
		tex->scale_y = tdef.scale[1]/8.0;

		// Set flags
		if (tdef.flags & TX_WORLDPANNING)
			tex->world_panning = true;

		// Read patches
		int16_t n_patches = 0;
		if (!texturex->read(&n_patches, 2)) {
			wxLogMessage("Error: TEXTUREx entry is corrupt (can't read patchcount #%d)", a);
			return false;
		}

		//wxLogMessage("Texture #%d: %d patch%s", a, n_patches, n_patches == 1 ? "" : "es");

		for (uint16_t p = 0; p < n_patches; p++) {
			// Read patch definition
			tx_patch_t pdef;
			if (!texturex->read(&pdef, 6)) {
				wxLogMessage("Error: TEXTUREx entry is corrupt (can't read patch definition #%d:%d)", a, p);
				wxLogMessage("Lump size %d, offset %d", texturex->getSize(), texturex->currentPos());
				return false;
			}

			// Skip unused
			if (txformat != TXF_STRIFE11) {
				if (!texturex->seek(4, SEEK_CUR)) {
					wxLogMessage("Error: TEXTUREx entry is corrupt (can't skip dummy data past #%d:%d)", a, p);
					return false;
				}
			}


			// Add it to the texture
			string patch;
			if (txformat == TXF_JAGUAR) {
				patch = tex->name.Upper();
			} else {
				patch = patch_table.patchName(pdef.patch);
			}
			if (patch.IsEmpty()) {
				//wxLogMessage("Warning: Texture %s contains patch %d which is invalid - may be incorrect PNAMES entry", CHR(tex->getName()), pdef.patch);
				patch = S_FMT("INVPATCH%04d", pdef.patch);
			}

			tex->addPatch(patch, pdef.left, pdef.top);
		}

		// Add texture to list
		addTexture(tex);
	}

	// Clean up
	delete[] offsets;

	return true;
}
Пример #17
0
/* EntryOperations::setGfxOffsets
 * Changes the offsets of the given gfx entry. Returns false if the
 * entry is invalid or not an offset-supported format, true otherwise
 *******************************************************************/
bool EntryOperations::setGfxOffsets(ArchiveEntry* entry, int x, int y)
{
	if (entry == NULL || entry->getType() == NULL)
		return false;

	// Check entry type
	EntryType* type = entry->getType();
	string entryformat = type->getFormat();
	if (!(entryformat == "img_doom" || entryformat == "img_doom_arah" ||
		entryformat == "img_doom_alpha" || entryformat == "img_doom_beta" ||
		entryformat == "img_png"))
	{
		wxLogMessage("Entry \"%s\" is of type \"%s\" which does not support offsets", entry->getName(), entry->getType()->getName());
		return false;
	}

	// Doom gfx format, normal and beta version.
	// Also arah format from alpha 0.2 because it uses the same header format.
	if (entryformat == "img_doom" || entryformat == "img_doom_beta" || entryformat == "image_doom_arah")
	{
		// Get patch header
		patch_header_t header;
		entry->seek(0, SEEK_SET);
		entry->read(&header, 8);

		// Apply new offsets
		header.left = wxINT16_SWAP_ON_BE((int16_t)x);
		header.top = wxINT16_SWAP_ON_BE((int16_t)y);

		// Write new header to entry
		entry->seek(0, SEEK_SET);
		entry->write(&header, 8);
	}

	// Doom alpha gfx format
	else if (entryformat == "img_doom_alpha")
	{
		// Get patch header
		entry->seek(0, SEEK_SET);
		oldpatch_header_t header;
		entry->read(&header, 4);

		// Apply new offsets
		header.left = (int8_t)x;
		header.top = (int8_t)y;

		// Write new header to entry
		entry->seek(0, SEEK_SET);
		entry->write(&header, 4);
	}

	// PNG format
	else if (entryformat == "img_png")
	{
		// Find existing grAb chunk
		const uint8_t* data = entry->getData(true);
		uint32_t grab_start = 0;
		for (uint32_t a = 0; a < entry->getSize(); a++)
		{
			// Check for 'grAb' header
			if (data[a] == 'g' && data[a + 1] == 'r' &&
				data[a + 2] == 'A' && data[a + 3] == 'b')
			{
				grab_start = a - 4;
				break;
			}

			// Stop when we get to the 'IDAT' chunk
			if (data[a] == 'I' && data[a + 1] == 'D' &&
				data[a + 2] == 'A' && data[a + 3] == 'T')
				break;
		}

		// Create new grAb chunk
		uint32_t csize = wxUINT32_SWAP_ON_LE(8);
		grab_chunk_t gc ={ { 'g', 'r', 'A', 'b' }, wxINT32_SWAP_ON_LE(x), wxINT32_SWAP_ON_LE(y) };
		uint32_t dcrc = wxUINT32_SWAP_ON_LE(Misc::crc((uint8_t*)&gc, 12));

		// Build new PNG from the original w/ the new grAb chunk
		MemChunk npng;
		uint32_t rest_start = 33;

		// Init new png data size
		if (grab_start == 0)
			npng.reSize(entry->getSize() + 20);
		else
			npng.reSize(entry->getSize());

		// Write PNG header and IHDR chunk
		npng.write(data, 33);

		// If no existing grAb chunk was found, write new one here
		if (grab_start == 0)
		{
			npng.write(&csize, 4);
			npng.write(&gc, 12);
			npng.write(&dcrc, 4);
		}
		else
		{
			// Otherwise write any other data before the existing grAb chunk
			uint32_t to_write = grab_start - 33;
			npng.write(data + 33, to_write);
			rest_start = grab_start + 20;

			// And now write the new grAb chunk
			npng.write(&csize, 4);
			npng.write(&gc, 12);
			npng.write(&dcrc, 4);
		}

		// Write the rest of the PNG data
		uint32_t to_write = entry->getSize() - rest_start;
		npng.write(data + rest_start, to_write);

		// Load new png data to the entry
		entry->importMemChunk(npng);

		// Set its type back to png
		entry->setType(type);
	}
	else
		return false;

	return true;
}
Пример #18
0
void Extract(bool bits16,
             bool sign,
             bool stereo,
             bool bigendian,
             bool offset,
             char *rawData, int dataSize,
             float *data1, float *data2, int *len1, int *len2)
{
   int rawCount = 0;
   int dataCount1 = 0;
   int dataCount2 = 0;
   int i;

   *len1 = 0;
   *len2 = 0;

   if (offset && bits16) {
      /* Special case so as to not flip stereo channels during analysis */
      if (stereo && !bigendian) {
         rawData += 3;
         dataSize -= 3;
      }
      else {
         rawData++;
         dataSize--;
      }
   }

   if (bits16) {
      if (sign && bigendian)
         while (rawCount + 1 < dataSize) {
            /* 16-bit signed BE */
            data1[dataCount1] =
               (wxINT16_SWAP_ON_LE(*((signed short *)
                                     &rawData[rawCount])))
               / 32768.0;
            dataCount1++;
            rawCount += 2;
         }
      if (!sign && bigendian)
         while (rawCount + 1 < dataSize) {
            /* 16-bit unsigned BE */
            data1[dataCount1] =
               (wxUINT16_SWAP_ON_LE(*((unsigned short *)
                                      &rawData[rawCount])))
               / 32768.0 - 1.0;
            dataCount1++;
            rawCount += 2;
         }
      if (sign && !bigendian)
         while (rawCount + 1 < dataSize) {
            /* 16-bit signed LE */
            data1[dataCount1] =
               (wxINT16_SWAP_ON_BE(*((signed short *)
                                     &rawData[rawCount])))
               / 32768.0;
            dataCount1++;
            rawCount += 2;
         }
      if (!sign && !bigendian)
         while (rawCount + 1 < dataSize) {
            /* 16-bit unsigned LE */
            data1[dataCount1] =
               (wxUINT16_SWAP_ON_BE(*((unsigned short *)
                                      &rawData[rawCount])))
               / 32768.0 - 1.0;
            dataCount1++;
            rawCount += 2;
         }
   }
   else {
      /* 8-bit */
      if (sign) {
         while (rawCount < dataSize) {
            /* 8-bit signed */
            data1[dataCount1++] =
               (*(signed char *) (&rawData[rawCount++])) / 128.0;
         }
      }
      else {
         while (rawCount < dataSize) {
            /* 8-bit unsigned */
            data1[dataCount1++] =
               (*(unsigned char *) &rawData[rawCount++]) / 128.0 - 1.0;
         }
      }
   }

   if (stereo) {
      dataCount1 /= 2;
      for(i=0; i<dataCount1; i++) {
         data2[i] = data1[2*i+1];
         data1[i] = data1[2*i];
      }
      dataCount2 = dataCount1;
   }

   *len1 = dataCount1;
   *len2 = dataCount2;
}
Пример #19
0
bool ExportCL(AudacityProject *project, bool stereo, wxString fName,
              bool selectionOnly, double t0, double t1)
{
   int rate = int(project->GetRate() + 0.5);
   wxWindow *parent = project;
   TrackList *tracks = project->GetTracks();
   
   wxString command = gPrefs->Read("/FileFormats/ExternalProgramExportCommand", "lame - '%f'");
   command.Replace("%f", fName);

   /* establish parameters */
   int channels = stereo ? 2 : 1;
   unsigned long totalSamples = (unsigned long)((t1 - t0) * rate + 0.5);
   unsigned long sampleBytes = totalSamples * channels * SAMPLE_SIZE(int16Sample);
   double timeStep = 10.0;      // write in blocks of 10 secs

   /* fill up the wav header */
   wav_header header;
   header.riffID[0] = 'R';
   header.riffID[1] = 'I';
   header.riffID[2] = 'F';
   header.riffID[3] = 'F';
   header.riffType[0] = 'W';
   header.riffType[1] = 'A';
   header.riffType[2] = 'V';
   header.riffType[3] = 'E';
   header.lenAfterRiff = sampleBytes + 32;

   header.fmtID[0]  = 'f';
   header.fmtID[1]  = 'm';
   header.fmtID[2]  = 't';
   header.fmtID[3]  = ' ';
   header.formatChunkLen = 16;
   header.formatTag      = 1;
   header.channels       = channels;
   header.sampleRate     = rate;
   header.bitsPerSample  = SAMPLE_SIZE(int16Sample) * 8;
   header.blockAlign     = header.bitsPerSample * header.channels;
   header.avgBytesPerSec = header.sampleRate * header.blockAlign;

   header.dataID[0] = 'd';
   header.dataID[1] = 'a';
   header.dataID[2] = 't';
   header.dataID[3] = 'a';
   header.dataLen   = sampleBytes;

   FILE *pipe = popen(command.c_str(), "w");

   /* write the header */

   fwrite( &header, sizeof(wav_header), 1, pipe );

   //sampleCount maxSamples = int (timeStep * rate + 0.5);

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;
   bool cancelling = false;

   double t = t0;

   while (t < t1 && !cancelling) {

      double deltat = timeStep;
      if (t + deltat > t1)
         deltat = t1 - t;

      sampleCount numSamples = int (deltat * rate + 0.5);

      Mixer *mixer = new Mixer(channels, numSamples, true, rate, int16Sample);
      wxASSERT(mixer);
      mixer->Clear();

      char *buffer = new char[numSamples * SAMPLE_SIZE(int16Sample) * channels];
      wxASSERT(buffer);

      TrackListIterator iter(tracks);
      VTrack *tr = iter.First();
      while (tr) {
         if (tr->GetKind() == VTrack::Wave) {
            if (tr->GetSelected() || !selectionOnly) {
               if (tr->GetChannel() == VTrack::MonoChannel)
                  mixer->MixMono((WaveTrack *) tr, t, t + deltat);
               if (tr->GetChannel() == VTrack::LeftChannel)
                  mixer->MixLeft((WaveTrack *) tr, t, t + deltat);
               if (tr->GetChannel() == VTrack::RightChannel)
                  mixer->MixRight((WaveTrack *) tr, t, t + deltat);
            }
         }
         tr = iter.Next();
      }

      samplePtr mixed = mixer->GetBuffer();

      // Byte-swapping is neccesary on big-endian machines, since
      // WAV files are little-endian
#if wxBYTE_ORDER == wxBIG_ENDIAN
      {
         short *buffer = (short*)mixed;
         for( int i = 0; i < numSamples; i++ )
            buffer[i] = wxINT16_SWAP_ON_BE(buffer[i]);
      }
#endif

      fwrite( mixed, numSamples * channels * SAMPLE_SIZE(int16Sample), 1, pipe );

      t += deltat;

      if (!progress && wxGetElapsedTime(false) > 500) {

         wxString message;

         if (selectionOnly)
            message = "Exporting the selected audio using command-line encoder";
         else
            message = "Exporting the entire project using command-line encoder";

         progress =
             new wxProgressDialog("Export",
                                  message,
                                  1000,
                                  parent,
                                  wxPD_CAN_ABORT |
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }
      if (progress) {
         cancelling =
             !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5));
      }

      delete mixer;
      delete[]buffer;
   }

   pclose( pipe );

   if(progress)
      delete progress;
   return true;
}
Пример #20
0
bool ExportCL(AudacityProject *project, bool stereo, wxString fName,
              bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec)
{
   int rate = int(project->GetRate() + 0.5);
   wxWindow *parent = project;
   TrackList *tracks = project->GetTracks();
   
   wxString command = gPrefs->Read(wxT("/FileFormats/ExternalProgramExportCommand"), wxT("lame - '%f'"));
   command.Replace(wxT("%f"), fName);

   /* establish parameters */
   int channels = stereo ? 2 : 1;
   unsigned long totalSamples = (unsigned long)((t1 - t0) * rate + 0.5);
   unsigned long sampleBytes = totalSamples * channels * SAMPLE_SIZE(int16Sample);

   /* fill up the wav header */
   wav_header header;
   header.riffID[0] = 'R';
   header.riffID[1] = 'I';
   header.riffID[2] = 'F';
   header.riffID[3] = 'F';
   header.riffType[0] = 'W';
   header.riffType[1] = 'A';
   header.riffType[2] = 'V';
   header.riffType[3] = 'E';
   header.lenAfterRiff = sampleBytes + 32;

   header.fmtID[0]  = 'f';
   header.fmtID[1]  = 'm';
   header.fmtID[2]  = 't';
   header.fmtID[3]  = ' ';
   header.formatChunkLen = 16;
   header.formatTag      = 1;
   header.channels       = channels;
   header.sampleRate     = rate;
   header.bitsPerSample  = SAMPLE_SIZE(int16Sample) * 8;
   header.blockAlign     = header.bitsPerSample * header.channels;
   header.avgBytesPerSec = header.sampleRate * header.blockAlign;

   header.dataID[0] = 'd';
   header.dataID[1] = 'a';
   header.dataID[2] = 't';
   header.dataID[3] = 'a';
   header.dataLen   = sampleBytes;

   FILE *pipe = popen(OSFILENAME(command), "w");

   /* write the header */

   fwrite( &header, sizeof(wav_header), 1, pipe );

   sampleCount maxBlockLen = 44100 * 5;

   bool cancelling = false;

   int numWaveTracks;
   WaveTrack **waveTracks;
   tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
   Mixer *mixer = new Mixer(numWaveTracks, waveTracks,
                            tracks->GetTimeTrack(),
                            t0, t1,
                            channels, maxBlockLen, true,
                            rate, int16Sample, true, mixerSpec);

   GetActiveProject()->ProgressShow(_("Export"),
      selectionOnly ?
      _("Exporting the selected audio using command-line encoder") :
      _("Exporting the entire project using command-line encoder"));

   while(!cancelling) {
      sampleCount numSamples = mixer->Process(maxBlockLen);

      if (numSamples == 0)
         break;
      
      samplePtr mixed = mixer->GetBuffer();

      char *buffer = new char[numSamples * SAMPLE_SIZE(int16Sample) * channels];
      wxASSERT(buffer);

      // Byte-swapping is neccesary on big-endian machines, since
      // WAV files are little-endian
#if wxBYTE_ORDER == wxBIG_ENDIAN
      {
         short *buffer = (short*)mixed;
         for( int i = 0; i < numSamples; i++ )
            buffer[i] = wxINT16_SWAP_ON_BE(buffer[i]);
      }
#endif

      fwrite( mixed, numSamples * channels * SAMPLE_SIZE(int16Sample), 1, pipe );

      int progressvalue = int (1000 * ((mixer->MixGetCurrentTime()-t0) /
                                       (t1-t0)));
      cancelling = !GetActiveProject()->ProgressUpdate(progressvalue);

      delete[]buffer;
   }
   GetActiveProject()->ProgressHide();

   delete mixer;

   pclose( pipe );

   return true;
}