Commit | Line | Data |
---|---|---|
21c4e167 H |
1 | /* Ghetto Sound - Sampler |
2 | * by: Harvie 2o1o | |
3 | * | |
4 | * TODO: | |
5 | * - port unbuffered getchar to windows | |
6 | */ | |
7 | ||
8 | #include <stdio.h> | |
9 | #include <stdlib.h> | |
10 | #include <string.h> | |
11 | #include <unistd.h> | |
12 | #include <termio.h> | |
13 | #include "SDL.h" | |
14 | #include "SDL_mixer.h" | |
15 | //Docs: http://www.libsdl.org/projects/SDL_mixer/docs/ | |
16 | //example http://www.kekkai.org/roger/sdl/mixer/ | |
17 | ||
18 | static struct termios stored_settings; | |
19 | void tc_reset() { tcsetattr(0,TCSANOW,&stored_settings); } | |
20 | void icanon_off() { | |
21 | struct termios new_settings; | |
22 | tcgetattr(0,&stored_settings); | |
23 | new_settings = stored_settings; | |
24 | new_settings.c_lflag &= (~ICANON); | |
25 | new_settings.c_lflag &= (~ECHO); | |
26 | new_settings.c_cc[VTIME] = 0; | |
27 | new_settings.c_cc[VMIN] = 1; | |
28 | tcsetattr(0,TCSANOW,&new_settings); | |
29 | atexit(tc_reset); | |
30 | } | |
31 | ||
32 | /*char gethit() { | |
33 | icanon_off(); | |
34 | char c = getchar(); | |
35 | tc_reset(); | |
36 | return c; | |
37 | }*/ | |
38 | ||
39 | Mix_Chunk **sample = NULL; | |
40 | int samplec = 0; | |
41 | ||
42 | void cleanUp() { | |
43 | int i; | |
44 | for(i=0;i<samplec;i++) { Mix_FreeChunk(sample[i]); } | |
45 | Mix_CloseAudio(); | |
46 | SDL_Quit(); | |
47 | } | |
48 | ||
49 | char *keymap = "xcvbnmasdfghjklwertuiop789456123zy"; | |
50 | int i; | |
51 | int main(int argc, char* argv[]) { | |
52 | if(argc == 1) { | |
53 | printf("\n\tUsage:\t%s *.wav *.ogg [...]\n", argv[0]); | |
54 | printf("\t\t%s --keys 7894561230 *.wav *.ogg [...] #to use own key-bindings\n", argv[0]); | |
55 | puts("\t\t- lowercase: play sample once; uppercase: loop sample;"); | |
56 | puts(""); | |
57 | puts("\t- currently supported formats: WAVE, AIFF, RIFF, OGG(libvorbis), VOC, MOD(libmikmod), MIDI, MP3(smpeg)"); | |
58 | puts("\t- currently there are issues with mp3s - you should convert it:"); | |
59 | puts("\t\t- mp3 to wav: ffmpeg -i in.mp3 out.wav"); | |
60 | puts("\t\t- mp3 to ogg: ffmpeg -i in.mp3 -acodec vorbis -ac 2 -aq 60 out.ogg"); | |
61 | puts(""); | |
62 | exit(-1); | |
63 | } | |
64 | ||
65 | //Init SDL: | |
66 | if(SDL_Init(SDL_INIT_AUDIO)) { | |
67 | perror("Cannot initialize SDL using SDL_Init!\n"); | |
68 | exit(1); | |
69 | } | |
70 | atexit(cleanUp); | |
71 | //Open audio | |
72 | if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 256)) { //sampl.freq(def22050), format, 2stereo/1mono, chunksize(default 4095) | |
73 | perror("Cannot open audio using Mix_OpenAudio!\n"); | |
74 | exit(2); | |
75 | } | |
76 | //alloc enough mixer channels | |
77 | Mix_AllocateChannels(argc*2); | |
78 | //set volume | |
79 | Mix_Volume(-1,MIX_MAX_VOLUME/2); | |
80 | ||
81 | //alloc enough samples | |
82 | sample = malloc(sizeof(Mix_Chunk)*argc); | |
83 | samplec = 0; | |
84 | ||
85 | ||
86 | i = 1; | |
87 | argv++; argc--; //get rid of argv[0] | |
88 | while(argc) { //loop through args (load samples and parse options) | |
89 | if(!strcmp(argv[0], "--keys")) { //alternative keymap | |
90 | if(samplec > 0) { | |
91 | puts("\nERR: Cannot specify keys after loading first sample!"); | |
92 | break; | |
93 | } | |
94 | if(--argc) { argv++; } | |
95 | else { break; } | |
96 | keymap = argv[0]; | |
97 | argv++; argc--; continue; | |
98 | } | |
99 | if(samplec < strlen(keymap)) { | |
100 | sample[samplec] = Mix_LoadWAV(argv[0]); | |
101 | if(sample[samplec]) { | |
102 | printf("[%c]: %s%c", keymap[samplec], argv[0], (samplec+1)%4==0?'\n':'\t'); | |
103 | samplec++; | |
104 | } else { | |
105 | printf("\nERR: Mix_LoadWAV(%s): %s\n", argv[0], Mix_GetError()); | |
106 | } | |
107 | } else { | |
108 | if(i) puts("\nERR: Not enough keys on keyboard (or in keymap)!"); | |
109 | i = 0; | |
110 | } | |
111 | ||
112 | argv++; argc--; | |
113 | } | |
114 | puts(""); | |
115 | ||
116 | //Main loop: | |
117 | puts("[Q]: exit!\t[SPACE]: silence!\t[ENTER]: delay\t[-]: halucination"); | |
118 | int keymaplen = strlen(keymap); | |
119 | //freopen("test.seq", "r", stdin); | |
120 | ||
121 | icanon_off(); | |
122 | char c; while(c = getchar()) { | |
123 | //lowercase: play sample once | |
124 | for(i=0;i<keymaplen && i < samplec;i++) if(c == keymap[i]) { | |
125 | if(Mix_PlayChannel(samplec+i, sample[i], 0) == -1) printf("ERR: Mix_PlayChannel(sample #%d): %s\n", i, Mix_GetError()); | |
126 | } | |
127 | //uppercase: start/stop loop | |
128 | for(i=0;i<keymaplen && i < samplec;i++) if(c == keymap[i]-'a'+'A') { | |
129 | if(Mix_Playing(i)) { | |
130 | Mix_HaltChannel(i); | |
131 | } else { | |
132 | if(Mix_PlayChannel(i, sample[i], -1) == -1) printf("ERR: Mix_PlayChannel(sample #%d, loop): %s\n", i, Mix_GetError()); | |
133 | } | |
134 | } | |
135 | if(c == ' ') Mix_HaltChannel(-1); | |
136 | if(c == '\n') sleep(1); | |
137 | if(c == '#') while(getchar() != '\n'); | |
138 | if(c == '?') while(Mix_Playing(-1)) usleep(1000); | |
139 | if(c == '}') rewind(stdin); | |
140 | if(c == 'Q' || c == 'q') break; | |
141 | if(c == '-') for(i=360;i>=0;i--) { //halucination | |
142 | Mix_SetPosition(MIX_CHANNEL_POST, i, 0); | |
143 | usleep(2000); | |
144 | } | |
145 | } | |
146 | ||
147 | exit(0); | |
148 | } | |
149 |