summaryrefslogtreecommitdiffstats
path: root/libao2/pl_format.c
blob: f4c58764229ee3a89f69e2fb31af84a6972ac0d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/* This is a null audio out plugin it doesnt't really do anything
   useful but serves an example of how audio plugins work. It delays
   the output signal by the nuber of samples set by aop_delay n
   where n is the number of bytes.
 */
#define PLUGIN

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "audio_out.h"
#include "audio_plugin.h"
#include "audio_plugin_internal.h"
#include "afmt.h"

static ao_info_t info =
{
        "Sample format conversion audio plugin",
        "format",
        "Anders",
        ""
};

LIBAO_PLUGIN_EXTERN(format)

// local data
typedef struct pl_format_s
{
  void*  data;       // local audio data block
  int    len;        // local buffer length
  int 	 in;  	     // Input fomat
  int    out;        // Output fomat
  double sz_mult;    // data size multiplier
} pl_format_t;

static pl_format_t pl_format={NULL,0,0,0,1};

// Number of bits
#define B08		0 
#define B16  		1	
#define B32  		2
#define NBITS_MASK	3

// Endianess
#define BE 		(0<<3) // Big endian
#define LE 		(1<<3) // Little endian
#define END_MASK	(1<<3)

// Signed
#define US		(0<<4)
#define SI		(1<<4)
#define SIGN_MASK	(1<<4)

// to set/get/query special features/parameters
static int control(int cmd,int arg){
  switch(cmd){
  case AOCONTROL_PLUGIN_SET_LEN:
    if(pl_format.data) 
      uninit();
    pl_format.len = ao_plugin_data.len;
    pl_format.data=(void*)malloc(ao_plugin_data.len);
    ao_plugin_data.len=(int)((double)ao_plugin_data.len*pl_format.sz_mult);
    return CONTROL_OK;
  }
  return -1;
}

// open & setup audio device
// return: 1=success 0=fail
static int init(){
  int i=0;
  int sign=0;
  int nbits=8;
  int be_le=BE;

  // Sheck input format
  switch(ao_plugin_data.format){
  case(AFMT_U8):
    pl_format.in=LE|B08|US; break;
  case(AFMT_S8):
    pl_format.in=LE|B08|SI; break;
  case(AFMT_S16_LE):
    pl_format.in=LE|B16|US; break;
  case(AFMT_S16_BE):
    pl_format.in=BE|B16|SI; break;
  case(AFMT_U16_LE):	
    pl_format.in=LE|B16|US; break;
  case(AFMT_U16_BE):	
    pl_format.in=BE|B16|US; break;
  case(AFMT_S32_LE):
    pl_format.in=LE|B32|SI; break;
  case(AFMT_S32_BE):	
    pl_format.in=BE|B32|SI; break;
  case(AFMT_IMA_ADPCM):		
  case(AFMT_MU_LAW):
  case(AFMT_A_LAW):
  case(AFMT_MPEG):
  case(AFMT_AC3):
    printf("[pl_format] Audio format not yet suported \n");
    return 0;
  default: 
    printf("[pl_format] Unsupported audio format\n"); // Should never happen...
    return 0;
  }
  // Sheck output format
  switch(ao_plugin_cfg.pl_format_type){
  case(AFMT_U8):
    pl_format.in=LE|B08|US; break;
  case(AFMT_S8):
    pl_format.in=LE|B08|SI; break;
  case(AFMT_S16_LE):
    pl_format.in=LE|B16|US; break;
  case(AFMT_S16_BE):
    pl_format.in=BE|B16|SI; break;
  case(AFMT_U16_LE):	
    pl_format.in=LE|B16|US; break;
  case(AFMT_U16_BE):	
    pl_format.in=BE|B16|US; break;
  case(AFMT_S32_LE):
    pl_format.in=LE|B32|SI; break;
  case(AFMT_S32_BE):	
    pl_format.in=BE|B32|SI; break;
  case(AFMT_IMA_ADPCM):		
  case(AFMT_MU_LAW):
  case(AFMT_A_LAW):
  case(AFMT_MPEG):
  case(AFMT_AC3):
    printf("[pl_format] Audio format not yet suported \n");
    return 0;
  default:
    printf("[pl_format] Unsupported audio format\n"); // Should never happen...
    return 0;
  }
  // We are changing the format
  ao_plugin_data.format=ao_plugin_cfg.pl_format_type;
  
  // And perhaps the buffer size
  pl_format.sz_mult=1;
  if((pl_format.in&NBITS_MASK) < (pl_format.out&NBITS_MASK))
    pl_format.sz_mult/=(double)(1<<(pl_format.out-pl_format.in));
  if((pl_format.in&NBITS_MASK) > (pl_format.out&NBITS_MASK))
    pl_format.sz_mult*=(double)(1<<(pl_format.out-pl_format.in));
  ao_plugin_data.sz_mult*=pl_format.sz_mult;
  return 1;
}

// close plugin
static void uninit(){
  if(pl_format.data) 
    free(pl_format.data);
}

// empty buffers
static void reset(){
  int i = 0;
  for(i=0;i<pl_format.len;i++)
    ((char*)pl_format.data)[i]=0;
}

// processes 'ao_plugin_data.len' bytes of 'data'
// called for every block of data
static int play(){
  register int i=0;
  void* in_data=ao_plugin_data.data;
  void* out_data=pl_format.data;
  int in_len=((int)(double)pl_format.len*pl_format.sz_mult);
  in_len>>=pl_format.in&NBITS_MASK;

  if((pl_format.in&END_MASK)!=(pl_format.out&END_MASK)){
    switch(pl_format.in&NBITS_MASK){
    case(B16):{
      register int16_t s;
      for(i=1;i<in_len;i++){
	s=((int16_t*)in_data)[i];
	((int16_t*)in_data)[i]=(int16_t)(((s&0x00FF)<<8) | (s&0xFF00)>>8);
      }
      break;
    }
    case(B32):{
      register int32_t s;
      for(i=1;i<in_len;i++){
	s=((int32_t*)in_data)[i];
	((int32_t*)in_data)[i]=(int32_t)(((s&0x000000FF)<<24) | ((s&0x0000FF00)<<8) |
	                                 ((s&0x00FF0000)>>8)  | ((s&0xFF000000)>>24));
      }
      break;
    }
    }
  }
  
  return 1;
}