/* * 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; }
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; }
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); }
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; }
/** * 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; }
/** * 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; }
/* * 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; }
/** * 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); }
/* * 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; }
/* * 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; }
/* * 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; }
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; }
/** * 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); }
/* * 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; }