/***************************************************************************
                          sndsrv.c  -  description
                             -------------------
    begin                : Thu Apr 20 2000
    copyright            : (C) 2000 by Michael Speck
    email                : kulkanie@gmx.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "sndsrv.h"

#ifdef SOUND

#include <stdlib.h>
#include <string.h>
#include <SDL_video.h>

extern char *src_dir;

// Wave //

Wave* Wave_Load(char *fname)
{
    Wave *w;
    char path[strlen(src_dir) + strlen(fname) + 1];
    sprintf(path,"%s%s",src_dir,fname);
    w = (Wave*)malloc(sizeof(Wave));
    if (w == 0) {
        fprintf(stderr, "ERR: wave_load: not enough memory\n");
        exit(1);
    }	
    w->buf = 0;
    w->len = 0;
    if (SDL_LoadWAV(path, &w->spec, &w->buf, &w->len) == 0) {
        fprintf(stderr, "ERR: wave_load: %s\n", SDL_GetError());
        exit(1);
    }
    w->spec.callback = 0;
    w->spec.userdata = 0;
    return w;
}

void Wave_Free(Wave *w)
{
    if (w->buf) SDL_FreeWAV(w->buf);
    free(w);
}

void Wave_Format(Wave *w, SDL_AudioSpec dest)
{
    SDL_AudioCVT cvt;

    printf("dst:\n");
    printf("ch: %i | smpls: %i | fmt: %i\n", dest.channels, dest.format, dest.samples);
    printf("src:\n");
    printf("ch: %i | smpls: %i | fmt: %i\n", w->spec.channels, w->spec.format, w->spec.samples);

    if (dest.channels != w->spec.channels || dest.format != w->spec.format || dest.samples != w->spec.samples) {
        SDL_BuildAudioCVT(&cvt, w->spec.format, w->spec.channels, w->spec.samples, dest.format, dest.channels, dest.samples);
        cvt.len = w->len;
        cvt.buf = (char*)malloc(cvt.len * cvt.len_mult);
        memcpy(cvt.buf, w->buf, w->len);
        SDL_ConvertAudio(&cvt);
        SDL_FreeWAV(w->buf);
        w->buf = cvt.buf;
    }
}

// Soundserver //

SndSrv sndsrv;

void SndSrv_Init(int t)
{
    int i;
    sndsrv.tracks = (Track*)malloc(sizeof(Track) * t);
    sndsrv.track_num = t;
    for (i = 0; i < t; i++)
        sndsrv.tracks[i].wave = 0;
    SndSrv_SetVolume(8);
    sndsrv.playing = 0;
    sndsrv.ok = 1;
}

void SndSrv_Quit()
{
    free(sndsrv.tracks);
}

int SndSrv_Open(SDL_AudioSpec wanted) {
    sndsrv.spec.callback = SndSrv_Callback;
    sndsrv.spec.userdata = 0;
    if (SDL_OpenAudio(&sndsrv.spec, 0) < 0) {
    	fprintf(stderr, "ERR: sndsrv_open: %s\n", SDL_GetError());
    	sndsrv.ok = 0;
    	return 1;
    }
    SndSrv_Pause(0);
    sndsrv.playing = 0;
    sndsrv.sleeping = 0;
    return 0;
}

void SndSrv_Close()
{
    if (sndsrv.ok)
        SDL_CloseAudio();
}

void SndSrv_Pause(int p)
{
    if (!sndsrv.ok) return;
    SDL_PauseAudio(p);
    if (p) sndsrv.playing = 0;
}

void SndSrv_Play(Wave *w, int p)
{
    int j;
    if (sndsrv.sleeping || !sndsrv.ok) return;
    //use free track if possible
    for (j = 0; j < sndsrv.track_num; j++)
        if (sndsrv.tracks[j].wave == 0) {
            //empty
            sndsrv.tracks[j].wave = w;
            sndsrv.tracks[j].audio_pos = w->buf;
            sndsrv.tracks[j].len = w->len;
            sndsrv.playing++;
            SndSrv_Pause(0);
            return;
        }
    for (j = 0; j < sndsrv.track_num; j++)
        if (sndsrv.tracks[j].priority <= p) {
           	//lower priority found
            sndsrv.tracks[j].wave = w;
            sndsrv.tracks[j].audio_pos = w->buf;
            sndsrv.tracks[j].len = w->len;
            sndsrv.playing++;
            SndSrv_Pause(0);
            return;
        }
    return; //cannot play sound, no track available
}

void SndSrv_SetVolume(char v)
{
    sndsrv.volume = v < 0 ? 0 : v > 8 ? 8 : v;
    if (sndsrv.volume) sndsrv.volume = sndsrv.volume * 16 - 1;
}

void SndSrv_SetActive(int a)
{
    sndsrv.sleeping = !a;
}

void SndSrv_Callback(void *udata, unsigned char *stream, int str_len)
{
    int i, len;
    Track *track;
    if (sndsrv.sleeping || !sndsrv.ok) return;
    for (i = 0; i < sndsrv.track_num; i++) {
       	track = &sndsrv.tracks[i];
        if (track->wave == 0) continue;
        len = str_len < track->len ? str_len : track->len;
        SDL_MixAudio(stream, track->audio_pos, len, sndsrv.volume);
        track->len -= len;
        track->audio_pos += len;
        if (track->len == 0) {
            track->wave = 0;
            sndsrv.playing--;
        }
        if (!sndsrv.playing) SndSrv_Pause(1);
    }
}

#endif

