summary refs log tree commit diff
path: root/src/portaudio.c
blob: e8e983979e323e43c3a428dbc0c6cdcbce091bb0 (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
#define SDL_MAIN_HANDLED
#include <portaudio.h>

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

#include "include.h"
#include "common/common.h"

#define eprintf(...) fprintf(stderr, __VA_ARGS__)

volatile sig_atomic_t keep_going = 1;

void sigint_handler(int sig_num) {
	signal(SIGINT, SIG_IGN);
	keep_going = 0;
}

struct blob load_file(char const *const name);

struct userdata userdata = {
	.callback = NULL,
	.user = NULL,
};

//void audio_callback(void *userdata_void, unsigned char *stream_void, int const length) {
int audio_callback(void const *inBuf, void *outBuf, unsigned long const frameCount, PaStreamCallbackTimeInfo const* timeInfo, PaStreamCallbackFlags statusFlags, void *userdata_void) {
	(void) inBuf;
	(void) timeInfo;
	(void) statusFlags;
	struct userdata *user = userdata_void;
	user->callback(user->user, outBuf, frameCount * sizeof (float) * 2);
	return 0;
}

int (*file_ext(char *file))(struct blob *, struct userdata *);

int main(int argc, char **argv) {
	if (argc != 2) {
		eprintf("usage: %s audio-file.{mid,mod,xm,it,s3m}\n", argv[0]);
		return EXIT_FAILURE;
	} else {
		int (*module_func)(struct blob *, struct userdata *) = file_ext(argv[1]);
		if (module_func == NULL) {
			eprintf("%s: unrecognized file extension\n", argv[1]);
			return EXIT_FAILURE;
		}
		struct blob file = load_file(argv[1]);
		if (file.data == NULL) {
			perror(argv[1]);
			return EXIT_FAILURE;
		}
		module_func(&file, &userdata);
	}
	
	signal(SIGINT, sigint_handler); // signal(3) claims this method is deprecated, but..
	
	PaError paErr;
	if ((paErr = Pa_Initialize()) != paNoError) {
		printf("error: Pa_Initialize: %s\n", Pa_GetErrorText(paErr));
		goto error;
	}
	
	PaStream *stream;
	if ((paErr = Pa_OpenDefaultStream(
		&stream,
		IN_CHANNELS,
		OUT_CHANNELS,
		paFloat32,
		SAMPLE_RATE,
		paFramesPerBufferUnspecified,
		audio_callback,
		&userdata
	)) != paNoError) {
		printf("error: Pa_OpenDefaultStream: %s\n", Pa_GetErrorText(paErr));
		goto error;
	}
	
	if ((paErr = Pa_StartStream(stream)) != paNoError) {
		printf("error: Pa_StartStream: %s\n", Pa_GetErrorText(paErr));
		goto error;
	}
	
	while (keep_going) {
		Pa_Sleep(1000);
	}
	
	if ((paErr = Pa_StopStream(stream)) != paNoError) {
		printf("error: Pa_StopStream: %s\n", Pa_GetErrorText(paErr));
		goto error;
	}
	
	if ((paErr = Pa_CloseStream(stream)) != paNoError) {
		printf("error: Pa_CloseStream: %s\n", Pa_GetErrorText(paErr));
		goto error;
	}
	
	if ((paErr = Pa_Terminate()) != paNoError) {
		printf("error: Pa_Terminate: %s\n", Pa_GetErrorText(paErr));
		goto error;
	}
	
	return EXIT_SUCCESS;
	
	error:
	return EXIT_FAILURE;
}