applied mp3 patch from Joel Yliluoma.
authorkramm <kramm>
Wed, 12 Oct 2005 18:27:22 +0000 (18:27 +0000)
committerkramm <kramm>
Wed, 12 Oct 2005 18:27:22 +0000 (18:27 +0000)
lib/modules/swfsound.c
lib/mp3.c [new file with mode: 0644]
lib/mp3.h [new file with mode: 0644]
lib/rfxswf.h
src/swfc.c

index 10a737a..8edec35 100644 (file)
@@ -312,3 +312,25 @@ void swf_SetSoundInfo(TAG*tag, SOUNDINFO*info)
 }
 
 
+void swf_SetSoundDefineMP3(TAG*tag, U8* data, unsigned length,
+                           unsigned SampRate,
+                           unsigned Channels,
+                           unsigned NumFrames)
+{
+    U8 compression = 2; // 0 = raw, 1 = ADPCM, 2 = mp3, 3 = raw le, 6 = nellymoser
+    U8 rate;     // 0 = 5.5 Khz, 1 = 11 Khz, 2 = 22 Khz, 3 = 44 Khz
+    U8 size = 1; // 0 = 8 bit, 1 = 16 bit
+    U8 type = Channels==2; // 0=mono, 1=stereo
+    
+    rate = (SampRate >= 40000) ? 3
+         : (SampRate >= 19000) ? 2
+         : (SampRate >= 8000) ? 1
+         : 0;
+
+    swf_SetU8(tag,(compression<<4)|(rate<<2)|(size<<1)|type);
+
+    swf_SetU32(tag, NumFrames * 576);
+
+    swf_SetU16(tag, 0); //delayseek
+    swf_SetBlock(tag, data, length);
+}
diff --git a/lib/mp3.c b/lib/mp3.c
new file mode 100644 (file)
index 0000000..8bb7ee7
--- /dev/null
+++ b/lib/mp3.c
@@ -0,0 +1,204 @@
+/* mp3.c
+   Routines for handling .mp3 files
+
+   Part of the swftools package.
+   
+   Copyright (c) 2005 Joel Yliluoma <bisqwit@iki.fi>
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mp3.h"
+
+struct MP3Frame
+{
+    unsigned bitrate;
+    unsigned samprate;
+    unsigned chanmode;
+    unsigned framesize;
+    unsigned char* data;
+    struct MP3Frame* next;
+};
+
+//                                    0          4           8               C
+static const unsigned BR_mpeg1[16] = {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0};
+static const unsigned BR_mpeg2[16] = {0,8, 16,24,32,40,48,56, 64, 80, 96,112,128,144,160,0};
+static const unsigned BR_reserved[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
+static const unsigned*const BR[4] = {BR_mpeg2, BR_reserved, BR_mpeg2, BR_mpeg1};
+
+static const unsigned SR_mpeg1[4] = {44100,48000,32000,0};
+static const unsigned SR_mpeg2[4] = {22050,24000,16000,0};
+static const unsigned SR_mpeg25[4] = {11025,12000,8000,0};
+static const unsigned SR_reserved[4] = {0,0,0,0};
+static const unsigned*const SR[4] = {SR_mpeg25, SR_reserved, SR_mpeg2, SR_mpeg1};
+
+int mp3_read(struct MP3*mp3, char* filename)
+{
+    struct MP3Frame* root = 0;
+    struct MP3Frame** cur = &root;
+    
+    unsigned totalsize      = 0;
+    unsigned first_samprate = 0;
+    unsigned nframes = 0;
+    int first_chanmode = -1;
+
+    FILE*fi = fopen(filename, "rb");
+    if(!fi) return 0;
+    
+    for(;;)
+    {
+        unsigned char FrameBuf[2048];
+        unsigned char* hdr = FrameBuf;
+        unsigned char* data = FrameBuf+4;
+        unsigned char* frdata;
+
+        unsigned char mpegver;
+        unsigned padding;
+        unsigned bitrate;
+        unsigned samprate;
+        unsigned framesize;
+        int chanmode;
+
+        if(fread(hdr,1,4,fi) < 4) break;
+        if(hdr[0] != 0xFF
+        || (hdr[1] & 0xE0) != 0xE0)
+        {
+            fprintf(stderr, "readMP3: invalid header %02X %02X %02X %02X\n",
+                hdr[0],hdr[1],hdr[2],hdr[3]);
+            break;
+        }
+        
+        mpegver = (hdr[1] >> 3) & 0x03;
+        
+        bitrate  = BR[mpegver][ (hdr[2] >> 4) & 0x0F ] * 1000;
+        samprate = SR[mpegver][ (hdr[2] >> 2) & 0x03 ];
+        chanmode = (hdr[3] >> 6) & 0x03;
+        
+        padding = (hdr[2] & 2) ? 1 : 0;
+        
+        if(!bitrate || !samprate)
+        {
+            /* Invalid frame */
+            /*break;*/
+        }
+        if(!first_samprate) first_samprate = samprate;
+        else if(first_samprate != samprate)
+        {
+            /* Sampling rate changed?!? */
+            fprintf(stderr, "readMP3: sampling rate changed?\n");
+            /*break;*/
+        }
+        if(first_chanmode<0) first_chanmode = chanmode;
+        else if(first_chanmode != chanmode)
+        {
+            /* Channel mode changed?!? */
+            fprintf(stderr, "readMP3: chanmode changed?\n");
+            /*break;*/
+        }
+        
+        framesize = ((mpegver == 3 ? 144 : 72) * bitrate) / samprate + padding;
+        
+/*
+        fprintf(stderr, "%02X %02X %02X %02X - bitrate=%u,samprate=%u,chanmode=%u,padding=%u,framesize=%u\n",
+            hdr[0],hdr[1],hdr[2],hdr[3],bitrate,samprate,chanmode,padding,framesize);
+*/
+        if(framesize > sizeof(FrameBuf)) break;
+        if(fread(data, 1, framesize - 4, fi) < framesize-4)
+        {
+            fprintf(stderr, "readMP3: short read at frame %u\n", nframes);
+            break;
+        }
+        
+        if(!bitrate || !samprate) continue; 
+        
+        frdata = (unsigned char*)malloc(framesize);
+        if(!frdata)
+        {
+            fprintf(stderr, "readMP3: malloc failed\n");
+            break;
+        }
+        
+        *cur = (struct MP3Frame*)malloc(sizeof(*root));
+        if(!*cur)
+        {
+            fprintf(stderr, "readMP3: malloc failed\n");
+            free(frdata);
+            break;
+        }
+        
+        (*cur)->next = 0;
+        (*cur)->bitrate = bitrate;
+        (*cur)->samprate = samprate;
+        (*cur)->chanmode = chanmode;
+        (*cur)->framesize = framesize;
+        (*cur)->data = frdata;
+        
+        memcpy(frdata, FrameBuf, framesize);
+        cur = &(*cur)->next;
+        
+        totalsize += framesize;
+        ++nframes;
+    }
+    if(!root)
+    {
+        fprintf(stderr, "readMP3: not a MP3 file\n");
+        return 0;
+    }
+    
+    /*
+    fprintf(stderr, "readMP3: read %u frames (%u bytes)\n", nframes, totalsize);
+    */
+
+    mp3->SampRate = first_samprate;
+    mp3->Channels = first_chanmode == 3 ? 1 : 2;
+    mp3->NumFrames = nframes;
+    mp3->size = totalsize;
+    mp3->data = (unsigned char*)malloc(mp3->size);
+    if(mp3->data)
+    {
+        unsigned pos=0;
+        struct MP3Frame* it;
+        for(it=root; it; it=it->next)
+        {
+            memcpy(mp3->data + pos, it->data, it->framesize);
+            pos += it->framesize;
+        }
+    }
+    else
+    {
+        fprintf(stderr, "readMP3: malloc failed\n");
+    }
+    
+    while(root)
+    {
+        struct MP3Frame* next = root->next;
+        free(root->data);
+        free(root);
+        root = next;
+    }
+    
+    return mp3->data != NULL;
+}
+
+void mp3_clear(struct MP3*mp3)
+{
+    free(mp3->data);
+    mp3->data = 0;
+}
+
+
diff --git a/lib/mp3.h b/lib/mp3.h
new file mode 100644 (file)
index 0000000..b76f3ce
--- /dev/null
+++ b/lib/mp3.h
@@ -0,0 +1,19 @@
+/* mp3.h
+   Header file for mp3.c
+
+   Part of the swftools package.
+   
+   Copyright (c) 2005 Joel Yliluoma <bisqwit@iki.fi>
+
+   This file is distributed under the GPL, see file COPYING for details */
+
+struct MP3 {
+    unsigned short  SampRate;
+    unsigned char   Channels;
+    unsigned int    NumFrames;
+    unsigned char*  data;
+    unsigned long   size;
+};
+
+int mp3_read(struct MP3*mp3, char* filename);
+void mp3_clear(struct MP3*mp3);
index 6fd2f3f..88d33e4 100644 (file)
@@ -746,6 +746,10 @@ TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quali
 void swf_SetSoundStreamHead(TAG*tag, int avgnumsamples);
 void swf_SetSoundStreamBlock(TAG*tag, S16*samples, int seek, char first); /* expects 2304 samples */
 void swf_SetSoundDefine(TAG*tag, S16*samples, int num);
+void swf_SetSoundDefineMP3(TAG*tag, U8* data, unsigned length,
+                           unsigned SampRate,
+                           unsigned Channels,
+                           unsigned NumFrames);
 void swf_SetSoundInfo(TAG*tag, SOUNDINFO*info);
 
 // swftools.c
index 009a215..301f542 100644 (file)
@@ -32,8 +32,9 @@
 #include "../lib/log.h"
 #include "../lib/args.h"
 #include "../lib/q.h"
+#include "../lib/mp3.h"
+#include "../lib/wav.h"
 #include "parser.h"
-#include "wav.h"
 #include "../lib/png.h"
 
 //#define DEBUG
@@ -1201,17 +1202,15 @@ typedef struct _sound_t
 void s_sound(char*name, char*filename)
 {
     struct WAV wav, wav2;
+    struct MP3 mp3;
     sound_t* sound;
-    U16*samples;
-    int numsamples;
-    int t;
-    int blocksize = 1152;
+    U16*samples = NULL;
+    unsigned numsamples;
+    unsigned blocksize = 1152;
+    int is_mp3 = 0;
 
-    if(!readWAV(filename, &wav)) {
-       warning("Couldn't read wav file \"%s\"", filename);
-       samples = 0;
-       numsamples = 0;
-    } else {
+    if(readWAV(filename, &wav)) {
+        int t;
        convertWAV2mono(&wav, &wav2, 44100);
        samples = (U16*)wav2.data;
        numsamples = wav2.size/2;
@@ -1222,6 +1221,16 @@ void s_sound(char*name, char*filename)
            samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
        }
 #endif
+    } else if(mp3_read(&mp3, filename)) {
+        fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
+        blocksize = 1;
+        is_mp3 = 1;
+    }
+    else
+    {
+       warning("Couldn't read WAV/MP3 file \"%s\"", filename);
+       samples = 0;
+       numsamples = 0;
     }
     
     if(numsamples%blocksize != 0)
@@ -1240,7 +1249,19 @@ void s_sound(char*name, char*filename)
 
     tag = swf_InsertTag(tag, ST_DEFINESOUND);
     swf_SetU16(tag, id); //id
-    swf_SetSoundDefine(tag, samples, numsamples);
+    if(is_mp3)
+    {
+        swf_SetSoundDefineMP3(
+                tag, mp3.data, mp3.size,
+                mp3.SampRate,
+                mp3.Channels,
+                mp3.NumFrames);
+       mp3_clear(&mp3);
+    }
+    else
+    {
+        swf_SetSoundDefine(tag, samples, numsamples);
+    }
    
     sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
     sound->tag = tag;