Subversion Repositories Games.Carmageddon

Rev

Rev 1 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
#include "include/smackw32/smackw32.h"
2
 
3
#include <assert.h>
4
#include <stddef.h>
5
#include <stdint.h>
6
#include <stdlib.h>
7
#include <string.h>
8
 
9
#include "harness/hooks.h"
10
#include "harness/trace.h"
11
// lib/libsmacker
12
#include "smacker.h"
13
 
14
#include "../miniaudio/include/miniaudio/miniaudio.h"
15
extern ma_engine miniaudio_engine; // defined in miniaudio_backend.c
16
extern int gSound_enabled; // defined in globvars.h
17
 
18
static uint32_t smack_last_frame_time = 0;
19
 
20
static void copy_palette(Smack* smack) {
21
    const unsigned char* pal = smk_get_palette(smack->smk_handle);
22
    memcpy(smack->Palette, pal, 256 * 3);
23
}
24
 
25
Smack* SmackOpen(const char* name, uint32_t flags, uint32_t extrabuf) {
26
    ma_format audioformat_ma;
27
    ma_paged_audio_buffer_config paged_audio_buffer_config;
28
    ma_data_converter_config data_converter_config;
29
    unsigned char track_mask_smk;
30
    unsigned char channels_smk[7];
31
    unsigned char bitdepth_smk[7];
32
    unsigned long sample_rate_smk[7];
33
    double microsecs_per_frame;
34
    Smack* smack;
35
    double fps;
36
 
37
    smk smk_handle = smk_open_file(name, SMK_MODE_MEMORY);
38
    if (smk_handle == NULL) {
39
        return NULL;
40
    }
41
 
42
    smack = malloc(sizeof(Smack));
43
 
44
    // libsmacker doesn't tell us whether the palette is new on each frame or not, so just assume it always is new
45
    smack->NewPalette = 1;
46
 
47
    // smk_handle is added to hold a pointer to the underlying libsmacker instance
48
    smack->smk_handle = smk_handle;
49
 
50
    smk_info_all(smk_handle, NULL, &smack->Frames, &microsecs_per_frame);
51
    fps = 1000000.0 / microsecs_per_frame;
52
    smack->MSPerFrame = (unsigned long) ((1 / fps) * 1000); // Pierre-Marie Baty -- added type cast
53
    smk_info_video(smk_handle, &smack->Width, &smack->Height, NULL);
54
    smk_enable_video(smk_handle, 1);
55
 
56
    // initialize video sound if required and present
57
    smack->audio_sample_rate = 0;
58
    smack->audio_frame_size_in_bytes = 0;
59
    smack->audio_paged_buffer = NULL;
60
    smack->audio_paged_buffer_data = NULL;
61
    smack->audio_converter = NULL;
62
    smack->audio_track = NULL;
63
    if (!gSound_enabled) {
8 pmbaty 64
        goto no_audio;
1 pmbaty 65
    }
66
 
67
    // get info about the audio tracks in this video
68
    smk_info_audio(smk_handle, &track_mask_smk, channels_smk, bitdepth_smk, sample_rate_smk);
69
    if (!(track_mask_smk & SMK_AUDIO_TRACK_0)) {
70
        LOG_INFO("Smacker file does not contain audio");
8 pmbaty 71
        goto no_audio;
1 pmbaty 72
    }
73
    smack->audio_sample_rate = sample_rate_smk[0];
74
    switch (bitdepth_smk[0]) {
75
    case 8:
76
        audioformat_ma = ma_format_u8;
77
        smack->audio_frame_size_in_bytes = 1 * channels_smk[0];
78
        break;
79
    case 16:
80
        audioformat_ma = ma_format_s16;
81
        smack->audio_frame_size_in_bytes = 2 * channels_smk[0];
82
        break;
83
    case 24:
84
        audioformat_ma = ma_format_s24;
85
        smack->audio_frame_size_in_bytes = 3 * channels_smk[0];
86
        break;
87
    case 32:
88
        audioformat_ma = ma_format_s32;
89
        smack->audio_frame_size_in_bytes = 4 * channels_smk[0];
90
        break;
91
    default:
92
        LOG_WARN("Smacker audio stream has invalid bit depth: %d", bitdepth_smk[0]);
8 pmbaty 93
        goto no_audio;
1 pmbaty 94
    }
95
 
96
    // allocate and initialize paged buffer data
97
    smack->audio_paged_buffer_data = malloc(sizeof(ma_paged_audio_buffer_data));
98
 
99
    if ((smack->audio_frame_size_in_bytes == 0) || (ma_paged_audio_buffer_data_init(audioformat_ma, channels_smk[0], smack->audio_paged_buffer_data) != MA_SUCCESS)) {
100
        LOG_WARN("Failed to create paged audio buffer data");
8 pmbaty 101
        goto no_audio;
1 pmbaty 102
    }
103
 
104
    // allocate and initialize paged buffer
105
    smack->audio_paged_buffer = malloc(sizeof(ma_paged_audio_buffer));
106
 
107
    paged_audio_buffer_config = ma_paged_audio_buffer_config_init(smack->audio_paged_buffer_data);
108
    if (ma_paged_audio_buffer_init (&paged_audio_buffer_config, smack->audio_paged_buffer) != MA_SUCCESS) {
109
        LOG_WARN("Failed to create paged audio buffer for smacker audio stream");
8 pmbaty 110
        goto no_audio;
1 pmbaty 111
    }
112
 
113
    // allocate and initialize sound
114
    smack->audio_track = malloc(sizeof(ma_sound));
115
 
116
    if (ma_sound_init_from_data_source(&miniaudio_engine, smack->audio_paged_buffer, MA_SOUND_FLAG_NO_PITCH | MA_SOUND_FLAG_NO_SPATIALIZATION, NULL, smack->audio_track) != MA_SUCCESS) {
117
        LOG_WARN("Failed to create sound from data source");
8 pmbaty 118
        goto no_audio;
1 pmbaty 119
    }
120
 
8 pmbaty 121
    // allocate and initialize data converter if miniaudio engine and Smack file soundtrack sample rates differ
122
    if (ma_engine_get_sample_rate(&miniaudio_engine) != sample_rate_smk[0]) {
123
        smack->audio_converter = malloc(sizeof(ma_data_converter));
1 pmbaty 124
 
8 pmbaty 125
        data_converter_config = ma_data_converter_config_init(audioformat_ma, audioformat_ma, channels_smk[0], channels_smk[0], smack->audio_sample_rate, ma_engine_get_sample_rate (&miniaudio_engine));
126
        if (ma_data_converter_init(&data_converter_config, NULL, smack->audio_converter) != MA_SUCCESS) {
127
            LOG_WARN("Failed to create sound data converter");
128
            goto no_audio;
129
        }
1 pmbaty 130
    }
131
 
132
    // tell libsmacker we can process audio now
133
    smk_enable_audio(smk_handle, 0, 1);
8 pmbaty 134
 
135
    // load the first frame and return a handle to the Smack file
136
    if (smk_first(smk_handle) == SMK_ERROR) {
137
        smk_close(smk_handle);
138
        free(smack);
139
        return NULL;
140
    }
141
    copy_palette(smack);
1 pmbaty 142
    return smack;
143
 
8 pmbaty 144
no_audio:
145
    // no audio or failed to init audio, cleanup audio stuff
1 pmbaty 146
    if (smack->audio_converter != NULL) {
147
        free(smack->audio_converter);
148
        smack->audio_converter = NULL;
149
    }
150
    if (smack->audio_track != NULL) {
151
        ma_sound_uninit(smack->audio_track);
152
        free(smack->audio_track);
153
        smack->audio_track = NULL;
154
    }
155
    if (smack->audio_paged_buffer != NULL) {
156
        ma_paged_audio_buffer_uninit(smack->audio_paged_buffer);
157
        free(smack->audio_paged_buffer);
158
        smack->audio_paged_buffer = NULL;
159
    }
160
    if (smack->audio_paged_buffer_data != NULL) {
161
        ma_paged_audio_buffer_data_uninit (smack->audio_paged_buffer_data, NULL);
162
        free(smack->audio_paged_buffer_data);
163
        smack->audio_paged_buffer_data = NULL;
164
    }
8 pmbaty 165
 
166
    // load the first frame and return a handle to the Smack file
167
    if (smk_first(smk_handle) == SMK_ERROR) {
168
        smk_close(smk_handle);
169
        free(smack);
170
        return NULL;
171
    }
172
    copy_palette(smack);
1 pmbaty 173
    return smack;
174
}
175
 
176
int SmackSoundUseDirectSound(void* dd) {
177
    // TODO: do some miniaudio init
178
 
179
    return 0;
180
}
181
 
182
void SmackToBuffer(Smack* smack, uint32_t left, uint32_t top, uint32_t pitch, uint32_t destheight, void* buf, uint32_t flags) {
183
    unsigned long i; // Pierre-Marie Baty -- fixed type
184
 
185
    // minimal implementation
186
    assert(left == 0);
187
    assert(top == 0);
188
    assert(flags == 0);
189
 
190
    char* char_buf = buf;
191
 
192
    const unsigned char* frame = smk_get_video(smack->smk_handle);
193
    for (i = 0; i < smack->Height; i++) {
194
        memcpy(&char_buf[(i * pitch)], &frame[i * smack->Width], smack->Width);
195
    }
196
}
197
 
198
uint32_t SmackDoFrame(Smack* smack) {
199
    const unsigned char *audio_data;
200
    unsigned long audio_data_size;
201
    ma_paged_audio_buffer_page *newPage;
202
    ma_uint64 current_pos;
203
    ma_uint64 nb_frames_in;
204
    ma_uint64 nb_frames_out;
205
 
206
    // process audio if we have some
8 pmbaty 207
    if (smack->audio_track != NULL) {
1 pmbaty 208
        audio_data = smk_get_audio (smack->smk_handle, 0);
209
        audio_data_size = smk_get_audio_size (smack->smk_handle, 0);
210
        if ((audio_data == NULL) || (audio_data_size == 0)) {
211
            return 0;
212
        }
213
 
214
        if (ma_paged_audio_buffer_get_length_in_pcm_frames (smack->audio_paged_buffer, &current_pos) != MA_SUCCESS) {
215
            LOG_WARN("ma_paged_audio_buffer_get_length_in_pcm_frames failed");
216
            return 0;
217
        }
218
 
8 pmbaty 219
        // do we need to convert the sample frequency?
220
        if (smack->audio_converter != NULL) {
221
            nb_frames_in = audio_data_size / smack->audio_frame_size_in_bytes;
222
            nb_frames_out = nb_frames_in * ma_engine_get_sample_rate (&miniaudio_engine) / smack->audio_sample_rate;
1 pmbaty 223
 
8 pmbaty 224
            if (ma_paged_audio_buffer_data_allocate_page (smack->audio_paged_buffer_data, nb_frames_out, NULL, NULL, &newPage) != MA_SUCCESS) {
225
                LOG_WARN("ma_paged_audio_buffer_data_allocate_page failed");
226
                return 0;
227
            }
228
            else if (ma_data_converter_process_pcm_frames (smack->audio_converter, audio_data, &nb_frames_in, newPage->pAudioData, &nb_frames_out) != MA_SUCCESS) {
229
                LOG_WARN("ma_data_converter_process_pcm_frames failed");
230
                return 0;
231
            }
232
            else if (ma_paged_audio_buffer_data_append_page (smack->audio_paged_buffer_data, newPage) != MA_SUCCESS) {
233
                LOG_WARN("ma_paged_audio_buffer_data_append_page failed");
234
                return 0;
235
            }
236
        } else { // no sampling frequency conversion needed
237
            if (ma_paged_audio_buffer_data_allocate_and_append_page(smack->audio_paged_buffer_data, (ma_uint32) (audio_data_size / (ma_uint64) smack->audio_frame_size_in_bytes), audio_data, NULL) != MA_SUCCESS) {
238
               LOG_WARN ("ma_paged_audio_buffer_data_allocate_and_append_page failed");
239
               return 0;
240
            }
1 pmbaty 241
        }
242
 
8 pmbaty 243
        if (!ma_sound_is_playing (smack->audio_track))
1 pmbaty 244
        {
8 pmbaty 245
            // seek either at start, or where the accumulated value hasn't played yet
246
            if (ma_sound_seek_to_pcm_frame (smack->audio_track, current_pos) != MA_SUCCESS) {
247
                LOG_WARN("ma_sound_seek_to_pcm_frame failed");
1 pmbaty 248
            }
8 pmbaty 249
            if (ma_sound_start (smack->audio_track) != MA_SUCCESS) {
250
                LOG_WARN("ma_sound_start failed");
1 pmbaty 251
            }
252
        }
8 pmbaty 253
        if (ma_sound_at_end (smack->audio_track)) {
254
            LOG_WARN ("video not playing fast enough: sound starved!");
255
        }
1 pmbaty 256
    }
257
 
258
    return 0;
259
}
260
 
261
void SmackNextFrame(Smack* smack) {
262
    smk_next(smack->smk_handle);
263
    copy_palette(smack);
264
}
265
 
266
uint32_t SmackWait(Smack* smack) {
267
    uint32_t now = gHarness_platform.GetTicks();
268
    if (now < smack_last_frame_time + smack->MSPerFrame) {
269
        gHarness_platform.Sleep(1);
270
        return 1;
271
    }
272
    smack_last_frame_time = now;
273
    return 0;
274
}
275
 
276
void SmackClose(Smack* smack) {
277
    if (smack->audio_converter != NULL) {
278
        ma_data_converter_uninit(smack->audio_converter, NULL);
279
        free(smack->audio_converter);
280
    }
281
    if (smack->audio_track != NULL) {
282
        ma_sound_stop(smack->audio_track);
283
        ma_sound_uninit(smack->audio_track);
284
        free(smack->audio_track);
285
    }
286
    if (smack->audio_paged_buffer != NULL) {
287
        ma_paged_audio_buffer_uninit(smack->audio_paged_buffer);
288
        free(smack->audio_paged_buffer);
289
    }
290
    if (smack->audio_paged_buffer_data != NULL) {
291
        ma_paged_audio_buffer_data_uninit(smack->audio_paged_buffer_data, NULL);
292
        free(smack->audio_paged_buffer_data);
293
    }
294
    smk_close(smack->smk_handle);
295
    free(smack);
296
}