Recording: Add AIFF recording to SWCODEC. Note: AIFF playback chokes on sample rates other than 44.1kHz whether recorded or created and saved with an external program. Recorded files will still open in an external editor however.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11583 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/codecs/Makefile b/apps/codecs/Makefile
index 12235b4..38723b7 100644
--- a/apps/codecs/Makefile
+++ b/apps/codecs/Makefile
@@ -61,6 +61,7 @@
 $(OBJDIR)/alac.elf : $(OBJDIR)/alac.o $(BUILDDIR)/libalac.a $(BUILDDIR)/libm4a.a
 $(OBJDIR)/aac.elf : $(OBJDIR)/aac.o $(BUILDDIR)/libfaad.a $(BUILDDIR)/libm4a.a
 $(OBJDIR)/shorten.elf : $(OBJDIR)/shorten.o $(BUILDDIR)/libffmpegFLAC.a
+$(OBJDIR)/aiff_enc.elf: $(OBJDIR)/aiff_enc.o
 $(OBJDIR)/mp3_enc.elf: $(OBJDIR)/mp3_enc.o
 $(OBJDIR)/wav_enc.elf: $(OBJDIR)/wav_enc.o
 $(OBJDIR)/wavpack_enc.elf: $(OBJDIR)/wavpack_enc.o $(BUILDDIR)/libwavpack.a
diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES
index feadcde..68bb04f 100644
--- a/apps/codecs/SOURCES
+++ b/apps/codecs/SOURCES
@@ -17,6 +17,7 @@
 adx.c
 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
 /* encoders */
+aiff_enc.c
 mp3_enc.c
 wav_enc.c
 wavpack_enc.c
diff --git a/apps/codecs/aiff_enc.c b/apps/codecs/aiff_enc.c
new file mode 100644
index 0000000..50c682f
--- /dev/null
+++ b/apps/codecs/aiff_enc.c
@@ -0,0 +1,408 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2006 Antonius Hellmann
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef SIMULATOR
+
+#include <inttypes.h>
+#include "codeclib.h"
+
+CODEC_ENC_HEADER
+
+#ifdef USE_IRAM
+extern char iramcopy[];
+extern char iramstart[];
+extern char iramend[];
+extern char iedata[];
+extern char iend[];
+#endif
+
+struct aiff_header
+{
+    uint8_t   form_id[4];           /* 00h - 'FORM'                          */
+    uint32_t  form_size;            /* 04h - size of file - 8                */
+    uint8_t   aiff_id[4];           /* 08h - 'AIFF'                          */
+    uint8_t   comm_id[4];           /* 0Ch - 'COMM'                          */
+    int32_t   comm_size;            /* 10h - num_channels through sample_rate
+                                             (18)                            */
+    int16_t   num_channels;         /* 14h - 1=M, 2=S, etc.                  */
+    uint32_t  num_sample_frames;    /* 16h - num samples for each channel    */
+    int16_t   sample_size;          /* 1ah - 1-32 bits per sample            */
+    uint8_t   sample_rate[10];      /* 1ch - IEEE 754 80-bit floating point  */
+    uint8_t   ssnd_id[4];           /* 26h - "SSND"                          */
+    int32_t   ssnd_size;            /* 2ah - size of chunk from offset to
+                                             end of pcm data                 */
+    uint32_t  offset;               /* 2eh - data offset from end of header  */
+    uint32_t  block_size;           /* 32h - pcm data alignment              */
+                                    /* 36h */
+} __attribute__((packed));
+
+#define PCM_DEPTH_BYTES             2
+#define PCM_DEPTH_BITS             16
+#define PCM_SAMP_PER_CHUNK       2048
+#define PCM_CHUNK_SIZE          (PCM_SAMP_PER_CHUNK*4)
+
+/* Template headers */
+struct aiff_header aiff_header =
+{
+    { 'F', 'O', 'R', 'M' },             /* form_id               */
+    0,                                  /* form_size         (*) */
+    { 'A', 'I', 'F', 'F' },             /* aiff_id               */
+    { 'C', 'O', 'M', 'M' },             /* comm_id               */
+    H_TO_BE32(18),                      /* comm_size             */
+    0,                                  /* num_channels      (*) */
+    0,                                  /* num_sample_frames (*) */
+    H_TO_BE32(PCM_DEPTH_BITS),          /* sample_size           */
+    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },   /* sample_rate       (*) */
+    { 'S', 'S', 'N', 'D' },             /* ssnd_id               */
+    0,                                  /* ssnd_size         (*) */
+    H_TO_BE32(0),                       /* offset                */
+    H_TO_BE32(0),                       /* block_size            */
+};
+
+/* (*) updated when finalizing file */
+
+static struct codec_api *ci;
+static int    num_channels;
+uint32_t      sample_rate;
+uint32_t      enc_size;
+
+/* convert unsigned 32 bit value to 80-bit floating point number */
+static void uint32_to_ieee754_extended(uint8_t f[10], uint32_t l) ICODE_ATTR;
+static void uint32_to_ieee754_extended(uint8_t f[10], uint32_t l)
+{
+    int32_t exp;
+
+    ci->memset(f, 0, 10);
+
+    if (l == 0)
+        return;
+
+    for (exp = 30; (l & (1ul << 31)) == 0; exp--)
+        l <<= 1;
+
+    /* sign always zero - bit 79 */
+    /* exponent is 0-31 (normalized: 31 - shift + 16383) - bits 64-78 */
+    f[0] = 0x40;
+    f[1] = (uint8_t)exp;
+    /* mantissa is value left justified with most significant non-zero
+       bit stored in bit 63 - bits 0-63 */
+    *(uint32_t *)&f[2] = htobe32(l);
+} /* long_to_ieee754_extended */
+
+/* called version often - inline */
+static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR;
+static inline bool is_file_data_ok(struct enc_file_event_data *data)
+{
+    return data->rec_file >= 0 && (long)data->chunk->flags >= 0;
+} /* is_file_data_ok */
+
+/* called version often - inline */
+static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR;
+static inline bool on_write_chunk(struct enc_file_event_data *data)
+{
+    if (!is_file_data_ok(data))
+        return false;
+
+    if (data->chunk->enc_data == NULL)
+    {
+#ifdef ROCKBOX_HAS_LOGF
+        ci->logf("aiff enc: NULL data");
+#endif
+        return true;
+    }
+
+    if (ci->write(data->rec_file, data->chunk->enc_data,
+                  data->chunk->enc_size) != (ssize_t)data->chunk->enc_size)
+        return false;
+
+    data->num_pcm_samples += data->chunk->num_pcm;
+    return true;
+} /* on_write_chunk */
+
+static bool on_start_file(struct enc_file_event_data *data)
+{
+    if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0')
+        return false;
+
+    data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC);
+
+    if (data->rec_file < 0)
+        return false;
+
+    /* reset sample count */
+    data->num_pcm_samples = 0;
+
+    /* write template headers */
+    if (ci->write(data->rec_file, &aiff_header, sizeof (aiff_header))
+            != sizeof (aiff_header))
+    {
+        return false;
+    }
+
+    data->new_enc_size += sizeof(aiff_header);
+    return true;
+} /* on_start_file */
+
+static bool on_end_file(struct enc_file_event_data *data)
+{
+    /* update template headers */
+    struct aiff_header hdr;
+    uint32_t data_size;
+
+    if (!is_file_data_ok(data))
+        return false;
+
+    if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 ||
+        ci->read(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr))
+    {
+        return false;
+    }
+
+    data_size = data->num_pcm_samples*num_channels*PCM_DEPTH_BYTES;
+
+    /* 'FORM' chunk */
+    hdr.form_size         = data_size + sizeof (hdr) - 8;
+
+    /* 'COMM' chunk */
+    hdr.num_channels      = htobe16(num_channels);
+    hdr.num_sample_frames = htobe32(data->num_pcm_samples*num_channels/2);
+    uint32_to_ieee754_extended(hdr.sample_rate, sample_rate);
+
+    /* 'SSND' chunk */
+    hdr.ssnd_size         = htobe32(data_size + 8);
+
+    if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 ||
+        ci->write(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr))
+    {
+        return false;
+    }
+
+    ci->fsync(data->rec_file);
+    ci->close(data->rec_file);
+    data->rec_file = -1;
+
+    return true;
+} /* on_end_file */
+
+static void enc_events_callback(enum enc_events event, void *data) ICODE_ATTR;
+static void enc_events_callback(enum enc_events event, void *data)
+{
+    if (event == ENC_WRITE_CHUNK)
+    {
+        if (on_write_chunk((struct enc_file_event_data *)data))
+            return;
+    }
+    else if (event == ENC_START_FILE)
+    {
+        if (on_start_file((struct enc_file_event_data *)data))
+            return;
+    }
+    else if (event == ENC_END_FILE)
+    {
+        if (on_end_file((struct enc_file_event_data *)data))
+            return;
+    }
+    else
+    {
+        return;
+    }
+
+    ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR;
+} /* enc_events_callback */
+
+/* convert native pcm samples to aiff format samples */
+static void chunk_to_aiff_format(uint32_t *src, uint32_t *dst) ICODE_ATTR;
+static void chunk_to_aiff_format(uint32_t *src, uint32_t *dst)
+{
+    if (num_channels == 1)
+    {
+        /* On big endian:
+         *  |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
+         *  |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
+         *  |MMMMMMMMmmmmmmmm|MMMMMMMMmmmmmmmm|
+         *
+         * On little endian:
+         *  |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR|
+         *  |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
+         *  |MMMMMMMMmmmmmmmm|MMMMMMMMmmmmmmmm|
+         */
+        uint32_t *src_end = src + PCM_SAMP_PER_CHUNK;
+
+        inline void to_mono(uint32_t **src, uint32_t **dst)
+        {
+            int32_t lr1, lr2;
+
+            lr1 = *(*src)++;
+            lr1 = ((int16_t)lr1 + (lr1 >> 16)) >> 1;
+
+            lr2 = *(*src)++;
+            lr2 = ((int16_t)lr2 + (lr2 >> 16)) >> 1;
+            *(*dst)++ = swap_odd_even_le32((lr1 << 16) | (uint16_t)lr2);
+        } /* to_mono */
+
+        do
+        {
+            to_mono(&src, &dst);
+            to_mono(&src, &dst);
+            to_mono(&src, &dst);
+            to_mono(&src, &dst);
+            to_mono(&src, &dst);
+            to_mono(&src, &dst);
+            to_mono(&src, &dst);
+            to_mono(&src, &dst);
+        }
+        while (src < src_end);
+    }
+    else
+    {
+#ifdef ROCKBOX_BIG_ENDIAN
+        /*  |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| =>
+         *  |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
+         */
+        ci->memcpy(dst, src, PCM_CHUNK_SIZE);
+#else
+        /*  |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| =>
+         *  |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr|
+         */
+        uint32_t *src_end = src + PCM_SAMP_PER_CHUNK;
+
+        do
+        {
+            *dst++ = swap_odd_even32(*src++);
+            *dst++ = swap_odd_even32(*src++);
+            *dst++ = swap_odd_even32(*src++);
+            *dst++ = swap_odd_even32(*src++);
+            *dst++ = swap_odd_even32(*src++);
+            *dst++ = swap_odd_even32(*src++);
+            *dst++ = swap_odd_even32(*src++);
+            *dst++ = swap_odd_even32(*src++);
+        }
+        while (src < src_end);
+#endif
+    }
+} /* chunk_to_aiff_format */
+
+static bool init_encoder(void)
+{
+    struct enc_inputs     inputs;
+    struct enc_parameters params;
+
+    if (ci->enc_get_inputs         == NULL ||
+        ci->enc_set_parameters     == NULL ||
+        ci->enc_get_chunk          == NULL ||
+        ci->enc_finish_chunk       == NULL ||
+        ci->enc_pcm_buf_near_empty == NULL ||
+        ci->enc_get_pcm_data       == NULL )
+        return false;
+
+    ci->enc_get_inputs(&inputs);
+
+    if (inputs.config->afmt != AFMT_AIFF)
+        return false;
+
+    sample_rate  = inputs.sample_rate;
+    num_channels = inputs.num_channels;
+
+    /* configure the buffer system */
+    params.afmt            = AFMT_AIFF;
+    enc_size               = PCM_CHUNK_SIZE*inputs.num_channels / 2;
+    params.chunk_size      = enc_size;
+    params.enc_sample_rate = sample_rate;
+    params.reserve_bytes   = 0;
+    params.events_callback = enc_events_callback;
+    ci->enc_set_parameters(&params);
+
+    return true;
+} /* init_encoder */
+
+/* main codec entry point */
+enum codec_status codec_start(struct codec_api* api)
+{
+    bool cpu_boosted;
+
+    ci = api; /* copy to global api pointer */
+
+#ifdef USE_IRAM
+    ci->memcpy(iramstart, iramcopy, iramend - iramstart);
+    ci->memset(iedata, 0, iend - iedata);
+#endif
+
+    if (!init_encoder())
+    {
+        ci->enc_codec_loaded = -1;
+        return CODEC_ERROR;
+    }
+
+    /* main application waits for this flag during encoder loading */
+    ci->enc_codec_loaded = 1;
+
+    ci->cpu_boost(true);
+    cpu_boosted = true;
+
+    /* main encoding loop */
+    while(!ci->stop_codec)
+    {
+        uint32_t *src;
+
+        while ((src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL)
+        {
+            struct enc_chunk_hdr *chunk;
+
+            if (ci->stop_codec)
+                break;
+
+            if (!cpu_boosted && ci->enc_pcm_buf_near_empty() == 0)
+            {
+                ci->cpu_boost(true);
+                cpu_boosted = true;
+            }
+
+            chunk           = ci->enc_get_chunk();
+            chunk->enc_size = enc_size;
+            chunk->num_pcm  = PCM_SAMP_PER_CHUNK;
+            chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
+
+            chunk_to_aiff_format(src, (uint32_t *)chunk->enc_data);
+
+            ci->enc_finish_chunk();
+            ci->yield();
+        }
+
+        if (cpu_boosted && ci->enc_pcm_buf_near_empty() != 0)
+        {
+            ci->cpu_boost(false);
+            cpu_boosted = false;
+        }
+
+        ci->yield();
+    }
+
+    if (cpu_boosted) /* set initial boost state */
+        ci->cpu_boost(false);
+
+    /* reset parameters to initial state */
+    ci->enc_set_parameters(NULL);
+ 
+    /* main application waits for this flag during encoder removing */
+    ci->enc_codec_loaded = 0;
+
+    return CODEC_OK;
+} /* codec_start */
+
+#endif /* ndef SIMULATOR */
diff --git a/apps/enc_config.c b/apps/enc_config.c
index 384e679..2d2abae 100644
--- a/apps/enc_config.c
+++ b/apps/enc_config.c
@@ -49,6 +49,8 @@
 /** Function definitions for each codec - add these to enc_data
     list following the definitions **/
 
+/** aiff_enc.codec **/
+
 /** mp3_enc.codec **/
 /* mp3_enc: return encoder capabilities */
 static void mp3_enc_get_caps(const struct encoder_config *cfg,
@@ -209,6 +211,13 @@
     bool   (*menu)(struct encoder_config *);
 } enc_data[REC_NUM_FORMATS] =
 {
+    /* aiff_enc.codec */
+    [REC_FORMAT_AIFF] = {
+        NULL,
+        NULL,
+        NULL,
+        enc_no_config_menu,
+    },
     /* mp3_enc.codec */
     [REC_FORMAT_MPA_L3] = {
         mp3_enc_get_caps,
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index f3603e9..a306138 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -10266,3 +10266,18 @@
     *: ""
   </voice>
 </phrase>
+<phrase>
+  id: LANG_AFMT_AIFF
+  desc: audio format description
+  user:
+  <source>
+    *: "AIFF"
+  </source>
+  <dest>
+    *: "AIFF"
+  </dest>
+  <voice>
+    *: "AIFF"
+  </voice>
+</phrase>
+
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c
index ba22bb5..4e1496e 100644
--- a/apps/recorder/icons.c
+++ b/apps/recorder/icons.c
@@ -121,6 +121,9 @@
     [0 ... Format_18x8Last-1] =   /* auto-blank */
         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ___ */
+    [Format_18x8_AIFF] =
+        {0x00, 0x3c, 0x0a, 0x0a, 0x0a, 0x3c, 0x00, 0x3e, 0x00,
+         0x3e, 0x0a, 0x02, 0x02, 0x00, 0x3e, 0x0a, 0x02, 0x02}, /* AIFF */
     [Format_18x8_MPA_L3] =
         {0x00, 0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* M__ */
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h
index 1e7b8db..5aec073 100644
--- a/apps/recorder/icons.h
+++ b/apps/recorder/icons.h
@@ -111,6 +111,7 @@
 #ifdef ID3_H
 /* This enum is redundant but sort of in keeping with the style */
 enum rec_format_18x8 {
+    Format_18x8_AIFF    = REC_FORMAT_AIFF,
     Format_18x8_MPA_L3  = REC_FORMAT_MPA_L3,
     Format_18x8_WAVPACK = REC_FORMAT_WAVPACK,
     Format_18x8_PCM_WAV = REC_FORMAT_PCM_WAV,
diff --git a/apps/settings.c b/apps/settings.c
index fc0e524..94d456f 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -533,6 +533,8 @@
     {REC_FORMAT_CFG_NUM_BITS ,S_O(rec_format), REC_FORMAT_DEFAULT,
         "rec format", REC_FORMAT_CFG_VAL_LIST },
     /** Encoder settings start - keep these together **/
+    /* aiff_enc */
+    /* (no settings yet) */
     /* mp3_enc */
     {5,S_O(mp3_enc_config.bitrate), MP3_ENC_BITRATE_CFG_DEFAULT,
         "mp3_enc bitrate", MP3_ENC_BITRATE_CFG_VALUE_LIST },
diff --git a/apps/settings.h b/apps/settings.h
index c0c6a94..cb57c1a 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -528,6 +528,7 @@
     struct mp3_enc_config     mp3_enc_config;
 #if 0 /* These currently contain no members but their places in line
          should be held */
+    struct aiff_enc_config    aiff_enc_config;
     struct wav_enc_config     wav_enc_config;
     struct wavpack_enc_config wavpack_enc_config;
 #endif
diff --git a/apps/sound_menu.c b/apps/sound_menu.c
index bcc9163..52a6c3b 100644
--- a/apps/sound_menu.c
+++ b/apps/sound_menu.c
@@ -363,6 +363,7 @@
 static bool recformat(void)
 {
     static const struct opt_items names[REC_NUM_FORMATS] = {
+        [REC_FORMAT_AIFF]    = { STR(LANG_AFMT_AIFF)    },
         [REC_FORMAT_MPA_L3]  = { STR(LANG_AFMT_MPA_L3)  },
         [REC_FORMAT_WAVPACK] = { STR(LANG_AFMT_WAVPACK) },
         [REC_FORMAT_PCM_WAV] = { STR(LANG_AFMT_PCM_WAV) },
diff --git a/firmware/enc_base.c b/firmware/enc_base.c
index e346064..6cd4211 100644
--- a/firmware/enc_base.c
+++ b/firmware/enc_base.c
@@ -19,6 +19,8 @@
 #include "config.h"
 #include "audio.h"
 
+/** aiff_enc.codec **/
+
 /** mp3_enc.codec **/
 
 /* These are in descending order rather than in MPEG frequency index
diff --git a/firmware/export/enc_base.h b/firmware/export/enc_base.h
index 85101ac..1be796e 100644
--- a/firmware/export/enc_base.h
+++ b/firmware/export/enc_base.h
@@ -24,6 +24,14 @@
 
 /** encoder config structures **/
 
+/** aiff_enc.codec **/
+struct aiff_enc_config
+{
+#if 0
+    unsigned long sample_depth;
+#endif
+};
+
 /** mp3_enc.codec **/
 #define MP3_BITR_CAP_8      (1 << 0)
 #define MP3_BITR_CAP_16     (1 << 1)
diff --git a/firmware/export/id3.h b/firmware/export/id3.h
index 3d24e20..b099aed 100644
--- a/firmware/export/id3.h
+++ b/firmware/export/id3.h
@@ -78,6 +78,7 @@
     /* start formats */
 
     REC_FORMAT_PCM_WAV,
+    REC_FORMAT_AIFF,
     REC_FORMAT_WAVPACK,
     REC_FORMAT_MPA_L3,
 
@@ -93,7 +94,7 @@
     REC_FORMAT_CFG_NUM_BITS = 2
 };
 
-#define REC_FORMAT_CFG_VAL_LIST "wave,wvpk,mpa3" 
+#define REC_FORMAT_CFG_VAL_LIST "aiff,wave,wvpk,mpa3" 
 
 /* get REC_FORMAT_* corresponding AFMT_* */
 extern const int rec_format_afmt[REC_NUM_FORMATS];
diff --git a/firmware/id3.c b/firmware/id3.c
index 90b5b3b..74cea7f 100644
--- a/firmware/id3.c
+++ b/firmware/id3.c
@@ -64,7 +64,7 @@
 #if CONFIG_CODEC == SWCODEC
     /* Audio Interchange File Format */
     [AFMT_AIFF] =
-        AFMT_ENTRY("AIFF", "aiff",    NULL,          "aiff\0aif\0"),
+        AFMT_ENTRY("AIFF", "aiff",    "aiff_enc",    "aiff\0aif\0"),
     /* Uncompressed PCM in a WAV file */
     [AFMT_PCM_WAV] =
         AFMT_ENTRY("WAV",  "wav",     "wav_enc",     "wav\0"      ),
@@ -108,6 +108,7 @@
     /* give AFMT_UNKNOWN by default */
     [0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN,
     /* add new entries below this line */
+    [REC_FORMAT_AIFF]    = AFMT_AIFF,
     [REC_FORMAT_MPA_L3]  = AFMT_MPA_L3,
     [REC_FORMAT_WAVPACK] = AFMT_WAVPACK,
     [REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV,
@@ -119,6 +120,7 @@
     /* give -1 by default */
     [0 ... AFMT_NUM_CODECS-1] = -1,
     /* add new entries below this line */
+    [AFMT_AIFF]    = REC_FORMAT_AIFF,
     [AFMT_MPA_L3]  = REC_FORMAT_MPA_L3,
     [AFMT_WAVPACK] = REC_FORMAT_WAVPACK,
     [AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV,