hallo, ich möchte mal in die cdt2wav von java oder windows reinschauen

Started by funkheld, 15:33, 26 October 10

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

funkheld

hallo , kann man mal in den sourcecoce reinschauen von dem exe- oder java-code von:
cdt2wav.

ich kann den ursprung-source nicht finden.
ich möchte gerne mal wissen wie dort die bytes als wav erzeugt werden.

danke.

gruss

Devilmarkus

JavaCPC benötigt dazu 3 Klassen:
package jemu.core.device.tape;

import jemu.core.Util;
/**
* Title:        JavaCPC
* Description:  The Java Amstrad CPC Emulator
* Copyright:    Copyright (c) 2006-2010
* Company:
* @author
* @version 6.8
*/
/**
* CDT2WAV conversion utilities
* Converted from "TZX to WAV Converter v0.2 (C) 2006 Francisco Javier Crespo <tzx2wav@ya.com>"
*
* @author John Girvin
*
*/
public class CDT2WAV {

    //
    // CONSTANTS
    //

    // Header magic number bytes of ZXTAPE format file
    private static byte[] ZXTAPE_HEADER = new byte[]{0x5A, 0x58, 0x54, 0x61, 0x70, 0x65, 0x21};

    //
    // INSTANCE VARIABLES
    //
    protected boolean debug = false;
    private byte[] inpbuf;
    private int frequency = 44100;
    private CDT2WAVBaseOutput output;
    private int currentBlock;       // Current block that is playing
    private int numBlocks;          // Total Num. of blocks
    private int blockStart[];        // Array of block start positions
    public String ids[];              // Array for all IDs
    public int blocks[];              // Array for all IDs
    private int id;                 // Current Block ID
    private int data;                // Data to be played
    private int datalen;            // Len of ^^^
    private int datapos;            // Position in ^^^
    private int bitcount;           // How many bits to play in current byte ?
    private int sb_bit;             // should we play bit 0 or 1 ?
    private byte databyte;          // Current Byte to be replayed of the data
    private int pilot;              // Len of Pilot signal (in hp's)
    private int sb_pilot;           // Pilot pulse
    private int sb_sync1;           // Sync first half-period (hp)
    private int sb_sync2;           // Sync second
    private int sb_bit0;            // Bit-0
    private int sb_bit1;            // Bit-1
    private int sb_pulse;           // Pulse in Sequence of pulses and direct recording block
    private int lastbyte;           // How many bits are in last byte of data ?
    private int pause;              // Pause after current block (in milliseconds)
    private int singlepulse;        // Flag to activate single pulse waves
    private short jump;              // Relative Jump
    private int loop_start = 0;       // Position of the last Loop Start block
    private int loop_count = 0;       // Counter of the Loop
    private int call_pos = 0;         // Position of the last Call Sequence block
    private int call_num = 0;         // Number of Calls in the last Call Sequence block
    private int call_cur = 0;         // Current Call to be made

    /*
    private int cpc=0;              // Amstrad CPC tape ?
     */
    /**
     * Create an object to convert ZXTAPE/CDT data to WAV format.
     *
     * @param input - the input data
     * @param output - buffer to hold the WAV data. Supply null for test mode.
     * @param freq - desired frequency in Hz for the WAV data
     */
    public CDT2WAV(byte[] input, int freq) {
        super();
        inpbuf = input;
        frequency = freq;
    }

    /**
     * Dereference any allocated resources. Do not call this object again
     * after calling dispose().
     */
    public void dispose() {
        inpbuf = null;
        blockStart = null;

        if (output != null) {
            output.dispose();
        }
        output = null;
    }

    //
    // TZX Blocks Parsing routines
    //
    // ...Standard Loading Data block
    private void analyseID10() {
        pause = get2(inpbuf, data);
        datalen = get2(inpbuf, data + 2);
        data += 4;
        if (inpbuf[data] == 0x00) {
            pilot = 8064;
        } else {
            pilot = 3220;
        }
        sb_pilot = output.samples(2168);
        sb_sync1 = output.samples(667);
        sb_sync2 = output.samples(735);
        sb_bit0 = output.samples(885);
        sb_bit1 = output.samples(1710);
        lastbyte = 8;
    }

    // ...Custom Loading Data block
    private void analyseID11() {
        sb_pilot = output.samples(get2(inpbuf, data + 0));
        sb_sync1 = output.samples(get2(inpbuf, data + 2));
        sb_sync2 = output.samples(get2(inpbuf, data + 4));
        sb_bit0 = output.samples(get2(inpbuf, data + 6));
        sb_bit1 = output.samples(get2(inpbuf, data + 8));
        pilot = get2(inpbuf, data + 10);
        lastbyte = (int) inpbuf[data + 12];
        pause = get2(inpbuf, data + 13);
        datalen = get3(inpbuf, data + 15);
        data += 18;
        if (debug) {
            System.out.println("Pilot is: " + pilot + " pause is: " + pause + " Length is: " + datalen);
        }
    }

    // ...Pure Tone
    private void analyseID12() {
        sb_pilot = output.samples(get2(inpbuf, data + 0));
        pilot = get2(inpbuf, data + 2);
        while (pilot > 0) {
            output.play(sb_pilot);
            output.toggleAmp();
            pilot--;
        }
    }

    // ...Sequence of Pulses
    private void analyseID13() {
        pilot = (int) inpbuf[data + 0];
        data++;
        while (pilot > 0) {
            sb_pulse = output.samples(get2(inpbuf, data + 0));
            output.play(sb_pulse);
            output.toggleAmp();
            pilot--;
            data += 2;
        }
    }

    // ...Pure Data
    private void analyseID14() {
        sb_pilot = pilot = sb_sync1 = sb_sync2 = 0;
        sb_bit0 = output.samples(get2(inpbuf, data + 0));
        sb_bit1 = output.samples(get2(inpbuf, data + 2));
        lastbyte = (int) inpbuf[data + 4];
        pause = get2(inpbuf, data + 5);
        datalen = get3(inpbuf, data + 7);
        data += 10;
    }

    // ...Direct Recording
    private void analyseID15() {
        // For now the BEST way is to use the sample frequency for replay that is
        // exactly the SAME as the Original Freq. used when sampling this block !
        // i.e. NO downsampling is handled YET ... use TAPER when you need it ! ;-)

        sb_pulse = output.samples(get2(inpbuf, data + 0));
        if (sb_pulse == 0) {
            sb_pulse = 1;           // In case sample frequency > 44100
        }
        pause = get2(inpbuf, data + 2);                // (Should work for frequencies up to 48000)
        lastbyte = (int) inpbuf[data + 4];
        datalen = get3(inpbuf, data + 5);

        data = data + 8;
        datapos = 0;
        // Replay Direct Recording block ...
        while (datalen > 0) {
            if (datalen != 1) {
                bitcount = 8;
            } else {
                bitcount = lastbyte;
            }
            databyte = inpbuf[data + datapos];
            while (bitcount > 0) {
                output.setAmp((databyte & 0x80) != 0);
                output.play(sb_pulse);
                databyte <<= 1;
                bitcount--;
            }
            datalen--;
            datapos++;
        }
        output.toggleAmp(); // Changed on 26-01-2005
        if (pause != 0) {
            output.pause(pause);
        }
    }

    // ...Pause or Stop the Tape
    private void analyseID20() {
        pause = get2(inpbuf, data + 0);
        output.setAmpNo();
        if (debug) {
            System.out.println("Pause is " + pause);
        }
        if (pause != 0) {
            output.pause(pause);
        } else {
            output.pause(5000); // 5 seconds of pause in "Stop Tape" wave output
            System.out.println("Pause is added: 5 secs");
        }
        output.setAmpLow();
    }

    // ...Group Start
    private void analyseID21() {
        // do nothing
    }

    // ...Group End
    private void analyseID22() {
        // do nothing
    }

    // ...Jump To Relative
    private void analyseID23() {
        jump = (short) (inpbuf[data + 0] + inpbuf[data + 1] * 256);
        currentBlock += jump;
        currentBlock--;
    }

    // ...Loop Start
    private void analyseID24() {
        loop_start = currentBlock;
        loop_count = get2(inpbuf, data + 0);
    }

    // ...Loop End
    private void analyseID25() {
        loop_count--;
        if (loop_count > 0) {
            currentBlock = loop_start;
        }
    }

    // ...Call Sequence
    private void analyseID26() {
        call_pos = currentBlock;
        call_num = get2(inpbuf, data + 0);
        call_cur = 0;
        jump = (short) (inpbuf[data + 2] + inpbuf[data + 3] * 256);
        currentBlock += jump;
        currentBlock--;
    }

    // ...Return from Sequence
    private void analyseID27() {
        call_cur++;
        if (call_cur == call_num) {
            currentBlock = call_pos;
        } else {
            currentBlock = call_pos;
            data = blockStart[currentBlock] + 1;
            jump = (short) (inpbuf[data + call_cur * 2 + 2] + inpbuf[data + call_cur * 2 + 3] * 256);
            currentBlock += jump;
            currentBlock--;
        }
    }

    // ...Stop the tape if in 48k mode
    private void analyseID2A() {
        output.pause(5000);
        output.setAmpLow();
    }

    // ...Hardware Info
    private void analyseID33() {
        /*
        if (inpbuf[data+1]==0 && inpbuf[data+2]>0x14 && inpbuf[data+2]<0x1a && inpbuf[data+3]==1) {
        cpc=1;
        }
         */
    }

    //
    // UTILITY METHODS
    //
    // Conversion routines to fetch bytes in Big Endian order
    private static int get2(byte[] data, int pos) {
        return (data[pos] & 0xff | ((data[pos + 1] << 8) & 0xff00));
    }

    private static int get3(byte[] data, int pos) {
        return (data[pos] & 0xff | (data[pos + 1] << 8) & 0xff00 | (data[pos + 2] << 16) & 0xff0000);
    }

    private static int get4(byte[] data, int pos) {
        return (data[pos] & 0xff | (data[pos + 1] << 8) & 0xff00 | (data[pos + 2] << 16) & 0xff0000 | (data[pos + 3] << 24) & 0xff000000);
    }

    /**
     * Count and optionally store the start positions of TZX blocks
     * in the input[] data array
     *
     * @param blockstarts - array to be filled in with block start positions
     * or null if this is not required.
     *
     * @return number of blocks found, or -1 if an unknown block was encountered
     */
    private int countBlocks(int[] blockstarts) {
        // Go through the file and record block starts
        int pos = 10;
        int numblocks = 0;

        while (pos < inpbuf.length) {
            if (blockstarts != null) {
                blockstarts[numblocks] = pos;
            }
            pos++;

            switch (inpbuf[pos - 1]) {
                case 0x10:
                    pos += get2(inpbuf, pos + 0x02) + 0x04;
                    break;
                case 0x11:
                    pos += get3(inpbuf, pos + 0x0F) + 0x12;
                    break;
                case 0x12:
                    pos += 0x04;
                    break;
                case 0x13:
                    pos += (inpbuf[pos + 0x00] * 0x02) + 0x01;
                    break;
                case 0x14:
                    pos += get3(inpbuf, pos + 0x07) + 0x0A;
                    break;
                case 0x15:
                    pos += get3(inpbuf, pos + 0x05) + 0x08;
                    break;
                case 0x16:
                    pos += get4(inpbuf, pos + 0x00) + 0x04;
                    break;
                case 0x17:
                    pos += get4(inpbuf, pos + 0x00) + 0x04;
                    break;

                case 0x20:
                    pos += 0x02;
                    break;
                case 0x21:
                    pos += inpbuf[pos + 0x00] + 0x01;
                    break;
                case 0x22:
                    break;
                case 0x23:
                    pos += 0x02;
                    break;
                case 0x24:
                    pos += 0x02;
                    break;
                case 0x25:
                    break;
                case 0x26:
                    pos += get2(inpbuf, pos + 0x00) * 0x02 + 0x02;
                    break;
                case 0x27:
                    break;
                case 0x28:
                    pos += get2(inpbuf, pos + 0x00) + 0x02;
                    break;
                case 0x2A:
                    pos += 0x04;
                    break;

                case 0x30:
                    pos += inpbuf[pos + 0x00] + 0x01;
                    break;
                case 0x31:
                    pos += inpbuf[pos + 0x01] + 0x02;
                    break;
                case 0x32:
                    pos += get2(inpbuf, pos + 0x00) + 0x02;
                    break;
                case 0x33:
                    pos += (inpbuf[pos + 0x00] * 0x03) + 0x01;
                    break;
                case 0x34:
                    pos += 0x08;
                    break;
                case 0x35:
                    pos += get4(inpbuf, pos + 0x10) + 0x14;
                    break;

                case 0x40:
                    pos += get3(inpbuf, pos + 0x01) + 0x04;
                    break;

                case 0x5A:
                    pos += 0x09;
                    break;

                default:
                    return -1;
            }

            numblocks++;
        }

        return numblocks;
    }

    /**
     * Run a pass of the conversion process, sending data to the supplied
     * output manager object.
     *
     * @param output - the output manager
     */
    private void convertPass(CDT2WAVBaseOutput output) {
        // Initialise
        currentBlock = 0;
        singlepulse = 0;

        // disable debug mode if this is a test run
        if (output == null) {
            debug = false;
        }

        // Start replay of blocks (Main loop of the program)
        while (currentBlock < numBlocks) {
            // Get ID of next block and start position in input byte array
            id = inpbuf[blockStart[currentBlock]];
            blocks[currentBlock] = output.outputTell();
            ids[currentBlock] = getID(id);
            if (debug) {
                System.out.println("Block: " + getBlock(currentBlock) + " - ID: " + getID(currentBlock));
            }
            if (debug) {
                System.out.println("ID is " + Util.hex(id));
            }
            data = blockStart[currentBlock] + 1;

            switch (id) {
                case 0x10:
                    analyseID10(); // Standard Loading Data block
                    break;
                case 0x11:
                    analyseID11(); // Custom Loading Data block
                    break;
                case 0x12:
                    analyseID12(); // Pure Tone
                    break;
                case 0x13:
                    analyseID13(); // Sequence of Pulses
                    break;
                case 0x14:
                    analyseID14(); // Pure Data
                    break;
                case 0x15:
                    analyseID15(); // Direct Recording
                    break;
                case 0x20:
                    analyseID20(); // Pause or Stop the Tape command
                    break;
                case 0x21:
                    analyseID21(); // Group Start
                    break;
                case 0x22:
                    analyseID22(); // Group End
                    break;
                case 0x23:
                    analyseID23(); // Jump To Relative
                    break;
                case 0x24:
                    analyseID24(); // Loop Start
                    break;
                case 0x25:
                    analyseID25(); // Loop End
                    break;
                case 0x26:
                    analyseID26(); // Call Sequence
                    break;
                case 0x27:
                    analyseID27(); // Return from Sequence
                    break;
                case 0x2A:
                    analyseID2A(); // Stop the tape if in 48k mode
                    break;
                case 0x33:
                    analyseID33(); // Hardware Info
                    break;

                // Ignored
                case 0x30: // Description
                case 0x31: // Message
                case 0x32: // Archive Info
                case 0x34: // Emulation info
                case 0x35: // Custom Info
                case 0x40: // Snapshot
                case 0x5A: // ZXTape!
                    break;

                // Unknown/Unsupported blocks
                case 0x16: // C64 ROM Type Data Block
                case 0x17: // C64 Turbo Tape Data Block
                case 0x28: // Select Block
                default: {
                    System.out.println("ERR_TZX_UNSUPPORTED");
                    break;
                }
            }

            // TZX file blocks analysis finished
            // Now we start generating the sound waves

            if (id == 0x10 || id == 0x11 || id == 0x14) {
                // One of the data blocks ...

                // Play PILOT TONE
                while (pilot > 0) {
                    output.play(sb_pilot);
                    output.toggleAmp();
                    pilot--;
                }

                // Play first SYNC pulse
                if (sb_sync1 > 0) {
                    output.play(sb_sync1);
                    output.toggleAmp();
                }

                // Play second SYNC pulse
                if (sb_sync2 > 0) {
                    output.play(sb_sync2);
                    output.toggleAmp();
                }

                // Play actual DATA
                datapos = 0;
                while (datalen > 0) {
                    if (datalen != 1) {
                        bitcount = 8;
                    } else {
                        bitcount = lastbyte;
                    }

                    databyte = inpbuf[data + datapos];

                    while (bitcount > 0) {
                        if ((databyte & 0x80) != 0) {
                            sb_bit = sb_bit1;
                        } else {
                            sb_bit = sb_bit0;
                        }
                        output.play(sb_bit); // Play first pulse of the bit
                        output.toggleAmp();
                        if (singlepulse == 0) {
                            output.play(sb_bit); // Play second pulse of the bit
                            output.toggleAmp();
                        }
                        databyte <<= 1;
                        bitcount--;
                    }
                    datalen--;
                    datapos++;
                }
                singlepulse = 0;   // Reset flag for next TZX blocks

                // If there is pause after block present then make first millisecond the oposite
                // pulse of last pulse played and the rest in LOAMP ... otherwise don't do ANY pause
                if (pause > 0) {
                    output.pause(1);
                    output.setAmpNo();
                    if (pause > 1) {
                        output.pause(pause - 1);
                    }
                }
            }

            // We continue to replay the next TZX block
            currentBlock++;
        }

        // 5 seconds of pause in "Stop Tape" wave output
        output.pause(5000);
        if (debug) {
            System.out.println("End of tape... 5 seconds pause added");
        }

        output.stop();

        if (debug) {
            System.out.println(" OK");
        }
    }

    /**
     * MAIN CONVERSION ENTRY POINT
     *
     * @return array of data bytes generated, or null on error
     */
    public byte[] convert() {
        // Sanity checks
        // ...check input and output
        if (inpbuf == null || inpbuf.length < 10) {
            System.out.println("ERR_ILLEGAL_ARGUMENT");
            return null;
        }

        // ...check for TZX header
        for (int i = 0; i < ZXTAPE_HEADER.length; i++) {
            if (inpbuf[i] != ZXTAPE_HEADER[i]) {
                System.out.println("ERR_NOT_TZX");
                return null;
            }
        }

        // ...check TZX version is supported
        int cdt_major = inpbuf[8];
        if (cdt_major == 0) {
            System.out.println("ERR_TZX_UNSUPPORTED");
            return null;
        }

        // Count blocks
        currentBlock = 0;
        numBlocks = countBlocks(null);
        if (numBlocks < 0) {
            System.out.println("ERR_TZX_UNSUPPORTED");
            return null;
        }

        // Store the start positions of all blocks
        blockStart = new int[numBlocks];
        ids = new String[numBlocks + 1];
        blocks = new int[numBlocks + 1];
        countBlocks(blockStart);

        // Initialise WAV format output manager, initially in test mode
        // @note: if you ever need to support a different output format,
        // create a new CDT2WAVxyzOutput class and switch it in here.
        output = new CDT2WAVWAVOutput(frequency);

        // Run first pass in test mode to determine data length
        debug = false;
        convertPass(output);

        // If the first pass succeeded, allocate an output buffer
        // of the correct length to hold the output data
        int dataLength = output.outputTell();
        byte[] data = null;
        if (dataLength > 0) {
            // Run second pass to generate data and store in output buffer
            data = new byte[dataLength];
            output.setOutputBuffer(data);
            convertPass(output);
        }

        // Return data buffer
        return data;
    }

    public int getBlock(int id) {
        if (blocks != null) {
            return blocks[id];
        }
        return 0;
    }

    public String getID(int id) {
        String ret = null;
        {
            switch (id) {
                case 0x10:
                    ret = "Turbo data II";
                    break;
                case 0x11:
                    ret = "Turbo data";
                    break;
                case 0x12:
                    ret = "Pure tone";
                    break;
                case 0x13:
                    ret = "Sequence of pulses";
                    break;
                case 0x14:
                    ret = "Pure Data";
                    break;
                case 0x15:
                    ret = "Direct recording";
                    break;
                case 0x20:
                    ret = "Pause";
                    break;
                case 0x21:
                    ret = "Group Start";
                    break;
                case 0x22:
                    ret = "Group End";
                    break;
                case 0x23:
                    ret = "Jump relative";
                    break;
                case 0x24:
                    ret = "Loop Start";
                    break;
                case 0x25:
                    ret = "Loop End";
                    break;
                case 0x26:
                    ret = "Call Sequence";
                    break;
                case 0x27:
                    ret = "Return from Sequence";
                    break;
                case 0x2A:
                    ret = "Stop tape";
                    break;
                case 0x33:
                    ret = "Hardware Info";
                    break;
                default:
                    ret = "Unknown block";
            }
        }
        return ret;
    }
}


Die hauptsächliche Klasse, welche die Impulse erzeugt.
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Devilmarkus

Die beiden anderen Klassen:
package jemu.core.device.tape;
/**
* Title:        JavaCPC
* Description:  The Java Amstrad CPC Emulator
* Copyright:    Copyright (c) 2006-2010
* Company:
* @author
* @version 6.8
*/
/**
* Generic wave data output manager
* Converted from "TZX to WAV Converter v0.2 (C) 2006 Francisco Javier Crespo <tzx2wav@ya.com>"
*
* @author John Girvin
*
*/
public abstract class CDT2WAVBaseOutput {

    //
    // CONSTANTS
    //
    private static final int LOAMP = 0x26;              // Low Level Amplitude  (-3 dB)
    private static final int HIAMP = 0xDA;              // High Level Amplitude (-3 dB)
    private static final int NOAMP = 0x80;              // Silent Amplitude

    //
    // INSTANCE VARIABLES
    //
    private double z80_freq = 3500000.0; // Z80 frequency in Hz
    private byte[] buf = null;            // output buffer
    private int bufPos = 0;
    private double frequency = 44100.0;    // wave data frequency
    private double cycle = 0.0;        // Z80 cycles per wave sample
    private int amp = LOAMP;            // current amplitude

    /**
     * Create an output manager in "test mode", where no output data
     * is generated but all other processing is the same.
     *
     * @param freq - frequency of output data to pretend-generate
     */
    public CDT2WAVBaseOutput(int freq) {
        super();

        this.buf = null;
        this.bufPos = 0;
        this.frequency = freq;
        /*    if (freq == 44100) {
        z80_freq = 3400000.0;
        } else if (freq == 22050) {
        z80_freq = 3494400.0;
        }*/
        this.cycle = frequency / z80_freq;

        init();
    }

    /**
     * Dereference any allocated resources. Do not call this object again
     * after calling dispose().
     */
    public void dispose() {
        buf = null;
    }

    //
    // Concrete implementation interface
    //
    protected abstract void init();

    protected abstract void write(int numsamples);

    protected abstract void stop();

    /**
     * Get the sample frequency to use when generating output
     *
     * @return frequency in Hz
     */
    protected double getFrequency() {
        return frequency;
    }

    /**
     * Set the current position in the output buffer.
     *
     * @return buffer position
     */
    protected void outputSeek(int pos) {
        bufPos = pos;
    }

    /**
     * Return the current position in the output buffer.
     * This is valid even if the output manager is in "test" mode.
     *
     * @return buffer position
     */
    protected int outputTell() {
        return bufPos;
    }

    /**
     * Write a byte to the output buffer
     *
     * @param b - the byte to write
     */
    protected final void outputByte(byte b) {
        if (buf != null) {
            buf[bufPos] = b;
        }
        bufPos++;
    }

    /**
     * Write bytes to the output buffer
     *
     * @param b - the byte to write
     * @param count - number of times to write the byte
     */
    protected final void outputByte(byte b, int count) {
        if (buf != null) {
            int p = bufPos;
            for (int i = 0; i < count; i++) {
                buf[p++] = b;
            }
        }
        bufPos += count;
    }

    //
    // PUBLIC INTERFACE
    //
    /**
     * Reset the output buffer. If the supplied buffer is null, the
     * output manager will operate in test mode.
     *
     * @param buf - output buffer
     */
    public void setOutputBuffer(byte[] buf) {
        this.buf = buf;
        this.bufPos = 0;
    }

    /**
     * Convert a sampling value in Z80 T-States to number of samples for wave output
     *
     * @param tstates - number of Z80 T-States
     * @return Number of wave samples at current frequency
     */
    public int samples(int tstates) {
        return ((int) (0.5 + (cycle * (double) tstates)));
    }

    /**
     * Sets the sign of the wave
     *
     * @param high - true to set the wave to high amplitude
     */
    public void setAmp(boolean high) {
        amp = (high ? HIAMP : LOAMP);
    }

    /**
     * Sets the sign of the wave to LO
     */
    public void setAmpLow() {
        amp = LOAMP;
    }

    /**
     * Sets the sign of the wave to Silent
     */
    public void setAmpNo() {
        amp = NOAMP;
    }

    /**
     * Toggles the sign of the wave
     * TODO: WHOLE CONCEPT TO BE RECODED IN ToggleSgn();
     */
    public void toggleAmp() {
        if (isLowAmp()) {
            amp = HIAMP;
        } else {
            amp = LOAMP;
        }
    }

    /**
     * Is the wave sign currently low amplitude?
     *
     * @return boolean - true iff the wave sign currently low amplitude
     */
    protected boolean isLowAmp() {
        return (amp == LOAMP);
    }

    /**
     * Is the wave sign currently silent amplitude?
     *
     * @return boolean - true iff the wave sign currently silent amplitude
     */
    protected boolean isNoAmp() {
        return (amp == NOAMP);
    }

    /**
     * Generate wave data for "len" samples.
     *
     * @param numsamples
     */
    public void play(int numsamples) {
        write(numsamples);
    }

    /**
     * Waits for a number of milliseconds
     *
     * @param ms - number of milliseconds
     */
    public void pause(int ms) {
        int p;
        //if (curr!=(numblocks-1))
        //{
        p = (int) ((((double) ms) * frequency) / 1000.0);
        play(p);
    //}
    }
}


Und:
package jemu.core.device.tape;
/**
* Title:        JavaCPC
* Description:  The Java Amstrad CPC Emulator
* Copyright:    Copyright (c) 2006-2010
* Company:
* @author
* @version 6.8
*/
/**
* WAV file format output manager
* Converted from "TZX to WAV Converter v0.2 (C) 2006 Francisco Javier Crespo <tzx2wav@ya.com>"
*
* Nice WAV format info in this web site:
* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
*
* @author John Girvin
*
*/
public class CDT2WAVWAVOutput extends CDT2WAVBaseOutput {

    //
    // INSTANCE VARIABLES
    //
    private WAVHeader wavHeader;

    //
    // Inner class to represent WAV file header data
    //
    public class WAVHeader {
        // header data members

        public int ChunkID;
        public int ChunkSize;
        public int Format;
        public int fmtChunkID;
        public int fmtChunkSize;
        public short AudioFormat;
        public short NumChannels;
        public int SampleRate;
        public int ByteRate;
        public short BlockAlign;
        public short BitsPerSample;
        public int Subchunk2ID;
        public int Subchunk2Size;

        /**
         * Write a 32 bit value to the output
         * @param data
         */
        private void writeInt(int data) {
            outputByte((byte) (data & 0xff));
            outputByte((byte) ((data >> 8) & 0xff));
            outputByte((byte) ((data >> 16) & 0xff));
            outputByte((byte) ((data >> 24) & 0xff));
        }

        /**
         * Write a 16 bit value to the output
         * @param data
         */
        private void writeShort(short data) {
            outputByte((byte) (data & 0xff));
            outputByte((byte) ((data >> 8) & 0xff));
        }

        /**
         * Write header content to the output
         */
        public void write() {
            // header goes at start of output
            int oldPos = outputTell();
            outputSeek(0);

            // output the header fields
            writeInt(ChunkID);
            writeInt(ChunkSize);
            writeInt(Format);
            writeInt(fmtChunkID);
            writeInt(fmtChunkSize);
            writeShort(AudioFormat);
            writeShort(NumChannels);
            writeInt(SampleRate);
            writeInt(ByteRate);
            writeShort(BlockAlign);
            writeShort(BitsPerSample);
            writeInt(Subchunk2ID);
            writeInt(Subchunk2Size);

            // reset back to previous position
            outputSeek(oldPos);
        }
    }

    /**
     * @see CDT2WAVBaseOutput
     */
    public CDT2WAVWAVOutput(int freq) {
        super(freq);
    }

    /**
     * @see CDT2WAVBaseOutput.dispose
     */
    public void dispose() {
        super.dispose();
        wavHeader = null;
    }

    /**
     * Prepare for output
     */
    protected void init() {
        // Initialise WAV file header for 8-bit mono output 95 26 CD 00
        wavHeader = new WAVHeader();
        wavHeader.ChunkID = 0x46464952;      // "RIFF" ID
        //wavHeader.ChunkSize = 0xCD2695;
        wavHeader.ChunkSize = 0;
        wavHeader.Format = 0x45564157;       // "WAVE" ID
        wavHeader.fmtChunkID = 0x20746D66;   // "fmt " ID
        wavHeader.fmtChunkSize = 16;
        wavHeader.AudioFormat = 1;           // PCM Linear Quantization
        wavHeader.SampleRate = (int) getFrequency();
        wavHeader.Subchunk2ID = 0x61746164;  // "data" ID
        wavHeader.Subchunk2Size = 0;
        wavHeader.NumChannels = 1;
        wavHeader.BitsPerSample = 8;
        wavHeader.ByteRate = (int) getFrequency();
        wavHeader.BlockAlign = 1;

    // Send WAV header to the output
    // wavHeader.write();
    }

    /**
     * Generate WAV data for "numsamples" samples.
     * @param numsamples
     */
    protected void write(int numsamples) {
        // Update data length in WAV header
        wavHeader.Subchunk2Size = (outputTell() + numsamples) - 44;
        wavHeader.ChunkSize = 36 + wavHeader.Subchunk2Size;

        // Write samples at current amplitude
        byte sample;
        if (isNoAmp()) {
            sample = (byte) 0x80;
        } else {
            sample = (isLowAmp() ? (byte) 0x26 : (byte) 0xDA);
        }
        outputByte(sample, numsamples);
    }

    /**
     * Finalise output.
     */
    protected void stop() {
        // Write updated WAV header to the output
        wavHeader.write();

    // seriously?
    //jemu.system.cpc.CPC.recordcount = bufPos;
    }
}


Ist also eine Menge WirrWarr!
(Übrigens reicht dieser Code alleine nicht zum Kompilieren, da JavaCPC keine direkten WAV erzeugt, sondern in einen internen Buffer schreibt)
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Devilmarkus

Den kompletten!!! Sourcecode von JavaCPC kann man übrigens immer (ziemlich aktuell) hier einsehen:
http://javacpc.svn.sourceforge.net/viewvc/javacpc/JavaCPC/src/jemu/

(jemu/ sind die Emulatorspezifischen Dinge drin, drum hab ich den hier angegeben. Du kannst aber auch noch in unteren Ebenen browsen.)
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

funkheld

hmm..., ich versteht den zusammenhang zwischen der zeit für 1 bit und der frequenz von der wav 44100 nicht, welche als ton zum cpc gesendet wird für eine normale baudübertragung.

1 bit muss ja eine bestimmte länge , bzw bei 44100  oftmal genug gesendet werden, damit der cpc dieses
als 1 bit erkennt.

klär mich hier mal auf mit dem zeitverhalten.

danke.


Devilmarkus

Man reiht einfach genügend "pulse's" zusammen, welche dann irgendwann ein bit ergeben...
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

funkheld

die möchte ich gerne mal wissen, wie das mit dem 44100hz und der baudzahl zb zusammenhängt.
wie oft die pulse zb für 1 bit gesendet werden müssen und wie lang ein pulse ist?

gruss

Devilmarkus

Die CDT-Unterstützung von JavaCPC wurde nicht von mir programmiert, weil ich da genausowenig Ahnung von habe.
(Juhuuuu!!! es gibt tatsächlich nette Menschen, die mir bei JavaCPC helfen)

Ich habe nur die Port-Anbindung und die Playback Routine programmiert (Welche allerdings die WAV verwendet)

Ich schicke eine bestimmte Anzahl von WAV-pulses je CPU cycles. Diese Anzahl variiert je nach Frequenz des WAV.

tape_delay = 1050000 / (freq);

freq beinhalted die Frequenz (44100 z.B.)

Also schaue ich in der CPC-cycle funktion nach und mach in etwa soetwas hier:
tapecount++;
if (tapecount > tape_delay){
       send next WAV byte to Port
}


Der CPC selbst "cycled" 1000000x pro Sekunde.
Ich verwende allerdings für das Delay 1050000 weil Speedlock sonst herummuckt.

Weiter kann ich Dir dazu aber nicht helfen.
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

funkheld

jup, hört sich gut an. danke.

ein frage versuch noch mal zuklären:
die blocks werden ja noch in segmente zu 256 byte aufgeteilt.
am ende vom jedem segment ist ein checksummenbyte von den 256 byte.

wie errechnet sich das  checksummenbyte vom segment?

wenn du das noch rauskriegst, wäre ich dir dankbar.

gruss.

arnoldemu

Quote from: funkheld on 12:01, 27 October 10
jup, hört sich gut an. danke.

ein frage versuch noch mal zuklären:
die blocks werden ja noch in segmente zu 256 byte aufgeteilt.
am ende vom jedem segment ist ein checksummenbyte von den 256 byte.

wie errechnet sich das  checksummenbyte vom segment?

wenn du das noch rauskrigst, wäre ich dir dankbar.

gruss.

http://www.cpctech.org.uk/docs/os.asm

"crc"

http://www.cpctech.org.uk/download/2cdt.zip
Checksum sind ein polynom. Es gibt ein 16-bit Nummer mit 0x0ffff initialisieren .  Verwenden das polynom jeden Byte.


(Checksum is calculated with a polynomial. Checksum initialised to 0x0ffff. Then use polynomial for every byte.
See source in 2cdt and operating system dissassembly).
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource


Devilmarkus

When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

funkheld

es gibt keine doofen fragen, nur unglückliche gestellte fragen... :) .

hmmm..., reine neugierde und ich habe zeit....und macht spass.

ist ja schliesslich ein hobby... :)

bin aber noch nicht so dahinter gestiegen, weil ich java nicht so kenne.

mich würde auch mal das cpm 2.2 auf den cpc464 auf einem tape(cdt) interessieren.
beim kc87 drüben haben die es ja in den achtzigern geschafft, weil sie eben in der disk-technik 120 jahre zurücklagen... :P

ist aber schon ein kunststück.

gruss

arnoldemu

Quote from: funkheld on 18:35, 27 October 10
es gibt keine doofen fragen, nur unglückliche gestellte fragen... :) .

hmmm..., reine neugierde und ich habe zeit....und macht spass.

ist ja schliesslich ein hobby... :)

bin aber noch nicht so dahinter gestiegen, weil ich java nicht so kenne.

mich würde auch mal das cpm 2.2 auf den cpc464 auf einem tape(cdt) interessieren.
beim kc87 drüben haben die es ja in den achtzigern geschafft, weil sie eben in der disk-technik 120 jahre zurücklagen... :P

ist aber schon ein kunststück.

gruss
Der AMSDOS-ROM habe der BIOS Funktions fur cpm 2.2.
Hier is ein unfertig Auflistung:
http://www.cpctech.org.uk/docs/amsdos.asm

Der CPC spezifisch COM-Programm treten das AMSDOS-Funktionen.

Dieses ROM ist intern der CPC6128 und die DDI-1 Disketten-Interface.

So wann du machen ein cpm2.2 fur CPC464 nach Kassetten/tape, du must ein neuer BIOS machen.

Ohne AMSDOS-ROM du habe kleine TPA weil Ihr BIOS-Funktion setzen ins RAM.

(Englisch: "The AMSDOS ROM has the BIOS functions. Here is an incomplete listing. The CPC specific COM programs call into the functions in the AMSDOS ROM. The ROM is inside the CPC6128 and the DDI-1 disk interface. So, if you made a cpm 2.2 for cpc464 on cassette, you must make a new BIOS. Without AMSDOS ROM you have small TPA because you must put your BIOS into RAM".
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Devilmarkus

Ich habe übrigens mal mit den KC Compact ROMs herumgespielt und auch das KCC DOS Rom in JavaCPC eingebaut.
JavaCPC's emulierte Floppy lädt das KCC MicroDos problemlos und man kann damit auch arbeiten!

[youtube=NLJkOUINQ3o]NLJkOUINQ3o[/youtube]
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

funkheld

hallo, habe deine gui für das cdt2 benutzt und habe festgestellt, das die baudrate und die ladeadresse nicht eingestellt werden kann. ansonsten tolle sache.

habe mal eine gui in purebasic für mich erstellt, mit baud und adresse, weil ich  nur noch mit dem ccz80 progge.
die adresse lege ich immer für ein gesamtes tape fest.  man könnte auch noch buttons dran klatschen bei den einzelnen programmen für die startadresse.
wer möchte kann damit auch rumwildern.

hmmm..., mit dem wav erstellen habe ich noch  die schwierigkeiten bei dem timing,
grübel...grübel..., da fehlt mir der zusammenhang zb für 1000baud und 44100hz...

wenn mir das einer mal zeichnerisch erklären kann, mit den ms-zeiten dafür.


Global cdtname.s, speed.s,cdtordner.s,edit_text.s,speed_text.s,adresse.s,adresse_text.s

Dim dateiname.s ( 8 )
Dim satz.s ( 8 )
Dim dummyname.s ( 8 )
Dim satz.s ( 8 )

Define.l Event, EventWindow, EventGadget, EventType, EventMenu

Enumeration
  #Window_0
 
  #Button_0
  #Button_1
 
  #text_0
  #text_1
  #text_2
  #text_3
  #text_4
 
  #editor_0
 
  #String_name
  #String_speed
  #String_adresse
 
  #String_0
  #String_1
  #String_2
  #String_3
  #String_4
  #String_5
  #String_6
  #String_7
 
  #String_00
  #String_11
  #String_22
  #String_33
  #String_44
  #String_55
  #String_66
  #String_77
 
  #Button_r0
  #Button_r1
  #Button_r2
  #Button_r3
  #Button_r4
  #Button_r5
  #Button_r6
  #Button_r7
EndEnumeration

OpenWindow(#Window_0, 400, 150, 600,550, "Window_0", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_MinimizeGadget|#PB_Window_TitleBar)

ButtonGadget(#Button_0, 10,35, 80, 25, "erstelle tape")

TextGadget(#text_0, 120,  20, 50, 20, "tape-name")
TextGadget(#text_1, 270,  20, 200, 20, "tape-speed: 0 / 1 oder baud: 100 - 3000")

StringGadget(#String_name, 120, 35, 140, 20, "")
StringGadget(#String_speed, 270, 35, 80, 20, "1")

TextGadget(#text_2, 120,  105, 100, 20, "startname im tape")
TextGadget(#text_3, 270,  105, 100, 20, "ordner mit name")

TextGadget(#text_4, 120,  60, 70, 20, "load-adresse")
StringGadget(#String_adresse, 120, 75, 80, 20, "")

abstd=60
StringGadget(#String_0, 120, 60+abstd, 140, 20, "")
StringGadget(#String_00, 270, 60+abstd, 200, 20, "")
StringGadget(#String_1, 120, 85+abstd, 140, 20, "")
StringGadget(#String_11, 270, 85+abstd, 200, 20, "")
StringGadget(#String_2, 120, 110+abstd, 140, 20, "")
StringGadget(#String_22, 270,110+abstd, 200, 20, "")
StringGadget(#String_3, 120, 135+abstd, 140, 20, "")
StringGadget(#String_33, 270, 135+abstd, 200, 20, "")
StringGadget(#String_4, 120, 160+abstd, 140, 20, "")
StringGadget(#String_44, 270,160+abstd, 200, 20, "")
StringGadget(#String_5, 120, 185+abstd, 140, 20, "")
StringGadget(#String_55, 270, 185+abstd, 200, 20, "")
StringGadget(#String_6, 120, 210+abstd, 140, 20, "")
StringGadget(#String_66, 270,210+abstd, 200, 20, "")
StringGadget(#String_7, 120, 235+abstd, 140, 20, "")
StringGadget(#String_77, 270, 235+abstd, 200, 20, "")

ButtonGadget(#Button_r0, 480,60+abstd, 20,20, "1")
ButtonGadget(#Button_r1, 480,85+abstd, 20,20, "2")
ButtonGadget(#Button_r2, 480,110+abstd, 20,20, "3")
ButtonGadget(#Button_r3, 480,135+abstd, 20,20, "4")
ButtonGadget(#Button_r4, 480,160+abstd, 20,20, "5")
ButtonGadget(#Button_r5, 480,185+abstd, 20,20, "6")
ButtonGadget(#Button_r6, 480,210+abstd, 20,20, "7")
ButtonGadget(#Button_r7, 480,235+abstd, 20,20, "8")

EditorGadget(#Editor_0, 120, 335, 400,180)

cdtordner="d:\cpc\make-cdt\2cdt"

Repeat
  Event = WaitWindowEvent()
       
  Select Event
    Case #PB_Event_Gadget
      EventGadget = EventGadget()
      EventType = EventType()
     
      If EventGadget = #Button_r0 
        dateiname(0)=OpenFileRequester("Load Bindatei","","Bindatei (*.bin",0)
        SetGadgetText(#String_0,GetFilePart(dateiname(0)))
        SetGadgetText(#String_00,dateiname(0))
      EndIf   
      If EventGadget = #Button_r1 
        dateiname(1)=OpenFileRequester("Load Bindatei","","Bindatei (*.bin",0)
        SetGadgetText(#String_1,GetFilePart(dateiname(1)))
        SetGadgetText(#String_11,dateiname(1))
      EndIf   
      If EventGadget = #Button_r2 
        dateiname(2)=OpenFileRequester("Load Bindatei","","Bindatei (*.bin",0)
        SetGadgetText(#String_2,GetFilePart(dateiname(2)))
        SetGadgetText(#String_22,dateiname(2))
      EndIf 
      If EventGadget = #Button_r3 
        dateiname(3)=OpenFileRequester("Load Bindatei","","Bindatei (*.bin",0)
        SetGadgetText(#String_3,GetFilePart(dateiname(3)))
        SetGadgetText(#String_33,dateiname(3))
      EndIf
      If EventGadget = #Button_r4 
        dateiname(4)=OpenFileRequester("Load Bindatei","","Bindatei (*.bin",0)
        SetGadgetText(#String_4,GetFilePart(dateiname(4)))
        SetGadgetText(#String_44,dateiname(4))
      EndIf   
      If EventGadget = #Button_r5 
        dateiname(5)=OpenFileRequester("Load Bindatei","","Bindatei (*.bin",0)
        SetGadgetText(#String_5,GetFilePart(dateiname(5)))
        SetGadgetText(#String_55,dateiname(5))
      EndIf   
      If EventGadget = #Button_r6 
        dateiname(6)=OpenFileRequester("Load Bindatei","","Bindatei (*.bin",0)
        SetGadgetText(#String_6,GetFilePart(dateiname(6)))
        SetGadgetText(#String_66,dateiname(6))
      EndIf 
      If EventGadget = #Button_r7 
        dateiname(7)=OpenFileRequester("Load Bindatei","","Bindatei (*.bin",0)
        SetGadgetText(#String_7,GetFilePart(dateiname(7)))
        SetGadgetText(#String_77,dateiname(7))
      EndIf
     
      If EventGadget = #Button_0   
        cdtname=GetGadgetText(#String_name)
        speed=GetGadgetText(#String_speed)
        adresse=GetGadgetText(#String_adresse)
        cdtname=cdtname+".cdt"
       
        ClearGadgetItems(#Editor_0)
        edit_text=""
       
        If Val(speed) = 0
          speed_text=" -s" + " "+ "0"
        ElseIf Val(speed) = 1
          speed_text=" -s" + " "+ "1"
        ElseIf Val(speed)> 99 And Val(speed) < 3001
          speed_text=" -b" + " "+ speed
        Else
          edit_text+"speed stimmt nicht"+Chr(10)
          SetGadgetText(#Editor_0, edit_text)
          Goto schluss
        EndIf
       
        If Val(adresse) => 8192
          adresse_text=" -L " + adresse
        Else
          adresse_text=""
        EndIf 
         
        If dateiname(0)
          dummyname(0)=GetGadgetText(#String_0)
          satz(0)= adresse_text + speed_text + " " + "-n -r "+ dummyname(0) + " " + dateiname(0) +" "+ cdtname
          RunProgram(cdtordner,satz(0) ,"",#PB_Program_Hide)
          edit_text+satz(0)+Chr(10)
          SetGadgetText(#Editor_0, edit_text)
        EndIf     
        If dateiname(1)
          Delay(100)
          dummyname(1)=GetGadgetText(#String_1)     
          satz(1)= adresse_text + speed_text + " " + "-r "+ dummyname(1) + " " + dateiname(1) +" "+ cdtname
          RunProgram(cdtordner,satz(1) ,"",#PB_Program_Hide)
          edit_text+satz(1)+Chr(10)
          SetGadgetText(#Editor_0, edit_text)
        EndIf     
        If dateiname(2)
          Delay(100)
          dummyname(2)=GetGadgetText(#String_2)     
          satz(2)= " -m 0 "+ adresse_text + speed_text + " " + "-r "+ dummyname(2) + " " + dateiname(2) +" "+ cdtname
          RunProgram(cdtordner,satz(2) ,"",#PB_Program_Hide)
          edit_text+satz(2)+Chr(10)
          SetGadgetText(#Editor_0, edit_text)
        EndIf       
        If dateiname(3)
          Delay(100)
          dummyname(3)=GetGadgetText(#String_3)     
          satz(3)= " -m 0 "+ adresse_text + speed_text + " " + "-r "+ dummyname(3) + " " + dateiname(3) +" "+ cdtname
          RunProgram(cdtordner,satz(3) ,"",#PB_Program_Hide)
          edit_text+satz(3)+Chr(10)
          SetGadgetText(#Editor_0, edit_text)
        EndIf 
        If dateiname(4)
          Delay(100)
          dummyname(4)=GetGadgetText(#String_4)     
          satz(4)= " -m 0 "+ adresse_text + speed_text + " " + "-r "+ dummyname(4) + " " + dateiname(4) +" "+ cdtname
          RunProgram(cdtordner,satz(4) ,"",#PB_Program_Hide)
          edit_text+satz(4)+Chr(10)
          SetGadgetText(#Editor_0, edit_text)
        EndIf     
        If dateiname(5)
          Delay(100)
          dummyname(5)=GetGadgetText(#String_5)     
          satz(5)= " -m 0 "+ adresse_text + speed_text + " " + "-r "+ dummyname(5) + " " + dateiname(5) +" "+ cdtname
          RunProgram(cdtordner,satz(5) ,"",#PB_Program_Hide)
          edit_text+satz(5)+Chr(10)
          SetGadgetText(#Editor_0, edit_text)
        EndIf     
        If dateiname(6)
          Delay(100)
          dummyname(6)=GetGadgetText(#String_6)     
          satz(6)= " -m 0 "+ adresse_text + speed_text + " " + "-r "+ dummyname(6) + " " + dateiname(6) +" "+ cdtname
          RunProgram(cdtordner,satz(6) ,"",#PB_Program_Hide)
          edit_text+satz(6)+Chr(10)
          SetGadgetText(#Editor_0, edit_text)
        EndIf       
        If dateiname(7)
          Delay(100)
          dummyname(7)=GetGadgetText(#String_7)     
          satz(7)= " -m 0 "+ adresse_text + speed_text + " " + "-r "+ dummyname(7) + " " + dateiname(7) +" "+ cdtname
          RunProgram(cdtordner,satz(7) ,"",#PB_Program_Hide)
          edit_text+satz(7)+Chr(10)
          SetGadgetText(#Editor_0, edit_text)
        EndIf 
        schluss:
      EndIf

    Case #PB_Event_CloseWindow
      EventWindow = EventWindow()
      If EventWindow = #Window_0
        CloseWindow(#Window_0)
        Break
      EndIf
  EndSelect
   
ForEver

Powered by SMFPacks Menu Editor Mod