#include "<SampleEd$Dir>.h.Driver"
#include "Libraries:SoundLib.h.Wave"
#include "sndfile.h"
#include <string.h>
#include <stdlib.h>
#include "kernel.h"
#include "wimp.h"

osbool driver_load_lame(char *filename);

/* Import Wave file */

osbool driver_import(char *filename,int filetype,int size)
    {
    SNDFILE *sndfile;     /* libsndfile handle     */

    SF_INFO wfinfo;       /* File format info      */

    int channelindex,     /* Channel counter       */
        count,            /* Counter               */
        error,            /* Error number          */
        format,           /* Default format number */
        index,            /* Index into sample     */
        out_index,
        default_channels,
        default_samplerate,
        lastpc = 0,       /* Previous percentge    */
        len,              /* Size to read          */
        pc,               /* Calculated percentage */
        totalsize;        /* Total read from file  */

    int data[32];         /* Channel data          */

    long pos;             /* File position         */

    double sample_time;   /* Calculated time       */

    WaveChunk wavechunk;  /* Wave chunk structure  */

    RIFFHeader riffheader; /* RIFF chunk structure */

    WaveFormatChunk formatchunk; /* Format chunk   */

    WaveDataChunk datachunk; /* Wave data chunk    */

    char buffer[16384];   /* Input buffer          */

    short out[8192];      /* Output buffer         */

    FILE *tfh,
         *fh;             /* File handle           */

    char tmpname[L_tmpnam];

    osbool res;

/* Check for MP3 wav files */

    if (filetype == 0xfb1)
        {
/* Open input file */

        if ((fh = fopen(filename,"r")) == NULL)
            {
            driver_report_error("DrvErrOpen");
            return TRUE;
            }

/* Default details */

        formatchunk.dwSamplesPerSec = 41666;
        formatchunk.wChannels = 1;
        formatchunk.wBlockAlign = 2;

/* Remember start */

        pos = ftell(fh);

/* Read initial chunk */

        if (fread(&wavechunk,
                  sizeof(WaveChunk),1,fh) != 1)
            {
            fclose(fh);
            driver_report_error("DrvErrRead");
            return TRUE;
            }

/* Should be RIFF */

        if (memcmp(&wavechunk.chunkID,WaveRIFFID,4))
            {
            fclose(fh);
            driver_report_error("DrvInvFrm");
            return TRUE;
            }

/* Reset position */

        fseek(fh,pos,SEEK_SET);

/* Read RIFF chunk */

        if (fread(&riffheader,
                  sizeof(RIFFHeader),
                  1,
                  fh) != 1)
            {
            fclose(fh);
            driver_report_error("DrvErrRead");
            return TRUE;
            }

/* Should be WAVE */

        if (memcmp(&riffheader.wave,WaveWaveID,4))
            {
            fclose(fh);
            driver_report_error("DrvInvFrm");
            return TRUE;
            }

/* Remember position */

        pos = ftell(fh);

/* Find format and data chunks */

        while (memcmp(&wavechunk.chunkID,WaveDataID,4) && !feof(fh))
            {
            if (fread(&wavechunk,
                      sizeof(WaveChunk),
                      1,
                      fh) != 1)
                {
                fclose(fh);
                driver_report_error("DrvErrRead");
                return TRUE;
                }

            if (!memcmp(&wavechunk.chunkID,WaveFormatID,4))
                {
                fseek(fh,pos,SEEK_SET);

                if (fread(&formatchunk,
                          sizeof(WaveFormatChunk),
                          1,
                          fh) != 1)
                    {
                    fclose(fh);
                    driver_report_error("DrvErrRead");
                    return TRUE;
                    }

/* Only interested in MPEG files */

                if (formatchunk.wFormatTag != 0x55)
                    {
                    break;
                    }

                pos = ftell(fh);
                pos += 14;
                }
            else if (!memcmp(&wavechunk.chunkID,WaveDataID,4))
                {
                fseek(fh,pos,SEEK_SET);

/* Read data chunk and decode */

                if (fread(&datachunk,
                          sizeof(WaveDataChunk),
                          1,
                          fh) != 1)
                    {
                    fclose(fh);
                    driver_report_error("DrvErrRead");
                    return TRUE;
                    }

/* Create temporay file for MP3 data */

                tmpnam(tmpname);

                if ((tfh = fopen(tmpname,"w+")) == NULL)
                    {
                    driver_report_error("DrvErrOpen");
                    return TRUE;
                    }

/* Set initial values */

                size = (int)datachunk.chunkSize;

                totalsize = size;

/* Loop while data to read */

                while (size)
                    {

/* Calculate size of block to read */

                    if (size >= 16384)
                        {
                        size -= 16384;
                        len = 16384;
                        }
                    else
                        {
                        len = size;
                        size = 0;
                        }

/* Read block */

                    fread(buffer,len,1,fh);

/* Write block */

                    fwrite(buffer,len,1,tfh);
                    }

/* Close file handles */

                fclose(fh);
                fclose(tfh);

/* Call LAME to handle actual MP3 load */

                res = driver_load_lame(tmpname);

/* Remove temporary file */

                remove(tmpname);

                return res;
                }
            else
                {
                pos += wavechunk.chunkSize;
                }

            fseek(fh,pos,SEEK_SET);
            }

        fclose(fh);
        }

/* Non MP3 wav and other file types */

/* Open file */

    if (filetype == 0x0cd)
        {
        wfinfo.samplerate = 44100;
        wfinfo.channels   = 2;
        wfinfo.format     = SF_FORMAT_PCM_16 | SF_FORMAT_RAW;
        }
    else
        {
        wfinfo.format = 0;
        }

    if ((fh = fopen(filename,"r")) == NULL)
        {
        driver_report_error("DrvErrOpen");
        return TRUE;
        }

    fclose(fh);

    if (!driver_get_defaults(&default_samplerate,
                             &default_channels,
                             &format))
        {
        sndfile = sf_open(filename,SFM_READ,&wfinfo);

        error = sf_error(sndfile);
        }
    else
        {
        error = 1;
        }

    if (error)
        {

/* Try using defaults */

        wfinfo.samplerate = default_samplerate;
        wfinfo.channels = default_channels;

        switch (format)
            {
            case DRIVER_IMPORT_PCM_U8:
                wfinfo.format = SF_FORMAT_PCM_U8;
                break;

            case DRIVER_IMPORT_PCM_S8:
                wfinfo.format = SF_FORMAT_PCM_S8;
                break;

            case DRIVER_IMPORT_PCM_16:
                wfinfo.format = SF_FORMAT_PCM_16;
                break;

            case DRIVER_IMPORT_PCM_24:
                wfinfo.format = SF_FORMAT_PCM_24;
                break;

            case DRIVER_IMPORT_PCM_32:
                wfinfo.format = SF_FORMAT_PCM_32;
                break;

            case DRIVER_IMPORT_ULAW:
                wfinfo.format = SF_FORMAT_ULAW;
                break;

            case DRIVER_IMPORT_ALAW:
                wfinfo.format = SF_FORMAT_ALAW;
                break;

            case DRIVER_IMPORT_GSM610:
                wfinfo.format = SF_FORMAT_GSM610;
                break;

            case DRIVER_IMPORT_32_FLOAT:
                wfinfo.format = SF_FORMAT_FLOAT;
                break;

            case DRIVER_IMPORT_64_FLOAT:
                wfinfo.format = SF_FORMAT_DOUBLE;
                break;

            case DRIVER_IMPORT_12_DWVW:
                wfinfo.format = SF_FORMAT_DWVW_12;
                break;

            case DRIVER_IMPORT_16_DWVW:
                wfinfo.format = SF_FORMAT_DWVW_16;
                break;

            case DRIVER_IMPORT_24_DWVW:
                wfinfo.format = SF_FORMAT_DWVW_24;
                break;

            case DRIVER_IMPORT_VOX_ADPCM:
                wfinfo.format = SF_FORMAT_VOX_ADPCM;
                break;
            }

        wfinfo.format |= SF_FORMAT_RAW;

        sndfile = sf_open(filename,SFM_READ,&wfinfo);

/* Report an error */

        error = sf_error(sndfile);

        if (error)
            {
            driver_report_error((char *)sf_error_number(error));
            return TRUE;
            }
        }

/* Read data */

    if (sndfile != NULL)
        {
/* Only do this for non wave files if not mp3 */

        if ((wfinfo.format & SF_FORMAT_WAV) != SF_FORMAT_WAV ||
            (wfinfo.format & SF_FORMAT_SUBMASK) != 0x55)
            {
            driver_set_driver_id(wfinfo.format & SF_FORMAT_TYPEMASK,
                                 wfinfo.format & SF_FORMAT_SUBMASK);

/* Calculate sample time */

            sample_time = 100.0 *
                          wfinfo.frames /
                          wfinfo.samplerate;

            driver_set_sample_details(wfinfo.samplerate,
                                      (int)sample_time,
                                      wfinfo.channels,
                                      16);

/* Loop round data */

            index = 0;

            while (index < wfinfo.frames)
                {
/* Calculate percentage */

                pc = 100 * index / wfinfo.frames;

/* Only set percentage if different */

                if (pc > lastpc)
                    {
                    driver_percentage(pc);
                    lastpc = pc;
                    }

                out_index = 0;

                while ((index + out_index) < wfinfo.frames &&
                       out_index < (sizeof(out) / 2 / wfinfo.channels))
                    {
/* Read input */

                    count = sf_read_int(sndfile,data,wfinfo.channels);

/* Check for error */

                    error = sf_error(sndfile);

                    if (error)
                        {
                        driver_report_error((char *)sf_error_number(error));
                        break;
                        }

/* Loop round each channel */

                    for (channelindex = 0;
                         channelindex < wfinfo.channels;
                         channelindex++)
                        {
                        out[out_index * wfinfo.channels + channelindex] = data[channelindex] >> 16;
                        }

                    out_index++;
                    }

                if (driver_set_sample_block(index * wfinfo.channels,
                                            out,
                                            out_index * wfinfo.channels))
                    {
                    sf_close(sndfile);
                    return TRUE;
                    }

                index += out_index;
                }

            sf_close(sndfile);

            return FALSE;
            }
        }

    return FALSE;
    }


/* Return list of allowed file types */

DriverFileType *driver_filetypes(void)
    {
    static DriverFileType filetypes[23];

    SF_FORMAT_INFO format_info;

    int index = 0;

    filetypes[index].filetype = 0xfb1;
    strcpy(filetypes[index].suffix,"wav");
    filetypes[index].id = SF_FORMAT_WAV;
    format_info.format = SF_FORMAT_WAV;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xfc2;
    strcpy(filetypes[index].suffix,"aiff");
    filetypes[index].id = SF_FORMAT_AIFF;
    format_info.format = SF_FORMAT_AIFF;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"au");
    filetypes[index].id = SF_FORMAT_AU;
    format_info.format = SF_FORMAT_AU;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"raw");
    filetypes[index].id = SF_FORMAT_RAW;
    format_info.format = SF_FORMAT_RAW;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"paf");
    filetypes[index].id = SF_FORMAT_PAF;
    format_info.format = SF_FORMAT_PAF;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"svx");
    filetypes[index].id = SF_FORMAT_SVX;
    format_info.format = SF_FORMAT_SVX;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"nist");
    filetypes[index].id = SF_FORMAT_NIST;
    format_info.format = SF_FORMAT_NIST;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"ircam");
    filetypes[index].id = SF_FORMAT_IRCAM;
    format_info.format = SF_FORMAT_IRCAM;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"voc");
    filetypes[index].id = SF_FORMAT_VOC;
    format_info.format = SF_FORMAT_VOC;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"w64");
    filetypes[index].id = SF_FORMAT_W64;
    format_info.format = SF_FORMAT_W64;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"mat4");
    filetypes[index].id = SF_FORMAT_MAT4;
    format_info.format = SF_FORMAT_MAT4;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"mat5");
    filetypes[index].id = SF_FORMAT_MAT5;
    format_info.format = SF_FORMAT_MAT5;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"pvf");
    filetypes[index].id = SF_FORMAT_PVF;
    format_info.format = SF_FORMAT_PVF;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"xi");
    filetypes[index].id = SF_FORMAT_XI;
    format_info.format = SF_FORMAT_XI;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"htk");
    filetypes[index].id = SF_FORMAT_HTK;
    format_info.format = SF_FORMAT_HTK;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"sds");
    filetypes[index].id = SF_FORMAT_SDS;
    format_info.format = SF_FORMAT_SDS;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"avr");
    filetypes[index].id = SF_FORMAT_AVR;
    format_info.format = SF_FORMAT_AVR;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"wavex");
    filetypes[index].id = SF_FORMAT_WAVEX;
    format_info.format = SF_FORMAT_WAVEX;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"sd2");
    filetypes[index].id = SF_FORMAT_SD2;
    format_info.format = SF_FORMAT_SD2;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"flac");
    filetypes[index].id = SF_FORMAT_FLAC;
    format_info.format = SF_FORMAT_FLAC;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0xffd;
    strcpy(filetypes[index].suffix,"caf");
    filetypes[index].id = SF_FORMAT_CAF;
    format_info.format = SF_FORMAT_CAF;
    sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
    strncpy(filetypes[index++].description,format_info.name,64);

    filetypes[index].filetype = 0x0cd;
    strcpy(filetypes[index].suffix,"raw");
    filetypes[index].id = 0x140000;
    format_info.format = 0x140000;
    strncpy(filetypes[index++].description,"CD Track",64);

    filetypes[index].filetype = 0;
    filetypes[index].suffix[0] = '\0';
    filetypes[index].description[0] = '\0';
    filetypes[index++].id = 0;

    return filetypes;
    }



/* Return list of sub file types */

DriverSubFileType *driver_subfiletypes(int id)
    {
    static DriverSubFileType filetypes[14];

    int index = 0;

    SF_FORMAT_INFO format_info;

    switch (id)
        {
        case SF_FORMAT_WAV:
            filetypes[index].id = SF_FORMAT_WAV | SF_FORMAT_PCM_U8;
            format_info.format = SF_FORMAT_PCM_U8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
            format_info.format = SF_FORMAT_PCM_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAV | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
            format_info.format = SF_FORMAT_FLOAT;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAV | SF_FORMAT_DOUBLE;
            format_info.format = SF_FORMAT_DOUBLE;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAV | SF_FORMAT_ULAW;
            format_info.format = SF_FORMAT_ULAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAV | SF_FORMAT_ALAW;
            format_info.format = SF_FORMAT_ALAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM;
            format_info.format = SF_FORMAT_IMA_ADPCM;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM;
            format_info.format = SF_FORMAT_MS_ADPCM;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAV | SF_FORMAT_GSM610;
            format_info.format = SF_FORMAT_GSM610;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_AIFF:
            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_PCM_U8;
            format_info.format = SF_FORMAT_PCM_U8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_PCM_S8;
            format_info.format = SF_FORMAT_PCM_S8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_PCM_24;
            format_info.format = SF_FORMAT_PCM_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_FLOAT;
            format_info.format = SF_FORMAT_FLOAT;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_DOUBLE;
            format_info.format = SF_FORMAT_DOUBLE;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_ULAW;
            format_info.format = SF_FORMAT_ULAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_ALAW;
            format_info.format = SF_FORMAT_ALAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_GSM610;
            format_info.format = SF_FORMAT_GSM610;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_DWVW_12;
            format_info.format = SF_FORMAT_DWVW_12;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_DWVW_16;
            format_info.format = SF_FORMAT_DWVW_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AIFF | SF_FORMAT_DWVW_24;
            format_info.format = SF_FORMAT_DWVW_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_AU:
            filetypes[index].id = SF_FORMAT_AU | SF_FORMAT_PCM_S8;
            format_info.format = SF_FORMAT_PCM_S8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AU | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AU | SF_FORMAT_PCM_24;
            format_info.format = SF_FORMAT_PCM_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AU | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AU | SF_FORMAT_FLOAT;
            format_info.format = SF_FORMAT_FLOAT;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AU | SF_FORMAT_DOUBLE;
            format_info.format = SF_FORMAT_DOUBLE;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AU | SF_FORMAT_ULAW;
            format_info.format = SF_FORMAT_ULAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AU | SF_FORMAT_ALAW;
            format_info.format = SF_FORMAT_ALAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AU | SF_FORMAT_G721_32;
            format_info.format = SF_FORMAT_G721_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AU | SF_FORMAT_G723_24;
            format_info.format = SF_FORMAT_G723_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_AU | SF_FORMAT_G723_40;
            strncpy(filetypes[index++].description,"40kbs G723 ADPCM",64);
            break;

        case SF_FORMAT_RAW:
            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_PCM_U8;
            format_info.format = SF_FORMAT_PCM_U8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_PCM_S8;
            format_info.format = SF_FORMAT_PCM_S8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_PCM_24;
            format_info.format = SF_FORMAT_PCM_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_FLOAT;
            format_info.format = SF_FORMAT_FLOAT;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_DOUBLE;
            format_info.format = SF_FORMAT_DOUBLE;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_ULAW;
            format_info.format = SF_FORMAT_ULAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_ALAW;
            format_info.format = SF_FORMAT_ALAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_GSM610;
            format_info.format = SF_FORMAT_GSM610;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_DWVW_12;
            format_info.format = SF_FORMAT_DWVW_12;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_DWVW_16;
            format_info.format = SF_FORMAT_DWVW_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_DWVW_24;
            format_info.format = SF_FORMAT_DWVW_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM;
            format_info.format = SF_FORMAT_VOX_ADPCM;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_PAF:
            filetypes[index].id = SF_FORMAT_PAF | SF_FORMAT_PCM_S8;
            format_info.format = SF_FORMAT_PCM_S8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_PAF | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_PAF | SF_FORMAT_PCM_24;
            format_info.format = SF_FORMAT_PCM_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_SVX:
            filetypes[index].id = SF_FORMAT_SVX | SF_FORMAT_PCM_S8;
            format_info.format = SF_FORMAT_PCM_S8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_SVX | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_NIST:
            filetypes[index].id = SF_FORMAT_NIST | SF_FORMAT_PCM_S8;
            format_info.format = SF_FORMAT_PCM_S8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_NIST | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_NIST | SF_FORMAT_PCM_24;
            format_info.format = SF_FORMAT_PCM_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_NIST | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_NIST | SF_FORMAT_ULAW;
            format_info.format = SF_FORMAT_ULAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_NIST | SF_FORMAT_ALAW;
            format_info.format = SF_FORMAT_ALAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_IRCAM:
            filetypes[index].id = SF_FORMAT_IRCAM | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_IRCAM | SF_FORMAT_PCM_24;
            format_info.format = SF_FORMAT_PCM_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_IRCAM | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_IRCAM | SF_FORMAT_FLOAT;
            format_info.format = SF_FORMAT_FLOAT;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_IRCAM | SF_FORMAT_ULAW;
            format_info.format = SF_FORMAT_ULAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_IRCAM | SF_FORMAT_ALAW;
            format_info.format = SF_FORMAT_ALAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_VOC:
            filetypes[index].id = SF_FORMAT_VOC | SF_FORMAT_PCM_U8;
            format_info.format = SF_FORMAT_PCM_U8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_VOC | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_VOC | SF_FORMAT_ULAW;
            format_info.format = SF_FORMAT_ULAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_VOC | SF_FORMAT_ALAW;
            format_info.format = SF_FORMAT_ALAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_W64:
            filetypes[index].id = SF_FORMAT_W64 | SF_FORMAT_PCM_U8;
            format_info.format = SF_FORMAT_PCM_U8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_W64 | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_W64 | SF_FORMAT_PCM_24;
            format_info.format = SF_FORMAT_PCM_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_W64 | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_W64 | SF_FORMAT_FLOAT;
            format_info.format = SF_FORMAT_FLOAT;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_W64 | SF_FORMAT_DOUBLE;
            format_info.format = SF_FORMAT_DOUBLE;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_W64 | SF_FORMAT_ULAW;
            format_info.format = SF_FORMAT_ULAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_W64 | SF_FORMAT_ALAW;
            format_info.format = SF_FORMAT_ALAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM;
            format_info.format = SF_FORMAT_IMA_ADPCM;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM;
            format_info.format = SF_FORMAT_MS_ADPCM;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_W64 | SF_FORMAT_GSM610;
            format_info.format = SF_FORMAT_GSM610;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_MAT4:
            filetypes[index].id = SF_FORMAT_MAT4 | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_MAT4 | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_MAT4 | SF_FORMAT_FLOAT;
            format_info.format = SF_FORMAT_FLOAT;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_MAT4 | SF_FORMAT_DOUBLE;
            format_info.format = SF_FORMAT_DOUBLE;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_MAT5:
            filetypes[index].id = SF_FORMAT_MAT5 | SF_FORMAT_PCM_U8;
            format_info.format = SF_FORMAT_PCM_U8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_MAT5 | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_MAT5 | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_MAT5 | SF_FORMAT_FLOAT;
            format_info.format = SF_FORMAT_FLOAT;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_MAT5 | SF_FORMAT_DOUBLE;
            format_info.format = SF_FORMAT_DOUBLE;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_PVF:
            filetypes[index].id = SF_FORMAT_PVF | SF_FORMAT_PCM_S8;
            format_info.format = SF_FORMAT_PCM_S8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_PVF | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_PVF | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_XI:
            filetypes[index].id = SF_FORMAT_XI | SF_FORMAT_DPCM_8;
            format_info.format = SF_FORMAT_DPCM_8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_XI | SF_FORMAT_DPCM_16;
            format_info.format = SF_FORMAT_DPCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_HTK:
            filetypes[index].id = SF_FORMAT_HTK | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_SDS:
            filetypes[index].id = SF_FORMAT_SDS;
            format_info.format = SF_FORMAT_SDS;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_AVR:
            filetypes[index].id = SF_FORMAT_AVR;
            format_info.format = SF_FORMAT_AVR;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_WAVEX:
            filetypes[index].id = SF_FORMAT_WAVEX | SF_FORMAT_PCM_24;
            format_info.format = SF_FORMAT_PCM_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAVEX | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAVEX | SF_FORMAT_FLOAT;
            format_info.format = SF_FORMAT_FLOAT;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_WAVEX | SF_FORMAT_DOUBLE;
            format_info.format = SF_FORMAT_DOUBLE;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_FLAC:
            filetypes[index].id = SF_FORMAT_FLAC | SF_FORMAT_PCM_S8;
            format_info.format = SF_FORMAT_PCM_S8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_FLAC | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_FLAC | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_SD2:
            filetypes[index].id = SF_FORMAT_SD2 | SF_FORMAT_PCM_S8;
            format_info.format = SF_FORMAT_PCM_S8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_SD2 | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_SD2 | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case SF_FORMAT_CAF:
            filetypes[index].id = SF_FORMAT_CAF | SF_FORMAT_PCM_S8;
            format_info.format = SF_FORMAT_PCM_S8;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_CAF | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_CAF | SF_FORMAT_PCM_24;
            format_info.format = SF_FORMAT_PCM_24;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_CAF | SF_FORMAT_PCM_32;
            format_info.format = SF_FORMAT_PCM_32;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_CAF | SF_FORMAT_FLOAT;
            format_info.format = SF_FORMAT_FLOAT;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_CAF | SF_FORMAT_DOUBLE;
            format_info.format = SF_FORMAT_DOUBLE;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_CAF | SF_FORMAT_ULAW;
            format_info.format = SF_FORMAT_ULAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);

            filetypes[index].id = SF_FORMAT_CAF | SF_FORMAT_ALAW;
            format_info.format = SF_FORMAT_ALAW;
            sf_command(NULL,SFC_GET_FORMAT_INFO,&format_info,sizeof(format_info));
            strncpy(filetypes[index++].description,format_info.name,64);
            break;

        case 0x140000:
            filetypes[index].id = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
            format_info.format = SF_FORMAT_PCM_16;
            strncpy(filetypes[index++].description,"16 bit stereo",64);
            break;
        }

    filetypes[index].id = 0;
    filetypes[index++].description[0] = '\0';

    return filetypes;
    }


osbool driver_load_lame(char *filename)
    {
    SNDFILE *sndfile;     /* libsndfile handle     */

    SF_INFO wfinfo;       /* File format info      */

    int channelindex,     /* Channel counter       */
        count,            /* Counter               */
        error,            /* Error number          */
        format,           /* Default format number */
        index,            /* Index into sample     */
        out_index,
        default_channels,
        default_samplerate,
        lastpc = 0,       /* Previous percentge    */
        pc;               /* Calculated percentage */

    _kernel_swi_regs r;

    int old_next_slotsize,
        new_next_slotsize;

    int data[32];         /* Channel data          */

    double sample_time;   /* Calculated time       */

    short out[8192];      /* Output buffer         */

    char lame_command[1024];

    char *lame_size,
         *lame_decode;

    FILE *fh;             /* File handle           */

    char tmpname[L_tmpnam];

/* Check that LAME can be found */

    if ((fh = fopen("Run:LAME","r")) == NULL)
        {
        driver_report_error("DrvErrLAME");
        return TRUE;
        }

    if ((fh = fopen(filename,"r")) == NULL)
        {
        driver_report_error("DrvErrOpen");
        return TRUE;
        }

    fclose(fh);

/* Run LAME command to decode file to WAV */

    tmpnam(tmpname);

    new_next_slotsize = 2048 * 1024;

    lame_size = getenv("SampleEd$LAMESlotSize");

    if (lame_size != NULL && atoi(lame_size) > new_next_slotsize)
        {
        new_next_slotsize = atoi(lame_size);
        }

/* Get old next slot size */

    r.r[0] = -1;
    r.r[1] = -1;

    _kernel_swi(Wimp_SlotSize,&r,&r);

    old_next_slotsize = r.r[1];

/* Set our next slot size */

    r.r[1] = new_next_slotsize;

    _kernel_swi(Wimp_SlotSize,&r,&r);

    if (r.r[1] < new_next_slotsize)
        {
        driver_report_error("DrvTaskMem");
        r.r[1] = old_next_slotsize;
        _kernel_swi(Wimp_SlotSize,&r,&r);
        return TRUE;
        }

/* Run task */

    lame_decode = getenv("SampleEd$LAMEDecode");

    if (lame_decode == NULL)
        {
        lame_decode = "";
        }

    sprintf(lame_command,"lame --decode --mp3input --silent %s \"%s\" %s { > null: }",lame_decode,filename,tmpname);

    if (wimp_start_task(lame_command))
        {
        driver_report_error("DrvTask");
        r.r[1] = old_next_slotsize;
        _kernel_swi(Wimp_SlotSize,&r,&r);
        return TRUE;
        }

/* Reset slot size */

    r.r[1] = old_next_slotsize;
    _kernel_swi(Wimp_SlotSize,&r,&r);

    if (!driver_get_defaults(&default_samplerate,
                             &default_channels,
                             &format))
        {
        sndfile = sf_open(tmpname,SFM_READ,&wfinfo);

        error = sf_error(sndfile);
        }
    else
        {
        error = 1;
        }

    if (error)
        {

/* Try using defaults */

        wfinfo.samplerate = default_samplerate;
        wfinfo.channels = default_channels;

        switch (format)
            {
            case DRIVER_IMPORT_PCM_U8:
                wfinfo.format = SF_FORMAT_PCM_U8;
                break;

            case DRIVER_IMPORT_PCM_S8:
                wfinfo.format = SF_FORMAT_PCM_S8;
                break;

            case DRIVER_IMPORT_PCM_16:
                wfinfo.format = SF_FORMAT_PCM_16;
                break;

            case DRIVER_IMPORT_PCM_24:
                wfinfo.format = SF_FORMAT_PCM_24;
                break;

            case DRIVER_IMPORT_PCM_32:
                wfinfo.format = SF_FORMAT_PCM_32;
                break;

            case DRIVER_IMPORT_ULAW:
                wfinfo.format = SF_FORMAT_ULAW;
                break;

            case DRIVER_IMPORT_ALAW:
                wfinfo.format = SF_FORMAT_ALAW;
                break;

            case DRIVER_IMPORT_GSM610:
                wfinfo.format = SF_FORMAT_GSM610;
                break;

            case DRIVER_IMPORT_32_FLOAT:
                wfinfo.format = SF_FORMAT_FLOAT;
                break;

            case DRIVER_IMPORT_64_FLOAT:
                wfinfo.format = SF_FORMAT_DOUBLE;
                break;

            case DRIVER_IMPORT_12_DWVW:
                wfinfo.format = SF_FORMAT_DWVW_12;
                break;

            case DRIVER_IMPORT_16_DWVW:
                wfinfo.format = SF_FORMAT_DWVW_16;
                break;

            case DRIVER_IMPORT_24_DWVW:
                wfinfo.format = SF_FORMAT_DWVW_24;
                break;

            case DRIVER_IMPORT_VOX_ADPCM:
                wfinfo.format = SF_FORMAT_VOX_ADPCM;
                break;
            }

        wfinfo.format |= SF_FORMAT_RAW;

        sndfile = sf_open(tmpname,SFM_READ,&wfinfo);

/* Report an error */

        error = sf_error(sndfile);

        if (error)
            {
            driver_report_error((char *)sf_error_number(error));
            remove(tmpname);
            return TRUE;
            }
        }

/* Read data */

    if (sndfile != NULL)
        {
        driver_set_driver_id(wfinfo.format & SF_FORMAT_TYPEMASK,
                             wfinfo.format & SF_FORMAT_SUBMASK);

/* Calculate sample time */

        sample_time = 100.0 *
                      wfinfo.frames /
                      wfinfo.samplerate;

        driver_set_sample_details(wfinfo.samplerate,
                                  (int)sample_time,
                                  wfinfo.channels,
                                  16);

/* Loop round data */

        index = 0;

        while (index < wfinfo.frames)
            {
/* Calculate percentage */

            pc = 100 * index / wfinfo.frames;

/* Only set percentage if different */

            if (pc > lastpc)
                {
                driver_percentage(pc);
                lastpc = pc;
                }

            out_index = 0;

            while ((index + out_index) < wfinfo.frames &&
                   out_index < (sizeof(out) / 2 / wfinfo.channels))
                {
/* Read input */

                count = sf_read_int(sndfile,data,wfinfo.channels);

/* Check for error */

                error = sf_error(sndfile);

                if (error)
                    {
                    driver_report_error((char *)sf_error_number(error));
                    break;
                    }

/* Loop round each channel */

                for (channelindex = 0;
                     channelindex < wfinfo.channels;
                     channelindex++)
                    {
                    out[out_index * wfinfo.channels + channelindex] = data[channelindex] >> 16;
                    }

                out_index++;
                }

            if (driver_set_sample_block(index * wfinfo.channels,
                                        out,
                                        out_index * wfinfo.channels))
                {
                sf_close(sndfile);
                remove(tmpname);
                return TRUE;
                }

            index += out_index;
            }

        sf_close(sndfile);

        remove(tmpname);
        return FALSE;
        }

    remove(tmpname);
    return FALSE;
    }

