/***************************************************************************
 *   Copyright (C) 2004 by Predrag Viceic                                  *
 *   viceic@net2000.ch                                            *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "midioutput.h"

MidiOutput::MidiOutput(QObject *parent, const char *name)
 : QObject(parent, name)
{
    if (snd_seq_open(&seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
        fprintf(stderr, "Error opening ALSA sequencer.\n");
    }
    snd_seq_set_client_name(seq_handle, "Freecycle");
    clientid = snd_seq_client_id(seq_handle);

    if ((portid_out = snd_seq_create_simple_port(seq_handle, "Freecycle",
         SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
         SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
             fprintf(stderr, "Error creating sequencer port.\n");
    }
    snd_seq_set_client_pool_output(seq_handle, SEQPOOL);
    queue_id = snd_seq_alloc_queue(seq_handle);
    bpm=180.0;
    setQueueTempo(bpm);
}


MidiOutput::~MidiOutput()
{
}

void MidiOutput::setQueueTempo(float bpm) {

    snd_seq_queue_tempo_t *queue_tempo;
    int msec_tempo;
    snd_seq_queue_tempo_malloc(&queue_tempo);
    msec_tempo = (int)(6e7 / (double)bpm);
    snd_seq_queue_tempo_set_tempo(queue_tempo, msec_tempo);
    snd_seq_queue_tempo_set_ppq(queue_tempo, TICKS_PER_QUARTER);
    snd_seq_set_queue_tempo(seq_handle, queue_id, queue_tempo);
    snd_seq_queue_tempo_free(queue_tempo);
}


void MidiOutput::doLoop() {
        snd_seq_tick_time_t next_tick=get_tick();
        for (int i=0;i<TICKS_PER_QUARTER;i++){
            //cout<<i<<endl;
            snd_seq_event_t evOut;
            snd_seq_ev_clear(&evOut);
            evOut.type = SND_SEQ_EVENT_CLOCK;
            snd_seq_ev_schedule_tick(&evOut, queue_id, next_tick, i*(TICKS_PER_QUARTER/24));
            snd_seq_ev_set_subs(&evOut);
            snd_seq_ev_set_source(&evOut, portid_out);
            snd_seq_event_output(seq_handle, &evOut);
        }
        snd_seq_drain_output(seq_handle);
        snd_seq_sync_output_queue(seq_handle);
}

snd_seq_tick_time_t MidiOutput::get_tick() {

    snd_seq_queue_status_t *status;
    snd_seq_tick_time_t current_tick;

    snd_seq_queue_status_malloc(&status);
    snd_seq_get_queue_status(seq_handle, queue_id, status);
    current_tick = snd_seq_queue_status_get_tick_time(status);
    snd_seq_queue_status_free(status);
    return(current_tick);
}




/*!
    \fn MidiOutput::startQueue()
 */
void MidiOutput::startQueue()
{
    snd_seq_start_queue(seq_handle, queue_id, NULL);
}


/*!
    \fn MidiOutput::stopQueue()
 */
void MidiOutput::stopQueue()
{
    snd_seq_stop_queue(seq_handle, queue_id, NULL);
}


/*!
    \fn MidiOutput::continueQueue()
 */
void MidiOutput::continueQueue()
{
    snd_seq_continue_queue(seq_handle, queue_id, NULL);
}


/*!
    \fn MidiOutput::setTempo(float tempo)
 */
void MidiOutput::setTempo(float tempo)
{
    bpm=tempo;
    setQueueTempo(bpm);
}

