Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* GCW Zero audio timing benchmark
- *
- * Copyright (C) 2014, Nebuleon Fumika <nebuleon@gcw-zero.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
- #include "SDL.h"
- #include <stdbool.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <time.h>
- #include <string.h>
- #include <inttypes.h>
- #define SAMPLE_RATE 44100
- #define RESULTS_FILE "benchaudiotiming.txt"
- uint32_t SamplesRemaining;
- uint8_t AlmostDone;
- volatile bool SecondDone;
- struct timespec EndTime;
- uint64_t Results[32]; /* nanoseconds to output SamplesEmitted[i] samples */
- uint32_t SamplesEmitted[32];
- uint8_t TestCount()
- {
- uint8_t i;
- for (i = 0; i < 32; i++)
- if ((UINT32_C(1) << i) >= SAMPLE_RATE)
- return i;
- return 31;
- }
- static inline int64_t NanosBetween(const struct timespec* Past, const struct timespec* Present)
- {
- return (Present->tv_sec - Past->tv_sec) * INT64_C(1000000000)
- + (Present->tv_nsec - Past->tv_nsec);
- }
- void BenchmarkCallback(void* userdata, Uint8* stream, int len)
- {
- SDL_AudioSpec* spec = (SDL_AudioSpec*) userdata;
- uint32_t SamplesWritten = len / (spec->size / spec->samples);
- memset(stream, spec->silence, len);
- if (SecondDone)
- ; /* Don't update anything anymore! */
- else if (AlmostDone) {
- if (--AlmostDone == 0) {
- clock_gettime(CLOCK_MONOTONIC, &EndTime);
- SecondDone = true;
- }
- } else if (SamplesWritten >= SamplesRemaining) {
- SamplesRemaining = 0;
- /* We are almost done, but we must wait for SDL to request 3 more
- * buffers via this callback, because only then will we know that
- * everything has actually played.
- * HACK - On the GCW Zero, SDL 1.2 uses 3 internal buffers for
- * audio, and plays the front buffer while one of the back buffers
- * is being requested. SDL does not provide a function to query
- * this detail, which has been reverse-engineered. */
- AlmostDone = 3;
- } else {
- SamplesRemaining -= SamplesWritten;
- }
- }
- uint32_t Benchmark(struct timespec* StartTime, uint32_t RequestedSize)
- {
- uint32_t RetVal;
- SecondDone = false;
- AlmostDone = 0;
- /* Open the audio device with a certain buffer size, in samples. */
- SDL_AudioSpec Requested, Actual;
- Requested.freq = SAMPLE_RATE;
- Requested.format = AUDIO_S16SYS;
- Requested.samples = RequestedSize;
- Requested.channels = 1; /* mono */
- Requested.callback = BenchmarkCallback;
- Requested.userdata = &Actual;
- if (SDL_OpenAudio(&Requested, &Actual) == -1) {
- fprintf(stderr, "Failed to open SDL audio: %s\n", SDL_GetError());
- return 0;
- }
- /* Now that we know how many samples the hardware wants us to write,
- * set the number of samples to be written during the next second. */
- SamplesRemaining = RetVal = (Actual.freq + Actual.samples - 1) / Actual.samples * Actual.samples;
- if (clock_gettime(CLOCK_MONOTONIC, StartTime) == -1) {
- fprintf(stderr, "\nclock_gettime failed: %s\n", strerror(errno));
- return 0;
- }
- SDL_PauseAudio(SDL_DISABLE);
- while (!SecondDone) {
- SDL_Delay(1000); /* one whole second, to minimise OS interference */
- }
- SDL_CloseAudio();
- /* EndTime was updated by the callback in the SDL audio thread. Return. */
- return RetVal;
- }
- int main(int argc, char** argv)
- {
- bool Error = false;
- uint8_t Test;
- char* ResultsPath = NULL;
- FILE* ResultsFile = NULL;
- if (SDL_Init(SDL_INIT_AUDIO) == -1) {
- fprintf(stderr, "SDL initialisation failed: %s\n", SDL_GetError());
- Error = true;
- goto end;
- }
- const char* Home = getenv("HOME");
- if (!Home) {
- fprintf(stderr, "HOME environment variable not set\n");
- Error = true;
- goto end;
- }
- ResultsPath = (char *) malloc(strlen(Home) + strlen(RESULTS_FILE) + 2);
- sprintf(ResultsPath, "%s/%s", Home, RESULTS_FILE);
- for (Test = 0; Test < TestCount(); Test++) {
- uint32_t Emitted;
- fprintf(stderr, "\rRunning tests, %2d/%2d", Test, TestCount());
- struct timespec StartTime;
- Emitted = Benchmark(&StartTime, UINT32_C(1) << Test);
- int64_t Duration = NanosBetween(&StartTime, &EndTime);
- Results[Test] = Duration;
- SamplesEmitted[Test] = Emitted;
- if (Emitted == 0) {
- Error = true;
- goto end;
- }
- }
- fprintf(stderr, "\rRunning tests, done.\n");
- SDL_QuitSubSystem(SDL_INIT_AUDIO);
- fprintf(stderr, "Dumping results to ~/%s", RESULTS_FILE);
- ResultsFile = fopen(ResultsPath, "wb");
- if (ResultsFile) {
- fprintf(ResultsFile, "Requested buffer samples,Samples output,Time taken to output (ns),Hz\n");
- for (Test = 0; Test < TestCount(); Test++) {
- fprintf(ResultsFile, "%" PRIu32 ",%" PRIu32 ",%" PRIu64 ",%f\n",
- UINT32_C(1) << Test,
- SamplesEmitted[Test],
- Results[Test],
- 1000000000.0f / ((float) Results[Test] / SamplesEmitted[Test]));
- }
- fclose(ResultsFile);
- fprintf(stderr, ", done.\n");
- } else {
- fprintf(stderr, "\nFile could not be written: %s\n", strerror(errno));
- }
- end:
- free(ResultsPath);
- SDL_Quit();
- fprintf(stderr, "Press Enter (Start) to exit.\n");
- char Dummy[2];
- fgets(Dummy, 2, stdin);
- return Error ? 1 : 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement