public int atracDecodeData(int atracID, int address, int channels) { int samples = 0; boolean isEnded = false; if (checkMediaEngineState()) { if (me.getContainer() == null && atracChannel != null) { if (requireAllAtracData) { if (atracChannel.length() >= atracFileSize) { requireAllAtracData = false; if (checkMediaEngineState() && ExternalDecoder.isEnabled()) { String decodedFile = externalDecoder.decodeAtrac( atracChannel, atracBufferAddress, atracFileSize, atracHash); if (decodedFile != null) { Modules.log.info( "AT3+ data decoded by the external decoder (all AT3+ data retrieved)."); me.finish(); atracChannel = null; me.init(new FileProtocolHandler(decodedFile), false, true, 0, 0); atracEndSample = -1; } else { Modules.log.info( "AT3+ data could not be decoded by the external decoder, even after retrieving all AT3+ data."); me = null; } } else { Modules.log.info( "AT3+ data could not be decoded by the external decoder, even after retrieving all AT3+ data."); me = null; } if (me == null) { return atracDecodeData(atracID, address, channels); } } else { // Fake returning 1 sample with remainFrames == 0 // to force a call to sceAtracAddStreamData. samples = 1; Memory.getInstance().memset(address, (byte) 0, samples * bytesPerSample); } } else if (atracChannel.length() >= getAtracChannelStartLength() || atracChannel.length() >= atracFileSize) { me.init(atracChannel, false, true, 0, 0); } else { // Fake returning 1 sample with remainFrames == 0 // to force a call to sceAtracAddStreamData. samples = 1; Memory.getInstance().memset(address, (byte) 0, samples * bytesPerSample); } } setChannels(channels); if (me.stepAudio(atracMaxSamples * bytesPerSample, channels)) { samples = copySamplesToMem(address); } if (samples == 0) { isEnded = true; } } else if (decodedStream != null) { try { int length = decodedStream.read(atracDecodeBuffer); if (length > 0) { samples = length / 4; Memory.getInstance() .copyToMemory(address, ByteBuffer.wrap(atracDecodeBuffer, 0, length), length); long restLength = decodedStream.length() - decodedStream.getFilePointer(); if (restLength <= 0) { isEnded = true; } } else { isEnded = true; } } catch (IOException e) { Modules.log.warn(e); } } else { samples = -1; isEnded = true; } if (isEnded) { atracEnd = 1; } else { atracEnd = 0; } return samples; }
public void atracSetData( int atracID, int codecType, int address, int length, int atracFileSize, int atracHash) { this.atracFileSize = atracFileSize; this.atracBufferAddress = address; this.atracHash = atracHash; id = generateID(address, length, atracFileSize); closeStreams(); atracEndSample = -1; requireAllAtracData = false; int memoryCodecType = sceAtrac3plus.getCodecType(address); if (memoryCodecType != codecType && memoryCodecType != 0) { Modules.log.info( String.format( "Different CodecType received %d != %d, assuming %d", codecType, memoryCodecType, memoryCodecType)); codecType = memoryCodecType; } if (codecType == 0x00001001) { Modules.log.info("Decodable AT3 data detected."); if (checkMediaEngineState()) { me.finish(); atracChannel = new PacketChannel(); atracChannel.setTotalStreamSize(atracFileSize); atracChannel.setFarRewindAllowed(true); atracChannel.write(address, length); // Defer the initialization of the MediaEngine until atracDecodeData() // to ensure we have enough data into the channel. atracEndSample = 0; return; } } else if (codecType == 0x00001000) { if (checkMediaEngineState() && ExternalDecoder.isEnabled()) { String decodedFile = externalDecoder.decodeAtrac(address, length, atracFileSize, atracHash, this); if (decodedFile != null) { Modules.log.info("AT3+ data decoded by the external decoder."); me.finish(); atracChannel = null; me.init(new FileProtocolHandler(decodedFile), false, true, 0, 0); atracEndSample = -1; return; } else if (requireAllAtracData) { // The external decoder requires all the atrac data // before it can try to decode the atrac. me.finish(); atracChannel = new PacketChannel(); atracChannel.setTotalStreamSize(atracFileSize); atracChannel.write(address, length); return; } Modules.log.info("AT3+ data could not be decoded by the external decoder."); } else { Modules.log.info("Undecodable AT3+ data detected."); } } me = null; File decodedFile = new File(getCompleteFileName(decodedAtracSuffix)); if (!decodedFile.canRead()) { // Try to read the decoded file using an alternate file name, // without HashCode. These files can be generated by external tools // decoding the Atrac3+ files. These tools can't generate the HashCode. // // Use the following alternate file name scheme: // Atrac-SSSSSSSS-NNNNNNNN-DDDDDDDD.at3.decoded // where SSSSSSSS is the file size in Hex // NNNNNNNN is the number of samples in Hex found in the "fact" Chunk // DDDDDDDD are the first 32-bit in Hex found in the "data" Chunk int numberOfSamples = 0; int data = 0; // Scan the Atrac data for NNNNNNNN and DDDDDDDD values Memory mem = Memory.getInstance(); int scanAddress = address + 12; int endScanAddress = address + length; while (scanAddress < endScanAddress) { int chunkHeader = mem.read32(scanAddress); int chunkSize = mem.read32(scanAddress + 4); if (chunkHeader == waveFactChunkHeader) { numberOfSamples = mem.read32(scanAddress + 8); } else if (chunkHeader == waveDataChunkHeader) { data = mem.read32(scanAddress + 8); break; } // Go to the next Chunk scanAddress += chunkSize + 8; } File alternateDecodedFile = new File( String.format( "%sAtrac-%08X-%08X-%08X%s", getBaseDirectory(), atracFileSize, numberOfSamples, data, decodedAtracSuffix)); if (alternateDecodedFile.canRead()) { decodedFile = alternateDecodedFile; } } File atracFile = new File(getCompleteFileName(atracSuffix)); if (decodedFile.canRead()) { try { decodedStream = new RandomAccessFile(decodedFile, "r"); atracEndSample = (int) (decodedFile.length() / 4); } catch (FileNotFoundException e) { // Decoded file should already be present Modules.log.warn(e); } } else if (atracFile.canRead() && atracFile.length() == atracFileSize) { // Atrac file is already written, no need to write it again } else if (sceAtrac3plus.isEnableConnector()) { commandFileDirty = true; displayInstructions(); new File(getBaseDirectory()).mkdirs(); try { atracStream = new FileOutputStream(getCompleteFileName(atracSuffix)); byte[] buffer = new byte[length]; IMemoryReader memoryReader = MemoryReader.getMemoryReader(address, length, 1); for (int i = 0; i < length; i++) { buffer[i] = (byte) memoryReader.readNext(); } atracStream.write(buffer); } catch (IOException e) { Modules.log.warn(e); } generateCommandFile(); } }