summaryrefslogtreecommitdiffhomepage
path: root/src/player.c
blob: c1a7fff0faaa3597283e2180fc19fb82d1a8f9d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "player.h"

#include <ctype.h>
#include <stdio.h>
#include <string.h>

/* ------------------------------------------------------------------ */
/* Helpers (module-private)                                           */
/* ------------------------------------------------------------------ */

static int ext_equals_nocase(const char *a, const char *b)
{
    while (*a && *b) {
        if (tolower((unsigned char)*a) != tolower((unsigned char)*b)) return 1;
        a++; b++;
    }
    return *a != *b;
}

static const char *basename_from_path(const char *path)
{
    const char *last = path;
    for (const char *p = path; *p; p++) {
        if (*p == '/' || *p == '\\') last = p + 1;
    }
    return last;
}

/* ------------------------------------------------------------------ */
/* Public API                                                         */
/* ------------------------------------------------------------------ */

bool player_load(PlayerState *state, const char *path)
{
    const char *ext = GetFileExtension(path);
    if (ext == NULL || ext_equals_nocase(ext, ".mp3") != 0) return false;

    if (state->loaded) {
        StopMusicStream(state->music);
        UnloadMusicStream(state->music);
        state->loaded = false;
        state->playing = false;
    }

    state->music = LoadMusicStream(path);
    state->duration = GetMusicTimeLength(state->music);
    state->loaded = true;
    state->playing = true;

    const char *base = basename_from_path(path);
    strncpy(state->filename, base, sizeof(state->filename) - 1);
    state->filename[sizeof(state->filename) - 1] = '\0';

    PlayMusicStream(state->music);
    return true;
}

void player_unload(PlayerState *state)
{
    if (!state->loaded) return;
    StopMusicStream(state->music);
    UnloadMusicStream(state->music);
    state->loaded = false;
    state->playing = false;
}

void player_play(PlayerState *state)
{
    if (!state->loaded || state->playing) return;
    ResumeMusicStream(state->music);
    state->playing = true;
}

void player_pause(PlayerState *state)
{
    if (!state->loaded || !state->playing) return;
    PauseMusicStream(state->music);
    state->playing = false;
}

void player_seek(PlayerState *state, float target)
{
    if (!state->loaded) return;
    if (target < 0.0f) target = 0.0f;
    if (target > state->duration) target = state->duration;
    SeekMusicStream(state->music, target);
    state->currentTime = target;
    state->skipAutoUpdate = 3; /* skip a few frames to let audio engine catch up */
}

void player_update(PlayerState *state)
{
    if (!state->loaded) return;
    UpdateMusicStream(state->music);
    if (state->playing) {
        if (state->skipAutoUpdate > 0) {
            state->skipAutoUpdate--;
        } else {
            state->currentTime = GetMusicTimePlayed(state->music);
        }
    }
}

void player_format_time(float seconds, char *buf, int bufsize)
{
    int total = (int)seconds;
    if (total < 0) total = 0;
    int h = total / 3600;
    int m = (total % 3600) / 60;
    int s = total % 60;
    if (h > 0)
        snprintf(buf, bufsize, "%d:%02d:%02d", h, m, s);
    else
        snprintf(buf, bufsize, "%d:%02d", m, s);
}