Skip to content
Snippets Groups Projects
Select Git revision
  • d3f6859ef0c324e2d0c56b9b7bd43c73d0b7fe91
  • main default protected
  • blm_dev_chan
  • release/1.4.0 protected
  • widgets_draw
  • return_of_melodic_demo
  • task_cleanup
  • mixer2
  • dx/fb-save-restore
  • dx/dldldld
  • fpletz/flake
  • dx/jacksense-headset-mic-only
  • release/1.3.0 protected
  • fil3s-limit-filesize
  • allow-reloading-sunmenu
  • wifi-json-error-handling
  • app_text_viewer
  • shoegaze-fps
  • media_has_video_has_audio
  • fil3s-media
  • more-accurate-battery
  • v1.4.0
  • v1.3.0
  • v1.2.0
  • v1.2.0+rc1
  • v1.1.1
  • v1.1.0
  • v1.1.0+rc1
  • v1.0.0
  • v1.0.0+rc6
  • v1.0.0+rc5
  • v1.0.0+rc4
  • v1.0.0+rc3
  • v1.0.0+rc2
  • v1.0.0+rc1
35 results

audio_mod.c

Blame
  • audio_mod.c 3.72 KiB
    #ifndef __clang__
    #pragma GCC optimize("O2")
    #endif
    
    #include <fcntl.h>
    #include <st3m_audio.h>
    #include <st3m_media.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    #include "ctx.h"
    
    #define POCKETMOD_IMPLEMENTATION
    #include "pocketmod.h"
    
    typedef struct {
        st3m_media control;
        pocketmod_context pocketmod;
        uint8_t *data;
        size_t size;
        char *path;
        float scroll_pos;
    } mod_state;
    
    static void mod_draw(st3m_media *media, Ctx *ctx) {
        mod_state *self = (void *)media;
    
        ctx_rectangle(ctx, -120, -120, 240, 240);
        ctx_gray(ctx, 0);
        ctx_fill(ctx);
        // ctx_arc(ctx, 0, 0, 10, 10);
        ctx_rgb(ctx, 1.0, 1.0, 1.0);
        ctx_font_size(ctx, 20);
        char buf[100];
        sprintf(buf, "pat:%i/%i line:%i", self->pocketmod.pattern,
                self->pocketmod.num_patterns, self->pocketmod.line);
        ctx_text_align(ctx, CTX_TEXT_ALIGN_CENTER);
        ctx_move_to(ctx, 0, -20);
        ctx_text(ctx, buf);
        ctx_fill(ctx);
    
        ctx_font_size(ctx, 14);
        int xpos = 0;
        int str_width = ctx_text_width(ctx, self->path);
        if (str_width > 220) {
            xpos = ctx_sinf(self->scroll_pos) * (str_width - 220) / 2;
        }
        ctx_move_to(ctx, xpos, 14);
        ctx_gray(ctx, 0.6);
        ctx_text(ctx, self->path);
    }
    
    static void mod_think(st3m_media *media, float ms_elapsed) {
        mod_state *self = (void *)media;
        if (self->control.paused) return;
    
        if (self->control.seek == 0) {
            pocketmod_init(&self->pocketmod, self->data, self->size, 48000);
            self->control.seek = -1;
        }
    
        int samples_needed = (ms_elapsed / 1000.0) * 48000;
        if (samples_needed > 1000) samples_needed = 1000;
    
        float rendered[samples_needed * 2];
        int rend = pocketmod_render(&self->pocketmod, rendered, sizeof(rendered));
        st3m_pcm_queue_float(48000, 2, rend / (sizeof(float) * 2), rendered);
    
        if (self->control.duration == 0) {
            self->control.duration = self->pocketmod.num_patterns + 1;
        }
        if (self->pocketmod.pattern >= self->control.duration)
            self->control.duration = self->pocketmod.pattern + 1;
        self->control.position = self->pocketmod.pattern;
        if (self->pocketmod.loop_count)
            self->control.duration = self->control.position;
    
        self->scroll_pos += ms_elapsed / 1000.0;
    }
    
    static void mod_destroy(st3m_media *media) {
        mod_state *self = (void *)media;
        if (self->data) free(self->data);
        if (self->path) free(self->path);
        free(self);
    }
    
    static int file_get_contents(const char *path, uint8_t **contents,
                                 size_t *length) {
        FILE *file;
        long size;
        long remaining;
        uint8_t *buffer;
        file = fopen(path, "rb");
        if (!file) {
            return -1;
        }
        fseek(file, 0, SEEK_END);
        size = remaining = ftell(file);
    
        if (length) {
            *length = size;
        }
        rewind(file);
        buffer = malloc(size + 2);
        if (!buffer) {
            fclose(file);
            return -1;
        }
        remaining -= fread(buffer, 1, remaining, file);
        if (remaining) {
            fclose(file);
            free(buffer);
            return -1;
        }
        fclose(file);
        *contents = (unsigned char *)buffer;
        buffer[size] = 0;
        return 0;
    }
    
    st3m_media *st3m_media_load_mod(const char *path) {
        mod_state *self = (mod_state *)malloc(sizeof(mod_state));
        memset(self, 0, sizeof(mod_state));
        self->control.draw = mod_draw;
        self->control.think = mod_think;
        self->control.destroy = mod_destroy;
        self->control.has_audio = true;
        file_get_contents(path, &self->data, &self->size);
        if (!self->data ||
            !pocketmod_init(&self->pocketmod, self->data, self->size, 48000)) {
            if (self->data) free(self->data);
            free(self);
            return NULL;
        }
        self->path = strdup(path);
        self->scroll_pos = 0;
        return (st3m_media *)self;
    }