UNPKG

maia-markov

Version:

Markov analysis and generation functions supporting various applications by Music Artificial Intelligence Algorithms, Inc.

281 lines (255 loc) 10 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = PatternGenerator; var _Analyzer = require('./Analyzer'); var _Analyzer2 = _interopRequireDefault(_Analyzer); var _Generator = require('./Generator'); var _Generator2 = _interopRequireDefault(_Generator); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // Imports var mu = require('maia-util'); // import { state2string, string2state } from './Analyzer' // import get_points_from_states from './Generator' // Constructor for PatternGenerator object function PatternGenerator(_onBgn, _onEnd, _midiBgn, _trans) { // Workaround for JS context peculiarities. // var self = this; this.onBgn = _onBgn; // Ontime of first segment of first occurrence. this.onEnd = _onEnd; // Ontime of last segment of first occurrence. this.midiBgn = _midiBgn; // MIDI note of lowest note in first segment. this.trans = _trans; // Translation vectors for all occurrences of the pattern. this.an = new _Analyzer2.default(); this.gn = new _Generator2.default(); // Possible to return something. // return sth; } // Methods for PatternGenerator object PatternGenerator.prototype = { constructor: PatternGenerator, generate_with_shortest_path: function generate_with_shortest_path(nCand, param) { var self = this; // Shorten a few parameters names. var stateType = param.stateType; var g = param.graph; var idxOn = param.indices.ontime; // Iterate until we have enough candidates. var stateSequences = new Array(nCand); var iCand = 0, nosAttempts = 1; // Set initial and final states. var initialObj = this.get_initial("initial", param); param.randCount = initialObj.randCount; var initialScPair = initialObj.stateContextPair; var finalObj = this.get_initial("final", param); param.randCount = finalObj.randCount; var finalScPair = finalObj.stateContextPair; // Does a (shortest) path exist between initial and final? var initialStr = self.an.state2string(initialScPair[stateType]); // console.log("initialStr:", initialStr) var finalStr = self.an.state2string(finalScPair[stateType]); // console.log("finalStr:", finalStr) var shortPath = g.print_shortest_path(initialStr, finalStr); if (shortPath !== undefined) { stateSequences[iCand] = shortPath; iCand++; } // To get up to the number of candidates we need, allow freedom in new // "final" state and "initial" state partway through the requested passage. while (iCand < nCand) { // Set the "free" initial and final states. var initialFreeObj = this.get_initial("initial", param); param.randCount = initialFreeObj.randCount; var initialFreeScPair = initialFreeObj.stateContextPair; var finalFreeObj = this.get_initial("final", param); param.randCount = finalFreeObj.randCount; var finalFreeScPair = finalFreeObj.stateContextPair; // Do shortest paths exist? var initialFreeStr = self.an.state2string(initialFreeScPair[stateType]); // console.log("initialFreeStr:", initialFreeStr) var finalFreeStr = self.an.state2string(finalFreeScPair[stateType]); // console.log("finalFreeStr:", finalFreeStr) var shortPathA = g.print_shortest_path(initialStr, finalFreeStr); // console.log("shortPathA:", shortPathA) var shortPathB = g.print_shortest_path(initialFreeStr, finalStr); // console.log("shortPathB:", shortPathB) if (shortPathA !== undefined && shortPathB !== undefined) { stateSequences[iCand] = shortPathA.concat(shortPathB); iCand++; } nosAttempts++; } // console.log("stateSequences:", stateSequences) // Convert to state-context pairs. var scPairSequences = stateSequences.map(function (ss) { return self.state_sequence2state_context_pairs(ss, param); }); var pointSets = scPairSequences.map(function (scPairInfo) { return self.gn.get_points_from_states(scPairInfo.stateContextPairs, param); }); // let metrics = self.get_metrics(pointSets) // let estStylisticSuccess = self.estimate_stylistic_success(pointSets, metrics) var psMetrics = pointSets.map(function (ps, idx) { return { "pointSet": ps, "stateCtxPairs": scPairSequences[idx].stateContextPairs // "metrics": metrics[idx], // "estStylisticSuccess": estStylisticSuccess[idx] }; }); // .sort(function(a, b){ // return a.estStylisticSuccess - b.estStylisticSuccess // }) return { "randCount": param.randCount, 'nosAttempts': nosAttempts, "psMetrics": psMetrics }; }, exampleDiscPatt: [{ "label": "A", "otherProperties": "here", "translators": [[0, 0], [12, 0], [28, 0], [40, 0]], "occurrences": [{ "label": "A0", "ontimeBgn": 0, "ontimeEnd": 8, "subsetScore": 1 }, { "label": "A1", "ontimeBgn": 12, "ontimeEnd": 20, "subsetScore": 1 }, { "label": "A2", "ontimeBgn": 28, "ontimeEnd": 36, "subsetScore": 1 }, { "label": "A3", "ontimeBgn": 40, "ontimeEnd": 48, "subsetScore": 1 }] }, { "label": "B", "otherProperties": "here", "translators": [[0, 0], [28, 0]], "occurrences": [{ "label": "B0", "ontimeBgn": 0, "ontimeEnd": 24, "subsetScore": 0 }, { "label": "B1", "ontimeBgn": 28, "ontimeEnd": 52, "subsetScore": 0 }] }], generate_with_patterns: function generate_with_patterns(discoveredPatterns, param) { var self = this; var ontimeWindow = [0, 64]; var winsAddressed = []; // Calculate max subset scores. discoveredPatterns.forEach(function (dp) { dp.maxArgmaxSubsetScore = mu.max_argmax(dp.occurrences.map(function (o) { return o.subsetScore; })); }); // Sort by max subset score. discoveredPatterns = discoveredPatterns.sort(function (x, y) { // DOUBLE-CHECK THIS! return x.maxArgmaxSubsetScore[0] - y.maxArgmaxSubsetScore[0]; }); // Go through each occurrence of each pattern and see if we can address it. discoveredPatterns.forEach(function (dp) { // Address the occurrence that received the maximum subset score. var occ = dp.occurrences[dp.maxArgmaxSubsetScore[1]]; // If we take the example of B0, when we come to it, winsAddressed will // already look like this: // [[0, 8], [12, 20], [28, 36], [40, 48]] // and we'll want the output of generate_time_windows() to be // [[8, 12], [20, 28]], // acknwoledging that these are the time windows belonging to B0 that // still need to be addressed. var winsToAddress = self.generate_time_windows(o.ontimeBgn, o.ontimeEnd, winsAddressed); // Generate content for these time windows. // Paste new content to time windows corresponding to translations of this // pattern (other occurrences), }); // Generate for time windows that remain unaddressed because they do not // feature in any pattern occurrences. }, get_initial: function get_initial(strRequest, aParam) { console.log("strRequest:", strRequest); var stateType = aParam.stateType; var randCount = aParam.randCount; var stateCtxPair = void 0; if (aParam[strRequest] !== null) { // It's an initial provided state or an initial distribution. if (aParam[strRequest][stateType] !== undefined) { // It's an initial provided state. stateCtxPair = aParam[strRequest][stateType]; } else { // It's an initial distribution. stateCtxPair = mu.choose_one(aParam[strRequest]); randCount++; } } else { // Choose an initial state from beat 1 of the stm. stateCtxPair = mu.choose_one(aParam.stm.filter(function (sc) { return sc[stateType][0] == 1; })); randCount++; } return { "randCount": randCount, "stateContextPair": stateCtxPair }; }, state_sequence2state_context_pairs: function state_sequence2state_context_pairs(stateSeq, aParam) { var self = this; var stateType = aParam.stateType; var randCount = aParam.randCount; var stateCtxPairs = stateSeq.map(function (stateStr, idx) { console.log("idx:", idx); var state = self.an.string2state(stateStr); // Locate the state. if (idx == 0) { // Edge case var relIdx = mu.array_object_index_of_array(aParam.initial, state, stateType); return aParam.initial[relIdx]; } else if (idx == stateSeq.length - 1) { // Edge case var _relIdx = mu.array_object_index_of_array(aParam.final, state, stateType); return aParam.final[_relIdx]; } else { // Usual case // Locate previous state in stm. Then choose from among potentially many // continuations with the appropriate state. var _relIdx2 = mu.array_object_index_of_array(aParam.stm, self.an.string2state(stateSeq[idx - 1]), stateType); console.log("relIdx:", _relIdx2); var candCont = aParam.stm[_relIdx2].continuations.filter(function (cont) { // console.log("cont[stateType]:", cont[stateType]) return cont[stateType].equals(state); }); randCount++; return mu.choose_one(candCont); } }) // When allowing freedom in concatenating two shortest paths, one ending in // state A and the other beginning in state B, it is unlikely that B is // among the continuations of A, so an undefined value will have crept in, // which is removed here. .filter(function (scp) { return scp !== undefined; }); // console.log("stateCtxPairs from state_sequence2state_context_pairs():", stateCtxPairs) return { "randCount": randCount, "stateContextPairs": stateCtxPairs }; } };