OSDN Git Service

Completed OSS backend
authorAlaskanEmily <emily@alaskanemily.net>
Fri, 18 Oct 2019 01:31:02 +0000 (01:31 +0000)
committerAlaskanEmily <emily@alaskanemily.net>
Fri, 15 Nov 2019 08:19:52 +0000 (00:19 -0800)
src/common/cin_convert_core.inc
src/common/cin_dsp.c
src/common/cin_dsp.h
src/common/cin_mixer_sound.h
src/common/makefile
src/oss/cin_oss.c
src/oss/cin_oss_driver.c
src/oss/cin_oss_sound.c
src/oss/makefile

index 75e59f7..718805b 100644 (file)
     CIN_DSP_CONVERT_SAMPLE_INT_TO_INT(COMMON_TYPE, OUT_TYPE, X)
 #endif
 
-static void CIN_DSP_CONVERT_NAME (
+/* Used in the stereo to mono specialization. */
+#define CIN_DSP_STEREO_TO_MONO(IN_PTR, COMMON_VALUE, DEST_PTR) do{ \
+        const IN_TYPE *const STM_in_ptr = (IN_PTR); \
+        const IN_TYPE STM_in_sample0 = in[0]; \
+        const IN_TYPE STM_in_sample1 = in[1]; \
+        const COMMON_TYPE STM_common_sample0 = \
+            CIN_DSP_CONVERT_SAMPLE_IN_TO_COMMON(STM_in_sample0); \
+        const COMMON_TYPE STM_common_sample1 = \
+            CIN_DSP_CONVERT_SAMPLE_IN_TO_COMMON(STM_in_sample1); \
+        const COMMON_TYPE STM_common_value = (COMMON_VALUE) = \
+            (STM_common_sample0 / (COMMON_TYPE)2) + \
+            (STM_common_sample1 / (COMMON_TYPE)2); \
+        (void)sizeof((COMMON_VALUE)); \
+        (DEST_PTR)[0] = \
+            CIN_DSP_CONVERT_SAMPLE_COMMON_TO_OUT(STM_common_value); \
+    } while(0)
+    
+
+static unsigned CIN_DSP_CONVERT_NAME (
     const unsigned num_in_frames,
     const IN_TYPE *in,
     OUT_TYPE *out,
@@ -45,10 +63,14 @@ static void CIN_DSP_CONVERT_NAME (
     const ldiv_t rate = ldiv(out_sample_rate, in_sample_rate);
     int at = 0;
     unsigned i, channel;
+    /* Used for the return value */
+    const unsigned char *const original_out = (unsigned char*)out;
+    
+    unsigned out_frames = 0;
     
     for(i = 0; i < num_in_frames; i++){
-        unsigned out_frames = 0;
         
+        out_frames = 0;
         at -= rate.rem;
         if(at < 0){
             at += in_sample_rate;
@@ -61,7 +83,14 @@ static void CIN_DSP_CONVERT_NAME (
         out_frames += rate.quot;
         if(out_frames != 0){
             
-            {
+            /* Special case for stereo -> mono. Ideally this would NOT be
+             * checked inside the loop :(
+             */
+            if(in_num_channels == 2 && out_num_channels == 1){
+                COMMON_TYPE unused;
+                CIN_DSP_STEREO_TO_MONO(in, unused, out);
+            }
+            else{
                 /* Hold on to the final channel we processed, so that we can
                  * paste it over all the remaining channels.
                  */
@@ -91,10 +120,45 @@ static void CIN_DSP_CONVERT_NAME (
             in += in_num_channels;
             
             out_frames--;
-            if(out_frames != 0){
+
+            if(out_frames != 0 && (i + 1) < num_in_frames){
                 COMMON_TYPE common_step, common_sample_begin;
+                
+                /* Special case for stereo -> mono. Ideally this would NOT be
+                 * checked inside the loop :(
+                 */
+                if(in_num_channels == 2 && out_num_channels == 1){
+                    unsigned frame = 0;
+                    /* Get the input samples we will lerp between. */
+                    COMMON_TYPE common_sample, common_sample_end;
+                    OUT_TYPE unused;
+                    CIN_DSP_STEREO_TO_MONO(in+0, common_sample, &unused);
+                    CIN_DSP_STEREO_TO_MONO(in+2, common_sample_end, &unused);
+                    /* This is slightly lossy with integer common types and
+                     * small steps. */
+                    common_step =
+                        (common_sample_end - common_sample) /
+                        ((COMMON_TYPE)out_frames);
+                    
+                    while(1){
+                        out[0] = common_sample;
+                        if(++frame == out_frames)
+                            break;
+                        common_sample += common_step;
+                        out++;
+                    }
+                    
+                    /* This skips the below loops in a way that plays well with
+                     * GCC, clang, and MSVC's optimizers.
+                     */
+                    channel = out_num_channels;
+                }
+                else{
+                    channel = 0;
+                }
+                
                 /* Process per-channel, since we need to do lerps. */
-                for(channel = 0; channel < num_common_channels; channel++){
+                for(;channel < num_common_channels; channel++){
                     /* Get the input samples we will lerp between. */
                     const IN_TYPE in_sample_start = in[channel];
                     const IN_TYPE in_sample_end =
@@ -110,7 +174,8 @@ static void CIN_DSP_CONVERT_NAME (
                     const COMMON_TYPE common_sample_end =
                         CIN_DSP_CONVERT_SAMPLE_IN_TO_COMMON(in_sample_end);
                     
-                    OUT_TYPE *dest = out + channel; /* Will be advanced on each frame */
+                    /* Will be advanced on each frame */
+                    OUT_TYPE *dest = out + channel;
                     unsigned frame = 0;
                     
                     /* This is slightly lossy with integer common types and
@@ -128,9 +193,11 @@ static void CIN_DSP_CONVERT_NAME (
                     }
                 }
                 
-                /* Repeat just the stepping for any remaining channels. */
+                /* Copy the last written channel over all remaining channels.
+                 */
                 for(; channel < out_num_channels; channel++){
-                    OUT_TYPE *dest = out + channel; /* Will be advanced on each frame */
+                    /* Will be advanced on each frame */
+                    OUT_TYPE *dest = out + channel;
                     COMMON_TYPE common_sample = common_sample_begin;
                     unsigned frame = 0;
                     while(1){
@@ -143,12 +210,15 @@ static void CIN_DSP_CONVERT_NAME (
                 }
                 
                 in += in_num_channels;
-                out += out_num_channels * (out_frames + 1);
+                out += out_num_channels * out_frames;
             }
         }
     }
+    
+    return ((unsigned char*)out) - original_out;
 }
 
+#undef CIN_DSP_STEREO_TO_MONO
 #undef COMMON_TYPE
 #undef OUT_TYPE
 #undef IN_TYPE
index 35de21a..0abf210 100644 (file)
@@ -97,7 +97,10 @@ static void Cin_DSP_Mix ## TYPE(unsigned num_bytes, \
     \
     switch(num_streams){ \
         case 0: return; \
-        case 1: memmove(out, *in, num_bytes); return; \
+        case 1: \
+            if(*in != out) \
+                memmove(out, *in, num_bytes); \
+            return; \
         default: \
         case 4: data[3] = in[3]; \
         case 3: data[2] = in[2]; \
@@ -475,7 +478,7 @@ unsigned Cin_DSP_Convert(unsigned num_bytes,
     void *out_data){
 
 #define CIN_DSP_CONVERT_CALL(IN_TYPE, OUT_TYPE) \
-    (num_bytes / sizeof(IN_TYPE))/in_format->num_channels, \
+    (num_bytes / (sizeof(IN_TYPE) * in_format->num_channels)), \
     (const IN_TYPE *)in_data, \
     (OUT_TYPE *)out_data, \
     in_format->sample_rate, \
@@ -486,39 +489,39 @@ unsigned Cin_DSP_Convert(unsigned num_bytes,
 #define CIN_DSP_CONVERT_1(IN_TYPE) \
     switch(out_format->sample_format){ \
         case CIN_DSP_FORMAT_S8: \
-            Cin_DSP_Convert ## IN_TYPE ## S8( \
-                CIN_DSP_CONVERT_CALL(IN_TYPE, S8) ); break; \
+            return Cin_DSP_Convert ## IN_TYPE ## S8( \
+                CIN_DSP_CONVERT_CALL(IN_TYPE, S8) ); \
         case CIN_DSP_FORMAT_S16: \
-            Cin_DSP_Convert ## IN_TYPE ## S16( \
-                CIN_DSP_CONVERT_CALL(IN_TYPE, S16) ); break; \
+            return Cin_DSP_Convert ## IN_TYPE ## S16( \
+                CIN_DSP_CONVERT_CALL(IN_TYPE, S16) ); \
         case CIN_DSP_FORMAT_S32: \
-            Cin_DSP_Convert ## IN_TYPE ## S32( \
-                CIN_DSP_CONVERT_CALL(IN_TYPE, S32) ); break; \
+            return Cin_DSP_Convert ## IN_TYPE ## S32( \
+                CIN_DSP_CONVERT_CALL(IN_TYPE, S32) ); \
         case CIN_DSP_FORMAT_FLOAT32: \
-            Cin_DSP_Convert ## IN_TYPE ## Float32( \
-                CIN_DSP_CONVERT_CALL(IN_TYPE, Float32) ); break; \
+            return Cin_DSP_Convert ## IN_TYPE ## Float32( \
+                CIN_DSP_CONVERT_CALL(IN_TYPE, Float32) ); \
         case CIN_DSP_FORMAT_FLOAT64: \
-            Cin_DSP_Convert ## IN_TYPE ## Float64( \
-                CIN_DSP_CONVERT_CALL(IN_TYPE, Float64) ); break; \
+            return Cin_DSP_Convert ## IN_TYPE ## Float64( \
+                CIN_DSP_CONVERT_CALL(IN_TYPE, Float64) ); \
         default: \
             return 0; \
     }
     
     switch(in_format->sample_format){
         case CIN_DSP_FORMAT_S8:
-            CIN_DSP_CONVERT_1(S8); break;
+            CIN_DSP_CONVERT_1(S8);
             
         case CIN_DSP_FORMAT_S16:
-            CIN_DSP_CONVERT_1(S16); break;
+            CIN_DSP_CONVERT_1(S16);
             
         case CIN_DSP_FORMAT_S32:
-            CIN_DSP_CONVERT_1(S32); break;
+            CIN_DSP_CONVERT_1(S32);
             
         case CIN_DSP_FORMAT_FLOAT32:
-            CIN_DSP_CONVERT_1(Float32); break;
+            CIN_DSP_CONVERT_1(Float32);
             
         case CIN_DSP_FORMAT_FLOAT64:
-            CIN_DSP_CONVERT_1(Float64); break;
+            CIN_DSP_CONVERT_1(Float64);
         
         default:
             return 0;
index febd904..d45f7bf 100644 (file)
@@ -416,7 +416,7 @@ CIN_DSP_CALL(unsigned) Cin_DSP_ConversionSize(unsigned num_bytes,
  * @param in_data Input data to convert
  * @param out_format Format to convert to
  * @param out_data Destination buffer.
- * @return Number of bytes converted.
+ * @return Number of bytes converted, or 0 on error.
  *
  * @sa Cin_DSP_ConversionSize
  */
@@ -430,6 +430,9 @@ CIN_DSP_CALL(unsigned) Cin_DSP_Convert(unsigned in_bytes,
 /**
  * @brief Mixes multiple audio buffers of the same format and size.
  *
+ * Mixing can re-use an input buffer, although if out_data appears in the
+ * in_data array it MUST be the first element and must only appear once.
+ *
  * @param num_bytes Number of bytes of data to consume
  * @param format Format of data to consume
  * @param num_streams Number of streams in @p in_data
index f6b53fc..42e6749 100644 (file)
@@ -73,6 +73,7 @@ CIN_PRIVATE(void) Cin_ResampleSound(const struct Cin_Loader *from,
  * You must include cin_soft_loader.h and cin_dsp.h to use this.
  * This is only a macro to allow us to avoid adding an additional library just
  * to glue together SoftLoader and MixerSound.
+ * TODO: This just swallows errors!
  */
 #define CIN_MIXER_SOUND_FROM_SOFT_LOADER(LD, FMT, OUT, ALLOCATOR) do{ \
         const struct Cin_Loader *const CIN_MIXER_loader = (LD);\
@@ -95,6 +96,7 @@ CIN_PRIVATE(void) Cin_ResampleSound(const struct Cin_Loader *from,
             struct Cin_MixerSound *const CIN_MIXER_out = \
                 ALLOCATOR(sizeof(struct Cin_MixerSound) + CIN_MIXER_out_size); \
             (OUT) = CIN_MIXER_out; \
+            CIN_MIXER_out->byte_len = CIN_MIXER_out_size; \
             for(CIN_MIXER_loader_data = CIN_MIXER_loader->first; \
                 CIN_MIXER_loader_data != NULL; \
                 CIN_MIXER_loader_data = CIN_MIXER_loader_data->next){ \
@@ -105,6 +107,7 @@ CIN_PRIVATE(void) Cin_ResampleSound(const struct Cin_Loader *from,
                     CIN_SOFT_LOADER_DATA(CIN_MIXER_loader_data), \
                     CIN_MIXER_out_format, \
                     CIN_MIXER_SOUND_PCM(CIN_MIXER_out) + CIN_MIXER_i); \
+                if(CIN_MIXER_added == 0) break; \
                 CIN_MIXER_i += CIN_MIXER_added; \
             } \
         } \
index 4e38fe9..9415865 100644 (file)
@@ -22,5 +22,5 @@ libcin_mixer.a: $(MIXER_OBJECTS)
 cin_mixer_sound.o: cin_mixer_sound.c cin_mixer_sound.h cin_dsp.h $(ROOTDIR)/cin_export.h $(ROOTDIR)/cin_format.h
        $(CC) $(CFLAGS) -I"$(ROOTDIR)" -c cin_mixer_sound.c -o cin_mixer_sound.o
 
-cin_dsp.o: cin_dsp.c cin_dsp.h
+cin_dsp.o: cin_dsp.c cin_dsp.h cin_convert_core.inc
        $(CC) $(CFLAGS) -c cin_dsp.c -o cin_dsp.o
index 4fa2f9c..48da313 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <assert.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #include <time.h>
@@ -40,6 +41,8 @@ void *Cin_OSS_ThreadFunc(void *v){
     const int bytes_per_frame = CIN_FORMAT_BYTES_PER_SAMPLE(format) * num_channels;
     const int buffer_size = (bytes_per_frame * rate) / 10;
     
+    const void *input_data[CIN_OSS_SOUND_CHANNELS+1];
+    
     void *const buffer = malloc(buffer_size);
     
     CIN_DSP_NEW_STACK_FMT_STRUCT(dsp_fmt);
@@ -73,11 +76,75 @@ iter:
     }
     
     if(active_channels != 0){
-        Cin_DSP_Mix(buffer_size, dsp_fmt, active_channels, channels, buffer);
+        /* First, mix any finalizing channels (channels without enough data to
+         * fill the buffer)
+         */
         i = 0;
+        
+        /* Find the first channel which is being finalized, if any. */
         do{
-            channels[i]->position += buffer_size;
+            if(channels[i]->position + buffer_size >
+                channels[i]->byte_len){
+                break;
+            }
         }while(++i < active_channels);
+        
+        /* Check this only if we broke early (found a finalizing channel) */
+        if(i != active_channels){
+            input_data[0] = buffer;
+            
+            /* Very fortunately, zero-init is ALSO zero in float and double */
+            memset(buffer, 0, buffer_size);
+            
+            do{
+                struct Cin_MixerSound *const snd = channels[i];
+                const int remaining_length =
+                    snd->byte_len - snd->position;
+                if(remaining_length < buffer_size){
+                    input_data[1] = CIN_MIXER_SOUND_PCM(channels[i]) +
+                        snd->position;
+                    
+                    Cin_DSP_Mix(remaining_length,
+                        dsp_fmt,
+                        2,
+                        input_data,
+                        buffer);
+                    
+                    /* Pull out this channel by simply swapping in the final
+                     * element. This makes removing any element constant time,
+                     * and is acceptable because the order of the channels is
+                     * not important.
+                     */
+                    channels[i] = channels[--active_channels];
+                }
+                else{
+                    i++;
+                }
+            }while(i < active_channels);
+            
+            /* Set i = 1, so that we do not place anything over the input_data
+             * element containing our mixed finalizing sounds.
+             */
+            i = 1;
+        }
+        else{
+            /* No finalizing sounds, so no extra inputs. */
+            i = 0;
+        }
+        
+        /* No need to remix if all channels were finalizing. */
+        if(active_channels != 0){
+            register unsigned source_i = 0;
+            do{
+                input_data[i++] = CIN_MIXER_SOUND_PCM(channels[source_i]) +
+                    channels[source_i]->position;
+                channels[source_i]->position += buffer_size;
+            }while(++source_i < active_channels);
+        }
+        /* i contains the final element placed into input_data, regardless
+         * of how many were from the input channels.
+         */
+        Cin_DSP_Mix(buffer_size, dsp_fmt, i, input_data, buffer);
     }
     else{
         memset(buffer, 0, buffer_size);
index 594d30e..17a8182 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "cin_oss_driver.h"
 #include "cin_oss_sound.h"
+#include "cin_mixer_sound.h"
 #include "cin_oss.h"
 #include "cinnamon.h"
 
@@ -119,7 +120,7 @@ CIN_PRIVATE(int) Cin_OSS_NewID(struct Cin_Driver *drv){
 CIN_PRIVATE(int) Cin_OSS_PushCommand(struct Cin_Driver *drv,
     struct Cin_OSS_Command *cmd){
     TAILQ_INSERT_TAIL(&drv->commands, cmd, entries);
-    return 1;
+    return 0;
 }
 
 /*****************************************************************************/
@@ -203,21 +204,30 @@ CIN_PRIVATE(int) Cin_OSS_ProcessCommands(struct Cin_Driver *drv){
             
             switch(command){
                 case CIN_OSS_INSERT:
-                    puts("CIN_OSS_INSERT");
+                    /* puts("CIN_OSS_INSERT"); */
                     SLIST_INSERT_HEAD(&drv->sounds, sound, entries);
                     break;
                 case CIN_OSS_DELETE:
-                    puts("CIN_OSS_DELETE");
+                    /* puts("CIN_OSS_DELETE"); */
                     if(prev == NULL)
                         SLIST_REMOVE_HEAD(&drv->sounds, entries);
                     else
+                    /* When compiling on Linux with OSS emulation, we need to
+                     * deal with not having this macro. */
+#ifndef SLIST_REMOVE_AFTER
+                        SLIST_REMOVE(&drv->sounds,
+                            SLIST_NEXT(prev, entries),
+                            Cin_OSS_Sound,
+                            entries);
+#else
                         SLIST_REMOVE_AFTER(prev, entries);
+#endif
                     /* We want to stop any playing instances of this sound. */
                     
                     /* FALLTHROUGH */
                 case CIN_OSS_STOP:
-                    if(command == CIN_OSS_STOP)
-                        puts("CIN_OSS_STOP");
+                    /* if(command == CIN_OSS_STOP)
+                        puts("CIN_OSS_STOP"); */
                     for(i = 0; i < CIN_OSS_SOUND_CHANNELS; i++){
                         if(drv->channels[i] == sound->snd){
                             drv->channels[i] = NULL;
@@ -225,10 +235,25 @@ CIN_PRIVATE(int) Cin_OSS_ProcessCommands(struct Cin_Driver *drv){
                     }
                     break;
                 case CIN_OSS_PLAY:
-                    puts("CIN_OSS_PLAY");
+                    /* puts("CIN_OSS_PLAY"); */
+                    
+                    /* Check if the sound is already playing, and do nothing
+                     * if it is.
+                     */
+                    for(i = 0; i < CIN_OSS_SOUND_CHANNELS; i++){
+                        if(drv->channels[i] == sound->snd){
+                            sound = NULL;
+                            /* Found. */
+                            break;
+                        }
+                    }
+                    if(sound == NULL)
+                        break;
+                    
                     for(i = 0; i < CIN_OSS_SOUND_CHANNELS; i++){
                         if(drv->channels[i] == NULL){
                             drv->channels[i] = sound->snd;
+                            drv->channels[i]->position = 0;
                             break;
                         }
                     }
@@ -239,7 +264,7 @@ CIN_PRIVATE(int) Cin_OSS_ProcessCommands(struct Cin_Driver *drv){
                      */
                     break;
                 case CIN_OSS_QUIT:
-                    puts("CIN_OSS_QUIT");
+                    /* puts("CIN_OSS_QUIT"); */
                     /* Keep going so that we at least drain the queue. */
                     val = 1;
                     break;
@@ -366,12 +391,12 @@ enum Cin_DriverError Cin_CreateDriver(struct Cin_Driver *drv){
         
         drv->rate = val;
         
-        /* Set the buffer size. */
+        /* Set the buffer size. 
         val = 0x0004000B;
         if(ioctl(dev, SNDCTL_DSP_SETFRAGMENT, &val) == -1){
             ret = Cin_eDriverFailure;
             goto fail_device;
-        }
+        } */
     }
     
     {
@@ -401,7 +426,7 @@ void Cin_DestroyDriver(struct Cin_Driver *drv){
     Cin_OSS_PushCommand(drv, quit);
     {
         void *unused;
-        pthread_join(&drv->thread, &unused);
+        pthread_join(drv->thread, &unused);
     }
     /* Finalize the driver. */
     close(drv->dev);
index de400db..fdfebb7 100644 (file)
@@ -26,16 +26,22 @@ static enum Cin_SoundError cin_sound_command(struct Cin_Sound *snd, int type){
     struct Cin_OSS_Command *cmd = Cin_OSS_NewCommand(snd->sound_id, type);
     
     if(Cin_OSS_Lock(snd->drv) != 0){
+        assert(!"Could not lock");
         return Cin_eSoundFailure;
     }
     
-    if(Cin_OSS_PushCommand(snd->drv, cmd) != 0)
+    if(Cin_OSS_PushCommand(snd->drv, cmd) != 0){
+        assert(!"Could not push command");
         ret = Cin_eSoundFailure;
-
-    if(Cin_OSS_Unlock(snd->drv) != 0)
+    }
+    
+    if(Cin_OSS_Unlock(snd->drv) != 0){
+        assert(!"Could not unlock");
         return Cin_eSoundFailure;
-    else
+    }
+    else{
         return ret;
+    }
 }
 
 /*****************************************************************************/
index e6a13bb..c8008ac 100644 (file)
@@ -9,14 +9,14 @@ CIN_COMMONLIB=$(ROOTDIR)/common/libcin_common.a
 CIN_MIXERLIB=$(ROOTDIR)/common/libcin_mixer.a
 
 libcin_oss_x.a: $(OBJECTS)
-       if [[ -f libcin_oss_x2.a ]] ; then rm libcin_oss_x2.a ; fi
+       if [ -f libcin_oss_x2.a ] ; then rm libcin_oss_x2.a ; fi
        $(AR) rc libcin_oss_x2.a $(OBJECTS)
        $(RANLIB) libcin_oss_x2.a
        mv libcin_oss_x2.a libcin_oss_x.a
 
 libcin_oss.a: $(CIN_COMMONLIB) $(CIN_MIXERLIB) libcin_oss_x.a
-       if [[ -f libcin_oss2.a ]] ; then rm libcin_oss2.a ; fi
-       echo $$'create libcin_oss2.a\naddlib libcin_oss_x.a\naddlib $(CIN_COMMONLIB)\naddlib $(CIN_MIXERLIB)\nsave\nend\n' | $(AR) M
+       if [ -f libcin_oss2.a ] ; then rm libcin_oss2.a ; fi
+       echo 'create libcin_oss2.a\naddlib libcin_oss_x.a\naddlib $(CIN_COMMONLIB)\naddlib $(CIN_MIXERLIB)\nsave\nend\n' | $(AR) M
        $(RANLIB) libcin_oss2.a
        mv libcin_oss2.a libcin_oss.a
 
@@ -26,7 +26,7 @@ cin_oss.o: cin_oss.c cin_oss.h cin_oss_driver.h cin_oss_sound.h $(COMMONHEADERS)
        $(CC) $(CFLAGS) -I"$(ROOTDIR)" -I"$(ROOTDIR)/common" -c cin_oss.c -o cin_oss.o
 
 cin_oss_driver.o: cin_oss_driver.c cin_oss_driver.h cin_oss.h $(COMMONHEADERS)
-       $(CC) $(CFLAGS) -I"$(ROOTDIR)" -c cin_oss_driver.c -o cin_oss_driver.o
+       $(CC) $(CFLAGS) -I"$(ROOTDIR)" -I"$(ROOTDIR)/common" -c cin_oss_driver.c -o cin_oss_driver.o
 
 cin_oss_sound.o: cin_oss_sound.c cin_oss.h $(COMMONHEADERS) ../common/cin_soft_loader.h ../common/cin_mixer_sound.h
        $(CC) $(CFLAGS) -I"$(ROOTDIR)" -I"$(ROOTDIR)/common" -c cin_oss_sound.c -o cin_oss_sound.o