Пример #1
0
bool psx_analog_controller_device::get_pad(int count, uint8_t *odata, uint8_t idata)
{
	if(m_confmode)
	{
		switch(count)
		{
			case 0:
				m_temp = 0;
				*odata = 0xf3;
				break;
			case 1:
				m_cmd = idata;
				if((m_cmd & 0xf0) != 0x40)
					return false;
				*odata = 0x5a;
				break;
			default:
				switch(m_cmd)
				{
					default: // 40,41,48,49,4a,4b,4f -- all unknown
						*odata = 0x00;
						break;
					case CONFIG_MODE: // 43
						if(count == 3)
							m_temp = idata;
						/* no break */
					case QUERY_PAD_STATE: // 42
						*odata = pad_data(count, true);
						break;
					case 0x44: // set mode and lock ?
						switch(count)
						{
							case 3:
								m_analogmode = idata ? true : false; // only 0x01 ?
								break;
							case 4:
								m_analoglock = idata ? true : false; // only 0x03 ?
								break;
						}
						*odata = 0x00;
						break;
					case 0x45: // get mode ?
					{
						const uint8_t val[] = { 1, 2, 0, 2, 1, 0 };
						if(count == 4)
							*odata = m_analogmode;
						else
							*odata = val[count-2];
						break;
					}
					case 0x46: // query act (vibrate) ?
					{
						const uint8_t val[2][6] = {{ 0, 0, 1, 2, 0, 10 },
												{ 0, 0, 1, 1, 1, 14 }};
						*odata = val[m_temp][count-2];
						if(count == 3)
							m_temp = idata ? 1 : 0;
						break;
					}
					case 0x47: // query comb (combination?) ?
					{
						const uint8_t val[] = { 0, 0, 2, 0, 1, 0 };
						*odata = val[count-2];
						break;
					}
					case 0x4c: // query mode ?
						switch(count)
						{
							case 3:
								m_temp = idata;
								/* no break */
							default:
								*odata = 0x00;
								break;
							case 5:
								*odata = m_analogmode ? 0x07 : 0x04; // ?
								break;
						}
						break;
					case 0x4d: // set act (vibrate) ?
						*odata = 0xff;
						break;
				}
				break;
			case 8:
				if(m_cmd == CONFIG_MODE)
					m_confmode = m_temp;
				return false;
		}
	}
	else if(m_analogmode)
	{
		switch(count)
		{
			case 0:
				if(m_type == JOYSTICK)
					*odata = 0x53;
				else
					*odata = 0x73;
				break;
			case 1:
				m_cmd = idata;
				if((m_cmd & 0xfe) != QUERY_PAD_STATE)
					return false;
				*odata = 0x5a;
				break;
			case 3:
				if(m_cmd == CONFIG_MODE)
					m_temp = idata;
				/* no break */
			default:
				*odata = pad_data(count, true);
				break;
			case 8:
				if(m_cmd == CONFIG_MODE)
					m_confmode = m_temp;
				return false;
		}
	}
	else
	{
		switch(count)
		{
			case 0:
				*odata = 0x41;
				break;
			case 1:
				m_cmd = idata;
				if((m_cmd & 0xfe) != QUERY_PAD_STATE)
					return false;
				*odata = 0x5a;
				break;
			case 3:
				if(m_cmd == CONFIG_MODE)
					m_temp = idata;
				/* no break */
			default:
				*odata = pad_data(count, false);
				break;
			case 4:
				if(m_cmd == CONFIG_MODE)
					m_confmode = m_temp;
				return false;
		}
	}
	return true;
}
Пример #2
0
int main (int argc, char **argv)
{
    FILE    *fp;
	char    *file_gp, *file_fp, *file_wav;
    int     nx, nt, ngath, ntraces, ret, size, nxwav;
    int     ntfft, nfreq, nxfft, nkx, i, j, n;
    float   dx, dt, fx, ft, xmin, xmax, scl, *den, dentmp;
    float   df, dw, dkx, eps, reps, leps, sclfk;
    float   *Gpd, *f1pd, *G_pad, *f_pad, *wav, *wav_pad, *outdata;
    complex *G_w, *f_w, *Gf, *amp, *wav_w, *S, *ZS, *SS;
    segy    *hdr_gp, *hdr_fp, *hdr_wav, *hdr_out;

	initargs(argc, argv);
	requestdoc(1);

	if(!getparstring("file_gp", &file_gp)) file_gp=NULL;
    if (file_gp==NULL) verr("file %s does not exist",file_gp);
    if(!getparstring("file_fp", &file_fp)) file_fp=NULL;
    if (file_fp==NULL) verr("file %s does not exist",file_fp);
    if(!getparstring("file_wav", &file_wav)) file_wav=NULL;
    if (file_wav==NULL) verr("file %s does not exist",file_wav);
	if(!getparfloat("eps", &eps)) eps=0.00;
	if(!getparfloat("reps", &reps)) reps=0.01;

    ngath = 1;
    ret = getFileInfo(file_gp, &nt, &nx, &ngath, &dt, &dx, &ft, &fx, &xmin, &xmax, &scl, &ntraces);

    size    = nt*nx;

	Gpd     = (float *)malloc(size*sizeof(float));
	hdr_gp  = (segy *) calloc(nx,sizeof(segy));
    fp      = fopen(file_gp, "r");
	if (fp == NULL) verr("error on opening input file_in1=%s", file_gp);
    nx      = readData(fp, Gpd, hdr_gp, nt);
    fclose(fp);

	f1pd    = (float *)malloc(size*sizeof(float));
	hdr_fp  = (segy *) calloc(nx,sizeof(segy));
    fp      = fopen(file_fp, "r");
	if (fp == NULL) verr("error on opening input file_in1=%s", file_fp);
    nx      = readData(fp, f1pd, hdr_fp, nt);
    fclose(fp);

    wav     = (float *)malloc(nt*sizeof(float));
	hdr_wav = (segy *) calloc(1,sizeof(segy));
    fp      = fopen(file_wav, "r");
	if (fp == NULL) verr("error on opening input file_in1=%s", file_fp);
    nxwav   = readData(fp, wav, hdr_wav, nt);
    fclose(fp);

    /* Start the scaling */
    ntfft   = optncr(nt);
	nfreq   = ntfft/2+1;
	df      = 1.0/(ntfft*dt);
    dw      = 2.0*PI*df;
	nkx     = optncc(nx);
	dkx     = 2.0*PI/(nkx*dx);
	sclfk   = dt*(dt*dx)*(dt*dx);

    vmess("ntfft:%d, nfreq:%d, nkx:%d dx:%.3f dt:%.3f",ntfft,nfreq,nkx,dx,dt);

    /* Allocate the arrays */
    G_pad = (float *)calloc(ntfft*nkx,sizeof(float));
	if (G_pad == NULL) verr("memory allocation error for G_pad");
    f_pad = (float *)calloc(ntfft*nkx,sizeof(float));
	if (f_pad == NULL) verr("memory allocation error for f_pad");
    wav_pad = (float *)calloc(ntfft,sizeof(float));
	if (wav_pad == NULL) verr("memory allocation error for wav_pad");
    G_w   = (complex *)calloc(nfreq*nkx,sizeof(complex));
	if (G_w == NULL) verr("memory allocation error for G_w");
    f_w   = (complex *)calloc(nfreq*nkx,sizeof(complex));
	if (f_w == NULL) verr("memory allocation error for f_w");
    Gf    = (complex *)calloc(nfreq*nkx,sizeof(complex));
	if (Gf == NULL) verr("memory allocation error for Gf");
    wav_w = (complex *)calloc(nfreq*nkx,sizeof(complex));
	if (wav_w == NULL) verr("memory allocation error for wav_w");
    amp   = (complex *)calloc(nfreq*nkx,sizeof(complex));
	if (amp == NULL) verr("memory allocation error for amp");
    S   = (complex *)calloc(nfreq*nkx,sizeof(complex));
	if (S == NULL) verr("memory allocation error for S");
    ZS   = (complex *)calloc(nfreq*nkx,sizeof(complex));
	if (ZS == NULL) verr("memory allocation error for ZS");
    SS   = (complex *)calloc(nfreq*nkx,sizeof(complex));
	if (SS == NULL) verr("memory allocation error for SS");
    den   = (float *)calloc(nfreq*nkx,sizeof(float));
	if (den == NULL) verr("memory allocation error for den");

    /* pad zeroes in 2 directions to reach FFT lengths */
	pad2d_data(Gpd, nt,nx,ntfft,nkx,G_pad);
	pad2d_data(f1pd,nt,nx,ntfft,nkx,f_pad);
    pad_data(  wav, nt, 1,ntfft,  wav_pad);

    /* double forward FFT */
	xt2wkx(&G_pad[0], &G_w[0], ntfft, nkx, ntfft, nkx, 0);
	xt2wkx(&f_pad[0], &f_w[0], ntfft, nkx, ntfft, nkx, 0);
    rcmfft(&wav_pad[0], &Gf[0], ntfft, 1, ntfft, nfreq, -1);

    for (i=0; i<nkx; i++) {
        for (j=0; j<nfreq; j++) {
            wav_w[j*nkx+i].r = Gf[j].r;
            wav_w[j*nkx+i].i = Gf[j].i;	
		}
    }

	for (i = 0; i < nkx*nfreq; i++) {
		Gf[i].r = (G_w[i].r*f_w[i].r - G_w[i].i*f_w[i].i);
		Gf[i].i = (G_w[i].r*f_w[i].i + G_w[i].i*f_w[i].r);

		S[i].r = (wav_w[i].r*wav_w[i].r + wav_w[i].i*wav_w[i].i);
		S[i].i = (wav_w[i].r*wav_w[i].i - wav_w[i].i*wav_w[i].r);

		ZS[i].r = (Gf[i].r*S[i].r + Gf[i].i*S[i].i);
		ZS[i].i = (Gf[i].r*S[i].i - Gf[i].i*S[i].r);

		SS[i].r = (S[i].r*S[i].r + S[i].i*S[i].i);
		SS[i].i = (S[i].r*S[i].i - S[i].i*S[i].r);

		if (i==0) dentmp=SS[i].r;
		else dentmp=MAX(dentmp,SS[i].r);
	}

	leps = reps*dentmp+eps;
	vmess("dentmp:%.4e leps:%.4e",dentmp,leps);

	for (i = 0; i < nkx*nfreq; i++) {
		S[i].r = (ZS[i].r*SS[i].r+ZS[i].i*SS[i].i)/(SS[i].r*SS[i].r+SS[i].i*SS[i].i+leps);
		S[i].i = (ZS[i].i*SS[i].r-ZS[i].r*SS[i].i)/(SS[i].r*SS[i].r+SS[i].i*SS[i].i+leps);

		amp[i].r = sqrtf(S[i].r*S[i].r+S[i].i*S[i].i);
		amp[i].i = 0.0;
		
		// complex_sqrt(&amp[i]);
		if (isnan(amp[i].r)) amp[i].r = 0;
		if (isnan(amp[i].i)) amp[i].i = 0;
		if (isinf(amp[i].r)) amp[i].r = 0;
		if (isinf(amp[i].i)) amp[i].i = 0;

		Gf[i].r = (G_w[i].r*amp[i].r - G_w[i].i*amp[i].i);
		Gf[i].i = (G_w[i].r*amp[i].i + G_w[i].i*amp[i].r);
	}

	// for (i=0; i<nfreq; i++) {
	// 	for (j=0; j<nkx; j++) {
	// 		Gpd[j*nfreq+i] = sqrtf(amp[i*nkx+j].r*amp[i*nkx+j].r+amp[i*nkx+j].i*amp[i*nkx+j].i);
	// 	}
	// }
    
    // conv_small(G_w, amp, Gf, nkx, nfreq); // Scaled data

    /* inverse double FFT */
	wkx2xt(&Gf[0], &G_pad[0], ntfft, nkx, nkx, ntfft, 0);
	/* select original samples and traces */
	scl = (1.0)/(nkx*ntfft);
	scl_data(G_pad,ntfft,nx,scl,Gpd ,nt);

    fp      = fopen("out.su", "w+");
    ret = writeData(fp, Gpd, hdr_gp, nt, nx);
	if (ret < 0 ) verr("error on writing output file.");
    fclose(fp);

	// fp      = fopen("wav.su", "w+");
	// for (j=0; j<nkx; j++) {
	// 	hdr_gp[j].ns = nfreq;
	// }
    // ret = writeData(fp, Gpd, hdr_gp, nfreq, nkx);
	// if (ret < 0 ) verr("error on writing output file.");
    // fclose(fp);

    free(f1pd);free(Gpd);free(hdr_gp);free(hdr_fp);

	return 0;
}
Пример #3
0
int main(int argc, char **argv)
{
    int i, j;
    int input = -1, output = -1, src_fmt = -1, dst_fmt = -1;
    
    if (argc == 9)
    {
        for (i = 1; i < argc; i++)
        {
            if (CHK_ARG("-i"))
            {
                if (input < 0)
                {
                    /* Get index value for the input file name */
                    i++;
                    input = i;
                } else {
                    input = -1;
                    break;
                }
            } else
            if (CHK_ARG("-o"))
            {
                if (output < 0)
                {
                    /* Get index value for the output file name */
                    i++;
                    output = i;
                } else {
                    output = -1;
                    break;
                }
            } else
            if (CHK_ARG("-s"))
            {
                if (src_fmt < 0)
                {
                    i++;
                    
                    /* Validate option */
                    for (j = 0; j < format_cnt; j++)
                    {
                        if (CHK_ARG(formats[j]))
                        {
                            /* Get index value for the input file format */
                            src_fmt = j;
                            break;
                        }
                    }
                    
                    if (src_fmt < 0) break;
                } else {
                    src_fmt = -1;
                    break;
                }
            } else
            if (CHK_ARG("-d"))
            {
                if (dst_fmt < 0)
                {
                    i++;
                    
                    /* Validate option */
                    for (j = 0; j < format_cnt; j++)
                    {
                        if (CHK_ARG(formats[j]))
                        {
                            /* Get index value for the input file format */
                            dst_fmt = j;
                            break;
                        }
                    }
                    
                    if (dst_fmt < 0) break;
                } else {
                    dst_fmt = -1;
                    break;
                }
            }
        }
    }
    
    if (input < 0 || output < 0 || src_fmt < 0 || dst_fmt < 0)
    {
        usage(argv);
        return 1;
    }
    
    if (src_fmt == dst_fmt)
    {
        printf("\n\tDestination file format cannot be the same as the source file format.\n\tProcess aborted.\n");
        return 1;
    }
    
    sixty_t *sixty_header = malloc(sizeof(sixty_t));
    if (!sixty_header)
    {
        printf("\n\tError allocating memory for the save header.\n");
        return 1;
    }
    
    memset(sixty_header, 0, sizeof(sixty_t));
    
    FILE *infile = fopen(argv[input], "rb");
    if (!infile)
    {
        printf("\n\tError opening \"%s\" for reading.\n", argv[input]);
        free(sixty_header);
        return 1;
    }
    
    fseek(infile, 0, SEEK_END);
    uint32_t fsize = ftell(infile);
    rewind(infile);
    
    if (fsize == 0 || fsize > CtrlPakx8 || (fsize % 4) != 0)
    {
        printf("\n\tInvalid N64 save file.\n");
        if (fsize == 0) printf("\n\tFile size is zero!\n");
        if (fsize > CtrlPakx8) printf("\n\tFile size is greater than %u KiB!\n", CtrlPakx8 / 1024);
        if ((fsize % 4) != 0) printf("\n\tFile size is not a multiple of 4!\n");
        free(sixty_header);
        fclose(infile);
        return 1;
    }
    
    if (src_fmt == 3 && fsize < sizeof(sixty_t))
    {
        printf("\n\tInput save file is not big enough to store a Sixtyforce save header!\n");
        free(sixty_header);
        fclose(infile);
        return 1;
    }
    
    FILE *outfile = fopen(argv[output], "wb");
    if (!outfile)
    {
        printf("\n\tError opening \"%s\" for writing.\n", argv[output]);
        free(sixty_header);
        fclose(infile);
        return 1;
    }
    
    char tmp[256] = {0};
    bool sixty_cp = false;
    uint32_t data = 0, save_size = 0;
    
    if (src_fmt == 3)
    {
        /* Check if this is a Sixtyforce save */
        
        fread(sixty_header, sizeof(sixty_t), 1, infile);
        rewind(infile);
        
        if (!strncmp(sixty_header->magic1, "60cs", 4) && !strncmp(sixty_header->magic2, "head", 4) && !strncmp(sixty_header->magic3, "time", 4) && \
            !strncmp(sixty_header->magic4, "save", 4) && !strncmp(sixty_header->magic5, "type", 4) && !strncmp(sixty_header->magic6, "size", 4) && \
            !strncmp(sixty_header->magic7, "data", 4))
        {
#ifdef DEBUG
            print_sixty_header(sixty_header);
#endif
            
            /* Get save size */
            save_size = bswap_32(sixty_header->datasize2); // Stored in Big Endian
            
            /* Check if this file contains a Controller Pak save */
            if (fsize > (0x84 + save_size + 8)) // Sixtyforce header + save data + "pak0" block
            {
                fseek(infile, 0x84 + save_size, SEEK_SET);
                fread(&data, 4, 1, infile);
                rewind(infile);
                sixty_cp = (data == bswap_32(PAK0_MAGIC));
            }
            
            /* Prepare file stream position for data access */
            fseek(infile, 0x84, SEEK_SET);
        } else {
            printf("\n\tInput save file is not a Sixtyforce save!\n");
            free(sixty_header);
            fclose(infile);
            fclose(outfile);
            remove(argv[output]);
            return 1;
        }
    } else {
        /* Get save size */
        save_size = fsize;
    }
    
    /* Try to guess the most probable save type using the save file size */
    int type = -1;
    uint32_t type_size = 0;
    
    if (save_size <= EEPROM)
    {
        type = 0;
        type_size = EEPROM;
    } else
    if (save_size <= EEPROMx4)
    {
        type = 0;
        type_size = EEPROMx4;
    } else
    if (save_size <= EEPROMx8)
    {
        type = 0;
        type_size = EEPROMx8;
    } else
    if (save_size <= EEPROMx32)
    {
        type = 0;
        type_size = EEPROMx32;
    } else
    if (save_size <= SRAM)
    {
        /* Even though this is the real size for Controller Pak saves, only Sixtyforce seems to use it */
        /* Let's just assume it's a SRAM save and call it a day */
        type = 1;
        type_size = SRAM;
    } else
    if (save_size <= FlashRAM)
    {
        /* Also applies to Controller Pak saves from Wii64. We'll ask about this later. */
        type = 2;
        type_size = FlashRAM;
    } else
    if (save_size <= CtrlPakx8)
    {
        type = 3;
        type_size = CtrlPakx8;
    }
    
    if (src_fmt == 0 && type == 2) // Input: Wii64 FlashRAM
    {
        if (!strncasecmp(argv[input] + strlen(argv[input]) - 4, ".fla", 4))
        {
            /* Assume that the input file is actually a FlashRAM save and remain unchanged */
        } else
        if (!strncasecmp(argv[input] + strlen(argv[input]) - 4, ".mpk", 4))
        {
            /* Assume that the input file is actually a Controller Pak save */
            type = 3;
        } else {
            /* Ask the user if the input save is actually a Controller Pak save */
            while(true)
            {
                if (getLine("\n\tIs the input file a Controller Pak save? (yes/no): ", tmp, sizeof(tmp)) == 0)
                {
                    if (strlen(tmp) == 3 && !strncmp(tmp, "yes", 3))
                    {
                        /* Change save type */
                        type = 3;
                        break;
                    } else
                    if (strlen(tmp) == 2 && !strncmp(tmp, "no", 2))
                    {
                        /* Remain unchanged */
                        break;
                    } else {
                        printf("\tInvalid input. Please answer with \"yes\" or \"no\".\n");
                    }
                } else {
                    printf("\tInvalid input. Please answer with \"yes\" or \"no\".\n");
                }
            }
        }
    }
    
    printf("\n\tDetected save type: %s (%u Kbits).\n", SAVE_TYPE_STR(type), ((type_size * 8) / 1024));
    if (src_fmt == 3 && sixty_cp && (dst_fmt == 0 || dst_fmt == 1)) printf("\n\tDetected Sixtyforce Controller Pak save data (SRAM %u Kbits).\n", ((CtrlPak * 8) / 1024));
    
    /* Redundancy checks: */
    /* Wii64 EEPROM -> Project64 EEPROM */
    /* Project64 EEPROM -> Wii64 EEPROM */
    /* Wii64 SRAM -> Wii N64 VC SRAM */
    /* Wii N64 VC SRAM -> Wii64 SRAM */
    /* Wii64 FlashRAM -> Wii N64 VC FlashRAM */
    /* Wii N64 VC FlashRAM -> Wii64 FlashRAM */
    if ((((src_fmt == 0 && dst_fmt == 1) || (src_fmt == 1 && dst_fmt == 0)) && type == 0) || \
        (((src_fmt == 0 && dst_fmt == 2) || (src_fmt == 2 && dst_fmt == 0)) && (type == 1 || type == 2)))
    {
        printf("\n\tThis %s save file doesn't need to be modified.\n\tJust try it with %s.\n", \
            SAVE_TYPE_STR(type), \
            (dst_fmt == 0 ? "Wii64" : (dst_fmt == 1 ? "Project64" : "your Wii N64 Virtual Console title")));
        free(sixty_header);
        fclose(infile);
        fclose(outfile);
        remove(argv[output]);
        return 1;
    }
    
    if (dst_fmt == 2 && type == 3) // Output: Wii N64 VC Controller Pak
    {
        printf("\n\tWii N64 Virtual Console isn't compatible with\n\tController Pak save data.\n");
        free(sixty_header);
        fclose(infile);
        fclose(outfile);
        remove(argv[output]);
        return 1;
    }
    
    if (dst_fmt == 3 && type == 3) // Output: Sixtyforce Controller Pak
    {
        printf("\n\tConversion of Controller Pak data to the Sixtyforce format\n\tisn't supported (yet).\n");
        free(sixty_header);
        fclose(infile);
        fclose(outfile);
        remove(argv[output]);
        return 1;
    }
    
    uint32_t outsize = 0;
    bool byteswap = false;
    
    switch(type)
    {
        case 0: // EEPROM
            /* Byteswapping isn't needed */
            byteswap = false;
            
            /* Adjust output save size according to the destination format */
            outsize = ((dst_fmt == 0 || dst_fmt == 1) ? EEPROMx4 : (dst_fmt == 2 ? EEPROMx32 : EEPROMx8));
            
            break;
        case 1: // SRAM
            /* Only apply 32-bit byteswapping if either the source or destiny format is Project64 */
            byteswap = (src_fmt == 1 || dst_fmt == 1);
            
            /* Adjust output save size */
            outsize = SRAM;
            
            break;
        case 2: // Flash RAM
            /* Only apply 32-bit byteswapping if either the source or destiny format is Project64 */
            byteswap = (src_fmt == 1 || dst_fmt == 1);
            
            /* Adjust output save size */
            outsize = FlashRAM;
            
            break;
        case 3: // Controller Pak
            /* Byteswapping isn't needed */
            byteswap = false;
            
            /* Adjust output save size according to the destination format */
            outsize = (dst_fmt == 0 ? CtrlPakx4 : CtrlPakx8);
            
            break;
        default:
            break;
    }
    
    /* Time to do the magic */
    
    if (dst_fmt == 3) // Sixtyforce
    {
        /* Generate Sixtyforce header */
        strcpy(sixty_header->magic1, "60cs");
        sixty_header->filesize = bswap_32((uint32_t)(0x84 - 0x08 + outsize));
        strcpy(sixty_header->magic2, "head");
        strcpy(sixty_header->magic3, "time");
        sixty_header->unk1 = bswap_32((uint32_t)0x04);
        strcpy(sixty_header->magic4, "save");
        sixty_header->savesize = bswap_32((uint32_t)(0x84 - 0x64 + outsize));
        strcpy(sixty_header->magic5, "type");
        sixty_header->unk2 = bswap_32((uint32_t)0x04);
        sixty_header->type = bswap_32((uint32_t)(type == 0 ? 0x01 : (type == 1 ? 0x03 : 0x04)));
        strcpy(sixty_header->magic6, "size");
        sixty_header->unk3 = bswap_32((uint32_t)0x04);
        sixty_header->datasize1 = bswap_32(outsize);
        strcpy(sixty_header->magic7, "data");
        sixty_header->datasize2 = bswap_32(outsize);
        
#ifdef DEBUG
        print_sixty_header(sixty_header);
#endif
        
        /* Write header to the output file */
        fwrite(sixty_header, sizeof(sixty_t), 1, outfile);
    }
    
    /* Write save data */
    write_data(data, infile, outfile, (outsize > save_size ? save_size : outsize), byteswap);
    if (outsize > save_size) pad_data((dst_fmt == 2), (outsize - save_size), outfile);
    
    /* Extract the Controller Pak data from the Sixtyforce save (if available) */
    if (sixty_cp && (dst_fmt == 0 || dst_fmt == 1))
    {
        rewind(infile);
        fseek(infile, (0x84 + save_size + 8), SEEK_SET); // Sixtyforce header + save data + "pak0" block
        
        uint32_t pak0_size = (fsize - (0x84 + save_size + 8)); // Remaining data
        
        snprintf(tmp, strlen(argv[output]), argv[output]);
        
        for(i = strlen(tmp); tmp[i] != '.'; i--);
        
        if (i > 0) tmp[i] = '\0';
        strncat(tmp, ".mpk", 4);
        
        FILE *cpak = fopen(tmp, "wb");
        if (!cpak)
        {
            printf("\n\tError opening \"%s\" for writing.\n", tmp);
        } else {
            write_data(data, infile, cpak, pak0_size, false);
            pad_data(false, (dst_fmt == 0 ? (CtrlPakx4 - pak0_size) : (CtrlPakx8 - pak0_size)), cpak);
            
            fclose(cpak);
            
            printf("\n\tSaved additional Controller Pak data to \"%s\".", tmp);
            printf("\n\tYou can use it with %s.\n", (dst_fmt == 0 ? "Wii64" : "Project64"));
        }
    }
    
    printf("\n\tConversion process successfully completed!\n");
    
    free(sixty_header);
    fclose(infile);
    fclose(outfile);
    
    return 0;
}
void convolhom(float *data1, float *data2, float *con, int nrec, int nsam, float dt, int shift, float rho, int mode)
{
    int     i, j, n, optn, nfreq, sign;
    float   df, dw, om, tau, scl;
    float   *qr, *qi, *p1r, *p1i, *p2r, *p2i, *rdata1, *rdata2;
    complex *cdata1, *cdata2, *ccon, tmp;

    optn = optncr(nsam);
    nfreq = optn/2+1;


    cdata1 = (complex *)malloc(nfreq*nrec*sizeof(complex));
    if (cdata1 == NULL) verr("memory allocation error for cdata1");
    cdata2 = (complex *)malloc(nfreq*nrec*sizeof(complex));
    if (cdata2 == NULL) verr("memory allocation error for cdata2");
    ccon = (complex *)malloc(nfreq*nrec*sizeof(complex));
    if (ccon == NULL) verr("memory allocation error for ccov");

    rdata1 = (float *)malloc(optn*nrec*sizeof(float));
    if (rdata1 == NULL) verr("memory allocation error for rdata1");
    rdata2 = (float *)malloc(optn*nrec*sizeof(float));
    if (rdata2 == NULL) verr("memory allocation error for rdata2");

    /* pad zeroes until Fourier length is reached */
    pad_data(data1, nsam, nrec, optn, rdata1);
    pad_data(data2, nsam, nrec, optn, rdata2);

    /* forward time-frequency FFT */
    sign = -1;
    rcmfft(&rdata1[0], &cdata1[0], optn, nrec, optn, nfreq, sign);
    rcmfft(&rdata2[0], &cdata2[0], optn, nrec, optn, nfreq, sign);

    /* apply convolution */
    p1r = (float *) &cdata1[0];
    p2r = (float *) &cdata2[0];
    qr = (float *) &ccon[0].r;
    p1i = p1r + 1;
    p2i = p2r + 1;
    qi = qr + 1;
    n = nrec*nfreq;
    for (j = 0; j < n; j++) {
        *qr = (*p2r**p1r-*p2i**p1i);
        *qi = (*p2r**p1i+*p2i**p1r);
        qr += 2;
        qi += 2;
        p1r += 2;
        p1i += 2;
        p2r += 2;
        p2i += 2;
    }
    free(cdata1);
    free(cdata2);

    if (shift) {
        df = 1.0/(dt*optn);
        dw = 2*PI*df;
        tau = dt*(nsam/2);
        for (j = 0; j < nrec; j++) {
            om = 0.0;
            for (i = 0; i < nfreq; i++) {
                tmp.r = ccon[j*nfreq+i].r*cos(om*tau) + ccon[j*nfreq+i].i*sin(om*tau);
                tmp.i = ccon[j*nfreq+i].i*cos(om*tau) - ccon[j*nfreq+i].r*sin(om*tau);
                ccon[j*nfreq+i] = tmp;
                om += dw;
            }
        }
    }

	/* Scaling for the homogeneous equation */
	if (mode==0) {//single source
    	df = 1.0/(dt*optn);
    	dw = 2.0*(M_PI)*df;
    	for (i=0; i<nrec; i++) {
			j=0;
			ccon[i*nfreq+j].r *= 0.0;
			ccon[i*nfreq+j].i *= 0.0;
        	for (j=1; j<nfreq; j++) {
            	ccon[i*nfreq+j].r *= (4.0/(rho*dw*j));
            	ccon[i*nfreq+j].i *= (4.0/(rho*dw*j));
        	}
    	}
	}
	else {//multiple sources
		df = 1.0/(dt*optn);
        dw = 2.0*(M_PI)*df;
        for (i=0; i<nrec; i++) {
			j=0;
            ccon[i*nfreq+j].r *= 0.0;
            ccon[i*nfreq+j].i *= 0.0;
            for (j=1; j<nfreq; j++) {
				tmp.r = (2.0/(rho*dw*j))*ccon[i*nfreq+j].i;
				tmp.i = (2.0/(rho*dw*j))*ccon[i*nfreq+j].r;
				ccon[i*nfreq+j]=tmp;
            }
        }
	}

    /* inverse frequency-time FFT and scale result */
    sign = 1;
    scl = 1.0/((float)(optn));
    crmfft(&ccon[0], &rdata1[0], optn, nrec, nfreq, optn, sign);
    scl_data(rdata1,optn,nrec,scl,con,nsam);

    free(ccon);
    free(rdata1);
    free(rdata2);
    return;
}