javasynthesizer

Beginner Digital Synth


I'm looking into writing a audio syntesizer in Java, and was wondering if anybody has any advice or good resources for writing such a program. I'm looking for info on generating raw sound waves, how to output them into a usable form (playing over speakers), as well as general theory on the topic. Thanks guys.


Solution

    1. This problem is basically about mapping functions to arrays of numbers. A language that supports first-class functions would come in really handy here.

    2. Check out http://www.harmony-central.com/Computer/Programming and http://www.developer.com/java/other/article.php/3071021 for some Java-related info.

    3. If you don't know the basic concepts of encoding sound data, then read http://en.wikipedia.org/wiki/Sampling_rate

    4. The canonical WAVE format is very simple, see http://www.lightlink.com/tjweber/StripWav/Canon.html. A header (first 44 bytes) + the wave-data. You don't need any library to implement that.

    In C/C++, the corresponding data structure would look something like this:

    typedef struct _WAVstruct
    {
        char headertag[4];
        unsigned int remnantlength;
        char fileid[4];
    
        char fmtchunktag[4];
        unsigned int fmtlength;
        unsigned short fmttag;
        unsigned short channels;
        unsigned int samplerate;
        unsigned int bypse;
        unsigned short ba;
        unsigned short bipsa;
    
        char datatag[4];
        unsigned int datalength;
    
        void* data; //<--- that's where the raw sound-data goes
    }* WAVstruct;
    

    I'm not sure about Java. I guess you'll have to substitute "struct" with "class" and "void* data" with "char[] data" or "short[] data" or "int[] data", corresponding to the number of bits per sample, as defined in the field bipsa.

    To fill it with data, you would use something like that in C/C++:

    int data2WAVstruct(unsigned short channels, unsigned short bipsa, unsigned int samplerate, unsigned int datalength, void* data, WAVstruct result)
    {
        result->headertag[0] = 'R';
        result->headertag[1] = 'I';
        result->headertag[2] = 'F';
        result->headertag[3] = 'F';
        result->remnantlength = 44 + datalength - 8;
        result->fileid[0] = 'W';
        result->fileid[1] = 'A';
        result->fileid[2] = 'V';
        result->fileid[3] = 'E';
    
        result->fmtchunktag[0] = 'f';
        result->fmtchunktag[1] = 'm'; 
        result->fmtchunktag[2] = 't';
        result->fmtchunktag[3] = ' ';
        result->fmtlength = 0x00000010;
        result->fmttag = 1;
        result->channels = channels;
        result->samplerate = samplerate;
        result->bipsa = bipsa;
        result->ba = channels*bipsa / 8;
        result->bypse = samplerate*result->ba;
    
        result->datatag[0] = 'd';
        result->datatag[1] = 'a';
        result->datatag[2] = 't';
        result->datatag[3] = 'a';
        result->datalength = datalength;
    
        result->data = data; // <--- that's were the data comes in
    
        return 0; // an error code, not implemented, yet ...; in Java: return result
    }
    

    Again, I'm not sure about Java but the conversion should be straightforward if you convert the void-pointer to an array corresponding to the bitrate.

    Then simply write the entire structure to a file to get a playable wave file.