//
// C++ Implementation: portmidimidiinput
//
// Description: 
//
//
// Author: Predrag Viceic <viceic@net2000.ch>, (C) 2005
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "portmidimidiinput.h"
#include "midiinput.h"

PortMidiMidiInput::PortMidiMidiInput(QObject *parent, const char *name)
 : MidiInput(parent,name)
{
    noteAssignements=new noteAssignements_t[127];
    for(int i=0;i<127;i++){
        noteAssignements[i].start=-1;
        noteAssignements[i].stop=-1;
    }
    
    midiFilter=(PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_F9 | PM_FILT_FD |
                PM_FILT_UNDEFINED | PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH |
                PM_FILT_PROGRAM | PM_FILT_CONTROL | PM_FILT_PITCHBEND | PM_FILT_SONG_SELECT |
                PM_FILT_TUNE | PM_FILT_SONG_POSITION | PM_FILT_CLOCK);
    
    deviceOpened=0;
    serviceInitDone=0;
    selectedDevice=-1;
    openDevice(getDefaultDevice());
    midiEventBuffer=new PmEvent[1024]; 
    
}


PortMidiMidiInput::~PortMidiMidiInput()
{
     if(serviceInitDone) Pm_Terminate();
     if (midiEventBuffer) zaparr(midiEventBuffer);
}

/*!
    \fn PortMidiMidiInput::process()
 */
void PortMidiMidiInput::process()
{
    static int currently_playing=-1;
    if(serviceInitDone && deviceOpened && stream){
        PmError err;
        if (Pm_HasHostError(stream)!=pmNoError){
            serviceInitDone=0;
            deviceOpened=0;
            cout<<"[Freecycle] Portmidi error\n";
        }else if((err=Pm_Poll(stream))){
            int available=Pm_Read( stream, midiEventBuffer, 1024 );
            for (int i=0;i<available;i++){
                if(midiEventBuffer[i].message){
                    //printMessage(midiEventBuffer[i].message);
                    if(midiEventBuffer[i].message==252) soundPlayer->setPlaying(FALSE);
                    if((Pm_MessageStatus(midiEventBuffer[i].message)>>4)== 8 ||
                        (Pm_MessageStatus(midiEventBuffer[i].message)>>4)== 9){
                        int onoff=Pm_MessageStatus(midiEventBuffer[i].message)>>4==9?1:0;
                        
                        if(onoff){
                            playNote(Pm_MessageData1(midiEventBuffer[i].message));
                            currently_playing=Pm_MessageData1(midiEventBuffer[i].message);
                        }
                        else{ //note off
                            if(currently_playing==Pm_MessageData1(midiEventBuffer[i].message))
                                soundPlayer->setPlaying(FALSE);
                        }
                        emitMidiNote(onoff,
                                     Pm_MessageData1(midiEventBuffer[i].message),
                                     Pm_MessageData2(midiEventBuffer[i].message));
                    }
                }
            }
        }else if(err!=pmNoError){
            serviceInitDone=0;
            deviceOpened=0;
            cout<<"[Freecycle] Portmidi error\n";
        }
    }
}

/*!
    \fn MidiInput::printMessage(int msg)
 */
void PortMidiMidiInput::printMessage(int msg)
{
    if((Pm_MessageStatus(msg)>>4)!= 8 &&
                    (Pm_MessageStatus(msg)>>4)!= 9){
    int channel=Pm_MessageStatus(msg)& 0x0F;
    cout<<"Midi Event channel:"<<channel;
    cout<<" status:"<<Pm_MessageStatus(msg);
    cout<<" data1: "<<Pm_MessageData1(msg);
    cout<<" data2: "<<Pm_MessageData2(msg);
    cout<<"\n";
    }else{
        int channel=Pm_MessageStatus(msg) & 0x0F;
        cout<<"Midi Event channel:"<<channel;
        if (Pm_MessageStatus(msg)>>4==9){
            cout<<" note on - key: ";
        }else{
            cout<<" note off - key: ";
        }
        cout<<Pm_MessageData1(msg);
        cout<<" velocity: "<<Pm_MessageData2(msg);
        cout<<"\n";
    }
}


/*!
    \fn PortMidiMidiInput::getDevices()
 */
QStringList PortMidiMidiInput::getDevices()
{
    if(deviceOpened && stream && Pm_HasHostError(stream)!=pmNoError) Pm_Close(stream);
    deviceOpened=0;
    if(serviceInitDone) Pm_Terminate();
    /*if(!serviceInitDone)*/ Pm_Initialize();
    serviceInitDone=1;
    QStringList list;
    int count=Pm_CountDevices();
    //cout<<"count: "<<count<<"\n";
    for (int i=0;i<count;i++){
        const PmDeviceInfo* deviceInfo=Pm_GetDeviceInfo(i);
        if(deviceInfo->input)
            list.append("("+QString(deviceInfo->interf)+")"+
                        " "+QString(deviceInfo->name));
    }
    return list;
}


/*!
    \fn PortMidiMidiInput::openDevice(int id)
 */
int PortMidiMidiInput::openDevice(int id)
{
    if(id!=pmNoDevice){
        if(!serviceInitDone) Pm_Initialize();
        serviceInitDone=1;
        if(deviceOpened) Pm_Close(stream);
        int e= Pm_OpenInput(&stream,
                    id,
                    NULL,
                    1024,//input buffer size
                    NULL, //time proc
                    NULL);
        if(!e){
            deviceOpened=1;
            selectedDevice=id;
            Pm_SetFilter(stream,midiFilter);
            cout<<"Midi Device opened:"<<getSelectedDeviceString()<<"\n";
        }
        return e;
    }
    return -1;
}




/*!
    \fn PortMidiMidiInput::getDefaultDevice()
 */
int PortMidiMidiInput::getDefaultDevice()
{

    if(serviceInitDone!=1) Pm_Initialize();
    serviceInitDone=1;
    return Pm_GetDefaultInputDeviceID();
}


/*!
    \fn PortMidiMidiInput::getSelectedDevice()
 */
int PortMidiMidiInput::getSelectedDevice()
{
    return selectedDevice;
}


/*!
    \fn PortMidiMidiInput::getSelectedDeviceString()
 */
QString PortMidiMidiInput::getSelectedDeviceString()
{
    const PmDeviceInfo* deviceInfo=Pm_GetDeviceInfo(selectedDevice);
        if(deviceInfo && deviceInfo->input)
            return QString("("+QString(deviceInfo->interf)+")"+
                        " "+QString(deviceInfo->name));
        else return "";
}


/*!
    \fn PortMidiMidiInput::getDefaultDeviceString()
 */
QString PortMidiMidiInput::getDefaultDeviceString()
{
    const PmDeviceInfo* deviceInfo=Pm_GetDeviceInfo(getDefaultDevice());
        if(deviceInfo->input)
            return QString("("+QString(deviceInfo->interf)+")"+
                        " "+QString(deviceInfo->name));
        else return ("");
}


/*!
    \fn PortMidiMidiInput::openDevice(QString device)
 */
int PortMidiMidiInput::openDevice(QString device)
{
    if(deviceOpened==1) Pm_Close(stream);
    deviceOpened=0;
    //if(serviceInitDone) Pm_Terminate();
    if(serviceInitDone!=1) Pm_Initialize();
    serviceInitDone=1;
    int count=Pm_CountDevices();
    for (int i=0;i<count;i++){
        const PmDeviceInfo* deviceInfo=Pm_GetDeviceInfo(i);
        if(deviceInfo->input){
            QString deviceName=QString("("+QString(deviceInfo->interf)+")"+
                        " "+QString(deviceInfo->name));
            if (deviceName==device){
                return openDevice(i);
            }
        }
    }
    return -1;
}


/*!
    \fn PortMidiMidiInput::setMidiChannel(int c)
 */
void PortMidiMidiInput::setMidiChannel(int c)
{
    //supposes that the stream is already opened !!!
    if (c==0)
        Pm_SetChannelMask(stream,65535);
    else
        Pm_SetChannelMask(stream,Pm_Channel(c));
}


