Annotation of hatari/src/wavFormat.c, revision 1.1.1.12

1.1       root        1: /*
1.1.1.4   root        2:   Hatari - wavFormat.c
                      3: 
                      4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
1.1       root        6: 
                      7:   WAV File output
                      8: 
1.1.1.6   root        9:   As well as YM file output we also have output in .WAV format. These .WAV
                     10:   files can then be run through convertors to any other format, such as MP3.
                     11:   We simply save out the WAVE format headers and then write the sample data
                     12:   (at the current rate of playback) as we build it up each frame. When we stop
                     13:   recording we complete the size information in the headers and close up.
1.1       root       14: 
                     15: 
                     16:   RIFF Chunk (12 bytes in length total) Byte Number
                     17:     0 - 3  "RIFF" (ASCII Characters)
                     18:     4 - 7  Total Length Of Package To Follow (Binary, little endian)
                     19:     8 - 12  "WAVE" (ASCII Characters)
                     20: 
                     21:   FORMAT Chunk (24 bytes in length total) Byte Number
                     22:     0 - 3  "fmt_" (ASCII Characters)
                     23:     4 - 7  Length Of FORMAT Chunk (Binary, always 0x10)
                     24:     8 - 9  Always 0x01
                     25:     10 - 11  Channel Numbers (Always 0x01=Mono, 0x02=Stereo)
                     26:     12 - 15  Sample Rate (Binary, in Hz)
                     27:     16 - 19  Bytes Per Second
                     28:     20 - 21  Bytes Per Sample: 1=8 bit Mono, 2=8 bit Stereo or 16 bit Mono, 4=16 bit Stereo
                     29:     22 - 23  Bits Per Sample
                     30: 
                     31:   DATA Chunk Byte Number
                     32:     0 - 3  "data" (ASCII Characters)
                     33:     4 - 7  Length Of Data To Follow
                     34:     8 - end  Data (Samples)
                     35: */
1.1.1.12! root       36: const char WAVFormat_fileid[] = "Hatari wavFormat.c : " __DATE__ " " __TIME__;
1.1       root       37: 
1.1.1.3   root       38: #include <SDL_endian.h>
                     39: 
1.1       root       40: #include "main.h"
                     41: #include "audio.h"
1.1.1.6   root       42: #include "configuration.h"
1.1       root       43: #include "file.h"
1.1.1.6   root       44: #include "log.h"
1.1       root       45: #include "sound.h"
1.1.1.5   root       46: #include "wavFormat.h"
1.1.1.2   root       47: 
1.1       root       48: 
1.1.1.3   root       49: static FILE *WavFileHndl;
                     50: static int nWavOutputBytes;             /* Number of samples bytes saved */
1.1.1.12! root       51: bool bRecordingWav = false;             /* Is a WAV file open and recording? */
        !            52: 
        !            53: 
        !            54: static Uint8 WavHeader[] =
        !            55: {
        !            56:        /* RIFF chunk */
        !            57:        'R', 'I', 'F', 'F',      /* "RIFF" (ASCII Characters) */
        !            58:        0, 0, 0, 0,              /* Total Length Of Package To Follow (patched when file is closed) */
        !            59:        'W', 'A', 'V', 'E',      /* "WAVE" (ASCII Characters) */
        !            60:        /* Format chunk */
        !            61:        'f', 'm', 't', ' ',      /* "fmt_" (ASCII Characters) */
        !            62:        0x10, 0, 0, 0,           /* Length Of FORMAT Chunk (always 0x10) */
        !            63:        0x01, 0,                 /* Always 0x01 */
        !            64:        0x02, 0,                 /* Number of channels (2 for stereo) */
        !            65:        0, 0, 0, 0,              /* Sample rate (patched when file header is written) */
        !            66:        0, 0, 0, 0,              /* Bytes per second (patched when file header is written) */
        !            67:        0x04, 0,                 /* Bytes per sample (4 = 16 bit stereo) */
        !            68:        0x10, 0,                 /* Bits per sample (16 bit) */
        !            69:        /* Data chunk */
        !            70:        'd', 'a', 't', 'a',
        !            71:        0, 0, 0, 0,              /* Length of data to follow (will be patched when file is closed) */
        !            72: };
1.1.1.3   root       73: 
1.1       root       74: 
1.1.1.9   root       75: /**
1.1.1.12! root       76:  * Open WAV output file and write header.
1.1.1.9   root       77:  */
1.1.1.10  root       78: bool WAVFormat_OpenFile(char *pszWavFileName)
1.1       root       79: {
1.1.1.12! root       80: 
        !            81:        Uint32 nSampleFreq, nBytesPerSec;
        !            82: 
        !            83:        bRecordingWav = false;
        !            84:        nWavOutputBytes = 0;
1.1.1.6   root       85: 
                     86:        /* Set frequency (11Khz, 22Khz or 44Khz) */
1.1.1.12! root       87:        nSampleFreq = ConfigureParams.Sound.nPlaybackFreq;
        !            88:        /* multiply by 4 for 16 bit stereo */
        !            89:        nBytesPerSec = nSampleFreq * 4;
1.1.1.6   root       90: 
                     91:        /* Create our file */
                     92:        WavFileHndl = fopen(pszWavFileName, "wb");
1.1.1.12! root       93:        if (!WavFileHndl)
1.1.1.6   root       94:        {
1.1.1.12! root       95:                perror("WAVFormat_OpenFile");
        !            96:                Log_AlertDlg(LOG_ERROR, "WAV recording: Failed to open file!");
        !            97:                return false;
        !            98:        }
1.1.1.6   root       99: 
1.1.1.12! root      100:        /* Patch sample frequency in header structure */
        !           101:        WavHeader[24] = (Uint8)nSampleFreq;
        !           102:        WavHeader[25] = (Uint8)(nSampleFreq >> 8);
        !           103:        WavHeader[26] = (Uint8)(nSampleFreq >> 16);
        !           104:        WavHeader[27] = (Uint8)(nSampleFreq >> 24);
        !           105: 
        !           106:        /* Patch bytes per second in header structure */
        !           107:        WavHeader[28] = (Uint8)nBytesPerSec;
        !           108:        WavHeader[29] = (Uint8)(nBytesPerSec >> 8);
        !           109:        WavHeader[30] = (Uint8)(nBytesPerSec >> 16);
        !           110:        WavHeader[31] = (Uint8)(nBytesPerSec >> 24);
1.1.1.6   root      111: 
1.1.1.12! root      112:        /* Write header to file */
        !           113:        if (fwrite(&WavHeader, sizeof(WavHeader), 1, WavFileHndl) == 1)
        !           114:        {
        !           115:                bRecordingWav = true;
1.1.1.6   root      116:                Log_AlertDlg(LOG_INFO, "WAV sound data recording has been started.");
                    117:        }
                    118:        else
1.1.1.12! root      119:        {
        !           120:                perror("WAVFormat_OpenFile");
        !           121:                Log_AlertDlg(LOG_ERROR, "WAV recording: Failed to write header!");
        !           122:        }
1.1       root      123: 
1.1.1.6   root      124:        /* Ok, or failed? */
                    125:        return bRecordingWav;
1.1       root      126: }
                    127: 
1.1.1.3   root      128: 
1.1.1.9   root      129: /**
1.1.1.12! root      130:  * Write sizes to WAV header, then close the WAV file.
1.1.1.9   root      131:  */
                    132: void WAVFormat_CloseFile(void)
1.1       root      133: {
1.1.1.6   root      134:        if (bRecordingWav)
                    135:        {
                    136:                Uint32 nWavFileBytes;
                    137:                Uint32 nWavLEOutBytes;
                    138: 
1.1.1.12! root      139:                bRecordingWav = false;
        !           140: 
1.1.1.6   root      141:                /* Update headers with sizes */
                    142:                nWavFileBytes = SDL_SwapLE32((12+24+8+nWavOutputBytes)-8);  /* File length, less 8 bytes for 'RIFF' and length */
                    143:                fseek(WavFileHndl, 4, SEEK_SET);                            /* 'Total Length Of Package' element */
1.1.1.12! root      144:                /* Write total length of package in 'RIFF' chunk */
        !           145:                if (fwrite(&nWavFileBytes, sizeof(Uint32), 1, WavFileHndl) != 1)
        !           146:                {
        !           147:                        perror("WAVFormat_CloseFile");
        !           148:                        fclose(WavFileHndl);
        !           149:                        WavFileHndl = NULL;
        !           150:                        return;
        !           151:                }
1.1.1.6   root      152: 
                    153:                fseek(WavFileHndl, 12+24+4, SEEK_SET);                      /* 'Length' element */
                    154:                nWavLEOutBytes = SDL_SwapLE32(nWavOutputBytes);
1.1.1.12! root      155:                /* Write length of data in 'DATA' chunk */
        !           156:                if (fwrite(&nWavLEOutBytes, sizeof(Uint32), 1, WavFileHndl) != 1)
        !           157:                {
        !           158:                        perror("WAVFormat_CloseFile");
        !           159:                }
1.1.1.6   root      160: 
                    161:                /* Close file */
                    162:                fclose(WavFileHndl);
                    163:                WavFileHndl = NULL;
                    164: 
                    165:                /* And inform user */
                    166:                Log_AlertDlg(LOG_INFO, "WAV Sound data recording has been stopped.");
                    167:        }
1.1       root      168: }
                    169: 
1.1.1.3   root      170: 
1.1.1.9   root      171: /**
1.1.1.12! root      172:  * Update WAV file with current samples
1.1.1.9   root      173:  */
1.1.1.10  root      174: void WAVFormat_Update(Sint16 pSamples[][2], int Index, int Length)
1.1       root      175: {
1.1.1.10  root      176:        Sint16 sample[2];
1.1.1.6   root      177:        int i;
1.1.1.3   root      178: 
1.1.1.6   root      179:        if (bRecordingWav)
                    180:        {
                    181:                /* Output, better if did in two section if wrap */
                    182:                for(i = 0; i < Length; i++)
                    183:                {
1.1.1.10  root      184:                        /* Convert sample to little endian */
                    185:                        sample[0] = SDL_SwapLE16(pSamples[(Index+i)%MIXBUFFER_SIZE][0]);
                    186:                        sample[1] = SDL_SwapLE16(pSamples[(Index+i)%MIXBUFFER_SIZE][1]);
1.1.1.6   root      187:                        /* And store */
1.1.1.12! root      188:                        if (fwrite(&sample, sizeof(sample), 1, WavFileHndl) != 1)
        !           189:                        {
        !           190:                                perror("WAVFormat_Update");
        !           191:                                WAVFormat_CloseFile();
        !           192:                                return;
        !           193:                        }
1.1.1.6   root      194:                }
                    195: 
1.1.1.12! root      196:                /* Add samples to wav file length counter */
1.1.1.10  root      197:                nWavOutputBytes += Length * 4;
1.1.1.6   root      198:        }
1.1       root      199: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.