Advertisement
Guest User

Untitled

a guest
Oct 31st, 2014
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.24 KB | None | 0 0
  1. /* GCW Zero audio timing benchmark
  2.  *
  3.  * Copyright (C) 2014, Nebuleon Fumika <nebuleon@gcw-zero.com>
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions are met:
  8.  *
  9.  * 1. Redistributions of source code must retain the above copyright notice,
  10.  *    this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright notice,
  12.  *    this list of conditions and the following disclaimer in the documentation
  13.  *    and/or other materials provided with the distribution.
  14.  *
  15.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  19.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25.  * POSSIBILITY OF SUCH DAMAGE.
  26.  */
  27.  
  28. #include "SDL.h"
  29.  
  30. #include <stdbool.h>
  31. #include <stdint.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <errno.h>
  35. #include <time.h>
  36. #include <string.h>
  37. #include <inttypes.h>
  38.  
  39. #define SAMPLE_RATE 44100
  40. #define RESULTS_FILE "benchaudiotiming.txt"
  41.  
  42. uint32_t SamplesRemaining;
  43. uint8_t AlmostDone;
  44. volatile bool SecondDone;
  45. struct timespec EndTime;
  46.  
  47. uint64_t Results[32]; /* nanoseconds to output SamplesEmitted[i] samples */
  48. uint32_t SamplesEmitted[32];
  49.  
  50. uint8_t TestCount()
  51. {
  52.     uint8_t i;
  53.  
  54.     for (i = 0; i < 32; i++)
  55.         if ((UINT32_C(1) << i) >= SAMPLE_RATE)
  56.             return i;
  57.     return 31;
  58. }
  59.  
  60. static inline int64_t NanosBetween(const struct timespec* Past, const struct timespec* Present)
  61. {
  62.     return (Present->tv_sec  - Past->tv_sec) * INT64_C(1000000000)
  63.          + (Present->tv_nsec - Past->tv_nsec);
  64. }
  65.  
  66. void BenchmarkCallback(void* userdata, Uint8* stream, int len)
  67. {
  68.     SDL_AudioSpec* spec = (SDL_AudioSpec*) userdata;
  69.     uint32_t SamplesWritten = len / (spec->size / spec->samples);
  70.     memset(stream, spec->silence, len);
  71.     if (SecondDone)
  72.         ; /* Don't update anything anymore! */
  73.     else if (AlmostDone) {
  74.         if (--AlmostDone == 0) {
  75.             clock_gettime(CLOCK_MONOTONIC, &EndTime);
  76.             SecondDone = true;
  77.         }
  78.     } else if (SamplesWritten >= SamplesRemaining) {
  79.         SamplesRemaining = 0;
  80.         /* We are almost done, but we must wait for SDL to request 3 more
  81.          * buffers via this callback, because only then will we know that
  82.          * everything has actually played.
  83.          * HACK - On the GCW Zero, SDL 1.2 uses 3 internal buffers for
  84.          * audio, and plays the front buffer while one of the back buffers
  85.          * is being requested. SDL does not provide a function to query
  86.          * this detail, which has been reverse-engineered. */
  87.         AlmostDone = 3;
  88.     } else {
  89.         SamplesRemaining -= SamplesWritten;
  90.     }
  91. }
  92.  
  93. uint32_t Benchmark(struct timespec* StartTime, uint32_t RequestedSize)
  94. {
  95.     uint32_t RetVal;
  96.  
  97.     SecondDone = false;
  98.     AlmostDone = 0;
  99.  
  100.     /* Open the audio device with a certain buffer size, in samples. */
  101.     SDL_AudioSpec Requested, Actual;
  102.     Requested.freq = SAMPLE_RATE;
  103.     Requested.format = AUDIO_S16SYS;
  104.     Requested.samples = RequestedSize;
  105.     Requested.channels = 1; /* mono */
  106.     Requested.callback = BenchmarkCallback;
  107.     Requested.userdata = &Actual;
  108.  
  109.     if (SDL_OpenAudio(&Requested, &Actual) == -1) {
  110.         fprintf(stderr, "Failed to open SDL audio: %s\n", SDL_GetError());
  111.         return 0;
  112.     }
  113.  
  114.     /* Now that we know how many samples the hardware wants us to write,
  115.      * set the number of samples to be written during the next second. */
  116.     SamplesRemaining = RetVal = (Actual.freq + Actual.samples - 1) / Actual.samples * Actual.samples;
  117.  
  118.     if (clock_gettime(CLOCK_MONOTONIC, StartTime) == -1) {
  119.         fprintf(stderr, "\nclock_gettime failed: %s\n", strerror(errno));
  120.         return 0;
  121.     }
  122.  
  123.     SDL_PauseAudio(SDL_DISABLE);
  124.  
  125.     while (!SecondDone) {
  126.         SDL_Delay(1000); /* one whole second, to minimise OS interference */
  127.     }
  128.  
  129.     SDL_CloseAudio();
  130.  
  131.     /* EndTime was updated by the callback in the SDL audio thread. Return. */
  132.     return RetVal;
  133. }
  134.  
  135. int main(int argc, char** argv)
  136. {
  137.     bool Error = false;
  138.     uint8_t Test;
  139.     char* ResultsPath = NULL;
  140.     FILE* ResultsFile = NULL;
  141.  
  142.     if (SDL_Init(SDL_INIT_AUDIO) == -1) {
  143.         fprintf(stderr, "SDL initialisation failed: %s\n", SDL_GetError());
  144.         Error = true;
  145.         goto end;
  146.     }
  147.  
  148.     const char* Home = getenv("HOME");
  149.     if (!Home) {
  150.         fprintf(stderr, "HOME environment variable not set\n");
  151.         Error = true;
  152.         goto end;
  153.     }
  154.     ResultsPath = (char *) malloc(strlen(Home) + strlen(RESULTS_FILE) + 2);
  155.     sprintf(ResultsPath, "%s/%s", Home, RESULTS_FILE);
  156.  
  157.     for (Test = 0; Test < TestCount(); Test++) {
  158.         uint32_t Emitted;
  159.         fprintf(stderr, "\rRunning tests, %2d/%2d", Test, TestCount());
  160.         struct timespec StartTime;
  161.         Emitted = Benchmark(&StartTime, UINT32_C(1) << Test);
  162.         int64_t Duration = NanosBetween(&StartTime, &EndTime);
  163.  
  164.         Results[Test] = Duration;
  165.         SamplesEmitted[Test] = Emitted;
  166.         if (Emitted == 0) {
  167.             Error = true;
  168.             goto end;
  169.         }
  170.     }
  171.  
  172.     fprintf(stderr, "\rRunning tests, done.\n");
  173.  
  174.     SDL_QuitSubSystem(SDL_INIT_AUDIO);
  175.  
  176.     fprintf(stderr, "Dumping results to ~/%s", RESULTS_FILE);
  177.     ResultsFile = fopen(ResultsPath, "wb");
  178.     if (ResultsFile) {
  179.         fprintf(ResultsFile, "Requested buffer samples,Samples output,Time taken to output (ns),Hz\n");
  180.         for (Test = 0; Test < TestCount(); Test++) {
  181.             fprintf(ResultsFile, "%" PRIu32 ",%" PRIu32 ",%" PRIu64 ",%f\n",
  182.                 UINT32_C(1) << Test,
  183.                 SamplesEmitted[Test],
  184.                 Results[Test],
  185.                 1000000000.0f / ((float) Results[Test] / SamplesEmitted[Test]));
  186.         }
  187.         fclose(ResultsFile);
  188.         fprintf(stderr, ", done.\n");
  189.     } else {
  190.         fprintf(stderr, "\nFile could not be written: %s\n", strerror(errno));
  191.     }
  192.  
  193. end:
  194.     free(ResultsPath);
  195.     SDL_Quit();
  196.  
  197.     fprintf(stderr, "Press Enter (Start) to exit.\n");
  198.     char Dummy[2];
  199.     fgets(Dummy, 2, stdin);
  200.  
  201.     return Error ? 1 : 0;
  202. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement