Subversion Repositories Games.Carmageddon

Rev

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

  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) {
  64.         goto no_audio;
  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");
  71.         goto no_audio;
  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]);
  93.         goto no_audio;
  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");
  101.         goto no_audio;
  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");
  110.         goto no_audio;
  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");
  118.         goto no_audio;
  119.     }
  120.  
  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));
  124.  
  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.         }
  130.     }
  131.  
  132.     // tell libsmacker we can process audio now
  133.     smk_enable_audio(smk_handle, 0, 1);
  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);
  142.     return smack;
  143.  
  144. no_audio:
  145.     // no audio or failed to init audio, cleanup audio stuff
  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.     }
  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);
  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
  207.     if (smack->audio_track != NULL) {
  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.  
  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;
  223.  
  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.             }
  241.         }
  242.  
  243.         if (!ma_sound_is_playing (smack->audio_track))
  244.         {
  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");
  248.             }
  249.             if (ma_sound_start (smack->audio_track) != MA_SUCCESS) {
  250.                 LOG_WARN("ma_sound_start failed");
  251.             }
  252.         }
  253.         if (ma_sound_at_end (smack->audio_track)) {
  254.             LOG_WARN ("video not playing fast enough: sound starved!");
  255.         }
  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. }
  297.