/* * dolmetschctl * * * Copyright (C) 2015 Christian Pointner * * This file is part of dolmetschctl. * * dolmetschctl is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * dolmetschctl is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with dolmetschctl. If not, see . */ #include "config.h" #include #include #include #include #include #include #include "mixer.h" static void free_lang_entry(void* ptr) { lang_t* l = ptr; assert(l); free(l->name_); slist_clear(&(l->cmds_)); free(l); } static int mixer_read_config_file(mixer_t* m, int dirfd, const char* filename) { assert(dirfd > 0); int fd = openat(dirfd, filename, O_RDONLY); if(fd < 0) { error(0, errno, "erorr open('%s')", filename); return -1; } FILE* conf = fdopen(fd, "r"); if(conf == NULL) { error(0, errno, "erorr fdopen('%s')", filename); return -1; } lang_t* lang = malloc(sizeof(lang_t)); assert(lang); assert((lang->name_ = strdup(filename))); slist_init(&(lang->cmds_), free); assert(slist_add(&(m->langs_), lang)); char buf[256]; while(fgets(buf, sizeof(buf), conf) != NULL) { midi_cmd_t* cmd = malloc(sizeof(midi_cmd_t)); if(!cmd) { error(0, ENOMEM, "can't create midi command stucture"); break; } if(sscanf(buf, "%02hhx %02hhx %02hhx", &(cmd->code_[0]), &(cmd->code_[1]), &(cmd->code_[2])) != 3) { continue; } assert(slist_add(&(lang->cmds_), cmd)); } fclose(conf); return 0; } static int mixer_read_config(mixer_t* m) { char path[1024]; int ret = snprintf(path, sizeof(path), "%s/%s", ETCDIR, m->name_); assert(ret < sizeof(path)); DIR* d = opendir(path); if(d == NULL) { error(0, errno, "MIXER: cannot open config directory '%s'", path); return -1; } struct dirent* entry; while((entry = readdir(d))) { if(entry->d_type == DT_REG) { if((ret = mixer_read_config_file(m, dirfd(d), entry->d_name))) break; } } if(closedir(d) < 0) { error(0, errno, "MIXER: cannot closeconfig directory '%s'", path); return -1; } return ret; } int mixer_init(mixer_t* m, const char* name, const char* device) { assert(m != NULL); m->name_ = name; m->output_ = NULL; slist_init(&(m->langs_), free_lang_entry); int ret = snd_rawmidi_open(NULL, &(m->output_), device, SND_RAWMIDI_NONBLOCK); if(ret < 0) { error(0, 0, "MIXER: cannot open midi port '%s': %s", device, snd_strerror(ret)); return ret; } return mixer_read_config(m);; } static void mixer_print_midi_cmds(slist_t cmds) { if(!slist_length(&(cmds))) printf("\n"); else { slist_element_t* tmp; for(tmp = cmds.first_; tmp; tmp = tmp->next_) { midi_cmd_t* c = (midi_cmd_t*)(tmp->data_); printf(" 0x%02X 0x%02X 0x%02X\n", c->code_[0], c->code_[1], c->code_[2]); } } } void mixer_print_langs(mixer_t* m) { assert(m); printf("mixer:\n"); if(!slist_length(&(m->langs_))) printf(" \n"); else { slist_element_t* tmp; for(tmp = m->langs_.first_; tmp; tmp = tmp->next_) { lang_t* l = (lang_t*)(tmp->data_); printf(" %s:\n", l->name_); mixer_print_midi_cmds(l->cmds_); } } } int mixer_get_poll_fd_count(mixer_t* m) { return snd_rawmidi_poll_descriptors_count(m->output_); } int mixer_get_poll_fds(mixer_t* m, struct pollfd *pfds, int npfds) { return snd_rawmidi_poll_descriptors(m->output_, pfds, npfds); } int mixer_handle_revents(mixer_t* m, struct pollfd *pfds, int npfds) { int err; unsigned short revents; if((err = snd_rawmidi_poll_descriptors_revents(m->output_, pfds, npfds, &revents)) < 0) { error(0, 0, "MIXER: cannot get poll events: %s", snd_strerror(errno)); return -1; } if(pfds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { error(0, 0, "MIXER: got POLLERR, POLLHUP or POLLNVAL"); return -1; } if(!(revents & POLLOUT)) return 0; u_int8_t buf[3] = { 0xB0, 0x00, 0x02 }; int ret = snd_rawmidi_write(m->output_, buf, sizeof(buf)); if(ret == -EAGAIN) return 0; if(ret < 0) { error(0, 0, "MIXER: cannot write to midi port: %s", snd_strerror(ret)); return -1; } assert(ret == sizeof(buf)); // TODO: try again?? if((err = snd_rawmidi_drain(m->output_)) < 0) { error(0, 0, "MIXER: cannot drain output: %s", snd_strerror(err)); return -1; } return 0; }