/*
 * new_fluid_winmidi_driver
 */
fluid_midi_driver_t*
new_fluid_winmidi_driver(fluid_settings_t* settings,
			handle_midi_event_func_t handler, void* data)
{
  fluid_winmidi_driver_t* dev;
  MMRESULT res;
  UINT i, err, num;
  MIDIINCAPS in_caps;
  int midi_num = 0;

  /* not much use doing anything */
  if (handler == NULL) {
    FLUID_LOG(FLUID_ERR, "Invalid argument");
    return NULL;
  }

  dev = FLUID_MALLOC(sizeof(fluid_winmidi_driver_t));
  if (dev == NULL) {
    return NULL;
  }

  dev->hmidiin = NULL;
  dev->driver.handler = handler;
  dev->driver.data = data;

  /* check if there any midi devices installed */
  num = midiInGetNumDevs();
  if (num == 0) {
    FLUID_LOG(FLUID_ERR, "no MIDI in devices found");
    goto error_recovery;
  }

  /* find the device */
  for (i = 0; i < num; i++) {
    res = midiInGetDevCaps(i, &in_caps, sizeof(LPMIDIINCAPS));
    if (res == MMSYSERR_NOERROR) {
    }
  }

  /* try opening the device */
  err = midiInOpen(&dev->hmidiin, midi_num,
		   (DWORD) fluid_winmidi_callback,
		   (DWORD) dev, CALLBACK_FUNCTION);
  if (err != MMSYSERR_NOERROR) {
    FLUID_LOG(FLUID_WARN, "Couldn't open MIDI input: %s (error %d)",
	     fluid_winmidi_input_error(err), err);
    goto error_recovery;
  }

  if (midiInStart(dev->hmidiin) != MMSYSERR_NOERROR) {
    FLUID_LOG(FLUID_ERR, "Failed to start the MIDI input. MIDI input not available.");
    goto error_recovery;
  }

  return (fluid_midi_driver_t*) dev;

 error_recovery:
  delete_fluid_winmidi_driver((fluid_midi_driver_t*) dev);
  return NULL;
}
Esempio n. 2
0
static char*
fluid_file_read_full(fluid_file fp, size_t* length)
{
    size_t buflen;
    char* buffer;
    size_t n;
    /* Work out the length of the file in advance */
    if (FLUID_FSEEK(fp, 0, SEEK_END) != 0)
    {
        FLUID_LOG(FLUID_ERR, "File load: Could not seek within file");
        return NULL;
    }
    buflen = ftell(fp);
    if (FLUID_FSEEK(fp, 0, SEEK_SET) != 0)
    {
        FLUID_LOG(FLUID_ERR, "File load: Could not seek within file");
        return NULL;
    }
    FLUID_LOG(FLUID_DBG, "File load: Allocating %d bytes", buflen);
    buffer = FLUID_MALLOC(buflen);
    if (buffer == NULL) {
        FLUID_LOG(FLUID_PANIC, "Out of memory");
        return NULL;
    }
    n = FLUID_FREAD(buffer, 1, buflen, fp);
    if (n != buflen) {
        FLUID_LOG(FLUID_ERR, "Only read %d bytes; expected %d", n,
                  buflen);
        FLUID_FREE(buffer);
        return NULL;
    };
    *length = n;
    return buffer;
}
Esempio n. 3
0
fluid_evt_heap_t*
_fluid_evt_heap_init(int nbEvents)
{
#ifdef HEAP_WITH_DYNALLOC

  int i;
  fluid_evt_heap_t* heap;
  fluid_evt_entry *tmp;

  heap = FLUID_NEW(fluid_evt_heap_t);
  if (heap == NULL) {
    fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
    return NULL;
  }

  heap->freelist = NULL;
  fluid_mutex_init(heap->mutex);

  /* LOCK */
  fluid_mutex_lock(heap->mutex);

  /* Allocate the event entries */
  for (i = 0; i < nbEvents; i++) {
    tmp = FLUID_NEW(fluid_evt_entry);
    tmp->next = heap->freelist;
    heap->freelist = tmp;
  }

  /* UNLOCK */
  fluid_mutex_unlock(heap->mutex);


#else
	int i;
	fluid_evt_heap_t* heap;
	int siz = 2*sizeof(fluid_evt_entry *) + sizeof(fluid_evt_entry)*nbEvents;

	heap = (fluid_evt_heap_t *)FLUID_MALLOC(siz);
  if (heap == NULL) {
    fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
    return NULL;
  }
  FLUID_MEMSET(heap, 0, siz);

  /* link all heap events */
  {
  	fluid_evt_entry *tmp = &(heap->pool);
	  for (i = 0 ; i < nbEvents - 1 ; i++)
 		 	tmp[i].next = &(tmp[i+1]);
 	 	tmp[nbEvents-1].next = NULL;

 	 	/* set head & tail */
 	 	heap->tail = &(tmp[nbEvents-1]);
  	heap->head = &(heap->pool);
  }
#endif
  return (heap);
}
Esempio n. 4
0
fluid_list_t*
new_fluid_list(void)
{
  fluid_list_t* list;
  list = (fluid_list_t*) FLUID_MALLOC(sizeof(fluid_list_t));
  list->data = NULL;
  list->next = NULL;
  return list;
}
Esempio n. 5
0
/**
 * Add a MIDI file to a player queue, from a buffer in memory.
 * @param player MIDI player instance
 * @param buffer Pointer to memory containing the bytes of a complete MIDI
 *   file. The data is copied, so the caller may free or modify it immediately
 *   without affecting the playlist.
 * @param len Length of the buffer, in bytes.
 * @return #FLUID_OK or #FLUID_FAILED
 */
int
fluid_player_add_mem(fluid_player_t* player, const void *buffer, size_t len)
{
    /* Take a copy of the buffer, so the caller can free immediately. */
    fluid_playlist_item *pi = FLUID_MALLOC(sizeof(fluid_playlist_item));
    void *buf_copy = FLUID_MALLOC(len);
    if (!pi || !buf_copy) {
        FLUID_FREE(pi);
        FLUID_FREE(buf_copy);
        FLUID_LOG(FLUID_PANIC, "Out of memory");
        return FLUID_FAILED;
    }

    FLUID_MEMCPY(buf_copy, buffer, len);
    pi->filename = NULL;
    pi->buffer = buf_copy;
    pi->buffer_len = len;
    player->playlist = fluid_list_append(player->playlist, pi);
    return FLUID_OK;
}
Esempio n. 6
0
/**
 * Add a MIDI file to a player queue.
 * @param player MIDI player instance
 * @param midifile File name of the MIDI file to add
 * @return #FLUID_OK or #FLUID_FAILED
 */
int
fluid_player_add(fluid_player_t *player, const char *midifile)
{
    fluid_playlist_item *pi = FLUID_MALLOC(sizeof(fluid_playlist_item));
    char* f = FLUID_STRDUP(midifile);
    if (!pi || !f) {
        FLUID_FREE(pi);
        FLUID_FREE(f);
        FLUID_LOG(FLUID_PANIC, "Out of memory");
        return FLUID_FAILED;
    }

    pi->filename = f;
    pi->buffer = NULL;
    pi->buffer_len = 0;
    player->playlist = fluid_list_append(player->playlist, pi);
    return FLUID_OK;
}
Esempio n. 7
0
/*
 * fluid_track_set_name
 */
int fluid_track_set_name(fluid_track_t* track, char* name)
{
	int len;
	if (track->name != NULL) {
		FLUID_FREE(track->name);
	}
	if (name == NULL) {
		track->name = NULL;
		return FLUID_OK;
	}
	len = FLUID_STRLEN(name);
	track->name = FLUID_MALLOC(len + 1);
	if (track->name == NULL) {
		FLUID_LOG(FLUID_ERR, "Out of memory");
		return FLUID_FAILED;
	}
	FLUID_STRCPY(track->name, name);
	return FLUID_OK;
}
Esempio n. 8
0
/**
 * Create a new sequencer object.
 * @param use_system_timer If TRUE, sequencer will advance at the rate of the
 *   system clock. If FALSE, call fluid_sequencer_process() to advance
 *   the sequencer.
 * @return New sequencer instance
 * @since 1.1.0
 */
fluid_sequencer_t*
new_fluid_sequencer2 (int use_system_timer)
{
	fluid_sequencer_t* seq;

	seq = FLUID_NEW(fluid_sequencer_t);
	if (seq == NULL) {
		fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
		return NULL;
	}

	FLUID_MEMSET(seq, 0, sizeof(fluid_sequencer_t));

	seq->scale = 1000;	// default value
	seq->useSystemTimer = use_system_timer ? TRUE : FALSE;
	seq->startMs = seq->useSystemTimer ? fluid_curtime() : 0;
	seq->clients = NULL;
	seq->clientsID = 0;

	if (-1 == _fluid_seq_queue_init(seq, FLUID_SEQUENCER_EVENTS_MAX)) {
		FLUID_FREE(seq);
		fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
		return NULL;
	}

#if FLUID_SEQ_WITH_TRACE
	seq->tracelen = 1024*100;
	seq->tracebuf = (char *)FLUID_MALLOC(seq->tracelen);
	if (seq->tracebuf == NULL) {
 		_fluid_seq_queue_end(seq);
 		FLUID_FREE(seq);
		fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
		return NULL;
	}
	seq->traceptr = seq->tracebuf;
#endif

	return(seq);
}
Esempio n. 9
0
/*
 * fluid_midi_file_read_event
 */
int
fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track, int num)
{
    int status;
    int type;
    int tempo;
    unsigned char *metadata = NULL;
    unsigned char *dyn_buf = NULL;
    unsigned char static_buf[256];
    int nominator, denominator, clocks, notes;
    fluid_midi_event_t *evt;
    int channel = 0;
    int param1 = 0;
    int param2 = 0;
    int size;

    /* read the delta-time of the event */
    if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
        return FLUID_FAILED;
    }
    mf->dtime += mf->varlen;

    /* read the status byte */
    status = fluid_midi_file_getc(mf);
    if (status < 0) {
        FLUID_LOG(FLUID_ERR, "Unexpected end of file");
        return FLUID_FAILED;
    }

    /* not a valid status byte: use the running status instead */
    if ((status & 0x80) == 0) {
        if ((mf->running_status & 0x80) == 0) {
            FLUID_LOG(FLUID_ERR, "Undefined status and invalid running status");
            return FLUID_FAILED;
        }
        fluid_midi_file_push(mf, status);
        status = mf->running_status;
    }

    /* check what message we have */

    mf->running_status = status;

    if ((status == MIDI_SYSEX)) { /* system exclusif */
        /* read the length of the message */
        if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
            return FLUID_FAILED;
        }

        if (mf->varlen) {
            FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__,
                    __LINE__, mf->varlen);
            metadata = FLUID_MALLOC(mf->varlen + 1);

            if (metadata == NULL) {
                FLUID_LOG(FLUID_PANIC, "Out of memory");
                return FLUID_FAILED;
            }

            /* read the data of the message */
            if (fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) {
                FLUID_FREE (metadata);
                return FLUID_FAILED;
            }

            evt = new_fluid_midi_event();
            if (evt == NULL) {
                FLUID_LOG(FLUID_ERR, "Out of memory");
                FLUID_FREE (metadata);
                return FLUID_FAILED;
            }

            evt->dtime = mf->dtime;
            size = mf->varlen;

            if (metadata[mf->varlen - 1] == MIDI_EOX)
                size--;

            /* Add SYSEX event and indicate that its dynamically allocated and should be freed with event */
            fluid_midi_event_set_sysex(evt, metadata, size, TRUE);
            fluid_track_add_event(track, evt);
            mf->dtime = 0;
        }

        return FLUID_OK;

    } else if (status == MIDI_META_EVENT) { /* meta events */

        int result = FLUID_OK;

        /* get the type of the meta message */
        type = fluid_midi_file_getc(mf);
        if (type < 0) {
            FLUID_LOG(FLUID_ERR, "Unexpected end of file");
            return FLUID_FAILED;
        }

        /* get the length of the data part */
        if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
            return FLUID_FAILED;
        }

        if (mf->varlen < 255) {
            metadata = &static_buf[0];
        } else {
            FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__,
                    __LINE__, mf->varlen);
            dyn_buf = FLUID_MALLOC(mf->varlen + 1);
            if (dyn_buf == NULL) {
                FLUID_LOG(FLUID_PANIC, "Out of memory");
                return FLUID_FAILED;
            }
            metadata = dyn_buf;
        }

        /* read the data */
        if (mf->varlen) {
            if (fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) {
                if (dyn_buf) {
                    FLUID_FREE(dyn_buf);
                }
                return FLUID_FAILED;
            }
        }

        /* handle meta data */
        switch (type) {

            case MIDI_COPYRIGHT:
                metadata[mf->varlen] = 0;
                break;

            case MIDI_TRACK_NAME:
                metadata[mf->varlen] = 0;
                fluid_track_set_name(track, (char *) metadata);
                break;

            case MIDI_INST_NAME:
                metadata[mf->varlen] = 0;
                break;

            case MIDI_LYRIC:
                break;

            case MIDI_MARKER:
                break;

            case MIDI_CUE_POINT:
                break; /* don't care much for text events */

            case MIDI_EOT:
                if (mf->varlen != 0) {
                    FLUID_LOG(FLUID_ERR, "Invalid length for EndOfTrack event");
                    result = FLUID_FAILED;
                    break;
                }
                mf->eot = 1;
                evt = new_fluid_midi_event();
                if (evt == NULL) {
                    FLUID_LOG(FLUID_ERR, "Out of memory");
                    result = FLUID_FAILED;
                    break;
                }
                evt->dtime = mf->dtime;
                evt->type = MIDI_EOT;
                fluid_track_add_event(track, evt);
                mf->dtime = 0;
                break;

            case MIDI_SET_TEMPO:
                if (mf->varlen != 3) {
                    FLUID_LOG(FLUID_ERR,
                            "Invalid length for SetTempo meta event");
                    result = FLUID_FAILED;
                    break;
                }
                tempo = (metadata[0] << 16) + (metadata[1] << 8) + metadata[2];
                evt = new_fluid_midi_event();
                if (evt == NULL) {
                    FLUID_LOG(FLUID_ERR, "Out of memory");
                    result = FLUID_FAILED;
                    break;
                }
                evt->dtime = mf->dtime;
                evt->type = MIDI_SET_TEMPO;
                evt->channel = 0;
                evt->param1 = tempo;
                evt->param2 = 0;
                fluid_track_add_event(track, evt);
                mf->dtime = 0;
                break;

            case MIDI_SMPTE_OFFSET:
                if (mf->varlen != 5) {
                    FLUID_LOG(FLUID_ERR,
                            "Invalid length for SMPTE Offset meta event");
                    result = FLUID_FAILED;
                    break;
                }
                break; /* we don't use smtp */

            case MIDI_TIME_SIGNATURE:
                if (mf->varlen != 4) {
                    FLUID_LOG(FLUID_ERR,
                            "Invalid length for TimeSignature meta event");
                    result = FLUID_FAILED;
                    break;
                }
                nominator = metadata[0];
                denominator = pow(2.0, (double) metadata[1]);
                clocks = metadata[2];
                notes = metadata[3];

                FLUID_LOG(FLUID_DBG,
                        "signature=%d/%d, metronome=%d, 32nd-notes=%d",
                        nominator, denominator, clocks, notes);

                break;

            case MIDI_KEY_SIGNATURE:
                if (mf->varlen != 2) {
                    FLUID_LOG(FLUID_ERR,
                            "Invalid length for KeySignature meta event");
                    result = FLUID_FAILED;
                    break;
                }
                /* We don't care about key signatures anyway */
                /* sf = metadata[0];
                mi = metadata[1]; */
                break;

            case MIDI_SEQUENCER_EVENT:
                break;

            default:
                break;
        }

        if (dyn_buf) {
            FLUID_LOG(FLUID_DBG, "%s: %d: free metadata", __FILE__, __LINE__);
            FLUID_FREE(dyn_buf);
        }

        return result;

    } else { /* channel messages */

        type = status & 0xf0;
        channel = status & 0x0f;

        /* all channel message have at least 1 byte of associated data */
        if ((param1 = fluid_midi_file_getc(mf)) < 0) {
            FLUID_LOG(FLUID_ERR, "Unexpected end of file");
            return FLUID_FAILED;
        }

        switch (type) {

            case NOTE_ON:
                if ((param2 = fluid_midi_file_getc(mf)) < 0) {
                    FLUID_LOG(FLUID_ERR, "Unexpected end of file");
                    return FLUID_FAILED;
                }
                break;

            case NOTE_OFF:
                if ((param2 = fluid_midi_file_getc(mf)) < 0) {
                    FLUID_LOG(FLUID_ERR, "Unexpected end of file");
                    return FLUID_FAILED;
                }
                break;

            case KEY_PRESSURE:
                if ((param2 = fluid_midi_file_getc(mf)) < 0) {
                    FLUID_LOG(FLUID_ERR, "Unexpected end of file");
                    return FLUID_FAILED;
                }
                break;

            case CONTROL_CHANGE:
                if ((param2 = fluid_midi_file_getc(mf)) < 0) {
                    FLUID_LOG(FLUID_ERR, "Unexpected end of file");
                    return FLUID_FAILED;
                }
                break;

            case PROGRAM_CHANGE:
                break;

            case CHANNEL_PRESSURE:
                break;

            case PITCH_BEND:
                if ((param2 = fluid_midi_file_getc(mf)) < 0) {
                    FLUID_LOG(FLUID_ERR, "Unexpected end of file");
                    return FLUID_FAILED;
                }

                param1 = ((param2 & 0x7f) << 7) | (param1 & 0x7f);
                param2 = 0;
                break;

            default:
                /* Can't possibly happen !? */
                FLUID_LOG(FLUID_ERR, "Unrecognized MIDI event");
                return FLUID_FAILED;
        }
        evt = new_fluid_midi_event();
        if (evt == NULL) {
            FLUID_LOG(FLUID_ERR, "Out of memory");
            return FLUID_FAILED;
        }
        evt->dtime = mf->dtime;
        evt->type = type;
        evt->channel = channel;
        evt->param1 = param1;
        evt->param2 = param2;
        evt->track = num;
        fluid_track_add_event(track, evt);
        mf->dtime = 0;
    }
    return FLUID_OK;
}
Esempio n. 10
0
/*
 * generic new : returns error
 */
int
start_fluid_sndmgr_audio_driver(fluid_settings_t* settings,
				fluid_sndmgr_audio_driver_t* dev,
				int buffer_size)
{
  int i;
  SndDoubleBufferHeader2* doubleHeader = NULL;
  SndDoubleBufferPtr doubleBuffer = NULL;
  OSErr err;
  SndChannelPtr channel = NULL;
  double sample_rate;

  fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);

  dev->doubleCallbackProc = NewSndDoubleBackProc(fluid_sndmgr_callback);

  /* the channel */
  FLUID_LOG(FLUID_DBG, "FLUID-SndManager@2");
  err = SndNewChannel(&channel, sampledSynth, initStereo, NULL);
  if ((err != noErr) || (channel == NULL)) {
    FLUID_LOG(FLUID_ERR, "Failed to allocate a sound channel (error %i)", err);
    return err;
  }

  /* the double buffer struct */
  FLUID_LOG(FLUID_DBG, "FLUID-SndManager@3");
  doubleHeader = FLUID_NEW(SndDoubleBufferHeader2);
  if (doubleHeader == NULL) {
    FLUID_LOG(FLUID_PANIC, "Out of memory");
    return -1;
  }
  doubleHeader->dbhBufferPtr[0] = NULL;
  doubleHeader->dbhBufferPtr[1] = NULL;
  doubleHeader->dbhNumChannels = 2;
  doubleHeader->dbhSampleSize = 16;
  doubleHeader->dbhCompressionID = 0;
  doubleHeader->dbhPacketSize = 0;
  doubleHeader->dbhSampleRate = fluid_sndmgr_double_to_fix((long double) sample_rate);
  doubleHeader->dbhDoubleBack = dev->doubleCallbackProc;
  doubleHeader->dbhFormat = 0;

  /* prepare dev */
  FLUID_LOG(FLUID_DBG, "FLUID-SndManager@4");
  dev->doubleHeader = doubleHeader;
  dev->channel = channel;
  dev->bufferFrameSize = buffer_size;
  dev->bufferByteSize = buffer_size * 2 * 2;

  /* the 2 doublebuffers */
  FLUID_LOG(FLUID_DBG, "FLUID-SndManager@5");
  for (i = 0; i < 2; i++) {
    doubleBuffer = (SndDoubleBufferPtr) FLUID_MALLOC(sizeof(SndDoubleBuffer)
						     + dev->bufferByteSize);
    if (doubleBuffer == NULL) {
      FLUID_LOG(FLUID_PANIC, "Out of memory");
      return -1;
    }
    doubleBuffer->dbNumFrames = 0;
    doubleBuffer->dbFlags = 0;
    doubleBuffer->dbUserInfo[0] = (long) dev;
    doubleHeader->dbhBufferPtr[i] = doubleBuffer;
    CallSndDoubleBackProc(doubleHeader->dbhDoubleBack, channel, doubleBuffer);
  }

  /* start */
  FLUID_LOG(FLUID_DBG, "FLUID-SndManager@6");

  err = SndPlayDoubleBuffer(channel, (SndDoubleBufferHeader *)doubleHeader);
  if (err != noErr) {
    FLUID_LOG(FLUID_ERR, "Failed to start the sound driver (error %i)", err);
    return err;
  }

  FLUID_LOG(FLUID_DBG, "FLUID-SndManager@7");
  return 0;
}
Esempio n. 11
0
/*
 * new_fluid_sndio_audio_driver
 */
fluid_audio_driver_t*
new_fluid_sndio_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
{
  fluid_sndio_audio_driver_t* dev = NULL;
  double sample_rate;
  int periods, period_size;
  char* devname;
  pthread_attr_t attr;
  int err;

  dev = FLUID_NEW(fluid_sndio_audio_driver_t);
  if (dev == NULL) {
    FLUID_LOG(FLUID_ERR, "Out of memory");
    return NULL;
  }
  FLUID_MEMSET(dev, 0, sizeof(fluid_sndio_audio_driver_t));

  fluid_settings_getint(settings, "audio.periods", &periods);
  fluid_settings_getint(settings, "audio.period-size", &period_size);
  fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);

  dev->hdl = NULL;
  dev->synth = synth;
  dev->callback = NULL;
  dev->data = NULL;
  dev->cont = 1;

  if (!fluid_settings_dupstr(settings, "audio.sndio.device", &devname)) {
    devname = NULL;
  }

  dev->hdl = sio_open(devname, SIO_PLAY, 0);
  if (dev->hdl == NULL) {
    FLUID_LOG(FLUID_ERR, "sndio could not be opened for writing");
    goto error_recovery;
  }

  sio_initpar(&dev->par);

  if (fluid_settings_str_equal(settings, "audio.sample-format", "16bits")) {
    dev->par.bits = 16;
    dev->par.le = SIO_LE_NATIVE;
    dev->read = fluid_synth_write_s16;
  } else {
    FLUID_LOG(FLUID_ERR, "Unknown sample format");
    goto error_recovery;
  }

  dev->par.appbufsz = period_size * periods;
  dev->par.round = period_size;

  dev->par.pchan = 2;
  dev->par.rate = sample_rate;

  if (!sio_setpar(dev->hdl, &dev->par)) {
    FLUID_LOG(FLUID_ERR, "Couldn't set sndio audio parameters");
    goto error_recovery;
  }

  if (!sio_getpar(dev->hdl, &dev->par)) {
    FLUID_LOG(FLUID_ERR, "Couldn't get sndio audio parameters");
    goto error_recovery;
  } else if (dev->par.pchan != 2 || dev->par.rate != sample_rate ||
      dev->par.bits != 16) {
    FLUID_LOG(FLUID_ERR, "Couldn't set sndio audio parameters as desired");
    goto error_recovery;
  }

  dev->buffer_size = dev->par.round;
  dev->buffer_byte_size = dev->par.round * dev->par.bps * dev->par.pchan;

  dev->buffer = FLUID_MALLOC(dev->buffer_byte_size);
  if (dev->buffer == NULL) {
    FLUID_LOG(FLUID_ERR, "Out of memory");
    goto error_recovery;
  }

  if (!sio_start(dev->hdl)) {
    FLUID_LOG(FLUID_ERR, "Couldn't start sndio");
    goto error_recovery;
  }

  if (pthread_attr_init(&attr)) {
    FLUID_LOG(FLUID_ERR, "Couldn't initialize audio thread attributes");
    goto error_recovery;
  }

  err = pthread_create(&dev->thread, &attr, fluid_sndio_audio_run, (void*) dev);
  if (err) {
    FLUID_LOG(FLUID_ERR, "Couldn't create audio thread");
    goto error_recovery;
  }

  return (fluid_audio_driver_t*) dev;

error_recovery:
  delete_fluid_sndio_audio_driver((fluid_audio_driver_t*) dev);
  return NULL;
}
Esempio n. 12
0
fluid_audio_driver_t*
new_fluid_sndio_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, void* data)
{
  fluid_sndio_audio_driver_t* dev = NULL;
  double sample_rate;
  int periods, period_size;
  char* devname;
  pthread_attr_t attr;
  int err;

  dev = FLUID_NEW(fluid_sndio_audio_driver_t);
  if (dev == NULL) {
    FLUID_LOG(FLUID_ERR, "Out of memory");
    return NULL;
  }
  FLUID_MEMSET(dev, 0, sizeof(fluid_sndio_audio_driver_t));

  fluid_settings_getint(settings, "audio.periods", &periods);
  fluid_settings_getint(settings, "audio.period-size", &period_size);
  fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);

  dev->hdl = NULL;
  dev->synth = NULL;
  dev->read = NULL;
  dev->callback = func;
  dev->data = data;
  dev->cont = 1;

  if (!fluid_settings_dupstr(settings, "audio.sndio.device", &devname)) {
    devname = NULL;
  }

  dev->hdl = sio_open(devname, SIO_PLAY, 0);
  if (dev->hdl == NULL) {
    FLUID_LOG(FLUID_ERR, "sndio could not be opened for writing");
    goto error_recovery;
  }

  sio_initpar(&dev->par);

  dev->par.appbufsz = period_size * periods;
  dev->par.round = period_size;

  dev->par.bits = 16;
  dev->par.le = SIO_LE_NATIVE;
  dev->par.pchan = 2;
  dev->par.rate = sample_rate;

  if (!sio_setpar(dev->hdl, &dev->par)){
    FLUID_LOG(FLUID_ERR, "Can't configure sndio parameters");
    goto error_recovery;
  }

  if (!sio_getpar(dev->hdl, &dev->par)) {
    FLUID_LOG(FLUID_ERR, "Couldn't get sndio audio parameters");
    goto error_recovery;
  } else if (dev->par.pchan != 2 || dev->par.rate != sample_rate ||
      dev->par.bits != 16) {
    FLUID_LOG(FLUID_ERR, "Couldn't set sndio audio parameters as desired");
    goto error_recovery;
  }

  dev->buffer_size = dev->par.round;
  dev->buffer_byte_size = dev->par.round * dev->par.bps * dev->par.pchan;

  /* allocate the buffers. FIXME!!! don't use interleaved samples */
  dev->buffer = FLUID_MALLOC(dev->buffer_byte_size);
  if (dev->buffer == NULL) {
    FLUID_LOG(FLUID_ERR, "Out of memory");
    goto error_recovery;
  }
  dev->buffers[0] = FLUID_ARRAY(float, dev->buffer_size);
  dev->buffers[1] = FLUID_ARRAY(float, dev->buffer_size);
  if ((dev->buffer == NULL) || (dev->buffers[0] == NULL) || (dev->buffers[1] == NULL)) {
    FLUID_LOG(FLUID_ERR, "Out of memory");
    goto error_recovery;
  }

  if (!sio_start(dev->hdl)) {
    FLUID_LOG(FLUID_ERR, "Couldn't start sndio");
    goto error_recovery;
  }

  if (pthread_attr_init(&attr)) {
    FLUID_LOG(FLUID_ERR, "Couldn't initialize audio thread attributes");
    goto error_recovery;
  }

  err = pthread_create(&dev->thread, &attr, fluid_sndio_audio_run2, (void*) dev);
  if (err) {
    FLUID_LOG(FLUID_ERR, "Couldn't create audio2 thread");
    goto error_recovery;
  }

  return (fluid_audio_driver_t*) dev;

error_recovery:
  delete_fluid_sndio_audio_driver((fluid_audio_driver_t*) dev);
  return NULL;
}
Esempio n. 13
0
/**
 * Concatenate options for a string setting together with a separator between.
 * @param settings Settings object
 * @param name Settings name
 * @param separator String to use between options (NULL to use ", ")
 * @return Newly allocated string or NULL on error (out of memory, not a valid
 *   setting \a name or not a string setting).  Free the string when finished with it.
 * @since 1.1.0
 */
char *
fluid_settings_option_concat (fluid_settings_t *settings, const char *name,
                              const char *separator)
{
  fluid_setting_node_t *node;
  fluid_str_setting_t *setting;
  fluid_list_t *p, *newlist = NULL;
  int count, len;
  char *str, *option;

  fluid_return_val_if_fail (settings != NULL, NULL);
  fluid_return_val_if_fail (name != NULL, NULL);

  if (!separator) separator = ", ";

  fluid_rec_mutex_lock (settings->mutex);       /* ++ lock */

  if (!fluid_settings_get (settings, name, &node) || node->type != FLUID_STR_TYPE)
  {
    fluid_rec_mutex_unlock (settings->mutex);   /* -- unlock */
    return (NULL);
  }

  setting = (fluid_str_setting_t*)node;

  /* Duplicate option list, count options and get total string length */
  for (p = setting->options, count = 0, len = 0; p; p = p->next, count++)
  {
    option = fluid_list_get (p);

    if (option)
    {
      newlist = fluid_list_append (newlist, option);
      len += strlen (option);
    }
  }

  if (count > 1) len += (count - 1) * strlen (separator);
  len++;        /* For terminator */

  /* Sort by name */
  newlist = fluid_list_sort (newlist, fluid_list_str_compare_func);

  str = FLUID_MALLOC (len);
  str[0] = 0;

  if (str)
  {
    for (p = newlist; p; p = p->next)
    {
      option = fluid_list_get (p);
      strcat (str, option);
      if (p->next) strcat (str, separator);
    }
  }

  fluid_rec_mutex_unlock (settings->mutex);   /* -- unlock */

  delete_fluid_list (newlist);

  if (!str) FLUID_LOG (FLUID_ERR, "Out of memory");

  return (str);
}
Esempio n. 14
0
/*
 * new_fluid_dsound_audio_driver
 */
fluid_audio_driver_t*
new_fluid_dsound_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
{
  HRESULT hr;
  DSBUFFERDESC desc;
  fluid_dsound_audio_driver_t* dev = NULL;
  DSCAPS caps;
  char *buf1;
  DWORD bytes1;
  double sample_rate;
  int periods, period_size;
  fluid_dsound_devsel_t devsel;

  /* check if the globals are initialized */
  if (FLUID_HINSTANCE == NULL) {
    FLUID_LOG(FLUID_ERR, "FluidSynth hinstance not set, which is needed for DirectSound");
    return NULL;
  }

/*
  if (fluid_wnd == NULL) {
    if (fluid_win32_create_window() != 0) {
      FLUID_LOG(FLUID_ERR, "Couldn't create window needed for DirectSound");
      return NULL;
    }
  }
*/
  /* create and clear the driver data */
  dev = FLUID_NEW(fluid_dsound_audio_driver_t);
  if (dev == NULL) {
    FLUID_LOG(FLUID_ERR, "Out of memory");
    return NULL;
  }
  FLUID_MEMSET(dev, 0, sizeof(fluid_dsound_audio_driver_t));

  dev->synth = synth;
  dev->cont = 1;

  fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
  fluid_settings_getint(settings, "audio.periods", &periods);
  fluid_settings_getint(settings, "audio.period-size", &period_size);

  /* check the format */
  if (!fluid_settings_str_equal(settings, "audio.sample-format", "16bits")) {
    FLUID_LOG(FLUID_ERR, "Unhandled sample format");
    goto error_recovery;
  }

  dev->frame_size = 2 * sizeof(short);
  dev->buffer_byte_size = period_size * dev->frame_size;
  dev->queue_byte_size = periods * dev->buffer_byte_size;
  dev->write = fluid_synth_write_s16;

  /* create and initialize the buffer format */
  dev->format = (WAVEFORMATEX*) FLUID_MALLOC(sizeof(WAVEFORMATEX));
  if (dev->format == NULL) {
    FLUID_LOG(FLUID_ERR, "Out of memory");
    goto error_recovery;
  }
  ZeroMemory(dev->format, sizeof(WAVEFORMATEX));

  dev->format->wFormatTag = WAVE_FORMAT_PCM;
  dev->format->nChannels = 2;
  dev->format->wBitsPerSample = 16;
  dev->format->nSamplesPerSec = (DWORD) sample_rate;
  dev->format->nBlockAlign = (WORD) dev->frame_size;
  dev->format->nAvgBytesPerSec = dev->format->nSamplesPerSec * dev->frame_size;
  dev->format->cbSize = 0;

  devsel.devGUID = NULL;
  /* get the selected device name. if none is specified, use NULL for the default device. */
  if(fluid_settings_dupstr(settings, "audio.dsound.device", &devsel.devname) == FLUID_OK /* ++ alloc device name */
     && devsel.devname && strlen (devsel.devname) > 0) {
    /* look for the GUID of the selected device */
    DirectSoundEnumerate((LPDSENUMCALLBACK) fluid_dsound_enum_callback2, (void *)&devsel);
  }

  if (devsel.devname) FLUID_FREE (devsel.devname);      /* -- free device name */

  /* open DirectSound */
  hr = DirectSoundCreate(devsel.devGUID, &dev->direct_sound, NULL);
  if (hr != DS_OK) {
    FLUID_LOG(FLUID_ERR, "Failed to create the DirectSound object");
    goto error_recovery;
  }

  hr = IDirectSound_SetCooperativeLevel(dev->direct_sound, fluid_win32_get_window(), DSSCL_PRIORITY);
  if (hr != DS_OK) {
    FLUID_LOG(FLUID_ERR, "Failed to set the cooperative level");
    goto error_recovery;
  }

  caps.dwSize = sizeof(caps);
  hr = IDirectSound_GetCaps(dev->direct_sound, &caps);
  if (hr != DS_OK)  {
    FLUID_LOG(FLUID_ERR, "Failed to query the device capacities");
    goto error_recovery;
  }

  /* create primary buffer */

  ZeroMemory(&desc, sizeof(DSBUFFERDESC));
  desc.dwSize = sizeof(DSBUFFERDESC);
  desc.dwFlags = DSBCAPS_PRIMARYBUFFER;

  if (caps.dwFreeHwMixingStreamingBuffers > 0) {
    desc.dwFlags |= DSBCAPS_LOCHARDWARE;
  }

  hr = IDirectSound_CreateSoundBuffer(dev->direct_sound, &desc, &dev->prim_buffer, NULL);
  if (hr != DS_OK) {
    FLUID_LOG(FLUID_ERR, "Failed to allocate the primary buffer");
    goto error_recovery;
  }

  /* set the primary sound buffer to this format. if it fails, just
     print a warning. */
  hr = IDirectSoundBuffer_SetFormat(dev->prim_buffer, dev->format);
  if (hr != DS_OK) {
    FLUID_LOG(FLUID_WARN, "Can't set format of primary sound buffer", fluid_win32_error(hr));
  }

  /* initialize the buffer description */

  ZeroMemory(&desc, sizeof(DSBUFFERDESC));
  desc.dwSize = sizeof(DSBUFFERDESC);
  desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
  desc.lpwfxFormat = dev->format;
  desc.dwBufferBytes = dev->queue_byte_size;
  desc.dwReserved = 0;

  if (caps.dwFreeHwMixingStreamingBuffers > 0) {
    desc.dwFlags |= DSBCAPS_LOCHARDWARE;
  }

  /* create the secondary sound buffer */

  hr = IDirectSound_CreateSoundBuffer(dev->direct_sound, &desc, &dev->sec_buffer, NULL);
  if (hr != DS_OK) {
    FLUID_LOG(FLUID_ERR, "dsound: Can't create sound buffer: %s", fluid_win32_error(hr));
    goto error_recovery;
  }


  /* Lock */
  hr = IDirectSoundBuffer_Lock(dev->sec_buffer, 0, 0, (void*) &buf1, &bytes1, 0, 0, DSBLOCK_ENTIREBUFFER);

  if ((hr != DS_OK) || (buf1 == NULL)) {
    FLUID_LOG(FLUID_PANIC, "Failed to lock the audio buffer. Exiting.");
    goto error_recovery;
  }

  /* fill the buffer with silence */
  memset(buf1, 0, bytes1);

  /* Unlock */
  IDirectSoundBuffer_Unlock(dev->sec_buffer, buf1, bytes1, 0, 0);


  /* start the audio thread */
  dev->thread = CreateThread(NULL, 0, &fluid_dsound_audio_run, (LPVOID) dev, 0, &dev->threadID);
  if (dev->thread == NULL) {
    goto error_recovery;
  }

  return (fluid_audio_driver_t*) dev;

 error_recovery:
  delete_fluid_dsound_audio_driver((fluid_audio_driver_t*) dev);
  return NULL;
}