Updated TODO.
[ahxm.git] / ss_output.c
blob25285f32f57a1de1e6f996d00631cd18589b0f62
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2007 Angel Ortega <angel@triptico.com>
6 ss_output.c - Softsynth output interface
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
26 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <math.h>
34 #include <signal.h>
36 #include "ahxm.h"
38 /*******************
39 Data
40 ********************/
42 /* master output volume */
43 sample_t ss_master_volume = 0.5;
45 /* output accounting */
46 int ss_output_clipped = 0;
47 sample_t ss_max = 0.0;
49 /* optimal output volume */
50 sample_t ss_optimal_volume;
52 /* driver data */
53 static void *outdev;
56 usual channel mapping:
58 mono: all
59 stereo: left | right
60 3 channel: left | right | center
61 quad: front left | front right | rear left | rear right
62 4 channel: left | center | right | surround
63 6 channel: left center | left | center | right center | right | surround
64 home cinema 5.1: front l | center | front r | real l | rear r | subwoofer
66 Converting from wav to 5.1 ac3:
68 ffmpeg -ac 6 -ab 192 -ar 44100 -i input.wav output.ac3
71 /* a copy of the output file name */
72 static char *ss_output_file_name = NULL;
74 /* cue file name and track */
75 char *ss_cue_file_name = NULL;
76 static int ss_cue_file_track = -1;
78 /*******************
79 Code
80 ********************/
82 void *ss_outdev_open(char *drvname, char *file, int freq, int n_channels);
83 void ss_outdev_write(void *drv, short int *frame);
84 void *ss_outdev_close(void *drv);
87 static void close_on_signal(int sig_num)
88 /* SIGINT (and other) signal handler */
90 /* close output device */
91 outdev = ss_outdev_close(outdev);
93 /* exit */
94 exit(0);
98 /**
99 * ss_output_open - Opens an output device.
100 * @name: name of the driver
101 * @filename: name of the file or device
103 * Opens an output device. @name contains the name of the driver
104 * (i.e. "oss" or "wav"), @filename contains the (optional) name
105 * of the output file or device (i.e. a filename
106 * "wav" or "/dev/dsp" for a direct audio device like "oss").
107 * @Name can be the special pseudo-driver "default"
108 * to select the most appropriate (usually a platform-specific
109 * direct output device, or "wav" if no one exists).
110 * @filename can also be NULL; in that case, a driver dependent,
111 * default value is used.
113 * Returns zero if the output device was correctly open, or
114 * nonzero otherwise.
116 int ss_output_open(char *drvname, char *filename)
118 if (strcmp(drvname, "default") == 0)
119 drvname = NULL;
121 /* reset accounting */
122 ss_output_clipped = 0;
123 ss_max = 0.0;
125 /* close the device on unexpected signals */
126 signal(SIGINT, close_on_signal);
128 /* store a copy of the filename */
129 ss_output_file_name = filename;
131 return (outdev = ss_outdev_open(drvname,
132 filename, ss_frequency, ss_nchannels)) == NULL;
137 * ss_output_init_frame - Inits a frame
138 * @frame: the frame
140 * Inits a frame, setting all samples to zero.
142 void ss_output_init_frame(sample_t frame[])
144 memset(frame, '\0', sizeof(sample_t) * SS_MAX_CHANNELS);
149 * ss_output_write - Outputs a frame of samples.
150 * @frame: the frame of samples
152 * Outputs a frame of samples. Applies master volume, tests for
153 * maximum amplitudes and clips all saturating ones.
155 * Returns a negative value in case of error, or 0 otherwise.
157 int ss_output_write(sample_t frame[])
159 int n, ret = 0;
160 sample_t s;
161 short int is[SS_MAX_CHANNELS];
163 /* final corrections */
164 for (n = 0; n < ss_nchannels; n++) {
165 s = frame[n];
167 /* test maximum amplitudes, apply master
168 volume and clipping */
169 if (s < 0) {
170 if (s < -ss_max)
171 ss_max = -s;
172 s *= ss_master_volume;
173 if (s < -1) {
174 s = -1;
175 ss_output_clipped++;
178 else {
179 if (s > ss_max)
180 ss_max = s;
181 s *= ss_master_volume;
182 if (s > 1) {
183 s = 1;
184 ss_output_clipped++;
188 /* convert to 16 bit signed */
189 s *= 32767.0;
191 /* store in buffer */
192 is[n] = (short int) s;
195 /* finally write */
196 ss_outdev_write(outdev, is);
198 return ret;
203 * ss_output_close - Closes the output device.
205 * Closes the output driver.
207 void ss_output_close(void)
209 /* back to default signal behaviour */
210 signal(SIGINT, SIG_DFL);
212 /* close the device */
213 outdev = ss_outdev_close(outdev);
215 /* calculate optimal master volume for zero saturation */
216 if (ss_max)
217 ss_optimal_volume = 1 / ss_max;
221 static int cue_file_init(void)
222 /* inits the cue file, writing the first line */
224 FILE *f;
226 if (ss_output_file_name == NULL || (f = fopen(ss_cue_file_name, "w")) == NULL)
227 return -2;
229 /* write first line */
230 fprintf(f, "FILE \"%s\" WAVE\n", ss_output_file_name);
231 fclose(f);
233 ss_cue_file_track = 0;
235 return 0;
239 int cue_file_song_info(int frame, char *author, char *name)
241 int s;
242 FILE *f;
244 if (ss_cue_file_name == NULL)
245 return 0;
247 /* init if it's the first time */
248 if (ss_cue_file_track == -1) {
249 /* can't open? fail */
250 if (cue_file_init() < 0) {
251 ss_cue_file_name = NULL;
252 return -1;
256 /* open or fail */
257 if ((f = fopen(ss_cue_file_name, "a")) == NULL)
258 return -1;
260 s = frame / ss_frequency;
262 fprintf(f, "TRACK %02d AUDIO\n", ss_cue_file_track++);
263 fprintf(f, " PERFORMER \"%s\"\n", author);
264 fprintf(f, " TITLE \"%s\"\n", name);
265 fprintf(f, " INDEX 01 %02d:%02d:00\n", s / 60, s % 60);
267 fclose(f);
268 return 0;