1 /*
2 Copyright (c) 2009-2010 Tero Lindeman (kometbomb)
3 
4 Permission is hereby granted, free of charge, to any person
5 obtaining a copy of this software and associated documentation
6 files (the "Software"), to deal in the Software without
7 restriction, including without limitation the rights to use,
8 copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following
11 conditions:
12 
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 */
25 
26 #include "export.h"
27 #include "gui/bevel.h"
28 #include "snd/cyd.h"
29 #include "macros.h"
30 #include "mused.h"
31 #include "gfx/gfx.h"
32 #include "gui/view.h"
33 #include "mybevdefs.h"
34 #include "gfx/font.h"
35 #include "theme.h"
36 #include <string.h>
37 #include "wavewriter.h"
38 
39 extern GfxDomain *domain;
40 
export_wav(MusSong * song,CydWavetableEntry * entry,FILE * f,int channel)41 bool export_wav(MusSong *song, CydWavetableEntry * entry, FILE *f, int channel)
42 {
43 	bool success = false;
44 
45 	MusEngine mus;
46 	CydEngine cyd;
47 
48 	cyd_init(&cyd, 44100, MUS_MAX_CHANNELS);
49 	cyd.flags |= CYD_SINGLE_THREAD;
50 	mus_init_engine(&mus, &cyd);
51 	mus.volume = song->master_volume;
52 	mus_set_fx(&mus, song);
53 	CydWavetableEntry * prev_entry = cyd.wavetable_entries; // save entries so they can be free'd
54 	cyd.wavetable_entries = entry;
55 	cyd_set_callback(&cyd, mus_advance_tick, &mus, song->song_rate);
56 	mus_set_song(&mus, song, 0);
57 	song->flags |= MUS_NO_REPEAT;
58 
59 	if (channel >= 0)
60 	{
61 		// if channel is positive then only export that channel (mute other chans)
62 
63 		for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i)
64 			mus.channel[i].flags |= MUS_CHN_DISABLED;
65 
66 		mus.channel[channel].flags &= ~MUS_CHN_DISABLED;
67 	}
68 	else
69 	{
70 		for (int i = 0 ; i < MUS_MAX_CHANNELS ; ++i)
71 			mus.channel[i].flags &= ~MUS_CHN_DISABLED;
72 	}
73 
74 	const int channels = 2;
75 	Sint16 buffer[2000 * channels];
76 
77 	int last_percentage = -1;
78 
79 	WaveWriter *ww = ww_create(f, cyd.sample_rate, 2);
80 
81 	for (;;)
82 	{
83 		memset(buffer, 0, sizeof(buffer)); // Zero the input to cyd
84 		cyd_output_buffer_stereo(&cyd, (Uint8*)buffer, sizeof(buffer));
85 
86 		if (cyd.samples_output > 0)
87 			ww_write(ww, buffer, cyd.samples_output);
88 
89 		if (mus.song_position >= song->song_length) break;
90 
91 		if (song->song_length != 0)
92 		{
93 			int percentage = (mus.song_position + (channel == -1 ? 0 : (channel * song->song_length))) * 100 / (song->song_length * (channel == -1 ? 1 : song->num_channels));
94 
95 			if (percentage > last_percentage)
96 			{
97 				last_percentage = percentage;
98 
99 				SDL_Rect area = {domain->screen_w / 2 - 140, domain->screen_h / 2 - 24, 280, 48};
100 				bevel(domain, &area, mused.slider_bevel, BEV_MENU);
101 
102 				adjust_rect(&area, 8);
103 				area.h = 16;
104 
105 				bevel(domain, &area, mused.slider_bevel, BEV_FIELD);
106 
107 				adjust_rect(&area, 2);
108 
109 				int t = area.w;
110 				area.w = area.w * percentage / 100;
111 
112 				gfx_rect(domain, &area, colors[COLOR_PROGRESS_BAR]);
113 
114 				area.y += 16 + 4 + 4;
115 				area.w = t;
116 
117 				font_write_args(&mused.smallfont, domain, &area, "Exporting... Press ESC to abort.");
118 
119 				SDL_Event e;
120 
121 				while (SDL_PollEvent(&e))
122 				{
123 					if (e.type == SDL_QUIT || (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE))
124 					{
125 						goto abort;
126 					}
127 				}
128 
129 				gfx_domain_flip(domain);
130 			}
131 		}
132 	}
133 
134 	success = true;
135 
136 abort:;
137 
138 	ww_finish(ww);
139 
140 	cyd.wavetable_entries = prev_entry;
141 
142 	cyd_deinit(&cyd);
143 
144 	song->flags &= ~MUS_NO_REPEAT;
145 
146 	return success;
147 }
148 
149