fluid_midi_driver_t * new_fluid_sndio_midi_driver(fluid_settings_t *settings, handle_midi_event_func_t handler, void *data) { int err; fluid_sndio_midi_driver_t *dev; char *device; /* not much use doing anything */ if (handler == NULL) { FLUID_LOG(FLUID_ERR, "Invalid argument"); return NULL; } /* allocate the device */ dev = FLUID_NEW(fluid_sndio_midi_driver_t); if (dev == NULL) { FLUID_LOG(FLUID_ERR, "Out of memory"); return NULL; } FLUID_MEMSET(dev, 0, sizeof(fluid_sndio_midi_driver_t)); dev->hdl = NULL; dev->driver.handler = handler; dev->driver.data = data; /* allocate one event to store the input data */ dev->parser = new_fluid_midi_parser(); if (dev->parser == NULL) { FLUID_LOG(FLUID_ERR, "Out of memory"); goto error_recovery; } /* get the device name. if none is specified, use the default device. */ if (!fluid_settings_dupstr(settings, "midi.sndio.device", &device)) { device = NULL; } /* open the default hardware device. only use midi in. */ dev->hdl = mio_open(device, MIO_IN, 0); if (dev->hdl == NULL) { FLUID_LOG(FLUID_ERR, "Couldn't open sndio midi device"); goto error_recovery; } dev->status = FLUID_MIDI_READY; err = pthread_create(&dev->thread, NULL, fluid_sndio_midi_run, (void *)dev); if (err) { FLUID_LOG(FLUID_PANIC, "Couldn't create the midi thread."); goto error_recovery; } return (fluid_midi_driver_t *) dev; error_recovery: delete_fluid_sndio_midi_driver((fluid_midi_driver_t *)dev); return NULL; }
/* * new_fluid_core_audio_driver2 */ fluid_audio_driver_t* new_fluid_core_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, void* data) { char* devname = NULL; fluid_core_audio_driver_t* dev = NULL; int period_size, periods; double sample_rate; OSStatus status; UInt32 size; int i; dev = FLUID_NEW(fluid_core_audio_driver_t); if (dev == NULL) { FLUID_LOG(FLUID_ERR, "Out of memory"); return NULL; } FLUID_MEMSET(dev, 0, sizeof(fluid_core_audio_driver_t)); dev->callback = func; dev->data = data; // Open the default output unit ComponentDescription desc; desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_HALOutput; //kAudioUnitSubType_DefaultOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; Component comp = FindNextComponent(NULL, &desc); if (comp == NULL) { FLUID_LOG(FLUID_ERR, "Failed to get the default audio device"); goto error_recovery; } status = OpenAComponent(comp, &dev->outputUnit); if (status != noErr) { FLUID_LOG(FLUID_ERR, "Failed to open the default audio device. Status=%ld\n", (long int)status); goto error_recovery; } // Set up a callback function to generate output AURenderCallbackStruct render; render.inputProc = fluid_core_audio_callback; render.inputProcRefCon = (void *) dev; status = AudioUnitSetProperty (dev->outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &render, sizeof(render)); if (status != noErr) { FLUID_LOG (FLUID_ERR, "Error setting the audio callback. Status=%ld\n", (long int)status); goto error_recovery; } 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); /* get the selected device name. if none is specified, use NULL for the default device. */ if (fluid_settings_dupstr(settings, "audio.coreaudio.device", &devname) /* alloc device name */ && devname && strlen (devname) > 0) { AudioObjectPropertyAddress pa; pa.mSelector = kAudioHardwarePropertyDevices; pa.mScope = kAudioObjectPropertyScopeWildcard; pa.mElement = kAudioObjectPropertyElementMaster; if (OK (AudioObjectGetPropertyDataSize (kAudioObjectSystemObject, &pa, 0, 0, &size))) { int num = size / (int) sizeof (AudioDeviceID); AudioDeviceID devs [num]; if (OK (AudioObjectGetPropertyData (kAudioObjectSystemObject, &pa, 0, 0, &size, devs))) { for (i = 0; i < num; ++i) { char name [1024]; size = sizeof (name); pa.mSelector = kAudioDevicePropertyDeviceName; if (OK (AudioObjectGetPropertyData (devs[i], &pa, 0, 0, &size, name))) { if (get_num_outputs (devs[i]) > 0 && strcasecmp(devname, name) == 0) { AudioDeviceID selectedID = devs[i]; status = AudioUnitSetProperty (dev->outputUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &selectedID, sizeof(AudioDeviceID)); if (status != noErr) { FLUID_LOG (FLUID_ERR, "Error setting the selected output device. Status=%ld\n", (long int)status); goto error_recovery; } } } } } } } if (devname) FLUID_FREE (devname); /* free device name */ dev->buffer_size = period_size * periods; // The DefaultOutputUnit should do any format conversions // necessary from our format to the device's format. dev->format.mSampleRate = sample_rate; // sample rate of the audio stream dev->format.mFormatID = kAudioFormatLinearPCM; // encoding type of the audio stream dev->format.mFormatFlags = kLinearPCMFormatFlagIsFloat; dev->format.mBytesPerPacket = 2*sizeof(float); dev->format.mFramesPerPacket = 1; dev->format.mBytesPerFrame = 2*sizeof(float); dev->format.mChannelsPerFrame = 2; dev->format.mBitsPerChannel = 8*sizeof(float); FLUID_LOG (FLUID_DBG, "mSampleRate %g", dev->format.mSampleRate); FLUID_LOG (FLUID_DBG, "mFormatFlags %08X", dev->format.mFormatFlags); FLUID_LOG (FLUID_DBG, "mBytesPerPacket %d", dev->format.mBytesPerPacket); FLUID_LOG (FLUID_DBG, "mFramesPerPacket %d", dev->format.mFramesPerPacket); FLUID_LOG (FLUID_DBG, "mChannelsPerFrame %d", dev->format.mChannelsPerFrame); FLUID_LOG (FLUID_DBG, "mBytesPerFrame %d", dev->format.mBytesPerFrame); FLUID_LOG (FLUID_DBG, "mBitsPerChannel %d", dev->format.mBitsPerChannel); status = AudioUnitSetProperty (dev->outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dev->format, sizeof(AudioStreamBasicDescription)); if (status != noErr) { FLUID_LOG (FLUID_ERR, "Error setting the audio format. Status=%ld\n", (long int)status); goto error_recovery; } status = AudioUnitSetProperty (dev->outputUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Input, 0, &dev->buffer_size, sizeof(unsigned int)); if (status != noErr) { FLUID_LOG (FLUID_ERR, "Failed to set the MaximumFramesPerSlice. Status=%ld\n", (long int)status); goto error_recovery; } FLUID_LOG (FLUID_DBG, "MaximumFramesPerSlice = %d", dev->buffer_size); dev->buffers[0] = FLUID_ARRAY(float, dev->buffer_size); dev->buffers[1] = FLUID_ARRAY(float, dev->buffer_size); // Initialize the audio unit status = AudioUnitInitialize(dev->outputUnit); if (status != noErr) { FLUID_LOG (FLUID_ERR, "Error calling AudioUnitInitialize(). Status=%ld\n", (long int)status); goto error_recovery; } // Start the rendering status = AudioOutputUnitStart (dev->outputUnit); if (status != noErr) { FLUID_LOG (FLUID_ERR, "Error calling AudioOutputUnitStart(). Status=%ld\n", (long int)status); goto error_recovery; } return (fluid_audio_driver_t*) dev; error_recovery: delete_fluid_core_audio_driver((fluid_audio_driver_t*) dev); return NULL; }
/* * main */ int main(int argc, char** argv) { fluid_settings_t* settings; int arg1 = 1; char buf[512]; int c, i; int interactive = 1; int midi_in = 1; fluid_player_t* player = NULL; fluid_midi_router_t* router = NULL; //fluid_sequencer_t* sequencer = NULL; fluid_midi_driver_t* mdriver = NULL; fluid_audio_driver_t* adriver = NULL; fluid_synth_t* synth = NULL; fluid_server_t* server = NULL; char* config_file = NULL; int audio_groups = 0; int audio_channels = 0; int with_server = 0; int dump = 0; int fast_render = 0; int connect_lash = 1; char *optchars = "a:C:c:dE:f:F:G:g:hijK:L:lm:nO:o:p:R:r:sT:Vvz:"; #ifdef LASH_ENABLED int enabled_lash = 0; /* set to TRUE if lash gets enabled */ fluid_lash_args_t *lash_args; lash_args = fluid_lash_extract_args (&argc, &argv); #endif print_welcome (); settings = new_fluid_settings(); #ifdef GETOPT_SUPPORT /* pre section of GETOPT supported argument handling */ opterr = 0; while (1) { int option_index = 0; static struct option long_options[] = { {"audio-bufcount", 1, 0, 'c'}, {"audio-bufsize", 1, 0, 'z'}, {"audio-channels", 1, 0, 'L'}, {"audio-driver", 1, 0, 'a'}, {"audio-file-endian", 1, 0, 'E'}, {"audio-file-format", 1, 0, 'O'}, {"audio-file-type", 1, 0, 'T'}, {"audio-groups", 1, 0, 'G'}, {"chorus", 1, 0, 'C'}, {"connect-jack-outputs", 0, 0, 'j'}, {"disable-lash", 0, 0, 'l'}, {"dump", 0, 0, 'd'}, {"fast-render", 1, 0, 'F'}, {"gain", 1, 0, 'g'}, {"help", 0, 0, 'h'}, {"load-config", 1, 0, 'f'}, {"midi-channels", 1, 0, 'K'}, {"midi-driver", 1, 0, 'm'}, {"no-midi-in", 0, 0, 'n'}, {"no-shell", 0, 0, 'i'}, {"option", 1, 0, 'o'}, {"portname", 1, 0, 'p'}, {"reverb", 1, 0, 'R'}, {"sample-rate", 1, 0, 'r'}, {"server", 0, 0, 's'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, optchars, long_options, &option_index); if (c == -1) { break; } #else /* "pre" section to non getopt argument handling */ for (i = 1; i < argc; i++) { char *optarg; /* Skip non switch arguments (assume they are file names) */ if ((argv[i][0] != '-') || (argv[i][1] == '\0')) break; c = argv[i][1]; optarg = strchr (optchars, c); /* find the option character in optchars */ if (optarg && optarg[1] == ':') /* colon follows if switch argument expected */ { if (++i >= argc) { printf ("Option -%c requires an argument\n", c); print_usage(); exit(0); } else { optarg = argv[i]; if (optarg[0] == '-') { printf ("Expected argument to option -%c found switch instead\n", c); print_usage(); exit(0); } } } else optarg = ""; #endif switch (c) { #ifdef GETOPT_SUPPORT case 0: /* shouldn't normally happen, a long option's flag is set to NULL */ printf ("option %s", long_options[option_index].name); if (optarg) { printf (" with arg %s", optarg); } printf ("\n"); break; #endif case 'a': if (FLUID_STRCMP (optarg, "help") == 0) { printf ("-a options (audio driver):\n "); show_settings_str_options (settings, "audio.driver"); exit (0); } else fluid_settings_setstr(settings, "audio.driver", optarg); break; case 'C': if ((optarg != NULL) && ((strcmp(optarg, "0") == 0) || (strcmp(optarg, "no") == 0))) { fluid_settings_setint(settings, "synth.chorus.active", FALSE); } else { fluid_settings_setint(settings, "synth.chorus.active", TRUE); } break; case 'c': fluid_settings_setint(settings, "audio.periods", atoi(optarg)); break; case 'd': fluid_settings_setint(settings, "synth.dump", TRUE); dump = 1; break; case 'E': if (FLUID_STRCMP (optarg, "help") == 0) { printf ("-E options (audio file byte order):\n "); show_settings_str_options (settings, "audio.file.endian"); #if LIBSNDFILE_SUPPORT printf ("\nauto: Use audio file format's default endian byte order\n" "cpu: Use CPU native byte order\n"); #else printf ("\nNOTE: No libsndfile support!\n" "cpu: Use CPU native byte order\n"); #endif exit (0); } else fluid_settings_setstr(settings, "audio.file.endian", optarg); break; case 'f': config_file = optarg; break; case 'F': fluid_settings_setstr(settings, "audio.file.name", optarg); fast_render = 1; break; case 'G': audio_groups = atoi(optarg); break; case 'g': fluid_settings_setnum(settings, "synth.gain", atof(optarg)); break; case 'h': print_help(settings); break; case 'i': interactive = 0; break; case 'j': fluid_settings_setint(settings, "audio.jack.autoconnect", 1); break; case 'K': fluid_settings_setint(settings, "synth.midi-channels", atoi(optarg)); break; case 'L': audio_channels = atoi(optarg); fluid_settings_setint(settings, "synth.audio-channels", audio_channels); break; case 'l': /* disable LASH */ connect_lash = 0; break; case 'm': if (FLUID_STRCMP (optarg, "help") == 0) { printf ("-m options (MIDI driver):\n "); show_settings_str_options (settings, "midi.driver"); exit (0); } else fluid_settings_setstr(settings, "midi.driver", optarg); break; case 'n': midi_in = 0; break; case 'O': if (FLUID_STRCMP (optarg, "help") == 0) { printf ("-O options (audio file format):\n "); show_settings_str_options (settings, "audio.file.format"); #if LIBSNDFILE_SUPPORT printf ("\ns8, s16, s24, s32: Signed PCM audio of the given number of bits\n"); printf ("float, double: 32 bit and 64 bit floating point audio\n"); printf ("u8: Unsigned 8 bit audio\n"); #else printf ("\nNOTE: No libsndfile support!\n"); #endif exit (0); } else fluid_settings_setstr(settings, "audio.file.format", optarg); break; case 'o': process_o_cmd_line_option(settings, optarg); break; case 'p' : fluid_settings_setstr(settings, "midi.portname", optarg); break; case 'R': if ((optarg != NULL) && ((strcmp(optarg, "0") == 0) || (strcmp(optarg, "no") == 0))) { fluid_settings_setint(settings, "synth.reverb.active", FALSE); } else { fluid_settings_setint(settings, "synth.reverb.active", TRUE); } break; case 'r': fluid_settings_setnum(settings, "synth.sample-rate", atof(optarg)); break; case 's': with_server = 1; break; case 'T': if (FLUID_STRCMP (optarg, "help") == 0) { printf ("-T options (audio file type):\n "); show_settings_str_options (settings, "audio.file.type"); #if LIBSNDFILE_SUPPORT printf ("\nauto: Determine type from file name extension, defaults to \"wav\"\n"); #else printf ("\nNOTE: No libsndfile support!\n"); #endif exit (0); } else fluid_settings_setstr(settings, "audio.file.type", optarg); break; case 'V': printf("FluidSynth %s\n", VERSION); exit (0); break; case 'v': fluid_settings_setint(settings, "synth.verbose", TRUE); break; case 'z': fluid_settings_setint(settings, "audio.period-size", atoi(optarg)); break; #ifdef GETOPT_SUPPORT case '?': printf ("Unknown option %c\n", optopt); print_usage(); exit(0); break; default: printf ("?? getopt returned character code 0%o ??\n", c); break; #else /* Non getopt default case */ default: printf ("Unknown switch '%c'\n", c); print_usage(); exit(0); break; #endif } /* end of switch statement */ } /* end of loop */ #ifdef GETOPT_SUPPORT arg1 = optind; #else arg1 = i; #endif /* option help requested? "-o help" */ if (option_help) { printf ("FluidSynth settings:\n"); fluid_settings_foreach (settings, settings, settings_foreach_func); exit (0); } #ifdef WIN32 SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); #endif #ifdef LASH_ENABLED /* connect to the lash server */ if (connect_lash) { enabled_lash = fluid_lash_connect (lash_args); fluid_settings_setint (settings, "lash.enable", enabled_lash ? 1 : 0); } #endif /* The 'groups' setting is only relevant for LADSPA operation * If not given, set number groups to number of audio channels, because * they are the same (there is nothing between synth output and 'sound card') */ if ((audio_groups == 0) && (audio_channels != 0)) { audio_groups = audio_channels; } fluid_settings_setint(settings, "synth.audio-groups", audio_groups); if (fast_render) { midi_in = 0; interactive = 0; with_server = 0; fluid_settings_setstr(settings, "player.timing-source", "sample"); fluid_settings_setint(settings, "synth.parallel-render", 1); /* TODO: Fast_render should not need this, but currently do */ } /* create the synthesizer */ synth = new_fluid_synth(settings); if (synth == NULL) { fprintf(stderr, "Failed to create the synthesizer\n"); exit(-1); } cmd_handler = new_fluid_cmd_handler(synth); if (cmd_handler == NULL) { fprintf(stderr, "Failed to create the command handler\n"); goto cleanup; } /* load the soundfonts (check that all non options are SoundFont or MIDI files) */ for (i = arg1; i < argc; i++) { if (fluid_is_soundfont(argv[i])) { if (fluid_synth_sfload(synth, argv[i], 1) == -1) fprintf(stderr, "Failed to load the SoundFont %s\n", argv[i]); } else if (!fluid_is_midifile(argv[i])) fprintf (stderr, "Parameter '%s' not a SoundFont or MIDI file or error occurred identifying it.\n", argv[i]); } #ifdef HAVE_SIGNAL_H /* signal(SIGINT, handle_signal); */ #endif /* start the synthesis thread */ if (!fast_render) { adriver = new_fluid_audio_driver(settings, synth); if (adriver == NULL) { fprintf(stderr, "Failed to create the audio driver\n"); goto cleanup; } } /* start the midi router and link it to the synth */ #if WITH_MIDI if (midi_in) { /* In dump mode, text output is generated for events going into and out of the router. * The example dump functions are put into the chain before and after the router.. */ //sequencer = new_fluid_sequencer2(0); router = new_fluid_midi_router( settings, dump ? fluid_midi_dump_postrouter : fluid_synth_handle_midi_event, (void*)synth); if (router == NULL) { fprintf(stderr, "Failed to create the MIDI input router; no MIDI input\n" "will be available. You can access the synthesizer \n" "through the console.\n"); } else { fluid_synth_set_midi_router(synth, router); /* Fixme, needed for command handler */ // fluid_sequencer_register_fluidsynth(sequencer, synth); mdriver = new_fluid_midi_driver( settings, dump ? fluid_midi_dump_prerouter : fluid_midi_router_handle_midi_event, (void*) router); if (mdriver == NULL) { fprintf(stderr, "Failed to create the MIDI thread; no MIDI input\n" "will be available. You can access the synthesizer \n" "through the console.\n"); } } } #endif /* run commands specified in config file */ if (config_file != NULL) { fluid_source(cmd_handler, config_file); } else if (fluid_get_userconf(buf, 512) != NULL) { fluid_source(cmd_handler, buf); } else if (fluid_get_sysconf(buf, 512) != NULL) { fluid_source(cmd_handler, buf); } /* play the midi files, if any */ for (i = arg1; i < argc; i++) { if ((argv[i][0] != '-') && fluid_is_midifile(argv[i])) { if (player == NULL) { player = new_fluid_player(synth); if (player == NULL) { fprintf(stderr, "Failed to create the midifile player.\n" "Continuing without a player.\n"); break; } } fluid_player_add(player, argv[i]); } } if (player != NULL) { fluid_player_play(player); } /* run the server, if requested */ #if !defined(MACINTOSH) if (with_server) { server = new_fluid_server(settings, newclient, synth); if (server == NULL) { fprintf(stderr, "Failed to create the server.\n" "Continuing without it.\n"); } } #endif #ifdef LASH_ENABLED if (enabled_lash) fluid_lash_create_thread (synth); #endif /* run the shell */ if (interactive) { printf ("Type 'help' for help topics.\n\n"); /* In dump mode we set the prompt to "". The UI cannot easily * handle lines, which don't end with CR. Changing the prompt * cannot be done through a command, because the current shell * does not handle empty arguments. The ordinary case is dump == * 0. */ fluid_settings_setstr(settings, "shell.prompt", dump ? "" : "> "); fluid_usershell(settings, cmd_handler); } if (fast_render) { char *filename; if (player == NULL) { fprintf(stderr, "No midi file specified!\n"); goto cleanup; } fluid_settings_dupstr (settings, "audio.file.name", &filename); printf ("Rendering audio to file '%s'..\n", filename); if (filename) FLUID_FREE (filename); fast_render_loop(settings, synth, player); } cleanup: #if !defined(MACINTOSH) && !defined(WIN32) if (server != NULL) { /* if the user typed 'quit' in the shell, kill the server */ if (!interactive) { fluid_server_join(server); } delete_fluid_server(server); } #endif if (cmd_handler != NULL) { delete_fluid_cmd_handler(cmd_handler); } if (player != NULL) { /* if the user typed 'quit' in the shell, stop the player */ if (interactive) { fluid_player_stop(player); } if (adriver != NULL || !fluid_settings_str_equal(settings, "player.timing-source", "sample")) { /* if no audio driver and sample timers are used, nothing makes the player advance */ fluid_player_join(player); } delete_fluid_player(player); } if (router) { #if WITH_MIDI if (mdriver) { delete_fluid_midi_driver(mdriver); } delete_fluid_midi_router(router); #endif } /*if (sequencer) { delete_fluid_sequencer(sequencer); }*/ if (adriver) { delete_fluid_audio_driver(adriver); } if (synth) { delete_fluid_synth(synth); } if (settings) { delete_fluid_settings(settings); } return 0; } static fluid_cmd_handler_t* newclient(void* data, char* addr) { fluid_synth_t* synth = (fluid_synth_t*) data; return new_fluid_cmd_handler(synth); }
fluid_audio_driver_t * new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth) { fluid_portaudio_driver_t *dev = NULL; PaStreamParameters outputParams; char *device = NULL; double sample_rate; int period_size; PaError err; dev = FLUID_NEW (fluid_portaudio_driver_t); if (dev == NULL) { FLUID_LOG (FLUID_ERR, "Out of memory"); return NULL; } err = Pa_Initialize (); if (err != paNoError) { FLUID_LOG (FLUID_ERR, "Error initializing PortAudio driver: %s", Pa_GetErrorText (err)); FLUID_FREE (dev); return NULL; } FLUID_MEMSET (dev, 0, sizeof (fluid_portaudio_driver_t)); dev->synth = synth; fluid_settings_getint (settings, "audio.period-size", &period_size); fluid_settings_getnum (settings, "synth.sample-rate", &sample_rate); fluid_settings_dupstr(settings, "audio.portaudio.device", &device); /* ++ alloc device name */ bzero (&outputParams, sizeof (outputParams)); outputParams.channelCount = 2; outputParams.suggestedLatency = (PaTime)period_size / sample_rate; /* Locate the device if specified */ if (strcmp (device, PORTAUDIO_DEFAULT_DEVICE) != 0) { const PaDeviceInfo *deviceInfo; int numDevices; int i; numDevices = Pa_GetDeviceCount (); if (numDevices < 0) { FLUID_LOG (FLUID_ERR, "PortAudio returned unexpected device count %d", numDevices); goto error_recovery; } for (i = 0; i < numDevices; i++) { deviceInfo = Pa_GetDeviceInfo (i); if (strcmp (device, deviceInfo->name) == 0) { outputParams.device = i; break; } } if (i == numDevices) { FLUID_LOG (FLUID_ERR, "PortAudio device '%s' was not found", device); goto error_recovery; } } else outputParams.device = Pa_GetDefaultOutputDevice(); if (fluid_settings_str_equal (settings, "audio.sample-format", "16bits")) { outputParams.sampleFormat = paInt16; dev->read = fluid_synth_write_s16; } else if (fluid_settings_str_equal (settings, "audio.sample-format", "float")) { outputParams.sampleFormat = paFloat32; dev->read = fluid_synth_write_float; } else { FLUID_LOG (FLUID_ERR, "Unknown sample format"); goto error_recovery; } /* PortAudio section */ /* Open an audio I/O stream. */ err = Pa_OpenStream (&dev->stream, NULL, /* Input parameters */ &outputParams, sample_rate, period_size, paNoFlag, fluid_portaudio_run, dev); if (err != paNoError) { FLUID_LOG (FLUID_ERR, "Error opening PortAudio stream: %s", Pa_GetErrorText (err)); goto error_recovery; } err = Pa_StartStream (dev->stream); if (err != paNoError) { FLUID_LOG (FLUID_ERR, "Error starting PortAudio stream: %s", Pa_GetErrorText (err)); goto error_recovery; } if (device) FLUID_FREE (device); /* -- free device name */ return (fluid_audio_driver_t *)dev; error_recovery: if (device) FLUID_FREE (device); /* -- free device name */ delete_fluid_portaudio_driver ((fluid_audio_driver_t *)dev); return NULL; }
fluid_audio_driver_t * new_fluid_portaudio_driver2 (fluid_settings_t *settings, fluid_audio_func_t func, void* data) { fluid_portaudio_driver_t *dev = NULL; PaStreamParameters outputParams; char *device = NULL; double sample_rate; int period_size; PaError err; int numOutputs = 2; dev = FLUID_NEW (fluid_portaudio_driver_t); if (dev == NULL) { FLUID_LOG (FLUID_ERR, "Out of memory"); return NULL; } err = Pa_Initialize (); if (err != paNoError) { FLUID_LOG (FLUID_ERR, "Error initializing PortAudio driver: %s", Pa_GetErrorText (err)); FLUID_FREE (dev); return NULL; } FLUID_MEMSET (dev, 0, sizeof (fluid_portaudio_driver_t)); dev->data = data; dev->callback = func; bzero (&outputParams, sizeof (outputParams)); fluid_settings_getint (settings, "audio.period-size", &period_size); fluid_settings_getnum (settings, "synth.sample-rate", &sample_rate); fluid_settings_dupstr(settings, "audio.portaudio.device", &device); /* ++ alloc device name */ /* Locate the device if specified */ if (strcmp (device, PORTAUDIO_DEFAULT_DEVICE) != 0) { const PaDeviceInfo *deviceInfo; int numDevices; int i; numDevices = Pa_GetDeviceCount (); if (numDevices < 0) { FLUID_LOG (FLUID_ERR, "PortAudio returned unexpected device count %d", numDevices); goto error_recovery; } for (i = 0; i < numDevices; i++) { deviceInfo = Pa_GetDeviceInfo (i); if (strcmp (device, deviceInfo->name) == 0) { outputParams.device = i; numOutputs = deviceInfo->maxOutputChannels; break; } } if (i == numDevices) { FLUID_LOG (FLUID_ERR, "PortAudio device '%s' was not found", device); goto error_recovery; } } else outputParams.device = Pa_GetDefaultOutputDevice(); fluid_settings_getint(settings, "audio.portaudio.channelL", &(dev->chanL)); fluid_settings_getint(settings, "audio.portaudio.channelR", &(dev->chanR)); dev->chansOpen = 1 + ((dev->chanL > dev->chanR) ? dev->chanL : dev->chanR); if (dev->chansOpen > numOutputs) { // error FLUID_LOG (FLUID_ERR, "One specified channel is greater than the maximum number of channels: L=%d, R=%d, max=%d\n", dev->chanL, dev->chanR, numOutputs-1); goto error_recovery; } dev->buffer_size = period_size; dev->buffers[0] = FLUID_ARRAY(float, dev->buffer_size); dev->buffers[1] = FLUID_ARRAY(float, dev->buffer_size); outputParams.channelCount = dev->chansOpen; outputParams.suggestedLatency = (PaTime)period_size / sample_rate; // force float format outputParams.sampleFormat = paFloat32; /* PortAudio section */ /* Open an audio I/O stream. */ err = Pa_OpenStream (&dev->stream, NULL, /* Input parameters */ &outputParams, sample_rate, period_size, paNoFlag, fluid_portaudio_run, dev); if (err != paNoError) { FLUID_LOG (FLUID_ERR, "Error opening PortAudio stream: %s", Pa_GetErrorText (err)); goto error_recovery; } err = Pa_StartStream (dev->stream); if (err != paNoError) { FLUID_LOG (FLUID_ERR, "Error starting PortAudio stream: %s", Pa_GetErrorText (err)); goto error_recovery; } if (device) FLUID_FREE (device); /* -- free device name */ return (fluid_audio_driver_t *)dev; error_recovery: if (device) FLUID_FREE (device); /* -- free device name */ delete_fluid_portaudio_driver ((fluid_audio_driver_t *)dev); return NULL; }
/* * 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; }
/* * 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; }