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

1.1       root        1: /*
1.1.1.4   root        2:   Hatari - wavFormat.c
                      3: 
1.1.1.13! root        4:   This file is distributed under the GNU General Public License, version 2
        !             5:   or at 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.